Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756495AbYH0PTY (ORCPT ); Wed, 27 Aug 2008 11:19:24 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753299AbYH0PTI (ORCPT ); Wed, 27 Aug 2008 11:19:08 -0400 Received: from ecfrec.frec.bull.fr ([129.183.4.8]:42168 "EHLO ecfrec.frec.bull.fr" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752724AbYH0PTF (ORCPT ); Wed, 27 Aug 2008 11:19:05 -0400 Message-ID: <48B57058.9000101@bull.net> Date: Wed, 27 Aug 2008 17:18:48 +0200 From: Benjamin Thery User-Agent: Thunderbird 2.0.0.16 (X11/20080723) MIME-Version: 1.0 To: "Eric W. Biederman" Cc: Greg KH , Greg Kroah-Hartman , Andrew Morton , Tejun Heo , Daniel Lezcano , linux-kernel@vger.kernel.org, Al Viro , Linux Containers , netdev@vger.kernel.org Subject: Re: [PATCH 1/8] sysfs: Implement sysfs tagged directory support. References: <20080820021754.GA25182@kroah.com> In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 25757 Lines: 793 Eric W. Biederman wrote: > The problem. When implementing a network namespace I need to be able > to have multiple network devices with the same name. Currently this > is a problem for /sys/class/net/*, /sys/devices/virtual/net/*, and > potentially a few other directories of the form /sys/ ... /net/*. > > What this patch does is to add an additional tag field to the > sysfs dirent structure. For directories that should show different > contents depending on the context such as /sys/class/net/, and > /sys/devices/virtual/net/ this tag field is used to specify the > context in which those directories should be visible. Effectively > this is the same as creating multiple distinct directories with > the same name but internally to sysfs the result is nicer. > > I am calling the concept of a single directory that looks like multiple > directories all at the same path in the filesystem tagged directories. > > For the networking namespace the set of directories whose contents I need > to filter with tags can depend on the presence or absence of hotplug > hardware or which modules are currently loaded. Which means I need > a simple race free way to setup those directories as tagged. > > To achieve a reace free design all tagged directories are created > and managed by sysfs itself. > > Users of this interface: > - define a type in the sysfs_tag_type enumeration. > - call sysfs_register_tag_types with the type and it's operations > - call sysfs_make_tagged_dir with the tag type on directories > to be managed by this tag type > - sysfs_exit_tag when an individual tag is no longer valid > > - Implement mount_tag() which returns the tag of the calling process > so we can attach it to a sysfs superblock. > - Implement ktype.sysfs_tag() which returns the tag of a syfs kobject. > > Everything else is left up to sysfs and the driver layer. > > For the network namespace mount_tag and sysfs_tag are essentially > one line functions, and look to remain that. > > Tags are currently represented a const void * pointers as that is > both generic, prevides enough information for equality comparisons, > and is trivial to create for current users, as it is just the > existing namespace pointer. > > The work needed in sysfs is more extensive. At each directory > or symlink creating I need to check if the directory it is being > created in is a tagged directory and if so generate the appropriate > tag to place on the sysfs_dirent. Likewise at each symlink or > directory removal I need to check if the sysfs directory it is > being removed from is a tagged directory and if so figure out > which tag goes along with the name I am deleting. > > Currently only directories which hold kobjects, and > symlinks are supported. There is not enough information > in the current file attribute interfaces to give us anything > to discriminate on which makes it useless, and there are > no potential users which makes it an uninteresting problem > to solve. > > Signed-off-by: Eric W. Biederman > Signed-off-by: Benjamin Thery > --- > fs/sysfs/bin.c | 2 +- > fs/sysfs/dir.c | 139 ++++++++++++++++++++++++++++++++++++++++++----- > fs/sysfs/file.c | 11 +++-- > fs/sysfs/group.c | 4 +- > fs/sysfs/inode.c | 7 ++- > fs/sysfs/mount.c | 115 +++++++++++++++++++++++++++++++++++++-- > fs/sysfs/symlink.c | 2 +- > fs/sysfs/sysfs.h | 19 ++++++- > include/linux/kobject.h | 1 + > include/linux/sysfs.h | 31 +++++++++++ > 10 files changed, 298 insertions(+), 33 deletions(-) > > diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c > index 006fc64..86e1128 100644 > --- a/fs/sysfs/bin.c > +++ b/fs/sysfs/bin.c > @@ -252,7 +252,7 @@ int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr) > > void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr) > { > - sysfs_hash_and_remove(kobj->sd, attr->attr.name); > + sysfs_hash_and_remove(kobj, kobj->sd, attr->attr.name); > } > > EXPORT_SYMBOL_GPL(sysfs_create_bin_file); > diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c > index 4ffcfd2..dec7586 100644 > --- a/fs/sysfs/dir.c > +++ b/fs/sysfs/dir.c > @@ -30,6 +30,30 @@ DEFINE_SPINLOCK(sysfs_assoc_lock); > static DEFINE_SPINLOCK(sysfs_ino_lock); > static DEFINE_IDA(sysfs_ino_ida); > > +static const void *sysfs_creation_tag(struct sysfs_dirent *parent_sd, > + struct sysfs_dirent *sd) > +{ > + const void *tag = NULL; > + > + if (sysfs_tag_type(parent_sd)) { > + struct kobject *kobj; > + switch (sysfs_type(sd)) { > + case SYSFS_DIR: > + kobj = sd->s_dir.kobj; > + break; > + case SYSFS_KOBJ_LINK: > + kobj = sd->s_symlink.target_sd->s_dir.kobj; > + break; > + default: > + BUG(); > + } > + tag = kobj->ktype->sysfs_tag(kobj); > + /* NULL tags are reserved for internal use */ > + BUG_ON(tag == NULL); > + } > + return tag; > +} > + > /** > * sysfs_link_sibling - link sysfs_dirent into sibling list > * @sd: sysfs_dirent of interest > @@ -101,8 +125,19 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) > struct dentry *sysfs_get_dentry(struct super_block *sb, > struct sysfs_dirent *sd) > { > - struct dentry *dentry = dget(sb->s_root); > + struct dentry *dentry; > + > + /* Bail if this sd won't show up in this superblock */ > + if (sd->s_parent) { > + enum sysfs_tag_type type; > + const void *tag; > + type = sysfs_tag_type(sd->s_parent); > + tag = sysfs_info(sb)->tag[type]; > + if (sd->s_tag != tag) > + return ERR_PTR(-EXDEV); > + } > > + dentry = dget(sb->s_root); > while (dentry->d_fsdata != sd) { > struct sysfs_dirent *cur; > struct dentry *parent; > @@ -421,10 +456,15 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, > */ > int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) > { > - if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) > + const void *tag = NULL; > + > + tag = sysfs_creation_tag(acxt->parent_sd, sd); > + > + if (sysfs_find_dirent(acxt->parent_sd, tag, sd->s_name)) > return -EEXIST; > > sd->s_parent = sysfs_get(acxt->parent_sd); > + sd->s_tag = tag; > > if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) > inc_nlink(acxt->parent_inode); > @@ -602,13 +642,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 *tag, > 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_tag != tag) > + continue; > if (!strcmp(sd->s_name, name)) > return sd; > + } > return NULL; > } > > @@ -632,7 +676,7 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, > struct sysfs_dirent *sd; > > mutex_lock(&sysfs_mutex); > - sd = sysfs_find_dirent(parent_sd, name); > + sd = sysfs_find_dirent(parent_sd, NULL, name); > sysfs_get(sd); > mutex_unlock(&sysfs_mutex); > > @@ -699,13 +743,18 @@ 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 sysfs_tag_type type; > + const void *tag; > > mutex_lock(&sysfs_mutex); > > - sd = sysfs_find_dirent(parent_sd, dentry->d_name.name); > + type = sysfs_tag_type(parent_sd); > + tag = sysfs_info(parent->d_sb)->tag[type]; > + sd = sysfs_find_dirent(parent_sd, tag, dentry->d_name.name); > > /* no such entry */ > if (!sd) { > @@ -913,19 +962,24 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) > struct sysfs_rename_struct *srs; > struct inode *parent_inode = NULL; > const char *dup_name = NULL; > + const void *old_tag, *tag; > int error; > > INIT_LIST_HEAD(&todo); > mutex_lock(&sysfs_rename_mutex); > + old_tag = sd->s_tag; > + tag = sysfs_creation_tag(sd->s_parent, sd); > > error = 0; > - if (strcmp(sd->s_name, new_name) == 0) > + if ((old_tag == tag) && (strcmp(sd->s_name, new_name) == 0)) > goto out; /* nothing to rename */ > > sysfs_grab_supers(); > - error = prep_rename(&todo, sd, sd->s_parent, new_name); > - if (error) > - goto out_release; > + if (old_tag == tag) { > + error = prep_rename(&todo, sd, sd->s_parent, new_name); > + if (error) > + goto out_release; > + } > > error = -ENOMEM; > mutex_lock(&sysfs_mutex); > @@ -938,7 +992,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) > mutex_lock(&sysfs_mutex); > > error = -EEXIST; > - if (sysfs_find_dirent(sd->s_parent, new_name)) > + if (sysfs_find_dirent(sd->s_parent, tag, new_name)) > goto out_unlock; > > /* rename sysfs_dirent */ > @@ -949,6 +1003,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) > > dup_name = sd->s_name; > sd->s_name = new_name; > + sd->s_tag = tag; > > /* rename */ > list_for_each_entry(srs, &todo, list) { > @@ -956,6 +1011,20 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) > d_move(srs->old_dentry, srs->new_dentry); > } > > + /* If we are moving across superblocks drop the dcache entries */ > + if (old_tag != tag) { > + struct super_block *sb; > + struct dentry *dentry; > + list_for_each_entry(sb, &sysfs_fs_type.fs_supers, s_instances) { > + dentry = __sysfs_get_dentry(sb, sd); > + if (!dentry) > + continue; > + shrink_dcache_parent(dentry); > + d_drop(dentry); > + dput(dentry); > + } > + } > + > error = 0; > out_unlock: > mutex_unlock(&sysfs_mutex); > @@ -978,11 +1047,13 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) > struct sysfs_rename_struct *srs; > struct inode *old_parent_inode = NULL, *new_parent_inode = NULL; > int error; > + const void *tag; > > INIT_LIST_HEAD(&todo); > mutex_lock(&sysfs_rename_mutex); > BUG_ON(!sd->s_parent); > new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; > + tag = sd->s_tag; > > error = 0; > if (sd->s_parent == new_parent_sd) > @@ -1016,7 +1087,7 @@ again: > mutex_lock(&sysfs_mutex); > > error = -EEXIST; > - if (sysfs_find_dirent(new_parent_sd, sd->s_name)) > + if (sysfs_find_dirent(new_parent_sd, tag, sd->s_name)) > goto out_unlock; > > error = 0; > @@ -1055,10 +1126,12 @@ static inline unsigned char dt_type(struct sysfs_dirent *sd) > > 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 dentry *parent = filp->f_path.dentry; > + struct sysfs_dirent *parent_sd = parent->d_fsdata; > struct sysfs_dirent *pos; > ino_t ino; > + enum sysfs_tag_type type; > + const void *tag; > > if (filp->f_pos == 0) { > ino = parent_sd->s_ino; > @@ -1076,6 +1149,9 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) > if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) { > mutex_lock(&sysfs_mutex); > > + type = sysfs_tag_type(parent_sd); > + tag = sysfs_info(parent->d_sb)->tag[type]; > + > /* Skip the dentries we have already reported */ > pos = parent_sd->s_dir.children; > while (pos && (filp->f_pos > pos->s_ino)) > @@ -1085,6 +1161,9 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) > const char * name; > int len; > > + if (pos->s_tag != tag) > + continue; > + > name = pos->s_name; > len = strlen(name); > filp->f_pos = ino = pos->s_ino; > @@ -1105,3 +1184,35 @@ const struct file_operations sysfs_dir_operations = { > .read = generic_read_dir, > .readdir = sysfs_readdir, > }; > + > +/** > + * sysfs_make_tagged_dir - Require tags of all the entries in a directory. > + * @kobj: object whose children should be filtered by tags > + * > + * Once tagging has been enabled on a directory the contents > + * of the directory become dependent upon context captured when > + * sysfs was mounted. > + */ > +int sysfs_make_tagged_dir(struct kobject *kobj, enum sysfs_tag_type type) > +{ > + struct sysfs_dirent *sd; > + int err; > + > + err = -ENOENT; > + sd = kobj->sd; > + > + mutex_lock(&sysfs_mutex); > + err = -EINVAL; > + /* We can only enable tagging when we have a valid tag type > + * on empty directories where taggint has not already been > + * enabled. > + */ > + if ((type > SYSFS_TAG_TYPE_NONE) && (type < SYSFS_TAG_TYPES) && > + tag_ops[type] && !sysfs_tag_type(sd) && > + (sysfs_type(sd) == SYSFS_DIR) && !sd->s_dir.children) { > + err = 0; > + sd->s_flags |= (type << SYSFS_TAG_TYPE_SHIFT); > + } > + mutex_unlock(&sysfs_mutex); > + return err; > +} > diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c > index 61c3476..091c0de 100644 > --- a/fs/sysfs/file.c > +++ b/fs/sysfs/file.c > @@ -476,9 +476,12 @@ void sysfs_notify(struct kobject *k, char *dir, char *attr) > mutex_lock(&sysfs_mutex); > > if (sd && dir) > - sd = sysfs_find_dirent(sd, dir); > + /* Only directories are tagged, so no need to pass > + * a tag explicitly. > + */ > + sd = sysfs_find_dirent(sd, NULL, dir); > if (sd && attr) > - sd = sysfs_find_dirent(sd, attr); > + sd = sysfs_find_dirent(sd, NULL, attr); > if (sd) > sysfs_notify_dirent(sd); > > @@ -640,7 +643,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file); > > void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) > { > - sysfs_hash_and_remove(kobj->sd, attr->name); > + sysfs_hash_and_remove(kobj, kobj->sd, attr->name); > } > > > @@ -660,7 +663,7 @@ void sysfs_remove_file_from_group(struct kobject *kobj, > else > dir_sd = sysfs_get(kobj->sd); > if (dir_sd) { > - sysfs_hash_and_remove(dir_sd, attr->name); > + sysfs_hash_and_remove(kobj, dir_sd, attr->name); > sysfs_put(dir_sd); > } > } > diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c > index fe61194..5fba6f2 100644 > --- a/fs/sysfs/group.c > +++ b/fs/sysfs/group.c > @@ -23,7 +23,7 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, > int i; > > for (i = 0, attr = grp->attrs; *attr; i++, attr++) > - sysfs_hash_and_remove(dir_sd, (*attr)->name); > + sysfs_hash_and_remove(kobj, dir_sd, (*attr)->name); > } > > static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, > @@ -39,7 +39,7 @@ static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, > * visibility. Do this by first removing then > * re-adding (if required) the file */ > if (update) > - sysfs_hash_and_remove(dir_sd, (*attr)->name); > + sysfs_hash_and_remove(kobj, dir_sd, (*attr)->name); > if (grp->is_visible) { > mode = grp->is_visible(kobj, *attr, i); > if (!mode) > diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c > index 80f8fd4..b5fc78a 100644 > --- a/fs/sysfs/inode.c > +++ b/fs/sysfs/inode.c > @@ -226,17 +226,20 @@ struct inode * sysfs_get_inode(struct sysfs_dirent *sd) > return inode; > } > > -int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) > +int sysfs_hash_and_remove(struct kobject *kobj, struct sysfs_dirent *dir_sd, > + const char *name) > { > struct sysfs_addrm_cxt acxt; > struct sysfs_dirent *sd; > + const void *tag; > > if (!dir_sd) > return -ENOENT; > > sysfs_addrm_start(&acxt, dir_sd); > + tag = kobj->sd->s_tag; > > - sd = sysfs_find_dirent(dir_sd, name); > + sd = sysfs_find_dirent(dir_sd, tag, name); > if (sd) > sysfs_remove_one(&acxt, sd); > > diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c > index 6ebda1a..8f2237a 100644 > --- a/fs/sysfs/mount.c > +++ b/fs/sysfs/mount.c > @@ -35,12 +35,15 @@ static const struct super_operations sysfs_ops = { > struct sysfs_dirent sysfs_root = { > .s_name = "", > .s_count = ATOMIC_INIT(1), > - .s_flags = SYSFS_DIR, > + .s_flags = SYSFS_DIR | (SYSFS_TAG_TYPE_NONE << SYSFS_TAG_TYPE_SHIFT), > .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, > .s_ino = 1, > }; > > -static int sysfs_fill_super(struct super_block *sb, void *data, int silent) > +struct sysfs_tag_type_operations *tag_ops[SYSFS_TAG_TYPES]; > + > +static int sysfs_fill_super(struct super_block *sb, void *data, int silent, > + const void *tags[SYSFS_TAG_TYPES]) > { > struct sysfs_super_info *info = NULL; > struct inode *inode = NULL; > @@ -76,8 +79,10 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) > goto out_err; > } > root->d_fsdata = &sysfs_root; > + root->d_sb = sb; > sb->s_root = root; > sb->s_fs_info = info; > + memcpy(info->tag, tags, sizeof(info->tag[0])*SYSFS_TAG_TYPES); > return 0; > > out_err: > @@ -89,20 +94,74 @@ out_err: > return error; > } > > +static int sysfs_test_super(struct super_block *sb, void *ptr) > +{ > + const void **tag = ptr; > + struct sysfs_super_info *info = sysfs_info(sb); > + enum sysfs_tag_type type; > + int found = 1; > + > + for (type = SYSFS_TAG_TYPE_NONE; type < SYSFS_TAG_TYPES; type++) { > + if (info->tag[type] != tag[type]) { > + found = 0; > + break; > + } > + } > + > + return found; > +} > + > static int sysfs_get_sb(struct file_system_type *fs_type, > int flags, const char *dev_name, void *data, struct vfsmount *mnt) > { > - int rc; > + const void *tag[SYSFS_TAG_TYPES]; > + struct super_block *sb; > + int error; > + enum sysfs_tag_type type; > + > + for (type = SYSFS_TAG_TYPE_NONE; type < SYSFS_TAG_TYPES; type++) { > + tag[type] = NULL; > + if (!tag_ops[type]) > + continue; > + tag[type] = tag_ops[type]->mount_tag(); > + } > + > mutex_lock(&sysfs_rename_mutex); > - rc = get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt); > + sb = sget(fs_type, sysfs_test_super, set_anon_super, tag); > + if (IS_ERR(sb)) { > + error = PTR_ERR(sb); > + goto out; > + } > + if (!sb->s_root) { > + sb->s_flags = flags; > + error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0, > + tag); > + if (error) { > + up_write(&sb->s_umount); > + deactivate_super(sb); > + goto out; > + } > + sb->s_flags |= MS_ACTIVE; > + } > + do_remount_sb(sb, flags, data, 0); > + error = simple_set_mnt(mnt, sb); > +out: > mutex_unlock(&sysfs_rename_mutex); > - return rc; > + return error; > +} > + > +static void sysfs_kill_sb(struct super_block *sb) > +{ > + struct sysfs_super_info *info = sysfs_info(sb); > + > + kill_anon_super(sb); > + kfree(info); > } > > struct file_system_type sysfs_fs_type = { > .name = "sysfs", > .get_sb = sysfs_get_sb, > - .kill_sb = kill_anon_super, > + .kill_sb = sysfs_kill_sb, > }; > > void sysfs_grab_supers(void) > @@ -146,6 +205,50 @@ restart: > spin_unlock(&sb_lock); > } > > +int sysfs_register_tag_type(enum sysfs_tag_type type, struct sysfs_tag_type_operations *ops) > +{ > + int error; > + > + mutex_lock(&sysfs_rename_mutex); > + > + error = -EINVAL; > + if (type >= SYSFS_TAG_TYPES) > + goto out; > + > + error = -EINVAL; > + if (type <= SYSFS_TAG_TYPE_NONE) > + goto out; > + > + error = -EBUSY; > + if (tag_ops[type]) > + goto out; > + > + error = 0; > + tag_ops[type] = ops; > + > +out: > + mutex_unlock(&sysfs_rename_mutex); > + return error; > +} > + > +void sysfs_exit_tag(enum sysfs_tag_type type, const void *tag) > +{ > + /* Allow the tag to go away while sysfs is still mounted. */ > + struct super_block *sb; > + mutex_lock(&sysfs_rename_mutex); > + sysfs_grab_supers(); > + mutex_lock(&sysfs_mutex); > + list_for_each_entry(sb, &sysfs_fs_type.fs_supers, s_instances) { > + struct sysfs_super_info *info = sysfs_info(sb); > + if (info->tag[type] != tag) > + continue; > + info->tag[type] = NULL; > + } > + mutex_unlock(&sysfs_mutex); > + sysfs_release_supers(); > + mutex_unlock(&sysfs_rename_mutex); > +} > + > int __init sysfs_init(void) > { > int err = -ENOMEM; > diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c > index a3ba217..54b2e5f 100644 > --- a/fs/sysfs/symlink.c > +++ b/fs/sysfs/symlink.c > @@ -119,7 +119,7 @@ void sysfs_remove_link(struct kobject * kobj, const char * name) > else > parent_sd = kobj->sd; > > - sysfs_hash_and_remove(parent_sd, name); > + sysfs_hash_and_remove(kobj, parent_sd, name); > } > > static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, > diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h > index f0e5ecb..67115ec 100644 > --- a/fs/sysfs/sysfs.h > +++ b/fs/sysfs/sysfs.h > @@ -45,6 +45,7 @@ struct sysfs_dirent { > struct sysfs_dirent *s_sibling; > const char *s_name; > > + const void *s_tag; > union { > struct sysfs_elem_dir s_dir; > struct sysfs_elem_symlink s_symlink; > @@ -67,14 +68,22 @@ struct sysfs_dirent { > #define SYSFS_KOBJ_LINK 0x0008 > #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) > > -#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK > -#define SYSFS_FLAG_REMOVED 0x0200 > +#define SYSFS_TAG_TYPE_MASK 0xff00 > +#define SYSFS_TAG_TYPE_SHIFT 8 > + > +#define SYSFS_FLAG_MASK ~(SYSFS_TYPE_MASK | SYSFS_TAG_TYPE_MASK) > +#define SYSFS_FLAG_REMOVED 0x020000 > > static inline unsigned int sysfs_type(struct sysfs_dirent *sd) > { > return sd->s_flags & SYSFS_TYPE_MASK; > } > > +static inline enum sysfs_tag_type sysfs_tag_type(struct sysfs_dirent *sd) > +{ > + return (sd->s_flags & SYSFS_TAG_TYPE_MASK) >> SYSFS_TAG_TYPE_SHIFT; > +} > + > /* > * Context structure to be used while adding/removing nodes. > */ > @@ -87,6 +96,7 @@ struct sysfs_addrm_cxt { > > struct sysfs_super_info { > int grabbed; > + const void *tag[SYSFS_TAG_TYPES]; > }; > > #define sysfs_info(SB) ((struct sysfs_super_info *)(SB)->s_fs_info) > @@ -98,6 +108,7 @@ extern struct sysfs_dirent sysfs_root; > extern struct super_block *sysfs_sb; > extern struct kmem_cache *sysfs_dir_cachep; > extern struct file_system_type sysfs_fs_type; > +extern struct sysfs_tag_type_operations *tag_ops[SYSFS_TAG_TYPES]; > > void sysfs_grab_supers(void); > void sysfs_release_supers(void); > @@ -124,6 +135,7 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd); > void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); > > struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, > + const void *tag, > const unsigned char *name); > struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, > const unsigned char *name); > @@ -158,7 +170,8 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) > struct inode *sysfs_get_inode(struct sysfs_dirent *sd); > int sysfs_sd_setattr(struct sysfs_dirent *sd, struct inode *inode, struct iattr *iattr); > int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); > -int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); > +int sysfs_hash_and_remove(struct kobject *kobj, struct sysfs_dirent *dir_sd, > + const char *name); > int sysfs_inode_init(void); > > /* > diff --git a/include/linux/kobject.h b/include/linux/kobject.h > index 5437ac0..beb3573 100644 > --- a/include/linux/kobject.h > +++ b/include/linux/kobject.h > @@ -105,6 +105,7 @@ struct kobj_type { > void (*release)(struct kobject *kobj); > struct sysfs_ops *sysfs_ops; > struct attribute **default_attrs; > + const void *(*sysfs_tag)(struct kobject *kobj); > }; > > struct kobj_uevent_env { > diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h > index d8e0230..ba68829 100644 > --- a/include/linux/sysfs.h > +++ b/include/linux/sysfs.h > @@ -80,6 +80,15 @@ struct sysfs_ops { > > struct sysfs_dirent; > > +enum sysfs_tag_type { > + SYSFS_TAG_TYPE_NONE = 0, > + SYSFS_TAG_TYPES > +}; > + > +struct sysfs_tag_type_operations { > + const void *(*mount_tag)(void); > +}; > + > #ifdef CONFIG_SYSFS > > int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), > @@ -126,6 +135,12 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, > struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd); > void sysfs_put(struct sysfs_dirent *sd); > void sysfs_printk_last_file(void); > + > +int sysfs_make_tagged_dir(struct kobject *, enum sysfs_tag_type tag_type); > +int sysfs_register_tag_type(enum sysfs_tag_type type, > + struct sysfs_tag_type_operations *ops); > +void sysfs_exit_tag(enum sysfs_tag_type type, const void *tag); > + > int __must_check sysfs_init(void); > > #else /* CONFIG_SYSFS */ > @@ -249,6 +264,22 @@ static inline void sysfs_put(struct sysfs_dirent *sd) > { > } > > +staticn inline int sysfs_make_tagged_dir(struct kobject *kobj, ______^ This typo is still present in your patch in the CONFIG_SYSFS=n case. Otherwise the patchset, combined with the patches Greg has already merged in his tree, still works great for me with network namespaces. --Benjamin > + enum sysfs_tag_type tag_type) > +{ > + return 0; > +} > + > +static inline int sysfs_register_tag_type(enum sysfs_tag_type type, > + struct sysfs_tag_type_operations *ops) > +{ > + return 0; > +} > + > +static inline void sysfs_exit_tag(enum sysfs_tag_type type, const void *tag) > +{ > +} > + > static inline int __must_check sysfs_init(void) > { > return 0; -- B e n j a m i n T h e r y - BULL/DT/Open Software R&D http://www.bull.com -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/