From 7d568a8383bbb9c1f5167781075906acb2bb1550 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Apr 2014 11:07:30 -0400 Subject: [PATCH 01/15] kernfs: implement kernfs_root->supers list Currently, there's no way to find out which super_blocks are associated with a given kernfs_root. Let's implement it - the planned inotify extension to kernfs_notify() needs it. Make kernfs_super_info point back to the super_block and chain it at kernfs_root->supers. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 1 + fs/kernfs/kernfs-internal.h | 5 +++++ fs/kernfs/mount.c | 11 +++++++++++ include/linux/kernfs.h | 4 ++++ 4 files changed, 21 insertions(+) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 78f3403300af..43aa97988c31 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -711,6 +711,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops, return ERR_PTR(-ENOMEM); ida_init(&root->ino_ida); + INIT_LIST_HEAD(&root->supers); kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO, KERNFS_DIR); diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 8be13b2a079b..dc84a3ef9ca2 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -49,6 +49,8 @@ static inline struct kernfs_root *kernfs_root(struct kernfs_node *kn) * mount.c */ struct kernfs_super_info { + struct super_block *sb; + /* * The root associated with this super_block. Each super_block is * identified by the root and ns it's associated with. @@ -62,6 +64,9 @@ struct kernfs_super_info { * an array and compare kernfs_node tag against every entry. */ const void *ns; + + /* anchored at kernfs_root->supers, protected by kernfs_mutex */ + struct list_head node; }; #define kernfs_info(SB) ((struct kernfs_super_info *)(SB->s_fs_info)) diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index 6a5f04ac8704..f25a7c0c3cdc 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c @@ -68,6 +68,7 @@ static int kernfs_fill_super(struct super_block *sb) struct inode *inode; struct dentry *root; + info->sb = sb; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = SYSFS_MAGIC; @@ -166,12 +167,18 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, *new_sb_created = !sb->s_root; if (!sb->s_root) { + struct kernfs_super_info *info = kernfs_info(sb); + error = kernfs_fill_super(sb); if (error) { deactivate_locked_super(sb); return ERR_PTR(error); } sb->s_flags |= MS_ACTIVE; + + mutex_lock(&kernfs_mutex); + list_add(&info->node, &root->supers); + mutex_unlock(&kernfs_mutex); } return dget(sb->s_root); @@ -190,6 +197,10 @@ void kernfs_kill_sb(struct super_block *sb) struct kernfs_super_info *info = kernfs_info(sb); struct kernfs_node *root_kn = sb->s_root->d_fsdata; + mutex_lock(&kernfs_mutex); + list_del(&info->node); + mutex_unlock(&kernfs_mutex); + /* * Remove the superblock from fs_supers/s_instances * so we can't find it, before freeing kernfs_super_info. diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index b0122dc6f96a..589318b73e61 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -144,6 +144,10 @@ struct kernfs_root { /* private fields, do not use outside kernfs proper */ struct ida ino_ida; struct kernfs_syscall_ops *syscall_ops; + + /* list of kernfs_super_info of this root, protected by kernfs_mutex */ + struct list_head supers; + wait_queue_head_t deactivate_waitq; }; From d911d98748018f7c8facc035ba39c30f5cce6f9c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Apr 2014 11:07:31 -0400 Subject: [PATCH 02/15] kernfs: make kernfs_notify() trigger inotify events too kernfs_notify() is used to indicate either new data is available or the content of a file has changed. It currently only triggers poll which may not be the most convenient to monitor especially when there are a lot to monitor. Let's hook it up to fsnotify too so that the events can be monitored via inotify too. fsnotify_modify() requires file * but kernfs_notify() doesn't have any specific file associated; however, we can walk all super_blocks associated with a kernfs_root and as kernfs always associate one ino with inode and one dentry with an inode, it's trivial to look up the dentry associated with a given kernfs_node. As any active monitor would pin dentry, just looking up existing dentry is enough. This patch looks up the dentry associated with the specified kernfs_node and generates events equivalent to fsnotify_modify(). Note that as fsnotify doesn't provide fsnotify_modify() equivalent which can be called with dentry, kernfs_notify() directly calls fsnotify_parent() and fsnotify(). It might be better to add a wrapper in fsnotify.h instead. Signed-off-by: Tejun Heo Cc: John McCutchan Cc: Robert Love Cc: Eric Paris Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 8034706a7af8..98bacd9ea7fd 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "kernfs-internal.h" @@ -785,20 +786,48 @@ static unsigned int kernfs_fop_poll(struct file *filp, poll_table *wait) */ void kernfs_notify(struct kernfs_node *kn) { + struct kernfs_root *root = kernfs_root(kn); struct kernfs_open_node *on; + struct kernfs_super_info *info; unsigned long flags; + if (WARN_ON(kernfs_type(kn) != KERNFS_FILE)) + return; + + /* kick poll */ spin_lock_irqsave(&kernfs_open_node_lock, flags); - if (!WARN_ON(kernfs_type(kn) != KERNFS_FILE)) { - on = kn->attr.open; - if (on) { - atomic_inc(&on->event); - wake_up_interruptible(&on->poll); - } + on = kn->attr.open; + if (on) { + atomic_inc(&on->event); + wake_up_interruptible(&on->poll); } spin_unlock_irqrestore(&kernfs_open_node_lock, flags); + + /* kick fsnotify */ + mutex_lock(&kernfs_mutex); + + list_for_each_entry(info, &root->supers, node) { + struct inode *inode; + struct dentry *dentry; + + inode = ilookup(info->sb, kn->ino); + if (!inode) + continue; + + dentry = d_find_any_alias(inode); + if (dentry) { + fsnotify_parent(NULL, dentry, FS_MODIFY); + fsnotify(inode, FS_MODIFY, inode, FSNOTIFY_EVENT_INODE, + NULL, 0); + dput(dentry); + } + + iput(inode); + } + + mutex_unlock(&kernfs_mutex); } EXPORT_SYMBOL_GPL(kernfs_notify); From 86d56134f1b67d0c18025ba5cade95c048ed528d Mon Sep 17 00:00:00 2001 From: Michael Marineau Date: Thu, 10 Apr 2014 14:09:31 -0700 Subject: [PATCH 03/15] kobject: Make support for uevent_helper optional. Support for uevent_helper, aka hotplug, is not required on many systems these days but it can still be enabled via sysfs or sysctl. Reported-by: Darren Shepherd Signed-off-by: Michael Marineau Signed-off-by: Greg Kroah-Hartman --- drivers/base/Kconfig | 17 +++++++++++------ include/linux/kobject.h | 2 ++ kernel/ksysfs.c | 5 ++++- kernel/sysctl.c | 4 ++-- lib/kobject_uevent.c | 6 ++++++ 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 8fa8deab6449..4b7b4522b64f 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -1,10 +1,10 @@ menu "Generic Driver Options" -config UEVENT_HELPER_PATH - string "path to uevent helper" - default "" +config UEVENT_HELPER + bool "Support for uevent helper" + default y help - Path to uevent helper program forked by the kernel for + The uevent helper program is forked by the kernel for every uevent. Before the switch to the netlink-based uevent source, this was used to hook hotplug scripts into kernel device events. It @@ -15,8 +15,13 @@ config UEVENT_HELPER_PATH that it creates a high system load, or on smaller systems it is known to create out-of-memory situations during bootup. - To disable user space helper program execution at early boot - time specify an empty string here. This setting can be altered +config UEVENT_HELPER_PATH + string "path to uevent helper" + depends on UEVENT_HELPER + default "" + help + To disable user space helper program execution at by default + specify an empty string here. This setting can still be altered via /proc/sys/kernel/hotplug or via /sys/kernel/uevent_helper later at runtime. diff --git a/include/linux/kobject.h b/include/linux/kobject.h index f896a33e8341..2d61b909f414 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -32,8 +32,10 @@ #define UEVENT_NUM_ENVP 32 /* number of env pointers */ #define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ +#ifdef CONFIG_UEVENT_HELPER /* path to the userspace helper executed on an event */ extern char uevent_helper[]; +#endif /* counter to tag the uevent, read only except for the kobject core */ extern u64 uevent_seqnum; diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index 2495a9b14ac8..6683ccef9fff 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -37,6 +37,7 @@ static ssize_t uevent_seqnum_show(struct kobject *kobj, } KERNEL_ATTR_RO(uevent_seqnum); +#ifdef CONFIG_UEVENT_HELPER /* uevent helper program, used during early boot */ static ssize_t uevent_helper_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -56,7 +57,7 @@ static ssize_t uevent_helper_store(struct kobject *kobj, return count; } KERNEL_ATTR_RW(uevent_helper); - +#endif #ifdef CONFIG_PROFILING static ssize_t profiling_show(struct kobject *kobj, @@ -189,7 +190,9 @@ EXPORT_SYMBOL_GPL(kernel_kobj); static struct attribute * kernel_attrs[] = { &fscaps_attr.attr, &uevent_seqnum_attr.attr, +#ifdef CONFIG_UEVENT_HELPER &uevent_helper_attr.attr, +#endif #ifdef CONFIG_PROFILING &profiling_attr.attr, #endif diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 74f5b580fe34..bc966a8ffc3e 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -643,7 +643,7 @@ static struct ctl_table kern_table[] = { .extra2 = &one, }, #endif - +#ifdef CONFIG_UEVENT_HELPER { .procname = "hotplug", .data = &uevent_helper, @@ -651,7 +651,7 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dostring, }, - +#endif #ifdef CONFIG_CHR_DEV_SG { .procname = "sg-big-buff", diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 4e3bd71bd949..9ebf9e20de53 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -29,7 +29,9 @@ u64 uevent_seqnum; +#ifdef CONFIG_UEVENT_HELPER char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; +#endif #ifdef CONFIG_NET struct uevent_sock { struct list_head list; @@ -109,6 +111,7 @@ static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data) } #endif +#ifdef CONFIG_UEVENT_HELPER static int kobj_usermode_filter(struct kobject *kobj) { const struct kobj_ns_type_operations *ops; @@ -147,6 +150,7 @@ static void cleanup_uevent_env(struct subprocess_info *info) { kfree(info->data); } +#endif /** * kobject_uevent_env - send an uevent with environmental data @@ -323,6 +327,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, #endif mutex_unlock(&uevent_sock_mutex); +#ifdef CONFIG_UEVENT_HELPER /* call uevent_helper, usually only enabled during early boot */ if (uevent_helper[0] && !kobj_usermode_filter(kobj)) { struct subprocess_info *info; @@ -347,6 +352,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, env = NULL; /* freed by cleanup_uevent_env */ } } +#endif exit: kfree(devpath); From 609013204fddd25ffde8ff5e1f32d72314397e14 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 23 May 2014 22:29:32 +0200 Subject: [PATCH 04/15] lib/devres.c: use dev in devm_request_and_ioremap devm_request_and_ioremap was the only function to use device instead of dev. This fixes kernel-doc warning. Cc: Andrew Morton Signed-off-by: Fabian Frederick Signed-off-by: Greg Kroah-Hartman --- lib/devres.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/devres.c b/lib/devres.c index 2f16c133fd36..c7596bb54cf3 100644 --- a/lib/devres.c +++ b/lib/devres.c @@ -157,12 +157,12 @@ EXPORT_SYMBOL(devm_ioremap_resource); * if (!base) * return -EADDRNOTAVAIL; */ -void __iomem *devm_request_and_ioremap(struct device *device, +void __iomem *devm_request_and_ioremap(struct device *dev, struct resource *res) { void __iomem *dest_ptr; - dest_ptr = devm_ioremap_resource(device, res); + dest_ptr = devm_ioremap_resource(dev, res); if (IS_ERR(dest_ptr)) return NULL; From 5cbb00cc4aae56378bf5376a62b4df3b89c28f92 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 23 May 2014 22:30:50 +0200 Subject: [PATCH 05/15] lib/devres.c: fix checkpatch warnings Fix 3 checkpatch warnings: 'ERROR: "foo * const * bar" should be "foo * const *bar"' Cc: Andrew Morton Signed-off-by: Fabian Frederick Signed-off-by: Greg Kroah-Hartman --- lib/devres.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/devres.c b/lib/devres.c index c7596bb54cf3..f562bf6ff71d 100644 --- a/lib/devres.c +++ b/lib/devres.c @@ -194,7 +194,7 @@ static int devm_ioport_map_match(struct device *dev, void *res, * Managed ioport_map(). Map is automatically unmapped on driver * detach. */ -void __iomem * devm_ioport_map(struct device *dev, unsigned long port, +void __iomem *devm_ioport_map(struct device *dev, unsigned long port, unsigned int nr) { void __iomem **ptr, *addr; @@ -265,7 +265,7 @@ static void pcim_iomap_release(struct device *gendev, void *res) * be safely called without context and guaranteed to succed once * allocated. */ -void __iomem * const * pcim_iomap_table(struct pci_dev *pdev) +void __iomem * const *pcim_iomap_table(struct pci_dev *pdev) { struct pcim_iomap_devres *dr, *new_dr; @@ -290,7 +290,7 @@ EXPORT_SYMBOL(pcim_iomap_table); * Managed pci_iomap(). Map is automatically unmapped on driver * detach. */ -void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen) +void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen) { void __iomem **tbl; From 1bb6c08abfb653ce6e65d8ab4ddef403227afedf Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 14 Apr 2014 12:54:47 +0200 Subject: [PATCH 06/15] driver core: Move driver_data back to struct device Having to allocate memory as part of dev_set_drvdata() is a problem because that memory may never get freed if the device itself is not created. So move driver_data back to struct device. This is a partial revert of commit b4028437. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 3 --- drivers/base/dd.c | 13 +++---------- include/linux/device.h | 3 +++ 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/base/base.h b/drivers/base/base.h index 24f424249d9b..251c5d30f963 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -63,8 +63,6 @@ struct driver_private { * binding of drivers which were unable to get all the resources needed by * the device; typically because it depends on another driver getting * probed first. - * @driver_data - private pointer for driver specific info. Will turn into a - * list soon. * @device - pointer back to the struct class that this structure is * associated with. * @@ -76,7 +74,6 @@ struct device_private { struct klist_node knode_driver; struct klist_node knode_bus; struct list_head deferred_probe; - void *driver_data; struct device *device; }; #define to_device_private_parent(obj) \ diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 62ec61e8f84a..d14b6e895896 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -594,22 +594,15 @@ void driver_detach(struct device_driver *drv) */ void *dev_get_drvdata(const struct device *dev) { - if (dev && dev->p) - return dev->p->driver_data; + if (dev) + return dev->driver_data; return NULL; } EXPORT_SYMBOL(dev_get_drvdata); int dev_set_drvdata(struct device *dev, void *data) { - int error; - - if (!dev->p) { - error = device_private_init(dev); - if (error) - return error; - } - dev->p->driver_data = data; + dev->driver_data = data; return 0; } EXPORT_SYMBOL(dev_set_drvdata); diff --git a/include/linux/device.h b/include/linux/device.h index d1d1c055b48e..5c94ac3e7972 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -673,6 +673,7 @@ struct acpi_dev_node { * variants, which GPIO pins act in what additional roles, and so * on. This shrinks the "Board Support Packages" (BSPs) and * minimizes board-specific #ifdefs in drivers. + * @driver_data: Private pointer for driver specific info. * @power: For device power management. * See Documentation/power/devices.txt for details. * @pm_domain: Provide callbacks that are executed during system suspend, @@ -734,6 +735,8 @@ struct device { device */ void *platform_data; /* Platform specific data, device core doesn't touch it */ + void *driver_data; /* Driver data, set and get with + dev_set/get_drvdata */ struct dev_pm_info power; struct dev_pm_domain *pm_domain; From 8283b4919e00fb110ac338d6b9984ca92d5030fa Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 14 Apr 2014 12:55:38 +0200 Subject: [PATCH 07/15] driver core: dev_set_drvdata can no longer fail So there is no point in checking its return value, which will soon disappear. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/exynos-iommu.c | 7 +------ drivers/vfio/vfio.c | 8 +------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 074018979cdf..b97a6ab95a9d 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -542,12 +542,7 @@ static int exynos_sysmmu_probe(struct platform_device *pdev) goto err_alloc; } - ret = dev_set_drvdata(dev, data); - if (ret) { - dev_dbg(dev, "Unabled to initialize driver data\n"); - goto err_init; - } - + dev_set_drvdata(dev, data); data->nsfrs = pdev->num_resources / 2; data->sfrbases = kmalloc(sizeof(*data->sfrbases) * data->nsfrs, GFP_KERNEL); diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 512f479d8a50..f018d8d0f975 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -349,7 +349,6 @@ struct vfio_device *vfio_group_create_device(struct vfio_group *group, void *device_data) { struct vfio_device *device; - int ret; device = kzalloc(sizeof(*device), GFP_KERNEL); if (!device) @@ -360,12 +359,7 @@ struct vfio_device *vfio_group_create_device(struct vfio_group *group, device->group = group; device->ops = ops; device->device_data = device_data; - - ret = dev_set_drvdata(dev, device); - if (ret) { - kfree(device); - return ERR_PTR(ret); - } + dev_set_drvdata(dev, device); /* No need to get group_lock, caller has group reference */ vfio_group_get(group); From 2c1f1ff0f0d9e0df8c9b6d3697ac250900091541 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 14 Apr 2014 12:56:34 +0200 Subject: [PATCH 08/15] driver core: dev_set_drvdata returns void dev_set_drvdata can no longer fail, so it could return void. All callers have hopefully been updated to no longer check for the return value. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 3 +-- include/linux/device.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index d14b6e895896..d21f4b8dc37b 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -600,9 +600,8 @@ void *dev_get_drvdata(const struct device *dev) } EXPORT_SYMBOL(dev_get_drvdata); -int dev_set_drvdata(struct device *dev, void *data) +void dev_set_drvdata(struct device *dev, void *data) { dev->driver_data = data; - return 0; } EXPORT_SYMBOL(dev_set_drvdata); diff --git a/include/linux/device.h b/include/linux/device.h index 5c94ac3e7972..6d3a75773cd4 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -911,7 +911,7 @@ extern const char *device_get_devnode(struct device *dev, umode_t *mode, kuid_t *uid, kgid_t *gid, const char **tmp); extern void *dev_get_drvdata(const struct device *dev); -extern int dev_set_drvdata(struct device *dev, void *data); +extern void dev_set_drvdata(struct device *dev, void *data); static inline bool device_supports_offline(struct device *dev) { From d4332013919aa87dbdede67d677e4cf2cd32e898 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 14 Apr 2014 12:57:43 +0200 Subject: [PATCH 09/15] driver core: dev_get_drvdata: Don't check for NULL dev There is no point in calling dev_get_drvdata without a valid device. So checking for dev == NULL is pointless. If such a check is ever needed - which I doubt - the driver should do it before calling dev_get_drvdata. We were returning NULL if dev was NULL, which the caller certainly did not expect anyway, so that was only delaying the crash if the caller is not paying attention. Signed-off-by: Jean Delvare Cc: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index d21f4b8dc37b..ba03353ff243 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -594,9 +594,7 @@ void driver_detach(struct device_driver *drv) */ void *dev_get_drvdata(const struct device *dev) { - if (dev) - return dev->driver_data; - return NULL; + return dev->driver_data; } EXPORT_SYMBOL(dev_get_drvdata); From a996d010b648788b615938f6a26be6cf08d96aaf Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 14 Apr 2014 12:58:53 +0200 Subject: [PATCH 10/15] driver core: Inline dev_set/get_drvdata dev_set_drvdata and dev_get_drvdata are now simple enough again that we can inline them as they used to be before commit b40284378. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 16 ---------------- include/linux/device.h | 12 ++++++++++-- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index ba03353ff243..e4ffbcf2f519 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -587,19 +587,3 @@ void driver_detach(struct device_driver *drv) put_device(dev); } } - -/* - * These exports can't be _GPL due to .h files using this within them, and it - * might break something that was previously working... - */ -void *dev_get_drvdata(const struct device *dev) -{ - return dev->driver_data; -} -EXPORT_SYMBOL(dev_get_drvdata); - -void dev_set_drvdata(struct device *dev, void *data) -{ - dev->driver_data = data; -} -EXPORT_SYMBOL(dev_set_drvdata); diff --git a/include/linux/device.h b/include/linux/device.h index 6d3a75773cd4..1b18c886445c 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -826,6 +826,16 @@ static inline void set_dev_node(struct device *dev, int node) } #endif +static inline void *dev_get_drvdata(const struct device *dev) +{ + return dev->driver_data; +} + +static inline void dev_set_drvdata(struct device *dev, void *data) +{ + dev->driver_data = data; +} + static inline struct pm_subsys_data *dev_to_psd(struct device *dev) { return dev ? dev->power.subsys_data : NULL; @@ -910,8 +920,6 @@ extern int device_move(struct device *dev, struct device *new_parent, extern const char *device_get_devnode(struct device *dev, umode_t *mode, kuid_t *uid, kgid_t *gid, const char **tmp); -extern void *dev_get_drvdata(const struct device *dev); -extern void dev_set_drvdata(struct device *dev, void *data); static inline bool device_supports_offline(struct device *dev) { From 451ef1caa8698511bb7766344ccec9f08d5d294b Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 13 May 2014 09:05:26 -0700 Subject: [PATCH 11/15] init.h: Update initcall_sync variants to fix build errors We are getting randconfig build errors on device drivers with tristate Kconfig option if they are using custom initcall levels. Rather than add ifdeffery into the drivers, let's add the missing initcall_sync variants. As the comment in init.h has kept people from updating the list of initcalls that can be just module_init when the driver is loaded as a loadable module, let's also update the comment a bit to describe valid use cases custom initcall levels. While most drivers should nowadays use just regular module_init because of the deferred probe, we do have quite a few custom initcall levels left that we cannot remove until tested properly. There are also still few valid cases where a custom initcall level might make sense that I'm aware of. For example a bus snooping driver can provide information about invalid bus access and is handy loader early when built in. But there's no hard dependency to have it necessarily built in and a loadable module is a valid option. Another example is a driver implementing a Linux framework like pinctrl framework. That driver may be needed early on some platforms because of legacy reasons, while it can be just a regular module_init on most platforms. Signed-off-by: Tony Lindgren Cc: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- include/linux/init.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/include/linux/init.h b/include/linux/init.h index a3ba27076342..2df8e8dd10a4 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -297,16 +297,28 @@ void __init parse_early_options(char *cmdline); #else /* MODULE */ -/* Don't use these in loadable modules, but some people do... */ +/* + * In most cases loadable modules do not need custom + * initcall levels. There are still some valid cases where + * a driver may be needed early if built in, and does not + * matter when built as a loadable module. Like bus + * snooping debug drivers. + */ #define early_initcall(fn) module_init(fn) #define core_initcall(fn) module_init(fn) +#define core_initcall_sync(fn) module_init(fn) #define postcore_initcall(fn) module_init(fn) +#define postcore_initcall_sync(fn) module_init(fn) #define arch_initcall(fn) module_init(fn) #define subsys_initcall(fn) module_init(fn) +#define subsys_initcall_sync(fn) module_init(fn) #define fs_initcall(fn) module_init(fn) +#define fs_initcall_sync(fn) module_init(fn) #define rootfs_initcall(fn) module_init(fn) #define device_initcall(fn) module_init(fn) +#define device_initcall_sync(fn) module_init(fn) #define late_initcall(fn) module_init(fn) +#define late_initcall_sync(fn) module_init(fn) #define console_initcall(fn) module_init(fn) #define security_initcall(fn) module_init(fn) From 78e1da627040ca49c41b456db707342ef210ae0f Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Wed, 16 Apr 2014 11:56:45 +0200 Subject: [PATCH 12/15] sysfs.h: don't return a void-valued expression in sysfs_remove_file Sparse was complaining about that: include/linux/sysfs.h:432:9: warning: returning void-valued expression Signed-off-by: Simon Wunderlich Signed-off-by: Greg Kroah-Hartman --- include/linux/sysfs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 5ffaa3443712..f97d0dbb59fa 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -437,7 +437,7 @@ static inline int __must_check sysfs_create_file(struct kobject *kobj, static inline void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr) { - return sysfs_remove_file_ns(kobj, attr, NULL); + sysfs_remove_file_ns(kobj, attr, NULL); } static inline int sysfs_rename_link(struct kobject *kobj, struct kobject *target, From 9f70a40128a4ddceffb6d21dd490f6ab4bc34c97 Mon Sep 17 00:00:00 2001 From: Robert ABEL Date: Mon, 5 May 2014 15:17:20 +0200 Subject: [PATCH 13/15] sysfs: fix attribute_group bin file path on removal Cody Schafer already fixed binary file creation for attribute groups, see [1]. This patch makes the appropriate changes for binary file removal of attribute groups. [1]: http://lkml.org/lkml/2014/2/27/832 Signed-off-by: Robert ABEL Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/group.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index aa0406895b53..7d2a860ba788 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -18,7 +18,7 @@ #include "sysfs.h" -static void remove_files(struct kernfs_node *parent, struct kobject *kobj, +static void remove_files(struct kernfs_node *parent, const struct attribute_group *grp) { struct attribute *const *attr; @@ -29,7 +29,7 @@ static void remove_files(struct kernfs_node *parent, struct kobject *kobj, kernfs_remove_by_name(parent, (*attr)->name); if (grp->bin_attrs) for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) - sysfs_remove_bin_file(kobj, *bin_attr); + kernfs_remove_by_name(parent, (*bin_attr)->attr.name); } static int create_files(struct kernfs_node *parent, struct kobject *kobj, @@ -62,7 +62,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj, break; } if (error) { - remove_files(parent, kobj, grp); + remove_files(parent, grp); goto exit; } } @@ -79,7 +79,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj, break; } if (error) - remove_files(parent, kobj, grp); + remove_files(parent, grp); } exit: return error; @@ -224,7 +224,7 @@ void sysfs_remove_group(struct kobject *kobj, kernfs_get(kn); } - remove_files(kn, kobj, grp); + remove_files(kn, grp); if (grp->name) kernfs_remove(kn); From 26fc9cd200ec839e0b3095e05ae018f27314e7aa Mon Sep 17 00:00:00 2001 From: Jianyu Zhan Date: Sat, 26 Apr 2014 15:40:28 +0800 Subject: [PATCH 14/15] kernfs: move the last knowledge of sysfs out from kernfs There is still one residue of sysfs remaining: the sb_magic SYSFS_MAGIC. However this should be kernfs user specific, so this patch moves it out. Kerrnfs user should specify their magic number while mouting. Signed-off-by: Jianyu Zhan Acked-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/mount.c | 11 ++++++----- fs/sysfs/mount.c | 4 +++- include/linux/kernfs.h | 13 ++++++++----- kernel/cgroup.c | 4 +++- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index f25a7c0c3cdc..d171b98a6cdd 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c @@ -62,7 +62,7 @@ struct kernfs_root *kernfs_root_from_sb(struct super_block *sb) return NULL; } -static int kernfs_fill_super(struct super_block *sb) +static int kernfs_fill_super(struct super_block *sb, unsigned long magic) { struct kernfs_super_info *info = kernfs_info(sb); struct inode *inode; @@ -71,7 +71,7 @@ static int kernfs_fill_super(struct super_block *sb) info->sb = sb; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = SYSFS_MAGIC; + sb->s_magic = magic; sb->s_op = &kernfs_sops; sb->s_time_gran = 1; @@ -132,6 +132,7 @@ const void *kernfs_super_ns(struct super_block *sb) * @fs_type: file_system_type of the fs being mounted * @flags: mount flags specified for the mount * @root: kernfs_root of the hierarchy being mounted + * @magic: file system specific magic number * @new_sb_created: tell the caller if we allocated a new superblock * @ns: optional namespace tag of the mount * @@ -143,8 +144,8 @@ const void *kernfs_super_ns(struct super_block *sb) * The return value can be passed to the vfs layer verbatim. */ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, - struct kernfs_root *root, bool *new_sb_created, - const void *ns) + struct kernfs_root *root, unsigned long magic, + bool *new_sb_created, const void *ns) { struct super_block *sb; struct kernfs_super_info *info; @@ -169,7 +170,7 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, if (!sb->s_root) { struct kernfs_super_info *info = kernfs_info(sb); - error = kernfs_fill_super(sb); + error = kernfs_fill_super(sb, magic); if (error) { deactivate_locked_super(sb); return ERR_PTR(error); diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 8794423f7efb..8a49486bf30c 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -13,6 +13,7 @@ #define DEBUG #include +#include #include #include #include @@ -38,7 +39,8 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, } ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); - root = kernfs_mount_ns(fs_type, flags, sysfs_root, &new_sb, ns); + root = kernfs_mount_ns(fs_type, flags, sysfs_root, + SYSFS_MAGIC, &new_sb, ns); if (IS_ERR(root) || !new_sb) kobj_ns_drop(KOBJ_NS_TYPE_NET, ns); return root; diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index c841688a78a3..17aa1cce6f8e 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -301,8 +301,8 @@ void kernfs_notify(struct kernfs_node *kn); const void *kernfs_super_ns(struct super_block *sb); struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, - struct kernfs_root *root, bool *new_sb_created, - const void *ns); + struct kernfs_root *root, unsigned long magic, + bool *new_sb_created, const void *ns); void kernfs_kill_sb(struct super_block *sb); void kernfs_init(void); @@ -395,7 +395,8 @@ static inline const void *kernfs_super_ns(struct super_block *sb) static inline struct dentry * kernfs_mount_ns(struct file_system_type *fs_type, int flags, - struct kernfs_root *root, bool *new_sb_created, const void *ns) + struct kernfs_root *root, unsigned long magic, + bool *new_sb_created, const void *ns) { return ERR_PTR(-ENOSYS); } static inline void kernfs_kill_sb(struct super_block *sb) { } @@ -453,9 +454,11 @@ static inline int kernfs_rename(struct kernfs_node *kn, static inline struct dentry * kernfs_mount(struct file_system_type *fs_type, int flags, - struct kernfs_root *root, bool *new_sb_created) + struct kernfs_root *root, unsigned long magic, + bool *new_sb_created) { - return kernfs_mount_ns(fs_type, flags, root, new_sb_created, NULL); + return kernfs_mount_ns(fs_type, flags, root, + magic, new_sb_created, NULL); } #endif /* __LINUX_KERNFS_H */ diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 3f1ca934a237..ceee0c54c6a4 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1604,7 +1605,8 @@ out_unlock: if (ret) return ERR_PTR(ret); - dentry = kernfs_mount(fs_type, flags, root->kf_root, &new_sb); + dentry = kernfs_mount(fs_type, flags, root->kf_root, + CGROUP_SUPER_MAGIC, &new_sb); if (IS_ERR(dentry) || !new_sb) cgroup_put(&root->cgrp); return dentry; From cda43576afa641d83ae268cb9795ae2a549d53d9 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 28 May 2014 14:02:24 +0200 Subject: [PATCH 15/15] crypto/nx/nx-842: dev_set_drvdata can no longer fail Don't check if dev_set_drvdata() failed, it can't, and it returns void now. Signed-off-by: Jean Delvare Cc: Robert Jennings Cc: Marcelo Henrique Cerri Cc: Fionnuala Gunter Reported-by: Stephen Rothwell Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/nx/nx-842.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c index 1e5481d88a26..5ce8b5765121 100644 --- a/drivers/crypto/nx/nx-842.c +++ b/drivers/crypto/nx/nx-842.c @@ -1197,12 +1197,7 @@ static int __init nx842_probe(struct vio_dev *viodev, } rcu_read_lock(); - if (dev_set_drvdata(&viodev->dev, rcu_dereference(devdata))) { - rcu_read_unlock(); - dev_err(&viodev->dev, "failed to set driver data for device\n"); - ret = -1; - goto error; - } + dev_set_drvdata(&viodev->dev, rcu_dereference(devdata)); rcu_read_unlock(); if (sysfs_create_group(&viodev->dev.kobj, &nx842_attribute_group)) {