aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/Kconfig17
-rw-r--r--fs/kernfs/dir.c1
-rw-r--r--fs/kernfs/file.c41
-rw-r--r--fs/kernfs/kernfs-internal.h5
-rw-r--r--fs/kernfs/mount.c11
-rw-r--r--include/linux/kernfs.h4
-rw-r--r--include/linux/kobject.h2
-rw-r--r--kernel/ksysfs.c5
-rw-r--r--kernel/sysctl.c4
-rw-r--r--lib/kobject_uevent.c6
10 files changed, 81 insertions, 15 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 @@
1menu "Generic Driver Options" 1menu "Generic Driver Options"
2 2
3config UEVENT_HELPER_PATH 3config UEVENT_HELPER
4 string "path to uevent helper" 4 bool "Support for uevent helper"
5 default "" 5 default y
6 help 6 help
7 Path to uevent helper program forked by the kernel for 7 The uevent helper program is forked by the kernel for
8 every uevent. 8 every uevent.
9 Before the switch to the netlink-based uevent source, this was 9 Before the switch to the netlink-based uevent source, this was
10 used to hook hotplug scripts into kernel device events. It 10 used to hook hotplug scripts into kernel device events. It
@@ -15,8 +15,13 @@ config UEVENT_HELPER_PATH
15 that it creates a high system load, or on smaller systems 15 that it creates a high system load, or on smaller systems
16 it is known to create out-of-memory situations during bootup. 16 it is known to create out-of-memory situations during bootup.
17 17
18 To disable user space helper program execution at early boot 18config UEVENT_HELPER_PATH
19 time specify an empty string here. This setting can be altered 19 string "path to uevent helper"
20 depends on UEVENT_HELPER
21 default ""
22 help
23 To disable user space helper program execution at by default
24 specify an empty string here. This setting can still be altered
20 via /proc/sys/kernel/hotplug or via /sys/kernel/uevent_helper 25 via /proc/sys/kernel/hotplug or via /sys/kernel/uevent_helper
21 later at runtime. 26 later at runtime.
22 27
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index ac127cd008bf..a693f5b01ae6 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -714,6 +714,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
714 return ERR_PTR(-ENOMEM); 714 return ERR_PTR(-ENOMEM);
715 715
716 ida_init(&root->ino_ida); 716 ida_init(&root->ino_ida);
717 INIT_LIST_HEAD(&root->supers);
717 718
718 kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO, 719 kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO,
719 KERNFS_DIR); 720 KERNFS_DIR);
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index e01ea4a14a01..40251cd741a0 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -14,6 +14,7 @@
14#include <linux/poll.h> 14#include <linux/poll.h>
15#include <linux/pagemap.h> 15#include <linux/pagemap.h>
16#include <linux/sched.h> 16#include <linux/sched.h>
17#include <linux/fsnotify.h>
17 18
18#include "kernfs-internal.h" 19#include "kernfs-internal.h"
19 20
@@ -787,20 +788,48 @@ static unsigned int kernfs_fop_poll(struct file *filp, poll_table *wait)
787 */ 788 */
788void kernfs_notify(struct kernfs_node *kn) 789void kernfs_notify(struct kernfs_node *kn)
789{ 790{
791 struct kernfs_root *root = kernfs_root(kn);
790 struct kernfs_open_node *on; 792 struct kernfs_open_node *on;
793 struct kernfs_super_info *info;
791 unsigned long flags; 794 unsigned long flags;
792 795
796 if (WARN_ON(kernfs_type(kn) != KERNFS_FILE))
797 return;
798
799 /* kick poll */
793 spin_lock_irqsave(&kernfs_open_node_lock, flags); 800 spin_lock_irqsave(&kernfs_open_node_lock, flags);
794 801
795 if (!WARN_ON(kernfs_type(kn) != KERNFS_FILE)) { 802 on = kn->attr.open;
796 on = kn->attr.open; 803 if (on) {
797 if (on) { 804 atomic_inc(&on->event);
798 atomic_inc(&on->event); 805 wake_up_interruptible(&on->poll);
799 wake_up_interruptible(&on->poll);
800 }
801 } 806 }
802 807
803 spin_unlock_irqrestore(&kernfs_open_node_lock, flags); 808 spin_unlock_irqrestore(&kernfs_open_node_lock, flags);
809
810 /* kick fsnotify */
811 mutex_lock(&kernfs_mutex);
812
813 list_for_each_entry(info, &root->supers, node) {
814 struct inode *inode;
815 struct dentry *dentry;
816
817 inode = ilookup(info->sb, kn->ino);
818 if (!inode)
819 continue;
820
821 dentry = d_find_any_alias(inode);
822 if (dentry) {
823 fsnotify_parent(NULL, dentry, FS_MODIFY);
824 fsnotify(inode, FS_MODIFY, inode, FSNOTIFY_EVENT_INODE,
825 NULL, 0);
826 dput(dentry);
827 }
828
829 iput(inode);
830 }
831
832 mutex_unlock(&kernfs_mutex);
804} 833}
805EXPORT_SYMBOL_GPL(kernfs_notify); 834EXPORT_SYMBOL_GPL(kernfs_notify);
806 835
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)
49 * mount.c 49 * mount.c
50 */ 50 */
51struct kernfs_super_info { 51struct kernfs_super_info {
52 struct super_block *sb;
53
52 /* 54 /*
53 * The root associated with this super_block. Each super_block is 55 * The root associated with this super_block. Each super_block is
54 * identified by the root and ns it's associated with. 56 * identified by the root and ns it's associated with.
@@ -62,6 +64,9 @@ struct kernfs_super_info {
62 * an array and compare kernfs_node tag against every entry. 64 * an array and compare kernfs_node tag against every entry.
63 */ 65 */
64 const void *ns; 66 const void *ns;
67
68 /* anchored at kernfs_root->supers, protected by kernfs_mutex */
69 struct list_head node;
65}; 70};
66#define kernfs_info(SB) ((struct kernfs_super_info *)(SB->s_fs_info)) 71#define kernfs_info(SB) ((struct kernfs_super_info *)(SB->s_fs_info))
67 72
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)
68 struct inode *inode; 68 struct inode *inode;
69 struct dentry *root; 69 struct dentry *root;
70 70
71 info->sb = sb;
71 sb->s_blocksize = PAGE_CACHE_SIZE; 72 sb->s_blocksize = PAGE_CACHE_SIZE;
72 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 73 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
73 sb->s_magic = SYSFS_MAGIC; 74 sb->s_magic = SYSFS_MAGIC;
@@ -166,12 +167,18 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
166 *new_sb_created = !sb->s_root; 167 *new_sb_created = !sb->s_root;
167 168
168 if (!sb->s_root) { 169 if (!sb->s_root) {
170 struct kernfs_super_info *info = kernfs_info(sb);
171
169 error = kernfs_fill_super(sb); 172 error = kernfs_fill_super(sb);
170 if (error) { 173 if (error) {
171 deactivate_locked_super(sb); 174 deactivate_locked_super(sb);
172 return ERR_PTR(error); 175 return ERR_PTR(error);
173 } 176 }
174 sb->s_flags |= MS_ACTIVE; 177 sb->s_flags |= MS_ACTIVE;
178
179 mutex_lock(&kernfs_mutex);
180 list_add(&info->node, &root->supers);
181 mutex_unlock(&kernfs_mutex);
175 } 182 }
176 183
177 return dget(sb->s_root); 184 return dget(sb->s_root);
@@ -190,6 +197,10 @@ void kernfs_kill_sb(struct super_block *sb)
190 struct kernfs_super_info *info = kernfs_info(sb); 197 struct kernfs_super_info *info = kernfs_info(sb);
191 struct kernfs_node *root_kn = sb->s_root->d_fsdata; 198 struct kernfs_node *root_kn = sb->s_root->d_fsdata;
192 199
200 mutex_lock(&kernfs_mutex);
201 list_del(&info->node);
202 mutex_unlock(&kernfs_mutex);
203
193 /* 204 /*
194 * Remove the superblock from fs_supers/s_instances 205 * Remove the superblock from fs_supers/s_instances
195 * so we can't find it, before freeing kernfs_super_info. 206 * 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 {
144 /* private fields, do not use outside kernfs proper */ 144 /* private fields, do not use outside kernfs proper */
145 struct ida ino_ida; 145 struct ida ino_ida;
146 struct kernfs_syscall_ops *syscall_ops; 146 struct kernfs_syscall_ops *syscall_ops;
147
148 /* list of kernfs_super_info of this root, protected by kernfs_mutex */
149 struct list_head supers;
150
147 wait_queue_head_t deactivate_waitq; 151 wait_queue_head_t deactivate_waitq;
148}; 152};
149 153
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 @@
32#define UEVENT_NUM_ENVP 32 /* number of env pointers */ 32#define UEVENT_NUM_ENVP 32 /* number of env pointers */
33#define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ 33#define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */
34 34
35#ifdef CONFIG_UEVENT_HELPER
35/* path to the userspace helper executed on an event */ 36/* path to the userspace helper executed on an event */
36extern char uevent_helper[]; 37extern char uevent_helper[];
38#endif
37 39
38/* counter to tag the uevent, read only except for the kobject core */ 40/* counter to tag the uevent, read only except for the kobject core */
39extern u64 uevent_seqnum; 41extern 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,
37} 37}
38KERNEL_ATTR_RO(uevent_seqnum); 38KERNEL_ATTR_RO(uevent_seqnum);
39 39
40#ifdef CONFIG_UEVENT_HELPER
40/* uevent helper program, used during early boot */ 41/* uevent helper program, used during early boot */
41static ssize_t uevent_helper_show(struct kobject *kobj, 42static ssize_t uevent_helper_show(struct kobject *kobj,
42 struct kobj_attribute *attr, char *buf) 43 struct kobj_attribute *attr, char *buf)
@@ -56,7 +57,7 @@ static ssize_t uevent_helper_store(struct kobject *kobj,
56 return count; 57 return count;
57} 58}
58KERNEL_ATTR_RW(uevent_helper); 59KERNEL_ATTR_RW(uevent_helper);
59 60#endif
60 61
61#ifdef CONFIG_PROFILING 62#ifdef CONFIG_PROFILING
62static ssize_t profiling_show(struct kobject *kobj, 63static ssize_t profiling_show(struct kobject *kobj,
@@ -189,7 +190,9 @@ EXPORT_SYMBOL_GPL(kernel_kobj);
189static struct attribute * kernel_attrs[] = { 190static struct attribute * kernel_attrs[] = {
190 &fscaps_attr.attr, 191 &fscaps_attr.attr,
191 &uevent_seqnum_attr.attr, 192 &uevent_seqnum_attr.attr,
193#ifdef CONFIG_UEVENT_HELPER
192 &uevent_helper_attr.attr, 194 &uevent_helper_attr.attr,
195#endif
193#ifdef CONFIG_PROFILING 196#ifdef CONFIG_PROFILING
194 &profiling_attr.attr, 197 &profiling_attr.attr,
195#endif 198#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[] = {
643 .extra2 = &one, 643 .extra2 = &one,
644 }, 644 },
645#endif 645#endif
646 646#ifdef CONFIG_UEVENT_HELPER
647 { 647 {
648 .procname = "hotplug", 648 .procname = "hotplug",
649 .data = &uevent_helper, 649 .data = &uevent_helper,
@@ -651,7 +651,7 @@ static struct ctl_table kern_table[] = {
651 .mode = 0644, 651 .mode = 0644,
652 .proc_handler = proc_dostring, 652 .proc_handler = proc_dostring,
653 }, 653 },
654 654#endif
655#ifdef CONFIG_CHR_DEV_SG 655#ifdef CONFIG_CHR_DEV_SG
656 { 656 {
657 .procname = "sg-big-buff", 657 .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 @@
29 29
30 30
31u64 uevent_seqnum; 31u64 uevent_seqnum;
32#ifdef CONFIG_UEVENT_HELPER
32char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; 33char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
34#endif
33#ifdef CONFIG_NET 35#ifdef CONFIG_NET
34struct uevent_sock { 36struct uevent_sock {
35 struct list_head list; 37 struct list_head list;
@@ -109,6 +111,7 @@ static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data)
109} 111}
110#endif 112#endif
111 113
114#ifdef CONFIG_UEVENT_HELPER
112static int kobj_usermode_filter(struct kobject *kobj) 115static int kobj_usermode_filter(struct kobject *kobj)
113{ 116{
114 const struct kobj_ns_type_operations *ops; 117 const struct kobj_ns_type_operations *ops;
@@ -147,6 +150,7 @@ static void cleanup_uevent_env(struct subprocess_info *info)
147{ 150{
148 kfree(info->data); 151 kfree(info->data);
149} 152}
153#endif
150 154
151/** 155/**
152 * kobject_uevent_env - send an uevent with environmental data 156 * kobject_uevent_env - send an uevent with environmental data
@@ -323,6 +327,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
323#endif 327#endif
324 mutex_unlock(&uevent_sock_mutex); 328 mutex_unlock(&uevent_sock_mutex);
325 329
330#ifdef CONFIG_UEVENT_HELPER
326 /* call uevent_helper, usually only enabled during early boot */ 331 /* call uevent_helper, usually only enabled during early boot */
327 if (uevent_helper[0] && !kobj_usermode_filter(kobj)) { 332 if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
328 struct subprocess_info *info; 333 struct subprocess_info *info;
@@ -347,6 +352,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
347 env = NULL; /* freed by cleanup_uevent_env */ 352 env = NULL; /* freed by cleanup_uevent_env */
348 } 353 }
349 } 354 }
355#endif
350 356
351exit: 357exit:
352 kfree(devpath); 358 kfree(devpath);