kobj: Add basic infrastructure for dealing with namespaces.
authorEric W. Biederman <ebiederm@xmission.com>
Tue, 30 Mar 2010 18:31:25 +0000 (11:31 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 21 May 2010 16:37:31 +0000 (09:37 -0700)
Move complete knowledge of namespaces into the kobject layer
so we can use that information when reporting kobjects to
userspace.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/base/class.c
drivers/base/core.c
include/linux/device.h
include/linux/kobject.h
lib/kobject.c

index 9c6a0d6..8e231d0 100644 (file)
@@ -63,6 +63,14 @@ static void class_release(struct kobject *kobj)
        kfree(cp);
 }
 
+static const struct kobj_ns_type_operations *class_child_ns_type(struct kobject *kobj)
+{
+       struct class_private *cp = to_class(kobj);
+       struct class *class = cp->class;
+
+       return class->ns_type;
+}
+
 static const struct sysfs_ops class_sysfs_ops = {
        .show   = class_attr_show,
        .store  = class_attr_store,
@@ -71,6 +79,7 @@ static const struct sysfs_ops class_sysfs_ops = {
 static struct kobj_type class_ktype = {
        .sysfs_ops      = &class_sysfs_ops,
        .release        = class_release,
+       .child_ns_type  = class_child_ns_type,
 };
 
 /* Hotplug events for classes go to the class class_subsys */
index 356dd01..f069991 100644 (file)
@@ -131,9 +131,21 @@ static void device_release(struct kobject *kobj)
        kfree(p);
 }
 
+static const void *device_namespace(struct kobject *kobj)
+{
+       struct device *dev = to_dev(kobj);
+       const void *ns = NULL;
+
+       if (dev->class && dev->class->ns_type)
+               ns = dev->class->namespace(dev);
+
+       return ns;
+}
+
 static struct kobj_type device_ktype = {
        .release        = device_release,
        .sysfs_ops      = &dev_sysfs_ops,
+       .namespace      = device_namespace,
 };
 
 
@@ -595,11 +607,59 @@ static struct kobject *virtual_device_parent(struct device *dev)
        return virtual_dir;
 }
 
