diff options
| -rw-r--r-- | drivers/base/class.c | 9 | ||||
| -rw-r--r-- | drivers/base/core.c | 77 | ||||
| -rw-r--r-- | include/linux/device.h | 3 | ||||
| -rw-r--r-- | include/linux/kobject.h | 26 | ||||
| -rw-r--r-- | lib/kobject.c | 103 | 
5 files changed, 204 insertions, 14 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c index 9c6a0d6408e..8e231d05b40 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -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 */ diff --git a/drivers/base/core.c b/drivers/base/core.c index 356dd011b8f..f0699918e2f 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -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; diff --git a/include/linux/device.h b/include/linux/device.h index 6f9619190aa..7bb9f426f3e 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -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; diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 3950d3c2850..d9456f69904 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -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.   * diff --git a/lib/kobject.c b/lib/kobject.c index 8115eb1bbf4..bbb2bb40ee1 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -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);  |