kobj: Add basic infrastructure for dealing with namespaces.
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>
This commit is contained in:
parent
ba514a57f5
commit
bc451f2058
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int retval;
|
||||
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
103
lib/kobject.c
103
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);
|
||||
|
|
Loading…
Reference in New Issue