diff options
| -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 |
