mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 06:31:52 +00:00
Driver core patches for 4.9-rc1
Here are the "big" driver core patches for 4.9-rc1. Also in here are a number of debugfs fixes that cropped up due to the changes that happened in 4.8 for that filesystem. Overall, nothing major, just a few fixes and cleanups. All of these have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iFYEABECABYFAlfyNw4PHGdyZWdAa3JvYWguY29tAAoJEDFH1A3bLfspLVYAoNXr FXBHGb2tNT/1PLfvUCwd5PqWAJ9Khb5WAHtvjTmEN1zabz45aSbcrA== =Uz6V -----END PGP SIGNATURE----- Merge tag 'driver-core-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core Pull driver core updates from Greg KH: "Here are the "big" driver core patches for 4.9-rc1. Also in here are a number of debugfs fixes that cropped up due to the changes that happened in 4.8 for that filesystem. Overall, nothing major, just a few fixes and cleanups. All of these have been in linux-next with no reported issues" * tag 'driver-core-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (23 commits) drivers: dma-coherent: Move spinlock in dma_alloc_from_coherent() drivers: dma-coherent: Fix DMA coherent size for less than page MAINTAINERS: extend firmware_class maintainer list debugfs: propagate release() call result driver-core: platform: Catch errors from calls to irq_get_irq_data sysfs print name of undiscoverable attribute group carl9170: fix debugfs crashes b43legacy: fix debugfs crash b43: fix debugfs crash debugfs: introduce a public file_operations accessor device core: Remove deprecated create_singlethread_workqueue drivers/base dmam_declare_coherent_memory leaks platform: don't return 0 from platform_get_irq[_byname]() on error cpu: clean up register_cpu func dma-mapping: use vma_pages(). drivers: dma-coherent: use vma_pages(). attribute_container: Fix typo base: soc: make it explicitly non-modular drivers: base: dma-mapping: page align the size when unmap_kernel_range platform driver: fix use-after-free in platform_device_del() ...
This commit is contained in:
commit
9929780e86
@ -4866,6 +4866,7 @@ F: tools/firewire/
|
||||
|
||||
FIRMWARE LOADER (request_firmware)
|
||||
M: Ming Lei <ming.lei@canonical.com>
|
||||
M: Luis R. Rodriguez <mcgrof@kernel.org>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/firmware_class/
|
||||
|
@ -212,6 +212,16 @@ config DEBUG_DEVRES
|
||||
|
||||
If you are unsure about this, Say N here.
|
||||
|
||||
config DEBUG_TEST_DRIVER_REMOVE
|
||||
bool "Test driver remove calls during probe"
|
||||
depends on DEBUG_KERNEL
|
||||
help
|
||||
Say Y here if you want the Driver core to test driver remove functions
|
||||
by calling probe, remove, probe. This tests the remove path without
|
||||
having to unbind the driver or unload the driver module.
|
||||
|
||||
If you are unsure about this, say N here.
|
||||
|
||||
config SYS_HYPERVISOR
|
||||
bool
|
||||
default n
|
||||
|
@ -243,7 +243,7 @@ attribute_container_remove_device(struct device *dev,
|
||||
* @dev: The generic device to run the trigger for
|
||||
* @fn the function to execute for each classdev.
|
||||
*
|
||||
* This funcion is for executing a trigger when you need to know both
|
||||
* This function is for executing a trigger when you need to know both
|
||||
* the container and the classdev. If you only care about the
|
||||
* container, then use attribute_container_trigger() instead.
|
||||
*/
|
||||
|
@ -836,11 +836,29 @@ static struct kobject *get_device_parent(struct device *dev,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool live_in_glue_dir(struct kobject *kobj,
|
||||
struct device *dev)
|
||||
{
|
||||
if (!kobj || !dev->class ||
|
||||
kobj->kset != &dev->class->p->glue_dirs)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline struct kobject *get_glue_dir(struct device *dev)
|
||||
{
|
||||
return dev->kobj.parent;
|
||||
}
|
||||
|
||||
/*
|
||||
* make sure cleaning up dir as the last step, we need to make
|
||||
* sure .release handler of kobject is run with holding the
|
||||
* global lock
|
||||
*/
|
||||
static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir)
|
||||
{
|
||||
/* see if we live in a "glue" directory */
|
||||
if (!glue_dir || !dev->class ||
|
||||
glue_dir->kset != &dev->class->p->glue_dirs)
|
||||
if (!live_in_glue_dir(glue_dir, dev))
|
||||
return;
|
||||
|
||||
mutex_lock(&gdp_mutex);
|
||||
@ -848,11 +866,6 @@ static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir)
|
||||
mutex_unlock(&gdp_mutex);
|
||||
}
|
||||
|
||||
static void cleanup_device_parent(struct device *dev)
|
||||
{
|
||||
cleanup_glue_dir(dev, dev->kobj.parent);
|
||||
}
|
||||
|
||||
static int device_add_class_symlinks(struct device *dev)
|
||||
{
|
||||
struct device_node *of_node = dev_of_node(dev);
|
||||
@ -1028,6 +1041,7 @@ int device_add(struct device *dev)
|
||||
struct kobject *kobj;
|
||||
struct class_interface *class_intf;
|
||||
int error = -EINVAL;
|
||||
struct kobject *glue_dir = NULL;
|
||||
|
||||
dev = get_device(dev);
|
||||
if (!dev)
|
||||
@ -1072,8 +1086,10 @@ int device_add(struct device *dev)
|
||||
/* first, register with generic layer. */
|
||||
/* we require the name to be set before, and pass NULL */
|
||||
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
|
||||
if (error)
|
||||
if (error) {
|
||||
glue_dir = get_glue_dir(dev);
|
||||
goto Error;
|
||||
}
|
||||
|
||||
/* notify platform of device entry */
|
||||
if (platform_notify)
|
||||
@ -1154,9 +1170,10 @@ done:
|
||||
device_remove_file(dev, &dev_attr_uevent);
|
||||
attrError:
|
||||
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
|
||||
glue_dir = get_glue_dir(dev);
|
||||
kobject_del(&dev->kobj);
|
||||
Error:
|
||||
cleanup_device_parent(dev);
|
||||
cleanup_glue_dir(dev, glue_dir);
|
||||
put_device(parent);
|
||||
name_error:
|
||||
kfree(dev->p);
|
||||
@ -1232,6 +1249,7 @@ EXPORT_SYMBOL_GPL(put_device);
|
||||
void device_del(struct device *dev)
|
||||
{
|
||||
struct device *parent = dev->parent;
|
||||
struct kobject *glue_dir = NULL;
|
||||
struct class_interface *class_intf;
|
||||
|
||||
/* Notify clients of device removal. This call must come
|
||||
@ -1277,8 +1295,9 @@ void device_del(struct device *dev)
|
||||
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
|
||||
BUS_NOTIFY_REMOVED_DEVICE, dev);
|
||||
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
|
||||
cleanup_device_parent(dev);
|
||||
glue_dir = get_glue_dir(dev);
|
||||
kobject_del(&dev->kobj);
|
||||
cleanup_glue_dir(dev, glue_dir);
|
||||
put_device(parent);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_del);
|
||||
|
@ -371,12 +371,13 @@ int register_cpu(struct cpu *cpu, int num)
|
||||
if (cpu->hotpluggable)
|
||||
cpu->dev.groups = hotplugable_cpu_attr_groups;
|
||||
error = device_register(&cpu->dev);
|
||||
if (!error)
|
||||
per_cpu(cpu_sys_devices, num) = &cpu->dev;
|
||||
if (!error)
|
||||
register_cpu_under_node(num, cpu_to_node(num));
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return error;
|
||||
per_cpu(cpu_sys_devices, num) = &cpu->dev;
|
||||
register_cpu_under_node(num, cpu_to_node(num));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct device *get_cpu_device(unsigned cpu)
|
||||
|
@ -51,7 +51,6 @@
|
||||
static DEFINE_MUTEX(deferred_probe_mutex);
|
||||
static LIST_HEAD(deferred_probe_pending_list);
|
||||
static LIST_HEAD(deferred_probe_active_list);
|
||||
static struct workqueue_struct *deferred_wq;
|
||||
static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
|
||||
|
||||
/*
|
||||
@ -175,7 +174,7 @@ static void driver_deferred_probe_trigger(void)
|
||||
* Kick the re-probe thread. It may already be scheduled, but it is
|
||||
* safe to kick it again.
|
||||
*/
|
||||
queue_work(deferred_wq, &deferred_probe_work);
|
||||
schedule_work(&deferred_probe_work);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -211,14 +210,10 @@ void device_unblock_probing(void)
|
||||
*/
|
||||
static int deferred_probe_initcall(void)
|
||||
{
|
||||
deferred_wq = create_singlethread_workqueue("deferwq");
|
||||
if (WARN_ON(!deferred_wq))
|
||||
return -ENOMEM;
|
||||
|
||||
driver_deferred_probe_enable = true;
|
||||
driver_deferred_probe_trigger();
|
||||
/* Sort as many dependencies as possible before exiting initcalls */
|
||||
flush_workqueue(deferred_wq);
|
||||
flush_work(&deferred_probe_work);
|
||||
return 0;
|
||||
}
|
||||
late_initcall(deferred_probe_initcall);
|
||||
@ -329,6 +324,7 @@ static int really_probe(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
int ret = -EPROBE_DEFER;
|
||||
int local_trigger_count = atomic_read(&deferred_trigger_count);
|
||||
bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE);
|
||||
|
||||
if (defer_all_probes) {
|
||||
/*
|
||||
@ -346,6 +342,7 @@ static int really_probe(struct device *dev, struct device_driver *drv)
|
||||
drv->bus->name, __func__, drv->name, dev_name(dev));
|
||||
WARN_ON(!list_empty(&dev->devres_head));
|
||||
|
||||
re_probe:
|
||||
dev->driver = drv;
|
||||
|
||||
/* If using pinctrl, bind pins now before probing */
|
||||
@ -383,6 +380,25 @@ static int really_probe(struct device *dev, struct device_driver *drv)
|
||||
goto probe_failed;
|
||||
}
|
||||
|
||||
if (test_remove) {
|
||||
test_remove = false;
|
||||
|
||||
if (dev->bus && dev->bus->remove)
|
||||
dev->bus->remove(dev);
|
||||
else if (drv->remove)
|
||||
drv->remove(dev);
|
||||
|
||||
devres_release_all(dev);
|
||||
driver_sysfs_remove(dev);
|
||||
dev->driver = NULL;
|
||||
dev_set_drvdata(dev, NULL);
|
||||
if (dev->pm_domain && dev->pm_domain->dismiss)
|
||||
dev->pm_domain->dismiss(dev);
|
||||
pm_runtime_reinit(dev);
|
||||
|
||||
goto re_probe;
|
||||
}
|
||||
|
||||
pinctrl_init_done(dev);
|
||||
|
||||
if (dev->pm_domain && dev->pm_domain->sync)
|
||||
@ -460,8 +476,7 @@ int driver_probe_done(void)
|
||||
void wait_for_device_probe(void)
|
||||
{
|
||||
/* wait for the deferred probe workqueue to finish */
|
||||
if (driver_deferred_probe_enable)
|
||||
flush_workqueue(deferred_wq);
|
||||
flush_work(&deferred_probe_work);
|
||||
|
||||
/* wait for the known devices to complete their probing */
|
||||
wait_event(probe_waitqueue, atomic_read(&probe_count) == 0);
|
||||
|
@ -165,6 +165,7 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size,
|
||||
int order = get_order(size);
|
||||
unsigned long flags;
|
||||
int pageno;
|
||||
int dma_memory_map;
|
||||
|
||||
if (!dev)
|
||||
return 0;
|
||||
@ -187,11 +188,12 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size,
|
||||
*/
|
||||
*dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
|
||||
*ret = mem->virt_base + (pageno << PAGE_SHIFT);
|
||||
if (mem->flags & DMA_MEMORY_MAP)
|
||||
dma_memory_map = (mem->flags & DMA_MEMORY_MAP);
|
||||
spin_unlock_irqrestore(&mem->spinlock, flags);
|
||||
if (dma_memory_map)
|
||||
memset(*ret, 0, size);
|
||||
else
|
||||
memset_io(*ret, 0, size);
|
||||
spin_unlock_irqrestore(&mem->spinlock, flags);
|
||||
|
||||
return 1;
|
||||
|
||||
@ -261,8 +263,8 @@ int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
|
||||
(mem->virt_base + (mem->size << PAGE_SHIFT))) {
|
||||
unsigned long off = vma->vm_pgoff;
|
||||
int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
||||
int user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
|
||||
int count = size >> PAGE_SHIFT;
|
||||
int user_count = vma_pages(vma);
|
||||
int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
||||
|
||||
*ret = -ENXIO;
|
||||
if (off < count && user_count <= count - off) {
|
||||
|
@ -198,10 +198,13 @@ int dmam_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
|
||||
|
||||
rc = dma_declare_coherent_memory(dev, phys_addr, device_addr, size,
|
||||
flags);
|
||||
if (rc == 0)
|
||||
if (rc) {
|
||||
devres_add(dev, res);
|
||||
else
|
||||
rc = 0;
|
||||
} else {
|
||||
devres_free(res);
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -247,7 +250,7 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||
{
|
||||
int ret = -ENXIO;
|
||||
#if defined(CONFIG_MMU) && !defined(CONFIG_ARCH_NO_COHERENT_DMA_MMAP)
|
||||
unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
|
||||
unsigned long user_count = vma_pages(vma);
|
||||
unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
||||
unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
|
||||
unsigned long off = vma->vm_pgoff;
|
||||
@ -334,7 +337,7 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
|
||||
return;
|
||||
}
|
||||
|
||||
unmap_kernel_range((unsigned long)cpu_addr, size);
|
||||
unmap_kernel_range((unsigned long)cpu_addr, PAGE_ALIGN(size));
|
||||
vunmap(cpu_addr);
|
||||
}
|
||||
#endif
|
||||
|
@ -97,7 +97,7 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
|
||||
int ret;
|
||||
|
||||
ret = of_irq_get(dev->dev.of_node, num);
|
||||
if (ret >= 0 || ret == -EPROBE_DEFER)
|
||||
if (ret > 0 || ret == -EPROBE_DEFER)
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -108,9 +108,14 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
|
||||
* IORESOURCE_BITS correspond 1-to-1 to the IRQF_TRIGGER*
|
||||
* settings.
|
||||
*/
|
||||
if (r && r->flags & IORESOURCE_BITS)
|
||||
irqd_set_trigger_type(irq_get_irq_data(r->start),
|
||||
r->flags & IORESOURCE_BITS);
|
||||
if (r && r->flags & IORESOURCE_BITS) {
|
||||
struct irq_data *irqd;
|
||||
|
||||
irqd = irq_get_irq_data(r->start);
|
||||
if (!irqd)
|
||||
return -ENXIO;
|
||||
irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS);
|
||||
}
|
||||
|
||||
return r ? r->start : -ENXIO;
|
||||
#endif
|
||||
@ -175,7 +180,7 @@ int platform_get_irq_byname(struct platform_device *dev, const char *name)
|
||||
int ret;
|
||||
|
||||
ret = of_irq_get_byname(dev->dev.of_node, name);
|
||||
if (ret >= 0 || ret == -EPROBE_DEFER)
|
||||
if (ret > 0 || ret == -EPROBE_DEFER)
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -434,6 +439,7 @@ void platform_device_del(struct platform_device *pdev)
|
||||
int i;
|
||||
|
||||
if (pdev) {
|
||||
device_remove_properties(&pdev->dev);
|
||||
device_del(&pdev->dev);
|
||||
|
||||
if (pdev->id_auto) {
|
||||
@ -446,8 +452,6 @@ void platform_device_del(struct platform_device *pdev)
|
||||
if (r->parent)
|
||||
release_resource(r);
|
||||
}
|
||||
|
||||
device_remove_properties(&pdev->dev);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(platform_device_del);
|
||||
|
@ -6,7 +6,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/slab.h>
|
||||
@ -160,11 +159,3 @@ static int __init soc_bus_register(void)
|
||||
return bus_register(&soc_bus_type);
|
||||
}
|
||||
core_initcall(soc_bus_register);
|
||||
|
||||
static void __exit soc_bus_unregister(void)
|
||||
{
|
||||
ida_destroy(&soc_ida);
|
||||
|
||||
bus_unregister(&soc_bus_type);
|
||||
}
|
||||
module_exit(soc_bus_unregister);
|
||||
|
@ -75,7 +75,8 @@ static ssize_t carl9170_debugfs_read(struct file *file, char __user *userbuf,
|
||||
|
||||
if (!ar)
|
||||
return -ENODEV;
|
||||
dfops = container_of(file->f_op, struct carl9170_debugfs_fops, fops);
|
||||
dfops = container_of(debugfs_real_fops(file),
|
||||
struct carl9170_debugfs_fops, fops);
|
||||
|
||||
if (!dfops->read)
|
||||
return -ENOSYS;
|
||||
@ -127,7 +128,8 @@ static ssize_t carl9170_debugfs_write(struct file *file,
|
||||
|
||||
if (!ar)
|
||||
return -ENODEV;
|
||||
dfops = container_of(file->f_op, struct carl9170_debugfs_fops, fops);
|
||||
dfops = container_of(debugfs_real_fops(file),
|
||||
struct carl9170_debugfs_fops, fops);
|
||||
|
||||
if (!dfops->write)
|
||||
return -ENOSYS;
|
||||
|
@ -524,7 +524,8 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
|
||||
dfops = container_of(debugfs_real_fops(file),
|
||||
struct b43_debugfs_fops, fops);
|
||||
if (!dfops->read) {
|
||||
err = -ENOSYS;
|
||||
goto out_unlock;
|
||||
@ -585,7 +586,8 @@ static ssize_t b43_debugfs_write(struct file *file,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
|
||||
dfops = container_of(debugfs_real_fops(file),
|
||||
struct b43_debugfs_fops, fops);
|
||||
if (!dfops->write) {
|
||||
err = -ENOSYS;
|
||||
goto out_unlock;
|
||||
|
@ -221,7 +221,8 @@ static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops);
|
||||
dfops = container_of(debugfs_real_fops(file),
|
||||
struct b43legacy_debugfs_fops, fops);
|
||||
if (!dfops->read) {
|
||||
err = -ENOSYS;
|
||||
goto out_unlock;
|
||||
@ -287,7 +288,8 @@ static ssize_t b43legacy_debugfs_write(struct file *file,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops);
|
||||
dfops = container_of(debugfs_real_fops(file),
|
||||
struct b43legacy_debugfs_fops, fops);
|
||||
if (!dfops->write) {
|
||||
err = -ENOSYS;
|
||||
goto out_unlock;
|
||||
|
@ -97,9 +97,6 @@ EXPORT_SYMBOL_GPL(debugfs_use_file_finish);
|
||||
|
||||
#define F_DENTRY(filp) ((filp)->f_path.dentry)
|
||||
|
||||
#define REAL_FOPS_DEREF(dentry) \
|
||||
((const struct file_operations *)(dentry)->d_fsdata)
|
||||
|
||||
static int open_proxy_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
const struct dentry *dentry = F_DENTRY(filp);
|
||||
@ -112,7 +109,7 @@ static int open_proxy_open(struct inode *inode, struct file *filp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
real_fops = REAL_FOPS_DEREF(dentry);
|
||||
real_fops = debugfs_real_fops(filp);
|
||||
real_fops = fops_get(real_fops);
|
||||
if (!real_fops) {
|
||||
/* Huh? Module did not clean up after itself at exit? */
|
||||
@ -143,7 +140,7 @@ static ret_type full_proxy_ ## name(proto) \
|
||||
{ \
|
||||
const struct dentry *dentry = F_DENTRY(filp); \
|
||||
const struct file_operations *real_fops = \
|
||||
REAL_FOPS_DEREF(dentry); \
|
||||
debugfs_real_fops(filp); \
|
||||
int srcu_idx; \
|
||||
ret_type r; \
|
||||
\
|
||||
@ -176,7 +173,7 @@ static unsigned int full_proxy_poll(struct file *filp,
|
||||
struct poll_table_struct *wait)
|
||||
{
|
||||
const struct dentry *dentry = F_DENTRY(filp);
|
||||
const struct file_operations *real_fops = REAL_FOPS_DEREF(dentry);
|
||||
const struct file_operations *real_fops = debugfs_real_fops(filp);
|
||||
int srcu_idx;
|
||||
unsigned int r = 0;
|
||||
|
||||
@ -193,7 +190,7 @@ static unsigned int full_proxy_poll(struct file *filp,
|
||||
static int full_proxy_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
const struct dentry *dentry = F_DENTRY(filp);
|
||||
const struct file_operations *real_fops = REAL_FOPS_DEREF(dentry);
|
||||
const struct file_operations *real_fops = debugfs_real_fops(filp);
|
||||
const struct file_operations *proxy_fops = filp->f_op;
|
||||
int r = 0;
|
||||
|
||||
@ -209,7 +206,7 @@ static int full_proxy_release(struct inode *inode, struct file *filp)
|
||||
replace_fops(filp, d_inode(dentry)->i_fop);
|
||||
kfree((void *)proxy_fops);
|
||||
fops_put(real_fops);
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __full_proxy_fops_init(struct file_operations *proxy_fops,
|
||||
@ -241,7 +238,7 @@ static int full_proxy_open(struct inode *inode, struct file *filp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
real_fops = REAL_FOPS_DEREF(dentry);
|
||||
real_fops = debugfs_real_fops(filp);
|
||||
real_fops = fops_get(real_fops);
|
||||
if (!real_fops) {
|
||||
/* Huh? Module did not cleanup after itself at exit? */
|
||||
|
@ -19,8 +19,4 @@ extern const struct file_operations debugfs_noop_file_operations;
|
||||
extern const struct file_operations debugfs_open_proxy_file_operations;
|
||||
extern const struct file_operations debugfs_full_proxy_file_operations;
|
||||
|
||||
struct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode,
|
||||
struct dentry *parent, void *data,
|
||||
const struct file_operations *fops);
|
||||
|
||||
#endif /* _DEBUGFS_INTERNAL_H_ */
|
||||
|
@ -233,8 +233,8 @@ void sysfs_remove_group(struct kobject *kobj,
|
||||
kn = kernfs_find_and_get(parent, grp->name);
|
||||
if (!kn) {
|
||||
WARN(!kn, KERN_WARNING
|
||||
"sysfs group %p not found for kobject '%s'\n",
|
||||
grp, kobject_name(kobj));
|
||||
"sysfs group '%s' not found for kobject '%s'\n",
|
||||
grp->name, kobject_name(kobj));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
@ -45,6 +45,23 @@ extern struct dentry *arch_debugfs_dir;
|
||||
|
||||
extern struct srcu_struct debugfs_srcu;
|
||||
|
||||
/**
|
||||
* debugfs_real_fops - getter for the real file operation
|
||||
* @filp: a pointer to a struct file
|
||||
*
|
||||
* Must only be called under the protection established by
|
||||
* debugfs_use_file_start().
|
||||
*/
|
||||
static inline const struct file_operations *debugfs_real_fops(struct file *filp)
|
||||
__must_hold(&debugfs_srcu)
|
||||
{
|
||||
/*
|
||||
* Neither the pointer to the struct file_operations, nor its
|
||||
* contents ever change -- srcu_dereference() is not needed here.
|
||||
*/
|
||||
return filp->f_path.dentry->d_fsdata;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
||||
struct dentry *debugfs_create_file(const char *name, umode_t mode,
|
||||
|
Loading…
Reference in New Issue
Block a user