diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig.kgdb | 24 | ||||
-rw-r--r-- | lib/kobject.c | 115 | ||||
-rw-r--r-- | lib/kobject_uevent.c | 109 | ||||
-rw-r--r-- | lib/kref.c | 15 |
4 files changed, 237 insertions, 26 deletions
diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb index 9b5d1d7f2ef7..43cb93fa2651 100644 --- a/lib/Kconfig.kgdb +++ b/lib/Kconfig.kgdb | |||
@@ -3,7 +3,7 @@ config HAVE_ARCH_KGDB | |||
3 | bool | 3 | bool |
4 | 4 | ||
5 | menuconfig KGDB | 5 | menuconfig KGDB |
6 | bool "KGDB: kernel debugging with remote gdb" | 6 | bool "KGDB: kernel debugger" |
7 | depends on HAVE_ARCH_KGDB | 7 | depends on HAVE_ARCH_KGDB |
8 | depends on DEBUG_KERNEL && EXPERIMENTAL | 8 | depends on DEBUG_KERNEL && EXPERIMENTAL |
9 | help | 9 | help |
@@ -57,4 +57,26 @@ config KGDB_TESTS_BOOT_STRING | |||
57 | information about other strings you could use beyond the | 57 | information about other strings you could use beyond the |
58 | default of V1F100. | 58 | default of V1F100. |
59 | 59 | ||
60 | config KGDB_LOW_LEVEL_TRAP | ||
61 | bool "KGDB: Allow debugging with traps in notifiers" | ||
62 | depends on X86 || MIPS | ||
63 | default n | ||
64 | help | ||
65 | This will add an extra call back to kgdb for the breakpoint | ||
66 | exception handler on which will will allow kgdb to step | ||
67 | through a notify handler. | ||
68 | |||
69 | config KGDB_KDB | ||
70 | bool "KGDB_KDB: include kdb frontend for kgdb" | ||
71 | default n | ||
72 | help | ||
73 | KDB frontend for kernel | ||
74 | |||
75 | config KDB_KEYBOARD | ||
76 | bool "KGDB_KDB: keyboard as input device" | ||
77 | depends on VT && KGDB_KDB | ||
78 | default n | ||
79 | help | ||
80 | KDB can use a PS/2 type keyboard for an input device | ||
81 | |||
60 | endif # KGDB | 82 | endif # KGDB |
diff --git a/lib/kobject.c b/lib/kobject.c index 8115eb1bbf4d..f07c57252e82 100644 --- a/lib/kobject.c +++ b/lib/kobject.c | |||
@@ -850,6 +850,121 @@ struct kset *kset_create_and_add(const char *name, | |||
850 | } | 850 | } |
851 | EXPORT_SYMBOL_GPL(kset_create_and_add); | 851 | EXPORT_SYMBOL_GPL(kset_create_and_add); |
852 | 852 | ||
853 | |||
854 | static DEFINE_SPINLOCK(kobj_ns_type_lock); | ||
855 | static const struct kobj_ns_type_operations *kobj_ns_ops_tbl[KOBJ_NS_TYPES]; | ||
856 | |||
857 | int kobj_ns_type_register(const struct kobj_ns_type_operations *ops) | ||
858 | { | ||
859 | enum kobj_ns_type type = ops->type; | ||
860 | int error; | ||
861 | |||
862 | spin_lock(&kobj_ns_type_lock); | ||
863 | |||
864 | error = -EINVAL; | ||
865 | if (type >= KOBJ_NS_TYPES) | ||
866 | goto out; | ||
867 | |||
868 | error = -EINVAL; | ||
869 | if (type <= KOBJ_NS_TYPE_NONE) | ||
870 | goto out; | ||
871 | |||
872 | error = -EBUSY; | ||
873 | if (kobj_ns_ops_tbl[type]) | ||
874 | goto out; | ||
875 | |||
876 | error = 0; | ||
877 | kobj_ns_ops_tbl[type] = ops; | ||
878 | |||
879 | out: | ||
880 | spin_unlock(&kobj_ns_type_lock); | ||
881 | return error; | ||
882 | } | ||
883 | |||
884 | int kobj_ns_type_registered(enum kobj_ns_type type) | ||
885 | { | ||
886 | int registered = 0; | ||
887 | |||
888 | spin_lock(&kobj_ns_type_lock); | ||
889 | if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES)) | ||
890 | registered = kobj_ns_ops_tbl[type] != NULL; | ||
891 | spin_unlock(&kobj_ns_type_lock); | ||
892 | |||
893 | return registered; | ||
894 | } | ||
895 | |||
896 | const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent) | ||
897 | { | ||
898 | const struct kobj_ns_type_operations *ops = NULL; | ||
899 | |||
900 | if (parent && parent->ktype->child_ns_type) | ||
901 | ops = parent->ktype->child_ns_type(parent); | ||
902 | |||
903 | return ops; | ||
904 | } | ||
905 | |||
906 | const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj) | ||
907 | { | ||
908 | return kobj_child_ns_ops(kobj->parent); | ||
909 | } | ||
910 | |||
911 | |||
912 | const void *kobj_ns_current(enum kobj_ns_type type) | ||
913 | { | ||
914 | const void *ns = NULL; | ||
915 | |||
916 | spin_lock(&kobj_ns_type_lock); | ||
917 | if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && | ||
918 | kobj_ns_ops_tbl[type]) | ||
919 | ns = kobj_ns_ops_tbl[type]->current_ns(); | ||
920 | spin_unlock(&kobj_ns_type_lock); | ||
921 | |||
922 | return ns; | ||
923 | } | ||
924 | |||
925 | const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk) | ||
926 | { | ||
927 | const void *ns = NULL; | ||
928 | |||
929 | spin_lock(&kobj_ns_type_lock); | ||
930 | if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && | ||
931 | kobj_ns_ops_tbl[type]) | ||
932 | ns = kobj_ns_ops_tbl[type]->netlink_ns(sk); | ||
933 | spin_unlock(&kobj_ns_type_lock); | ||
934 | |||
935 | return ns; | ||
936 | } | ||
937 | |||
938 | const void *kobj_ns_initial(enum kobj_ns_type type) | ||
939 | { | ||
940 | const void *ns = NULL; | ||
941 | |||
942 | spin_lock(&kobj_ns_type_lock); | ||
943 | if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && | ||
944 | kobj_ns_ops_tbl[type]) | ||
945 | ns = kobj_ns_ops_tbl[type]->initial_ns(); | ||
946 | spin_unlock(&kobj_ns_type_lock); | ||
947 | |||
948 | return ns; | ||
949 | } | ||
950 | |||
951 | /* | ||
952 | * kobj_ns_exit - invalidate a namespace tag | ||
953 | * | ||
954 | * @type: the namespace type (i.e. KOBJ_NS_TYPE_NET) | ||
955 | * @ns: the actual namespace being invalidated | ||
956 | * | ||
957 | * This is called when a tag is no longer valid. For instance, | ||
958 | * when a network namespace exits, it uses this helper to | ||
959 | * make sure no sb's sysfs_info points to the now-invalidated | ||
960 | * netns. | ||
961 | */ | ||
962 | void kobj_ns_exit(enum kobj_ns_type type, const void *ns) | ||
963 | { | ||
964 | sysfs_exit_ns(type, ns); | ||
965 | } | ||
966 | |||
967 | |||
853 | EXPORT_SYMBOL(kobject_get); | 968 | EXPORT_SYMBOL(kobject_get); |
854 | EXPORT_SYMBOL(kobject_put); | 969 | EXPORT_SYMBOL(kobject_put); |
855 | EXPORT_SYMBOL(kobject_del); | 970 | EXPORT_SYMBOL(kobject_del); |
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 7b48d44ced6e..59c15511d58a 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c | |||
@@ -19,18 +19,24 @@ | |||
19 | #include <linux/kobject.h> | 19 | #include <linux/kobject.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | 22 | #include <linux/user_namespace.h> | |
23 | #include <linux/socket.h> | 23 | #include <linux/socket.h> |
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 */ |
@@ -77,6 +83,37 @@ out: | |||
77 | return ret; | 83 | return ret; |
78 | } | 84 | } |
79 | 85 | ||
86 | static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data) | ||
87 | { | ||
88 | struct kobject *kobj = data; | ||
89 | const struct kobj_ns_type_operations *ops; | ||
90 | |||
91 | ops = kobj_ns_ops(kobj); | ||
92 | if (ops) { | ||
93 | const void *sock_ns, *ns; | ||
94 | ns = kobj->ktype->namespace(kobj); | ||
95 | sock_ns = ops->netlink_ns(dsk); | ||
96 | return sock_ns != ns; | ||
97 | } | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int kobj_usermode_filter(struct kobject *kobj) | ||
103 | { | ||
104 | const struct kobj_ns_type_operations *ops; | ||
105 | |||
106 | ops = kobj_ns_ops(kobj); | ||
107 | if (ops) { | ||
108 | const void *init_ns, *ns; | ||
109 | ns = kobj->ktype->namespace(kobj); | ||
110 | init_ns = ops->initial_ns(); | ||
111 | return ns != init_ns; | ||
112 | } | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
80 | /** | 117 | /** |
81 | * kobject_uevent_env - send an uevent with environmental data | 118 | * kobject_uevent_env - send an uevent with environmental data |
82 | * | 119 | * |
@@ -100,6 +137,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, | |||
100 | u64 seq; | 137 | u64 seq; |
101 | int i = 0; | 138 | int i = 0; |
102 | int retval = 0; | 139 | int retval = 0; |
140 | #ifdef CONFIG_NET | ||
141 | struct uevent_sock *ue_sk; | ||
142 | #endif | ||
103 | 143 | ||
104 | pr_debug("kobject: '%s' (%p): %s\n", | 144 | pr_debug("kobject: '%s' (%p): %s\n", |
105 | kobject_name(kobj), kobj, __func__); | 145 | kobject_name(kobj), kobj, __func__); |
@@ -211,7 +251,9 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, | |||
211 | 251 | ||
212 | #if defined(CONFIG_NET) | 252 | #if defined(CONFIG_NET) |
213 | /* send netlink message */ | 253 | /* send netlink message */ |
214 | if (uevent_sock) { | 254 | mutex_lock(&uevent_sock_mutex); |
255 | list_for_each_entry(ue_sk, &uevent_sock_list, list) { | ||
256 | struct sock *uevent_sock = ue_sk->sk; | ||
215 | struct sk_buff *skb; | 257 | struct sk_buff *skb; |
216 | size_t len; | 258 | size_t len; |
217 | 259 | ||
@@ -233,18 +275,21 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, | |||
233 | } | 275 | } |
234 | 276 | ||
235 | NETLINK_CB(skb).dst_group = 1; | 277 | NETLINK_CB(skb).dst_group = 1; |
236 | retval = netlink_broadcast(uevent_sock, skb, 0, 1, | 278 | retval = netlink_broadcast_filtered(uevent_sock, skb, |
237 | GFP_KERNEL); | 279 | 0, 1, GFP_KERNEL, |
280 | kobj_bcast_filter, | ||
281 | kobj); | ||
238 | /* ENOBUFS should be handled in userspace */ | 282 | /* ENOBUFS should be handled in userspace */ |
239 | if (retval == -ENOBUFS) | 283 | if (retval == -ENOBUFS) |
240 | retval = 0; | 284 | retval = 0; |
241 | } else | 285 | } else |
242 | retval = -ENOMEM; | 286 | retval = -ENOMEM; |
243 | } | 287 | } |
288 | mutex_unlock(&uevent_sock_mutex); | ||
244 | #endif | 289 | #endif |
245 | 290 | ||
246 | /* call uevent_helper, usually only enabled during early boot */ | 291 | /* call uevent_helper, usually only enabled during early boot */ |
247 | if (uevent_helper[0]) { | 292 | if (uevent_helper[0] && !kobj_usermode_filter(kobj)) { |
248 | char *argv [3]; | 293 | char *argv [3]; |
249 | 294 | ||
250 | argv [0] = uevent_helper; | 295 | argv [0] = uevent_helper; |
@@ -320,18 +365,58 @@ int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) | |||
320 | EXPORT_SYMBOL_GPL(add_uevent_var); | 365 | EXPORT_SYMBOL_GPL(add_uevent_var); |
321 | 366 | ||
322 | #if defined(CONFIG_NET) | 367 | #if defined(CONFIG_NET) |
323 | static int __init kobject_uevent_init(void) | 368 | static int uevent_net_init(struct net *net) |
324 | { | 369 | { |
325 | uevent_sock = netlink_kernel_create(&init_net, NETLINK_KOBJECT_UEVENT, | 370 | struct uevent_sock *ue_sk; |
326 | 1, NULL, NULL, THIS_MODULE); | 371 | |
327 | if (!uevent_sock) { | 372 | ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL); |
373 | if (!ue_sk) | ||
374 | return -ENOMEM; | ||
375 | |||
376 | ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT, | ||
377 | 1, NULL, NULL, THIS_MODULE); | ||
378 | if (!ue_sk->sk) { | ||
328 | printk(KERN_ERR | 379 | printk(KERN_ERR |
329 | "kobject_uevent: unable to create netlink socket!\n"); | 380 | "kobject_uevent: unable to create netlink socket!\n"); |
330 | return -ENODEV; | 381 | return -ENODEV; |
331 | } | 382 | } |
332 | netlink_set_nonroot(NETLINK_KOBJECT_UEVENT, NL_NONROOT_RECV); | 383 | mutex_lock(&uevent_sock_mutex); |
384 | list_add_tail(&ue_sk->list, &uevent_sock_list); | ||
385 | mutex_unlock(&uevent_sock_mutex); | ||
333 | return 0; | 386 | return 0; |
334 | } | 387 | } |
335 | 388 | ||
389 | static void uevent_net_exit(struct net *net) | ||
390 | { | ||
391 | struct uevent_sock *ue_sk; | ||
392 | |||
393 | mutex_lock(&uevent_sock_mutex); | ||
394 | list_for_each_entry(ue_sk, &uevent_sock_list, list) { | ||
395 | if (sock_net(ue_sk->sk) == net) | ||
396 | goto found; | ||
397 | } | ||
398 | mutex_unlock(&uevent_sock_mutex); | ||
399 | return; | ||
400 | |||
401 | found: | ||
402 | list_del(&ue_sk->list); | ||
403 | mutex_unlock(&uevent_sock_mutex); | ||
404 | |||
405 | netlink_kernel_release(ue_sk->sk); | ||
406 | kfree(ue_sk); | ||
407 | } | ||
408 | |||
409 | static struct pernet_operations uevent_net_ops = { | ||
410 | .init = uevent_net_init, | ||
411 | .exit = uevent_net_exit, | ||
412 | }; | ||
413 | |||
414 | static int __init kobject_uevent_init(void) | ||
415 | { | ||
416 | netlink_set_nonroot(NETLINK_KOBJECT_UEVENT, NL_NONROOT_RECV); | ||
417 | return register_pernet_subsys(&uevent_net_ops); | ||
418 | } | ||
419 | |||
420 | |||
336 | postcore_initcall(kobject_uevent_init); | 421 | postcore_initcall(kobject_uevent_init); |
337 | #endif | 422 | #endif |
diff --git a/lib/kref.c b/lib/kref.c index 6d19f690380b..d3d227a08a4b 100644 --- a/lib/kref.c +++ b/lib/kref.c | |||
@@ -16,23 +16,13 @@ | |||
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | 17 | ||
18 | /** | 18 | /** |
19 | * kref_set - initialize object and set refcount to requested number. | ||
20 | * @kref: object in question. | ||
21 | * @num: initial reference counter | ||
22 | */ | ||
23 | void kref_set(struct kref *kref, int num) | ||
24 | { | ||
25 | atomic_set(&kref->refcount, num); | ||
26 | smp_mb(); | ||
27 | } | ||
28 | |||
29 | /** | ||
30 | * kref_init - initialize object. | 19 | * kref_init - initialize object. |
31 | * @kref: object in question. | 20 | * @kref: object in question. |
32 | */ | 21 | */ |
33 | void kref_init(struct kref *kref) | 22 | void kref_init(struct kref *kref) |
34 | { | 23 | { |
35 | kref_set(kref, 1); | 24 | atomic_set(&kref->refcount, 1); |
25 | smp_mb(); | ||
36 | } | 26 | } |
37 | 27 | ||
38 | /** | 28 | /** |
@@ -72,7 +62,6 @@ int kref_put(struct kref *kref, void (*release)(struct kref *kref)) | |||
72 | return 0; | 62 | return 0; |
73 | } | 63 | } |
74 | 64 | ||
75 | EXPORT_SYMBOL(kref_set); | ||
76 | EXPORT_SYMBOL(kref_init); | 65 | EXPORT_SYMBOL(kref_init); |
77 | EXPORT_SYMBOL(kref_get); | 66 | EXPORT_SYMBOL(kref_get); |
78 | EXPORT_SYMBOL(kref_put); | 67 | EXPORT_SYMBOL(kref_put); |