-static struct kobject *get_device_parent(struct device *dev,
-                                        struct device *parent)
+struct class_dir {
+       struct kobject kobj;
+       struct class *class;
+};
+
+#define to_class_dir(obj) container_of(obj, struct class_dir, kobj)
+
+static void class_dir_release(struct kobject *kobj)
+{
+       struct class_dir *dir = to_class_dir(kobj);
+       kfree(dir);
+}
+
+static const
+struct kobj_ns_type_operations *class_dir_child_ns_type(struct kobject *kobj)
 {
+       struct class_dir *dir = to_class_dir(kobj);
+       return dir->class->ns_type;
+}
+
+static struct kobj_type class_dir_ktype = {
+       .release        = class_dir_release,
+       .sysfs_ops      = &kobj_sysfs_ops,
+       .child_ns_type  = class_dir_child_ns_type
+};
+
+static struct kobject *
+class_dir_create_and_add(struct class *class, struct kobject *parent_kobj)
+{
+       struct class_dir *dir;
        int retval;
 
+       dir = kzalloc(sizeof(*dir), GFP_KERNEL);
+       if (!dir)
+               return NULL;
+
+       dir->class = class;
+       kobject_init(&dir->kobj, &class_dir_ktype);
+
+       dir->kobj.kset = &class->p->class_dirs;
+
+       retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name);
+       if (retval < 0) {
+               kobject_put(&dir->kobj);
+               return NULL;
+       }
+       return &dir->kobj;
+}
+
+
+static struct kobject *get_device_parent(struct device *dev,
+                                        struct device *parent)
+{
        if (dev->class) {
                static DEFINE_MUTEX(gdp_mutex);
                struct kobject *kobj = NULL;
@@ -634,18 +694,7 @@ static struct kobject *get_device_parent(struct device *dev,
                }
 
                /* or create a new class-directory at the parent device */
-               k = kobject_create();
-               if (!k) {
-                       mutex_unlock(&gdp_mutex);
-                       return NULL;
-               }
-               k->kset = &dev->class->p->class_dirs;
-               retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
-               if (retval < 0) {
-                       mutex_unlock(&gdp_mutex);
-                       kobject_put(k);
-                       return NULL;
-               }
+               k = class_dir_create_and_add(dev->class, parent_kobj);
                /* do not emit an uevent for this simple "glue" directory */
                mutex_unlock(&gdp_mutex);
                return k;
index 6f96191..7bb9f42 100644 (file)
@@ -202,6 +202,9 @@ struct class {
        int (*suspend)(struct device *dev, pm_message_t state);
        int (*resume)(struct device *dev);
 
+       const struct kobj_ns_type_operations *ns_type;
+       const void *(*namespace)(struct device *dev);
+
        const struct dev_pm_ops *pm;
 
        struct class_private *p;
index 3950d3c..d9456f6 100644 (file)
@@ -108,6 +108,8 @@ struct kobj_type {
        void (*release)(struct kobject *kobj);
        const struct sysfs_ops *sysfs_ops;
        struct attribute **default_attrs;
+       const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
+       const void *(*namespace)(struct kobject *kobj);
 };
 
 struct kobj_uevent_env {
@@ -134,6 +136,30 @@ struct kobj_attribute {
 
 extern const struct sysfs_ops kobj_sysfs_ops;
 
+enum kobj_ns_type {
+       KOBJ_NS_TYPE_NONE = 0,
+       KOBJ_NS_TYPES
+};
+
+struct sock;
+struct kobj_ns_type_operations {
+       enum kobj_ns_type type;
+       const void *(*current_ns)(void);
+       const void *(*netlink_ns)(struct sock *sk);
+       const void *(*initial_ns)(void);
+};
+
+int kobj_ns_type_register(const struct kobj_ns_type_operations *ops);
+int kobj_ns_type_registered(enum kobj_ns_type type);
+const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent);
+const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj);
+
+const void *kobj_ns_current(enum kobj_ns_type type);
+const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk);
+const void *kobj_ns_initial(enum kobj_ns_type type);
+void kobj_ns_exit(enum kobj_ns_type type, const void *ns);
+
+
 /**
  * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
  *
index 8115eb1..bbb2bb4 100644 (file)
@@ -850,6 +850,109 @@ struct kset *kset_create_and_add(const char *name,
 }
 EXPORT_SYMBOL_GPL(kset_create_and_add);
 
+
+static DEFINE_SPINLOCK(kobj_ns_type_lock);
+static const struct kobj_ns_type_operations *kobj_ns_ops_tbl[KOBJ_NS_TYPES];
+
+int kobj_ns_type_register(const struct kobj_ns_type_operations *ops)
+{
+       enum kobj_ns_type type = ops->type;
+       int error;
+
+       spin_lock(&kobj_ns_type_lock);
+
+       error = -EINVAL;
+       if (type >= KOBJ_NS_TYPES)
+               goto out;
+
+       error = -EINVAL;
+       if (type <= KOBJ_NS_TYPE_NONE)
+               goto out;
+
+       error = -EBUSY;
+       if (kobj_ns_ops_tbl[type])
+               goto out;
+
+       error = 0;
+       kobj_ns_ops_tbl[type] = ops;
+
+out:
+       spin_unlock(&kobj_ns_type_lock);
+       return error;
+}
+
+int kobj_ns_type_registered(enum kobj_ns_type type)
+{
+       int registered = 0;
+
+       spin_lock(&kobj_ns_type_lock);
+       if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES))
+               registered = kobj_ns_ops_tbl[type] != NULL;
+       spin_unlock(&kobj_ns_type_lock);
+
+       return registered;
+}
+
+const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent)
+{
+       const struct kobj_ns_type_operations *ops = NULL;
+
+       if (parent && parent->ktype->child_ns_type)
+               ops = parent->ktype->child_ns_type(parent);
+
+       return ops;
+}
+
+const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj)
+{
+       return kobj_child_ns_ops(kobj->parent);
+}
+
+
+const void *kobj_ns_current(enum kobj_ns_type type)
+{
+       const void *ns = NULL;
+
+       spin_lock(&kobj_ns_type_lock);
+       if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
+           kobj_ns_ops_tbl[type])
+               ns = kobj_ns_ops_tbl[type]->current_ns();
+       spin_unlock(&kobj_ns_type_lock);
+
+       return ns;
+}
+
+const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk)
+{
+       const void *ns = NULL;
+
+       spin_lock(&kobj_ns_type_lock);
+       if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
+           kobj_ns_ops_tbl[type])
+               ns = kobj_ns_ops_tbl[type]->netlink_ns(sk);
+       spin_unlock(&kobj_ns_type_lock);
+
+       return ns;
+}
+
+const void *kobj_ns_initial(enum kobj_ns_type type)
+{
+       const void *ns = NULL;
+
+       spin_lock(&kobj_ns_type_lock);
+       if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
+           kobj_ns_ops_tbl[type])
+               ns = kobj_ns_ops_tbl[type]->initial_ns();
+       spin_unlock(&kobj_ns_type_lock);
+
+       return ns;
+}
+
+void kobj_ns_exit(enum kobj_ns_type type, const void *ns)
+{
+}
+
+
 EXPORT_SYMBOL(kobject_get);
 EXPORT_SYMBOL(kobject_put);
 EXPORT_SYMBOL(kobject_del);