aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/class.c9
-rw-r--r--drivers/base/core.c77
-rw-r--r--include/linux/device.h3
-rw-r--r--include/linux/kobject.h26
-rw-r--r--lib/kobject.c103
5 files changed, 204 insertions, 14 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 9c6a0d6408e7..8e231d05b400 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -63,6 +63,14 @@ static void class_release(struct kobject *kobj)
63 kfree(cp); 63 kfree(cp);
64} 64}
65 65
66static const struct kobj_ns_type_operations *class_child_ns_type(struct kobject *kobj)
67{
68 struct class_private *cp = to_class(kobj);
69 struct class *class = cp->class;
70
71 return class->ns_type;
72}
73
66static const struct sysfs_ops class_sysfs_ops = { 74static const struct sysfs_ops class_sysfs_ops = {
67 .show = class_attr_show, 75 .show = class_attr_show,
68 .store = class_attr_store, 76 .store = class_attr_store,
@@ -71,6 +79,7 @@ static const struct sysfs_ops class_sysfs_ops = {
71static struct kobj_type class_ktype = { 79static struct kobj_type class_ktype = {
72 .sysfs_ops = &class_sysfs_ops, 80 .sysfs_ops = &class_sysfs_ops,
73 .release = class_release, 81 .release = class_release,
82 .child_ns_type = class_child_ns_type,
74}; 83};
75 84
76/* Hotplug events for classes go to the class class_subsys */ 85/* Hotplug events for classes go to the class class_subsys */
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 356dd011b8f9..f0699918e2f6 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -131,9 +131,21 @@ static void device_release(struct kobject *kobj)
131 kfree(p); 131 kfree(p);
132} 132}
133 133
134static const void *device_namespace(struct kobject *kobj)
135{
136 struct device *dev = to_dev(kobj);
137 const void *ns = NULL;
138
139 if (dev->class && dev->class->ns_type)
140 ns = dev->class->namespace(dev);
141
142 return ns;
143}
144
134static struct kobj_type device_ktype = { 145static struct kobj_type device_ktype = {
135 .release = device_release, 146 .release = device_release,
136 .sysfs_ops = &dev_sysfs_ops, 147 .sysfs_ops = &dev_sysfs_ops,
148 .namespace = device_namespace,
137}; 149};
138 150
139 151
@@ -595,11 +607,59 @@ static struct kobject *virtual_device_parent(struct device *dev)
595 return virtual_dir; 607 return virtual_dir;
596} 608}
597 609
598static struct kobject *get_device_parent(struct device *dev, 610struct class_dir {
599 struct device *parent) 611 struct kobject kobj;
612 struct class *class;
613};
614
615#define to_class_dir(obj) container_of(obj, struct class_dir, kobj)
616
617static void class_dir_release(struct kobject *kobj)
618{
619 struct class_dir *dir = to_class_dir(kobj);
620 kfree(dir);
621}
622
623static const
624struct kobj_ns_type_operations *class_dir_child_ns_type(struct kobject *kobj)
600{ 625{
626 struct class_dir *dir = to_class_dir(kobj);
627 return dir->class->ns_type;
628}
629
630static struct kobj_type class_dir_ktype = {
631 .release = class_dir_release,
632 .sysfs_ops = &kobj_sysfs_ops,
633 .child_ns_type = class_dir_child_ns_type
634};
635
636static struct kobject *
637class_dir_create_and_add(struct class *class, struct kobject *parent_kobj)
638{
639 struct class_dir *dir;
601 int retval; 640 int retval;
602 641
642 dir = kzalloc(sizeof(*dir), GFP_KERNEL);
643 if (!dir)
644 return NULL;
645
646 dir->class = class;
647 kobject_init(&dir->kobj, &class_dir_ktype);
648
649 dir->kobj.kset = &class->p->class_dirs;
650
651 retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name);
652 if (retval < 0) {
653 kobject_put(&dir->kobj);
654 return NULL;
655 }
656 return &dir->kobj;
657}
658
659
660static struct kobject *get_device_parent(struct device *dev,
661 struct device *parent)
662{
603 if (dev->class) { 663 if (dev->class) {
604 static DEFINE_MUTEX(gdp_mutex); 664 static DEFINE_MUTEX(gdp_mutex);
605 struct kobject *kobj = NULL; 665 struct kobject *kobj = NULL;
@@ -634,18 +694,7 @@ static struct kobject *get_device_parent(struct device *dev,
634 } 694 }
635 695
636 /* or create a new class-directory at the parent device */ 696 /* or create a new class-directory at the parent device */
637 k = kobject_create(); 697 k = class_dir_create_and_add(dev->class, parent_kobj);
638 if (!k) {
639 mutex_unlock(&gdp_mutex);
640 return NULL;
641 }
642 k->kset = &dev->class->p->class_dirs;
643 retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
644 if (retval < 0) {
645 mutex_unlock(&gdp_mutex);
646 kobject_put(k);
647 return NULL;
648 }
649 /* do not emit an uevent for this simple "glue" directory */ 698 /* do not emit an uevent for this simple "glue" directory */
650 mutex_unlock(&gdp_mutex); 699 mutex_unlock(&gdp_mutex);
651 return k; 700 return k;
diff --git a/include/linux/device.h b/include/linux/device.h
index 6f9619190aaf..7bb9f426f3e6 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -202,6 +202,9 @@ struct class {
202 int (*suspend)(struct device *dev, pm_message_t state); 202 int (*suspend)(struct device *dev, pm_message_t state);
203 int (*resume)(struct device *dev); 203 int (*resume)(struct device *dev);
204 204
205 const struct kobj_ns_type_operations *ns_type;
206 const void *(*namespace)(struct device *dev);
207
205 const struct dev_pm_ops *pm; 208 const struct dev_pm_ops *pm;
206 209
207 struct class_private *p; 210 struct class_private *p;
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index 3950d3c2850d..d9456f69904f 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -108,6 +108,8 @@ struct kobj_type {
108 void (*release)(struct kobject *kobj); 108 void (*release)(struct kobject *kobj);
109 const struct sysfs_ops *sysfs_ops; 109 const struct sysfs_ops *sysfs_ops;
110 struct attribute **default_attrs; 110 struct attribute **default_attrs;
111 const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
112 const void *(*namespace)(struct kobject *kobj);
111}; 113};
112 114
113struct kobj_uevent_env { 115struct kobj_uevent_env {
@@ -134,6 +136,30 @@ struct kobj_attribute {
134 136
135extern const struct sysfs_ops kobj_sysfs_ops; 137extern const struct sysfs_ops kobj_sysfs_ops;
136 138
139enum kobj_ns_type {
140 KOBJ_NS_TYPE_NONE = 0,
141 KOBJ_NS_TYPES
142};
143
144struct sock;
145struct kobj_ns_type_operations {
146 enum kobj_ns_type type;
147 const void *(*current_ns)(void);
148 const void *(*netlink_ns)(struct sock *sk);
149 const void *(*initial_ns)(void);
150};
151
152int kobj_ns_type_register(const struct kobj_ns_type_operations *ops);
153int kobj_ns_type_registered(enum kobj_ns_type type);
154const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent);
155const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj);
156
157const void *kobj_ns_current(enum kobj_ns_type type);
158const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk);
159const void *kobj_ns_initial(enum kobj_ns_type type);
160void kobj_ns_exit(enum kobj_ns_type type, const void *ns);
161
162
137/** 163/**
138 * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem. 164 * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
139 * 165 *
diff --git a/lib/kobject.c b/lib/kobject.c
index 8115eb1bbf4d..bbb2bb40ee1f 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -850,6 +850,109 @@ struct kset *kset_create_and_add(const char *name,
850} 850}
851EXPORT_SYMBOL_GPL(kset_create_and_add); 851EXPORT_SYMBOL_GPL(kset_create_and_add);
852 852
853
854static DEFINE_SPINLOCK(kobj_ns_type_lock);
855static const struct kobj_ns_type_operations *kobj_ns_ops_tbl[KOBJ_NS_TYPES];
856
857int 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
879out:
880 spin_unlock(&kobj_ns_type_lock);
881 return error;
882}
883
884int 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
896const 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
906const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj)
907{
908 return kobj_child_ns_ops(kobj->parent);
909}
910
911
912const 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
925const 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
938const 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
951void kobj_ns_exit(enum kobj_ns_type type, const void *ns)
952{
953}
954
955
853EXPORT_SYMBOL(kobject_get); 956EXPORT_SYMBOL(kobject_get);
854EXPORT_SYMBOL(kobject_put); 957EXPORT_SYMBOL(kobject_put);
855EXPORT_SYMBOL(kobject_del); 958EXPORT_SYMBOL(kobject_del);