diff options
Diffstat (limited to 'lib/kobject_uevent.c')
-rw-r--r-- | lib/kobject_uevent.c | 68 |
1 files changed, 60 insertions, 8 deletions
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 7b48d44ced6e..9084f2550c2a 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c | |||
@@ -24,13 +24,19 @@ | |||
24 | #include <linux/skbuff.h> | 24 | #include <linux/skbuff.h> |
25 | #include <linux/netlink.h> | 25 | #include <linux/netlink.h> |
26 | #include <net/sock.h> | 26 | #include <net/sock.h> |
27 | #include <net/net_namespace.h> | ||
27 | 28 | ||
28 | 29 | ||
29 | u64 uevent_seqnum; | 30 | u64 uevent_seqnum; |
30 | char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; | 31 | char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; |
31 | static DEFINE_SPINLOCK(sequence_lock); | 32 | static DEFINE_SPINLOCK(sequence_lock); |
32 | #if defined(CONFIG_NET) | 33 | #ifdef CONFIG_NET |
33 | static struct sock *uevent_sock; | 34 | struct uevent_sock { |
35 | struct list_head list; | ||
36 | struct sock *sk; | ||
37 | }; | ||
38 | static LIST_HEAD(uevent_sock_list); | ||
39 | static DEFINE_MUTEX(uevent_sock_mutex); | ||
34 | #endif | 40 | #endif |
35 | 41 | ||
36 | /* the strings here must match the enum in include/linux/kobject.h */ | 42 | /* the strings here must match the enum in include/linux/kobject.h */ |
@@ -100,6 +106,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, | |||
100 | u64 seq; | 106 | u64 seq; |
101 | int i = 0; | 107 | int i = 0; |
102 | int retval = 0; | 108 | int retval = 0; |
109 | #ifdef CONFIG_NET | ||
110 | struct uevent_sock *ue_sk; | ||
111 | #endif | ||
103 | 112 | ||
104 | pr_debug("kobject: '%s' (%p): %s\n", | 113 | pr_debug("kobject: '%s' (%p): %s\n", |
105 | kobject_name(kobj), kobj, __func__); | 114 | kobject_name(kobj), kobj, __func__); |
@@ -211,7 +220,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, | |||
211 | 220 | ||
212 | #if defined(CONFIG_NET) | 221 | #if defined(CONFIG_NET) |
213 | /* send netlink message */ | 222 | /* send netlink message */ |
214 | if (uevent_sock) { | 223 | mutex_lock(&uevent_sock_mutex); |
224 | list_for_each_entry(ue_sk, &uevent_sock_list, list) { | ||
225 | struct sock *uevent_sock = ue_sk->sk; | ||
215 | struct sk_buff *skb; | 226 | struct sk_buff *skb; |
216 | size_t len; | 227 | size_t len; |
217 | 228 | ||
@@ -241,6 +252,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, | |||
241 | } else | 252 | } else |
242 | retval = -ENOMEM; | 253 | retval = -ENOMEM; |
243 | } | 254 | } |
255 | mutex_unlock(&uevent_sock_mutex); | ||
244 | #endif | 256 | #endif |
245 | 257 | ||
246 | /* call uevent_helper, usually only enabled during early boot */ | 258 | /* call uevent_helper, usually only enabled during early boot */ |
@@ -320,18 +332,58 @@ int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) | |||
320 | EXPORT_SYMBOL_GPL(add_uevent_var); | 332 | EXPORT_SYMBOL_GPL(add_uevent_var); |
321 | 333 | ||
322 | #if defined(CONFIG_NET) | 334 | #if defined(CONFIG_NET) |
323 | static int __init kobject_uevent_init(void) | 335 | static int uevent_net_init(struct net *net) |
324 | { | 336 | { |
325 | uevent_sock = netlink_kernel_create(&init_net, NETLINK_KOBJECT_UEVENT, | 337 | struct uevent_sock *ue_sk; |
326 | 1, NULL, NULL, THIS_MODULE); | 338 | |
327 | if (!uevent_sock) { | 339 | ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL); |
340 | if (!ue_sk) | ||
341 | return -ENOMEM; | ||
342 | |||
343 | ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT, | ||
344 | 1, NULL, NULL, THIS_MODULE); | ||
345 | if (!ue_sk->sk) { | ||
328 | printk(KERN_ERR | 346 | printk(KERN_ERR |
329 | "kobject_uevent: unable to create netlink socket!\n"); | 347 | "kobject_uevent: unable to create netlink socket!\n"); |
330 | return -ENODEV; | 348 | return -ENODEV; |
331 | } | 349 | } |
332 | netlink_set_nonroot(NETLINK_KOBJECT_UEVENT, NL_NONROOT_RECV); | 350 | mutex_lock(&uevent_sock_mutex); |
351 | list_add_tail(&ue_sk->list, &uevent_sock_list); | ||
352 | mutex_unlock(&uevent_sock_mutex); | ||
333 | return 0; | 353 | return 0; |
334 | } | 354 | } |
335 | 355 | ||
356 | static void uevent_net_exit(struct net *net) | ||
357 | { | ||
358 | struct uevent_sock *ue_sk; | ||
359 | |||
360 | mutex_lock(&uevent_sock_mutex); | ||
361 | list_for_each_entry(ue_sk, &uevent_sock_list, list) { | ||
362 | if (sock_net(ue_sk->sk) == net) | ||
363 | goto found; | ||
364 | } | ||
365 | mutex_unlock(&uevent_sock_mutex); | ||
366 | return; | ||
367 | |||
368 | found: | ||
369 | list_del(&ue_sk->list); | ||
370 | mutex_unlock(&uevent_sock_mutex); | ||
371 | |||
372 | netlink_kernel_release(ue_sk->sk); | ||
373 | kfree(ue_sk); | ||
374 | } | ||
375 | |||
376 | static struct pernet_operations uevent_net_ops = { | ||
377 | .init = uevent_net_init, | ||
378 | .exit = uevent_net_exit, | ||
379 | }; | ||
380 | |||
381 | static int __init kobject_uevent_init(void) | ||
382 | { | ||
383 | netlink_set_nonroot(NETLINK_KOBJECT_UEVENT, NL_NONROOT_RECV); | ||
384 | return register_pernet_subsys(&uevent_net_ops); | ||
385 | } | ||
386 | |||
387 | |||
336 | postcore_initcall(kobject_uevent_init); | 388 | postcore_initcall(kobject_uevent_init); |
337 | #endif | 389 | #endif |