- patches.arch/x86_mce_intel_decode_physical_address.patch:
[linux-flexiantxendom0-3.2.10.git] / fs / sysfs / dir.c
index 5907178..7e54bac 100644 (file)
@@ -380,7 +380,7 @@ 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;
 
        sd->s_parent = sysfs_get(acxt->parent_sd);
@@ -533,13 +533,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 (ns && sd->s_ns && (sd->s_ns != ns))
+                       continue;
                if (!strcmp(sd->s_name, name))
                        return sd;
+       }
        return NULL;
 }
 
@@ -558,12 +562,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 +577,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 +589,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 +610,33 @@ 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);
+}
+
+/**
+ *     sysfs_read_ns_type: return associated ns_type
+ *     @kobj: the kobject being queried
+ *
+ *     Each kobject can be tagged with exactly one namespace type
+ *     (i.e. network or user).  Return the ns_type associated with
+ *     this object if any
+ */
+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 +645,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 +657,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 +671,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 +782,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 +791,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 +818,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 +829,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 +865,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 && 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 && pos->s_ns != ns)
+               pos = pos->s_sibling;
        return pos;
 }
 
@@ -841,8 +902,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 +923,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;