|
@@ -380,9 +380,15 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
|
|
|
{
|
|
|
struct sysfs_inode_attrs *ps_iattr;
|
|
|
|
|
|
- if (sysfs_find_dirent(acxt->parent_sd, sd->s_name))
|
|
|
+ if (sysfs_find_dirent(acxt->parent_sd, sd->s_ns, sd->s_name))
|
|
|
return -EEXIST;
|
|
|
|
|
|
+ if (sysfs_ns_type(acxt->parent_sd) && !sd->s_ns) {
|
|
|
+ WARN(1, KERN_WARNING "sysfs: ns required in '%s' for '%s'\n",
|
|
|
+ acxt->parent_sd->s_name, sd->s_name);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
sd->s_parent = sysfs_get(acxt->parent_sd);
|
|
|
|
|
|
sysfs_link_sibling(sd);
|
|
@@ -533,13 +539,17 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
|
|
|
* Pointer to sysfs_dirent if found, NULL if not.
|
|
|
*/
|
|
|
struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
|
|
|
+ const void *ns,
|
|
|
const unsigned char *name)
|
|
|
{
|
|
|
struct sysfs_dirent *sd;
|
|
|
|
|
|
- for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)
|
|
|
+ for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) {
|
|
|
+ if (sd->s_ns != ns)
|
|
|
+ continue;
|
|
|
if (!strcmp(sd->s_name, name))
|
|
|
return sd;
|
|
|
+ }
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
@@ -558,12 +568,13 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
|
|
|
* Pointer to sysfs_dirent if found, NULL if not.
|
|
|
*/
|
|
|
struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
|
|
|
+ const void *ns,
|
|
|
const unsigned char *name)
|
|
|
{
|
|
|
struct sysfs_dirent *sd;
|
|
|
|
|
|
mutex_lock(&sysfs_mutex);
|
|
|
- sd = sysfs_find_dirent(parent_sd, name);
|
|
|
+ sd = sysfs_find_dirent(parent_sd, ns, name);
|
|
|
sysfs_get(sd);
|
|
|
mutex_unlock(&sysfs_mutex);
|
|
|
|
|
@@ -572,7 +583,8 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
|
|
|
EXPORT_SYMBOL_GPL(sysfs_get_dirent);
|
|
|
|
|
|
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
|
|
|
- const char *name, struct sysfs_dirent **p_sd)
|
|
|
+ enum kobj_ns_type type, const void *ns, const char *name,
|
|
|
+ struct sysfs_dirent **p_sd)
|
|
|
{
|
|
|
umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
|
|
|
struct sysfs_addrm_cxt acxt;
|
|
@@ -583,6 +595,9 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
|
|
|
sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
|
|
|
if (!sd)
|
|
|
return -ENOMEM;
|
|
|
+
|
|
|
+ sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT);
|
|
|
+ sd->s_ns = ns;
|
|
|
sd->s_dir.kobj = kobj;
|
|
|
|
|
|
/* link in */
|
|
@@ -601,7 +616,25 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
|
|
|
int sysfs_create_subdir(struct kobject *kobj, const char *name,
|
|
|
struct sysfs_dirent **p_sd)
|
|
|
{
|
|
|
- return create_dir(kobj, kobj->sd, name, p_sd);
|
|
|
+ return create_dir(kobj, kobj->sd,
|
|
|
+ KOBJ_NS_TYPE_NONE, NULL, name, p_sd);
|
|
|
+}
|
|
|
+
|
|
|
+static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj)
|
|
|
+{
|
|
|
+ const struct kobj_ns_type_operations *ops;
|
|
|
+ enum kobj_ns_type type;
|
|
|
+
|
|
|
+ ops = kobj_child_ns_ops(kobj);
|
|
|
+ if (!ops)
|
|
|
+ return KOBJ_NS_TYPE_NONE;
|
|
|
+
|
|
|
+ type = ops->type;
|
|
|
+ BUG_ON(type <= KOBJ_NS_TYPE_NONE);
|
|
|
+ BUG_ON(type >= KOBJ_NS_TYPES);
|
|
|
+ BUG_ON(!kobj_ns_type_registered(type));
|
|
|
+
|
|
|
+ return type;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -610,7 +643,9 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name,
|
|
|
*/
|
|
|
int sysfs_create_dir(struct kobject * kobj)
|
|
|
{
|
|
|
+ enum kobj_ns_type type;
|
|
|
struct sysfs_dirent *parent_sd, *sd;
|
|
|
+ const void *ns = NULL;
|
|
|
int error = 0;
|
|
|
|
|
|
BUG_ON(!kobj);
|
|
@@ -620,7 +655,11 @@ int sysfs_create_dir(struct kobject * kobj)
|
|
|
else
|
|
|
parent_sd = &sysfs_root;
|
|
|
|
|
|
- error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
|
|
|
+ if (sysfs_ns_type(parent_sd))
|
|
|
+ ns = kobj->ktype->namespace(kobj);
|
|
|
+ type = sysfs_read_ns_type(kobj);
|
|
|
+
|
|
|
+ error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd);
|
|
|
if (!error)
|
|
|
kobj->sd = sd;
|
|
|
return error;
|
|
@@ -630,13 +669,19 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
|
|
|
struct nameidata *nd)
|
|
|
{
|
|
|
struct dentry *ret = NULL;
|
|
|
- struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata;
|
|
|
+ struct dentry *parent = dentry->d_parent;
|
|
|
+ struct sysfs_dirent *parent_sd = parent->d_fsdata;
|
|
|
struct sysfs_dirent *sd;
|
|
|
struct inode *inode;
|
|
|
+ enum kobj_ns_type type;
|
|
|
+ const void *ns;
|
|
|
|
|
|
mutex_lock(&sysfs_mutex);
|
|
|
|
|
|
- sd = sysfs_find_dirent(parent_sd, dentry->d_name.name);
|
|
|
+ type = sysfs_ns_type(parent_sd);
|
|
|
+ ns = sysfs_info(dir->i_sb)->ns[type];
|
|
|
+
|
|
|
+ sd = sysfs_find_dirent(parent_sd, ns, dentry->d_name.name);
|
|
|
|
|
|
/* no such entry */
|
|
|
if (!sd) {
|
|
@@ -735,7 +780,8 @@ void sysfs_remove_dir(struct kobject * kobj)
|
|
|
}
|
|
|
|
|
|
int sysfs_rename(struct sysfs_dirent *sd,
|
|
|
- struct sysfs_dirent *new_parent_sd, const char *new_name)
|
|
|
+ struct sysfs_dirent *new_parent_sd, const void *new_ns,
|
|
|
+ const char *new_name)
|
|
|
{
|
|
|
const char *dup_name = NULL;
|
|
|
int error;
|
|
@@ -743,12 +789,12 @@ int sysfs_rename(struct sysfs_dirent *sd,
|
|
|
mutex_lock(&sysfs_mutex);
|
|
|
|
|
|
error = 0;
|
|
|
- if ((sd->s_parent == new_parent_sd) &&
|
|
|
+ if ((sd->s_parent == new_parent_sd) && (sd->s_ns == new_ns) &&
|
|
|
(strcmp(sd->s_name, new_name) == 0))
|
|
|
goto out; /* nothing to rename */
|
|
|
|
|
|
error = -EEXIST;
|
|
|
- if (sysfs_find_dirent(new_parent_sd, new_name))
|
|
|
+ if (sysfs_find_dirent(new_parent_sd, new_ns, new_name))
|
|
|
goto out;
|
|
|
|
|
|
/* rename sysfs_dirent */
|
|
@@ -770,6 +816,7 @@ int sysfs_rename(struct sysfs_dirent *sd,
|
|
|
sd->s_parent = new_parent_sd;
|
|
|
sysfs_link_sibling(sd);
|
|
|
}
|
|
|
+ sd->s_ns = new_ns;
|
|
|
|
|
|
error = 0;
|
|
|
out:
|
|
@@ -780,19 +827,28 @@ int sysfs_rename(struct sysfs_dirent *sd,
|
|
|
|
|
|
int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
|
|
|
{
|
|
|
- return sysfs_rename(kobj->sd, kobj->sd->s_parent, new_name);
|
|
|
+ struct sysfs_dirent *parent_sd = kobj->sd->s_parent;
|
|
|
+ const void *new_ns = NULL;
|
|
|
+
|
|
|
+ if (sysfs_ns_type(parent_sd))
|
|
|
+ new_ns = kobj->ktype->namespace(kobj);
|
|
|
+
|
|
|
+ return sysfs_rename(kobj->sd, parent_sd, new_ns, new_name);
|
|
|
}
|
|
|
|
|
|
int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
|
|
|
{
|
|
|
struct sysfs_dirent *sd = kobj->sd;
|
|
|
struct sysfs_dirent *new_parent_sd;
|
|
|
+ const void *new_ns = NULL;
|
|
|
|
|
|
BUG_ON(!sd->s_parent);
|
|
|
+ if (sysfs_ns_type(sd->s_parent))
|
|
|
+ new_ns = kobj->ktype->namespace(kobj);
|
|
|
new_parent_sd = new_parent_kobj && new_parent_kobj->sd ?
|
|
|
new_parent_kobj->sd : &sysfs_root;
|
|
|
|
|
|
- return sysfs_rename(sd, new_parent_sd, sd->s_name);
|
|
|
+ return sysfs_rename(sd, new_parent_sd, new_ns, sd->s_name);
|
|
|
}
|
|
|
|
|
|
/* Relationship between s_mode and the DT_xxx types */
|
|
@@ -807,32 +863,35 @@ static int sysfs_dir_release(struct inode *inode, struct file *filp)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static struct sysfs_dirent *sysfs_dir_pos(struct sysfs_dirent *parent_sd,
|
|
|
- ino_t ino, struct sysfs_dirent *pos)
|
|
|
+static struct sysfs_dirent *sysfs_dir_pos(const void *ns,
|
|
|
+ struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos)
|
|
|
{
|
|
|
if (pos) {
|
|
|
int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) &&
|
|
|
pos->s_parent == parent_sd &&
|
|
|
ino == pos->s_ino;
|
|
|
sysfs_put(pos);
|
|
|
- if (valid)
|
|
|
- return pos;
|
|
|
+ if (!valid)
|
|
|
+ pos = NULL;
|
|
|
}
|
|
|
- pos = NULL;
|
|
|
- if ((ino > 1) && (ino < INT_MAX)) {
|
|
|
+ if (!pos && (ino > 1) && (ino < INT_MAX)) {
|
|
|
pos = parent_sd->s_dir.children;
|
|
|
while (pos && (ino > pos->s_ino))
|
|
|
pos = pos->s_sibling;
|
|
|
}
|
|
|
+ while (pos && pos->s_ns != ns)
|
|
|
+ pos = pos->s_sibling;
|
|
|
return pos;
|
|
|
}
|
|
|
|
|
|
-static struct sysfs_dirent *sysfs_dir_next_pos(struct sysfs_dirent *parent_sd,
|
|
|
- ino_t ino, struct sysfs_dirent *pos)
|
|
|
+static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns,
|
|
|
+ struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos)
|
|
|
{
|
|
|
- pos = sysfs_dir_pos(parent_sd, ino, pos);
|
|
|
+ pos = sysfs_dir_pos(ns, parent_sd, ino, pos);
|
|
|
if (pos)
|
|
|
pos = pos->s_sibling;
|
|
|
+ while (pos && pos->s_ns != ns)
|
|
|
+ pos = pos->s_sibling;
|
|
|
return pos;
|
|
|
}
|
|
|
|
|
@@ -841,8 +900,13 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
|
|
|
struct dentry *dentry = filp->f_path.dentry;
|
|
|
struct sysfs_dirent * parent_sd = dentry->d_fsdata;
|
|
|
struct sysfs_dirent *pos = filp->private_data;
|
|
|
+ enum kobj_ns_type type;
|
|
|
+ const void *ns;
|
|
|
ino_t ino;
|
|
|
|
|
|
+ type = sysfs_ns_type(parent_sd);
|
|
|
+ ns = sysfs_info(dentry->d_sb)->ns[type];
|
|
|
+
|
|
|
if (filp->f_pos == 0) {
|
|
|
ino = parent_sd->s_ino;
|
|
|
if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0)
|
|
@@ -857,9 +921,9 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
|
|
|
filp->f_pos++;
|
|
|
}
|
|
|
mutex_lock(&sysfs_mutex);
|
|
|
- for (pos = sysfs_dir_pos(parent_sd, filp->f_pos, pos);
|
|
|
+ for (pos = sysfs_dir_pos(ns, parent_sd, filp->f_pos, pos);
|
|
|
pos;
|
|
|
- pos = sysfs_dir_next_pos(parent_sd, filp->f_pos, pos)) {
|
|
|
+ pos = sysfs_dir_next_pos(ns, parent_sd, filp->f_pos, pos)) {
|
|
|
const char * name;
|
|
|
unsigned int type;
|
|
|
int len, ret;
|