Skip to content

Commit

Permalink
kobj: Add basic infrastructure for dealing with namespaces.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Eric W. Biederman authored and Greg Kroah-Hartman committed May 21, 2010
1 parent ba514a5 commit bc451f2
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 14 deletions.
9 changes: 9 additions & 0 deletions drivers/base/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 */
Expand Down
77 changes: 63 additions & 14 deletions drivers/base/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};


Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions include/linux/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
26 changes: 26 additions & 0 deletions include/linux/kobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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.
*
Expand Down
103 changes: 103 additions & 0 deletions lib/kobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit bc451f2

Please sign in to comment.