All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] sysfs: Remove first pass at shadow directory support
       [not found]               ` <20070625212339.GA13398-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
@ 2007-07-19  4:43                 ` Eric W. Biederman
       [not found]                   ` <m14pk13svx.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-19  4:43 UTC (permalink / raw)
  To: Greg KH; +Cc: Linux Containers, Tejun Heo, Greg KH, Dave Hansen


While shadow directories appear to be a good idea, the current scheme
of controlling their creation and destruction outside of sysfs appears
to be a locking and maintenance nightmare in the face of sysfs
directories dynamically coming and going.  Which can now occur for
directories containing network devices when CONFIG_SYSFS_DEPRECATED is
not set.

This patch removes everything from the initial shadow directory support
that allowed the shadow directory creation to be controlled at a higher
level.  So except for a few bits of sysfs_rename_dir everything from
commit b592fcfe7f06c15ec11774b5be7ce0de3aa86e73 is now gone.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
This patchset is against 589f1e81bde732dd0b1bc5d01b6bddd4bcb4527b
in Linus's tree.  I took a quick skim through your tree and all
of the sysfs patches appear to be merged.

Sorry for taking so long getting this done but the locking
changes in the last round for Tejun were significant.  Plus
there was some additional work needed to actually test the
shadow directory support.

 fs/sysfs/dir.c          |  167 ++++++----------------------------------------
 fs/sysfs/group.c        |    1 -
 fs/sysfs/inode.c        |   10 ---
 fs/sysfs/mount.c        |    2 +-
 fs/sysfs/sysfs.h        |    6 --
 include/linux/kobject.h |    5 --
 include/linux/sysfs.h   |   27 +-------
 lib/kobject.c           |   44 ++-----------
 8 files changed, 33 insertions(+), 229 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 048e605..f88130c 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -569,9 +569,6 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd)
 	spin_unlock(&dcache_lock);
 	spin_unlock(&sysfs_assoc_lock);
 
-	/* dentries for shadowed inodes are pinned, unpin */
-	if (dentry && sysfs_is_shadowed_inode(dentry->d_inode))
-		dput(dentry);
 	dput(dentry);
 
 	/* adjust nlink and update timestamp */
@@ -723,19 +720,15 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name,
 /**
  *	sysfs_create_dir - create a directory for an object.
  *	@kobj:		object we're creating directory for. 
- *	@shadow_parent:	parent object.
  */
-int sysfs_create_dir(struct kobject *kobj,
-		     struct sysfs_dirent *shadow_parent_sd)
+int sysfs_create_dir(struct kobject * kobj)
 {
 	struct sysfs_dirent *parent_sd, *sd;
 	int error = 0;
 
 	BUG_ON(!kobj);
 
-	if (shadow_parent_sd)
-		parent_sd = shadow_parent_sd;
-	else if (kobj->parent)
+	if (kobj->parent)
 		parent_sd = kobj->parent->sd;
 	else if (sysfs_mount && sysfs_mount->mnt_sb)
 		parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
@@ -887,45 +880,44 @@ void sysfs_remove_dir(struct kobject * kobj)
 	__sysfs_remove_dir(sd);
 }
 
-int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
-		     const char *new_name)
+int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
 {
-	struct sysfs_dirent *sd = kobj->sd;
-	struct dentry *new_parent = NULL;
+	struct sysfs_dirent *sd;
+	struct dentry *parent = NULL;
 	struct dentry *old_dentry = NULL, *new_dentry = NULL;
+	struct sysfs_dirent *parent_sd;
 	const char *dup_name = NULL;
 	int error;
 
+	if (!kobj->parent)
+		return -EINVAL;
+
 	/* get dentries */
+	sd = kobj->sd;
 	old_dentry = sysfs_get_dentry(sd);
 	if (IS_ERR(old_dentry)) {
 		error = PTR_ERR(old_dentry);
 		goto out_dput;
 	}
 
-	new_parent = sysfs_get_dentry(new_parent_sd);
-	if (IS_ERR(new_parent)) {
-		error = PTR_ERR(new_parent);
+	parent_sd = kobj->parent->sd;
+	parent = sysfs_get_dentry(parent_sd);
+	if (IS_ERR(parent)) {
+		error = PTR_ERR(parent);
 		goto out_dput;
 	}
 
-	/* lock new_parent and get dentry for new name */
-	mutex_lock(&new_parent->d_inode->i_mutex);
+	/* lock parent and get dentry for new name */
+	mutex_lock(&parent->d_inode->i_mutex);
 
-	new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
+	new_dentry = lookup_one_len(new_name, parent, strlen(new_name));
 	if (IS_ERR(new_dentry)) {
 		error = PTR_ERR(new_dentry);
 		goto out_unlock;
 	}
 
-	/* By allowing two different directories with the same
-	 * d_parent we allow this routine to move between different
-	 * shadows of the same directory
-	 */
 	error = -EINVAL;
-	if (old_dentry->d_parent->d_inode != new_parent->d_inode ||
-	    new_dentry->d_parent->d_inode != new_parent->d_inode ||
-	    old_dentry == new_dentry)
+	if (old_dentry == new_dentry)
 		goto out_unlock;
 
 	error = -EEXIST;
@@ -952,9 +944,9 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
 	mutex_lock(&sysfs_mutex);
 
 	sysfs_unlink_sibling(sd);
-	sysfs_get(new_parent_sd);
+	sysfs_get(parent_sd);
 	sysfs_put(sd->s_parent);
-	sd->s_parent = new_parent_sd;
+	sd->s_parent = parent_sd;
 	sysfs_link_sibling(sd);
 
 	mutex_unlock(&sysfs_mutex);
@@ -965,10 +957,10 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
  out_drop:
 	d_drop(new_dentry);
  out_unlock:
-	mutex_unlock(&new_parent->d_inode->i_mutex);
+	mutex_unlock(&parent->d_inode->i_mutex);
  out_dput:
 	kfree(dup_name);
-	dput(new_parent);
+	dput(parent);
 	dput(old_dentry);
 	dput(new_dentry);
 	return error;
@@ -1189,121 +1181,6 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
 	return offset;
 }
 
-
-/**
- *	sysfs_make_shadowed_dir - Setup so a directory can be shadowed
- *	@kobj:	object we're creating shadow of.
- */
-
-int sysfs_make_shadowed_dir(struct kobject *kobj,
-	void * (*follow_link)(struct dentry *, struct nameidata *))
-{
-	struct dentry *dentry;
-	struct inode *inode;
-	struct inode_operations *i_op;
-
-	/* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */
-	dentry = sysfs_get_dentry(kobj->sd);
-	if (IS_ERR(dentry))
-		return PTR_ERR(dentry);
-
-	inode = dentry->d_inode;
-	if (inode->i_op != &sysfs_dir_inode_operations) {
-		dput(dentry);
-		return -EINVAL;
-	}
-
-	i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
-	if (!i_op)
-		return -ENOMEM;
-
-	memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op));
-	i_op->follow_link = follow_link;
-
-	/* Locking of inode->i_op?
-	 * Since setting i_op is a single word write and they
-	 * are atomic we should be ok here.
-	 */
-	inode->i_op = i_op;
-	return 0;
-}
-
-/**
- *	sysfs_create_shadow_dir - create a shadow directory for an object.
- *	@kobj:	object we're creating directory for.
- *
- *	sysfs_make_shadowed_dir must already have been called on this
- *	directory.
- */
-
-struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj)
-{
-	struct sysfs_dirent *parent_sd = kobj->sd->s_parent;
-	struct dentry *dir, *parent, *shadow;
-	struct inode *inode;
-	struct sysfs_dirent *sd;
-	struct sysfs_addrm_cxt acxt;
-
-	dir = sysfs_get_dentry(kobj->sd);
-	if (IS_ERR(dir)) {
-		sd = (void *)dir;
-		goto out;
-	}
-	parent = dir->d_parent;
-
-	inode = dir->d_inode;
-	sd = ERR_PTR(-EINVAL);
-	if (!sysfs_is_shadowed_inode(inode))
-		goto out_dput;
-
-	shadow = d_alloc(parent, &dir->d_name);
-	if (!shadow)
-		goto nomem;
-
-	sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR);
-	if (!sd)
-		goto nomem;
-	sd->s_elem.dir.kobj = kobj;
-
-	sysfs_addrm_start(&acxt, parent_sd);
-
-	/* add but don't link into children list */
-	sysfs_add_one(&acxt, sd);
-
-	/* attach and instantiate dentry */
-	sysfs_attach_dentry(sd, shadow);
-	d_instantiate(shadow, igrab(inode));
-	inc_nlink(inode);	/* tj: synchronization? */
-
-	sysfs_addrm_finish(&acxt);
-
-	dget(shadow);		/* Extra count - pin the dentry in core */
-
-	goto out_dput;
-
- nomem:
-	dput(shadow);
-	sd = ERR_PTR(-ENOMEM);
- out_dput:
-	dput(dir);
- out:
-	return sd;
-}
-
-/**
- *	sysfs_remove_shadow_dir - remove an object's directory.
- *	@shadow_sd: sysfs_dirent of shadow directory
- *
- *	The only thing special about this is that we remove any files in
- *	the directory before we remove the directory, and we've inlined
- *	what used to be sysfs_rmdir() below, instead of calling separately.
- */
-
-void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd)
-{
-	__sysfs_remove_dir(shadow_sd);
-}
-
 const struct file_operations sysfs_dir_operations = {
 	.open		= sysfs_dir_open,
 	.release	= sysfs_dir_close,
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index f318b73..4606f7c 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -13,7 +13,6 @@
 #include <linux/dcache.h>
 #include <linux/namei.h>
 #include <linux/err.h>
-#include <linux/fs.h>
 #include <asm/semaphore.h>
 #include "sysfs.h"
 
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 10d1b52..9671164 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -34,16 +34,6 @@ static const struct inode_operations sysfs_inode_operations ={
 	.setattr	= sysfs_setattr,
 };
 
-void sysfs_delete_inode(struct inode *inode)
-{
-	/* Free the shadowed directory inode operations */
-	if (sysfs_is_shadowed_inode(inode)) {
-		kfree(inode->i_op);
-		inode->i_op = NULL;
-	}
-	return generic_delete_inode(inode);
-}
-
 int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
 {
 	struct inode * inode = dentry->d_inode;
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 60714d0..e2073e6 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -21,7 +21,7 @@ struct kmem_cache *sysfs_dir_cachep;
 
 static const struct super_operations sysfs_ops = {
 	.statfs		= simple_statfs,
-	.drop_inode	= sysfs_delete_inode,
+	.drop_inode	= generic_delete_inode,
 };
 
 struct sysfs_dirent sysfs_root = {
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 6b8c8d7..b55e510 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -70,7 +70,6 @@ extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt,
 			     struct sysfs_dirent *sd);
 extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
 
-extern void sysfs_delete_inode(struct inode *inode);
 extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd);
 extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode);
 
@@ -121,8 +120,3 @@ static inline void sysfs_put(struct sysfs_dirent * sd)
 	if (sd && atomic_dec_and_test(&sd->s_count))
 		release_sysfs_dirent(sd);
 }
-
-static inline int sysfs_is_shadowed_inode(struct inode *inode)
-{
-	return S_ISDIR(inode->i_mode) && inode->i_op->follow_link;
-}
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index aa2fe22..7108a3e 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -80,14 +80,9 @@ extern void kobject_init(struct kobject *);
 extern void kobject_cleanup(struct kobject *);
 
 extern int __must_check kobject_add(struct kobject *);
-extern int __must_check kobject_shadow_add(struct kobject *kobj,
-					   struct sysfs_dirent *shadow_parent);
 extern void kobject_del(struct kobject *);
 
 extern int __must_check kobject_rename(struct kobject *, const char *new_name);
-extern int __must_check kobject_shadow_rename(struct kobject *kobj,
-					      struct sysfs_dirent *new_parent,
-					      const char *new_name);
 extern int __must_check kobject_move(struct kobject *, struct kobject *);
 
 extern int __must_check kobject_register(struct kobject *);
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index be8228e..c16e4c5 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -17,9 +17,6 @@
 
 struct kobject;
 struct module;
-struct nameidata;
-struct dentry;
-struct sysfs_dirent;
 
 /* FIXME
  * The *owner field is no longer used, but leave around
@@ -94,14 +91,13 @@ extern int sysfs_schedule_callback(struct kobject *kobj,
 		void (*func)(void *), void *data, struct module *owner);
 
 extern int __must_check
-sysfs_create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent_sd);
+sysfs_create_dir(struct kobject *);
 
 extern void
 sysfs_remove_dir(struct kobject *);
 
 extern int __must_check
-sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
-		 const char *new_name);
+sysfs_rename_dir(struct kobject *kobj, const char *new_name);
 
 extern int __must_check
 sysfs_move_dir(struct kobject *, struct kobject *);
@@ -138,12 +134,6 @@ void sysfs_remove_file_from_group(struct kobject *kobj,
 
 void sysfs_notify(struct kobject * k, char *dir, char *attr);
 
-
-extern int sysfs_make_shadowed_dir(struct kobject *kobj,
-	void * (*follow_link)(struct dentry *, struct nameidata *));
-extern struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj);
-extern void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd);
-
 extern int __must_check sysfs_init(void);
 
 #else /* CONFIG_SYSFS */
@@ -154,8 +144,7 @@ static inline int sysfs_schedule_callback(struct kobject *kobj,
 	return -ENOSYS;
 }
 
-static inline int sysfs_create_dir(struct kobject *kobj,
-				   struct sysfs_dirent *shadow_parent_sd)
+static inline int sysfs_create_dir(struct kobject * kobj)
 {
 	return 0;
 }
@@ -165,9 +154,7 @@ static inline void sysfs_remove_dir(struct kobject * k)
 	;
 }
 
-static inline int sysfs_rename_dir(struct kobject *kobj,
-				   struct sysfs_dirent *new_parent_sd,
-				   const char *new_name)
+static inline int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
 {
 	return 0;
 }
@@ -242,12 +229,6 @@ static inline void sysfs_notify(struct kobject * k, char *dir, char *attr)
 {
 }
 
-static inline int sysfs_make_shadowed_dir(struct kobject *kobj,
-	void * (*follow_link)(struct dentry *, struct nameidata *))
-{
-	return 0;
-}
-
 static inline int __must_check sysfs_init(void)
 {
 	return 0;
diff --git a/lib/kobject.c b/lib/kobject.c
index 4b08e0f..2fc9fc6 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -44,11 +44,11 @@ static int populate_dir(struct kobject * kobj)
 	return error;
 }
 
-static int create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
+static int create_dir(struct kobject * kobj)
 {
 	int error = 0;
 	if (kobject_name(kobj)) {
-		error = sysfs_create_dir(kobj, shadow_parent);
+		error = sysfs_create_dir(kobj);
 		if (!error) {
 			if ((error = populate_dir(kobj)))
 				sysfs_remove_dir(kobj);
@@ -157,12 +157,11 @@ static void unlink(struct kobject * kobj)
 }
 
 /**
- *	kobject_shadow_add - add an object to the hierarchy.
+ *	kobject_add - add an object to the hierarchy.
  *	@kobj:	object.
- *	@shadow_parent: sysfs directory to add to.
  */
 
-int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
+int kobject_add(struct kobject * kobj)
 {
 	int error = 0;
 	struct kobject * parent;
@@ -194,7 +193,7 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
 		kobj->parent = parent;
 	}
 
-	error = create_dir(kobj, shadow_parent);
+	error = create_dir(kobj);
 	if (error) {
 		/* unlink does the kobject_put() for us */
 		unlink(kobj);
@@ -216,16 +215,6 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
 }
 
 /**
- *	kobject_add - add an object to the hierarchy.
- *	@kobj:	object.
- */
-int kobject_add(struct kobject * kobj)
-{
-	return kobject_shadow_add(kobj, NULL);
-}
-
-
-/**
  *	kobject_register - initialize and add an object.
  *	@kobj:	object in question.
  */
@@ -338,7 +327,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name)
 	/* Note : if we want to send the new name alone, not the full path,
 	 * we could probably use kobject_name(kobj); */
 
-	error = sysfs_rename_dir(kobj, kobj->parent->sd, new_name);
+	error = sysfs_rename_dir(kobj, new_name);
 
 	/* This function is mostly/only used for network interface.
 	 * Some hotplug package track interfaces by their name and
@@ -355,27 +344,6 @@ out:
 }
 
 /**
- *	kobject_rename - change the name of an object
- *	@kobj:	object in question.
- *	@new_parent: object's new parent
- *	@new_name: object's new name
- */
-
-int kobject_shadow_rename(struct kobject *kobj,
-			  struct sysfs_dirent *new_parent, const char *new_name)
-{
-	int error = 0;
-
-	kobj = kobject_get(kobj);
-	if (!kobj)
-		return -EINVAL;
-	error = sysfs_rename_dir(kobj, new_parent, new_name);
-	kobject_put(kobj);
-
-	return error;
-}
-
-/**
  *	kobject_move - move object to another parent
  *	@kobj:	object in question.
  *	@new_parent: object's new parent (can be NULL)
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                   ` <m14pk13svx.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-19  4:45                     ` Eric W. Biederman
       [not found]                       ` <m1zm1t2e92.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-21  6:36                     ` patch sysfs-remove-first-pass-at-shadow-directory-support.patch added to gregkh-2.6 tree gregkh-l3A5Bk7waGM
  2007-07-22 18:35                     ` [PATCH 1/4] sysfs: Remove first pass at shadow directory support Tejun Heo
  2 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-19  4:45 UTC (permalink / raw)
  To: Greg KH; +Cc: Linux Containers, Tejun Heo, Greg KH, Dave Hansen


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 I want is for each network namespace to have it's own separate
set of directories.  /sys/class/net/, /sys/devices/virtual/net,
and /sys/ ... /net/, and in each set I want to name them
/sys/class/net/, sys/devices/virtual/net/ and /sys/ ... /net/ respectively.

I looked and the VFS actually allows that.  All that is needed is
for /sys/class/net to implement a follow link method to redirect
lookups to the real directory you want.

I am calling the concept of multiple directories all at the same path
in the filesystem shadow directories, the directory entry that
implements the follow_link method the shadow master, and the directories
that are the target of the follow link method shadow directories.

It turns out that just implementing a follow_link method is not
quite enough.  The existince of directories of the form /sys/ ... /net/
can depend on the presence or absence of hotplug hardware, which
means I need a simple race free way to create and destroy these
directories.

To achieve a race free design all shadow directories are created
and managed by sysfs itself.  The upper level code that knows what
shadow directories we need provides just two methods that enable
this:
  current_tag() - that returns a "void *" tag that identifies the context of
	the current process.
  kobject_tag(kobj) - that returns a "void *" tag that identifies the context
	a kobject should be in.
Everything else is left up to sysfs.

For the network namespace current_tag and kobject_tag are essentially
one line functions, and look to remain that.

The work needed in sysfs is more extensive.  At each directory or
symlink creation I need to check if the shadow directory it belongs
in exists and if it does not create it.  Likewise at each symlink
or directory removal I need to check if sysfs directory it is being
removed from is a shadow directory and if this is the last object
in the shadow directory and if so to remove the shadow directory
as well.

I also need a bunch of boiler plate that properly finds, creates, and
removes/frees the shadow directories.

Doing all of that in sysfs isn't bad it is just a bit tedious.  Being race
free is just a manner of ensure we have the directory inode mutex
and the sysfs mutex when we add or remove a shadow directory.  Trying to do
this race free anywhere besides in sysfs is very nasty, and requires unhealthy
amounts of information about how sysfs is implemented.

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
not potential users which makes it an uniteresting problem
to solve.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/sysfs/bin.c        |    2 +-
 fs/sysfs/dir.c        |  404 +++++++++++++++++++++++++++++++++++++++++--------
 fs/sysfs/file.c       |    4 +-
 fs/sysfs/group.c      |   12 +-
 fs/sysfs/inode.c      |   11 +-
 fs/sysfs/symlink.c    |   30 +++-
 fs/sysfs/sysfs.h      |    9 +-
 include/linux/sysfs.h |   15 ++
 8 files changed, 396 insertions(+), 91 deletions(-)

diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index 135353f..1ef0a07 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -248,7 +248,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)
 {
-	if (sysfs_hash_and_remove(kobj->sd, attr->attr.name) < 0) {
+	if (sysfs_hash_and_remove(kobj, kobj->sd, attr->attr.name) < 0) {
 		printk(KERN_ERR "%s: "
 			"bad dentry or inode or no such file: \"%s\"\n",
 			__FUNCTION__, attr->attr.name);
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index f88130c..e6d367e 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -14,12 +14,33 @@
 #include <asm/semaphore.h>
 #include "sysfs.h"
 
+static void sysfs_prune_shadow_sd(struct sysfs_dirent *sd);
+
 DEFINE_MUTEX(sysfs_mutex);
 spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED;
 
 static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED;
 static DEFINE_IDA(sysfs_ino_ida);
 
+static struct sysfs_dirent *find_shadow_sd(struct sysfs_dirent *parent_sd, const void *target)
+{
+	/* Find the shadow directory for the specified tag */
+	struct sysfs_dirent *sd;
+
+	for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
+		if (sd->s_name != target)
+			continue;
+		break;
+	}
+	return sd;
+}
+
+static const void *find_shadow_tag(struct kobject *kobj)
+{
+	/* Find the tag the current kobj is cached with */
+	return kobj->sd->s_parent->s_name;
+}
+
 /**
  *	sysfs_link_sibling - link sysfs_dirent into sibling list
  *	@sd: sysfs_dirent of interest
@@ -323,7 +344,8 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)
 	if (sysfs_type(sd) & SYSFS_COPY_NAME)
 		kfree(sd->s_name);
 	kfree(sd->s_iattr);
-	sysfs_free_ino(sd->s_ino);
+	if (sysfs_type(sd) != SYSFS_SHADOW_DIR)
+		sysfs_free_ino(sd->s_ino);
 	kmem_cache_free(sysfs_dir_cachep, sd);
 
 	sd = parent_sd;
@@ -414,7 +436,8 @@ static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry)
 	sd->s_dentry = dentry;
 	spin_unlock(&sysfs_assoc_lock);
 
-	d_rehash(dentry);
+	if (dentry->d_flags & DCACHE_UNHASHED)
+		d_rehash(dentry);
 }
 
 static int sysfs_ilookup_test(struct inode *inode, void *arg)
@@ -569,6 +592,10 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd)
 	spin_unlock(&dcache_lock);
 	spin_unlock(&sysfs_assoc_lock);
 
+	/* dentries for shadowed directories are pinned, unpin */
+	if ((sysfs_type(sd) == SYSFS_SHADOW_DIR) ||
+	    (sd->s_flags & SYSFS_FLAG_SHADOWED))
+		dput(dentry);
 	dput(dentry);
 
 	/* adjust nlink and update timestamp */
@@ -622,6 +649,7 @@ int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
 		acxt->removed = sd->s_sibling;
 		sd->s_sibling = NULL;
 
+		sysfs_prune_shadow_sd(sd->s_parent);
 		sysfs_drop_dentry(sd);
 		sysfs_deactivate(sd);
 		sysfs_put(sd);
@@ -687,6 +715,7 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
 	umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
 	struct sysfs_addrm_cxt acxt;
 	struct sysfs_dirent *sd;
+	int err;
 
 	/* allocate */
 	sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
@@ -696,15 +725,21 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
 
 	/* link in */
 	sysfs_addrm_start(&acxt, parent_sd);
+	err = -ENOENT;
+	if (!sysfs_resolve_for_create(kobj, &acxt.parent_sd))
+		goto addrm_finish;
 
-	if (!sysfs_find_dirent(parent_sd, name)) {
+	err = -EEXIST;
+	if (!sysfs_find_dirent(acxt.parent_sd, name)) {
 		sysfs_add_one(&acxt, sd);
 		sysfs_link_sibling(sd);
+		err = 0;
 	}
 
+addrm_finish:
 	if (!sysfs_addrm_finish(&acxt)) {
 		sysfs_put(sd);
-		return -EEXIST;
+		return err;
 	}
 
 	*p_sd = sd;
@@ -813,18 +848,56 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 	return NULL;
 }
 
+static void *sysfs_shadow_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	struct sysfs_dirent *sd;
+	struct dentry *dest;
+
+	sd = dentry->d_fsdata;
+	dest = NULL;
+	if (sd->s_flags & SYSFS_FLAG_SHADOWED) {
+		const struct shadow_dir_operations *shadow_ops;
+		const void *tag;
+
+		mutex_lock(&sysfs_mutex);
+
+		shadow_ops = dentry->d_inode->i_private;
+		tag = shadow_ops->current_tag();
+
+		sd = find_shadow_sd(sd, tag);
+		if (sd)
+			dest = sd->s_dentry;
+		dget(dest);
+
+		mutex_unlock(&sysfs_mutex);
+	}
+	if (!dest)
+		dest = dget(dentry);
+	dput(nd->dentry);
+	nd->dentry = dest;
+
+	return NULL;
+}
+
+
 const struct inode_operations sysfs_dir_inode_operations = {
 	.lookup		= sysfs_lookup,
 	.setattr	= sysfs_setattr,
+	.follow_link	= sysfs_shadow_follow_link,
 };
 
+static void __remove_dir(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
+{
+	sysfs_unlink_sibling(sd);
+	sysfs_remove_one(acxt, sd);
+}
+
 static void remove_dir(struct sysfs_dirent *sd)
 {
 	struct sysfs_addrm_cxt acxt;
 
 	sysfs_addrm_start(&acxt, sd->s_parent);
-	sysfs_unlink_sibling(sd);
-	sysfs_remove_one(&acxt, sd);
+	__remove_dir(&acxt, sd);
 	sysfs_addrm_finish(&acxt);
 }
 
@@ -833,17 +906,11 @@ void sysfs_remove_subdir(struct sysfs_dirent *sd)
 	remove_dir(sd);
 }
 
-
-static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
+static void sysfs_empty_dir(struct sysfs_addrm_cxt *acxt,
+			    struct sysfs_dirent *dir_sd)
 {
-	struct sysfs_addrm_cxt acxt;
 	struct sysfs_dirent **pos;
 
-	if (!dir_sd)
-		return;
-
-	pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
-	sysfs_addrm_start(&acxt, dir_sd);
 	pos = &dir_sd->s_children;
 	while (*pos) {
 		struct sysfs_dirent *sd = *pos;
@@ -851,10 +918,39 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
 		if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) {
 			*pos = sd->s_sibling;
 			sd->s_sibling = NULL;
-			sysfs_remove_one(&acxt, sd);
+			sysfs_remove_one(acxt, sd);
 		} else
 			pos = &(*pos)->s_sibling;
 	}
+}
+
+static void sysfs_remove_shadows(struct sysfs_addrm_cxt * acxt,
+					struct sysfs_dirent *dir_sd)
+{
+	struct sysfs_dirent **pos;
+
+	pos = &dir_sd->s_children;
+	while (*pos) {
+		struct sysfs_dirent *sd = *pos;
+
+		sysfs_empty_dir(acxt, sd);
+		__remove_dir(acxt, sd);
+	}
+}
+
+static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
+{
+	struct sysfs_addrm_cxt acxt;
+
+	if (!dir_sd)
+		return;
+
+	pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
+	sysfs_addrm_start(&acxt, dir_sd);
+	if (sysfs_type(dir_sd) == SYSFS_DIR)
+		sysfs_empty_dir(&acxt, dir_sd);
+	else
+		sysfs_remove_shadows(&acxt, dir_sd);
 	sysfs_addrm_finish(&acxt);
 
 	remove_dir(dir_sd);
@@ -882,86 +978,75 @@ void sysfs_remove_dir(struct kobject * kobj)
 
 int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
 {
+	struct dentry *old_dentry, *new_dentry, *parent;
+	struct sysfs_addrm_cxt acxt;
 	struct sysfs_dirent *sd;
-	struct dentry *parent = NULL;
-	struct dentry *old_dentry = NULL, *new_dentry = NULL;
-	struct sysfs_dirent *parent_sd;
-	const char *dup_name = NULL;
+	const char *dup_name;
 	int error;
 
-	if (!kobj->parent)
-		return -EINVAL;
+	dup_name = NULL;
+	new_dentry = NULL;
 
-	/* get dentries */
 	sd = kobj->sd;
-	old_dentry = sysfs_get_dentry(sd);
-	if (IS_ERR(old_dentry)) {
-		error = PTR_ERR(old_dentry);
-		goto out_dput;
-	}
-
-	parent_sd = kobj->parent->sd;
-	parent = sysfs_get_dentry(parent_sd);
-	if (IS_ERR(parent)) {
-		error = PTR_ERR(parent);
-		goto out_dput;
-	}
-
-	/* lock parent and get dentry for new name */
-	mutex_lock(&parent->d_inode->i_mutex);
+	sysfs_addrm_start(&acxt, sd->s_parent);
+	error = -ENOENT;
+	if (!sysfs_resolve_for_create(kobj, &acxt.parent_sd))
+		goto addrm_finish;
 
-	new_dentry = lookup_one_len(new_name, parent, strlen(new_name));
-	if (IS_ERR(new_dentry)) {
-		error = PTR_ERR(new_dentry);
-		goto out_unlock;
-	}
+	error = -EEXIST;
+	if (sysfs_find_dirent(acxt.parent_sd, new_name))
+		goto addrm_finish;
 
 	error = -EINVAL;
-	if (old_dentry == new_dentry)
-		goto out_unlock;
+	if ((sd->s_parent == acxt.parent_sd) &&
+	    (strcmp(new_name, sd->s_name) == 0))
+		goto addrm_finish;
+
+	old_dentry = sd->s_dentry;
+	parent = acxt.parent_sd->s_dentry;
+	if (old_dentry) {
+		old_dentry = sd->s_dentry;
+		parent = acxt.parent_sd->s_dentry;
+		new_dentry = lookup_one_len(new_name, parent, strlen(new_name));
+		if (IS_ERR(new_dentry)) {
+			error = PTR_ERR(new_dentry);
+			goto addrm_finish;
+		}
 
-	error = -EEXIST;
-	if (new_dentry->d_inode)
-		goto out_unlock;
+		error = -EINVAL;
+		if (old_dentry == new_dentry)
+			goto addrm_finish;
+	}
 
 	/* rename kobject and sysfs_dirent */
 	error = -ENOMEM;
 	new_name = dup_name = kstrdup(new_name, GFP_KERNEL);
 	if (!new_name)
-		goto out_drop;
+		goto addrm_finish;
 
 	error = kobject_set_name(kobj, "%s", new_name);
 	if (error)
-		goto out_drop;
+		goto addrm_finish;
 
 	dup_name = sd->s_name;
 	sd->s_name = new_name;
 
 	/* move under the new parent */
-	d_add(new_dentry, NULL);
-	d_move(sd->s_dentry, new_dentry);
-
-	mutex_lock(&sysfs_mutex);
-
 	sysfs_unlink_sibling(sd);
-	sysfs_get(parent_sd);
+	sysfs_get(acxt.parent_sd);
 	sysfs_put(sd->s_parent);
-	sd->s_parent = parent_sd;
+	sd->s_parent = acxt.parent_sd;
 	sysfs_link_sibling(sd);
 
-	mutex_unlock(&sysfs_mutex);
-
+	if (new_dentry) {
+		d_add(new_dentry, NULL);
+		d_move(old_dentry, new_dentry);
+	}
 	error = 0;
-	goto out_unlock;
+addrm_finish:
+	sysfs_addrm_finish(&acxt);
 
- out_drop:
-	d_drop(new_dentry);
- out_unlock:
-	mutex_unlock(&parent->d_inode->i_mutex);
- out_dput:
 	kfree(dup_name);
-	dput(parent);
-	dput(old_dentry);
 	dput(new_dentry);
 	return error;
 }
@@ -1098,8 +1183,11 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
 			i++;
 			/* fallthrough */
 		default:
-			mutex_lock(&sysfs_mutex);
+			/* If I am the shadow master return nothing. */
+			if (parent_sd->s_flags & SYSFS_FLAG_SHADOWED)
+				return 0;
 
+			mutex_lock(&sysfs_mutex);
 			pos = &parent_sd->s_children;
 			while (*pos != cursor)
 				pos = &(*pos)->s_sibling;
@@ -1188,3 +1276,185 @@ const struct file_operations sysfs_dir_operations = {
 	.read		= generic_read_dir,
 	.readdir	= sysfs_readdir,
 };
+
+
+static void sysfs_prune_shadow_sd(struct sysfs_dirent *sd)
+{
+	struct sysfs_addrm_cxt acxt;
+
+	/* If a shadow directory goes empty remove it. */
+	if (sysfs_type(sd) != SYSFS_SHADOW_DIR)
+		return;
+
+	if (sd->s_children)
+		return;
+
+	sysfs_addrm_start(&acxt, sd->s_parent);
+
+	if (sd->s_flags & SYSFS_FLAG_REMOVED)
+		goto addrm_finish;
+
+	if (sd->s_children)
+		goto addrm_finish;
+
+	__remove_dir(&acxt, sd);
+addrm_finish:
+	sysfs_addrm_finish(&acxt);
+}
+
+static struct sysfs_dirent *add_shadow_sd(struct sysfs_dirent *parent_sd, const void *tag)
+{
+	struct sysfs_dirent *sd = NULL;
+	struct dentry *dir, *shadow;
+	struct inode *inode;
+
+	dir = parent_sd->s_dentry;
+	inode = dir->d_inode;
+
+	shadow = d_alloc(dir->d_parent, &dir->d_name);
+	if (!shadow)
+		goto out;
+
+	/* Since the shadow directory is reachable make it look
+	 * like it is actually hashed.
+	 */
+	shadow->d_hash.pprev = &shadow->d_hash.next;
+	shadow->d_hash.next = NULL;
+	shadow->d_flags &= ~DCACHE_UNHASHED;
+
+	sd = sysfs_new_dirent(tag, parent_sd->s_mode, SYSFS_SHADOW_DIR);
+	if (!sd)
+		goto error;
+
+	sd->s_elem.dir.kobj = parent_sd->s_elem.dir.kobj;
+	sd->s_parent = sysfs_get(parent_sd);
+
+	/* Use the inode number of the parent we are shadowing */
+	sysfs_free_ino(sd->s_ino);
+	sd->s_ino = parent_sd->s_ino;
+
+	inc_nlink(inode);
+	inc_nlink(dir->d_parent->d_inode);
+
+	sysfs_link_sibling(sd);
+	__iget(inode);
+	sysfs_instantiate(shadow, inode);
+	sysfs_attach_dentry(sd, shadow);
+out:
+	return sd;
+error:
+	dput(shadow);
+	goto out;
+}
+
+int sysfs_resolve_for_create(struct kobject *kobj,
+				struct sysfs_dirent **parent_sd)
+{
+	const struct shadow_dir_operations *shadow_ops;
+	struct sysfs_dirent *sd, *shadow_sd;
+
+	sd = *parent_sd;
+	if (sysfs_type(sd) == SYSFS_SHADOW_DIR)
+		sd = sd->s_parent;
+
+	if (sd->s_flags & SYSFS_FLAG_SHADOWED) {
+		const void *tag;
+
+		shadow_ops = sd->s_dentry->d_inode->i_private;
+		tag = shadow_ops->kobject_tag(kobj);
+
+		shadow_sd = find_shadow_sd(sd, tag);
+		if (!shadow_sd)
+			shadow_sd = add_shadow_sd(sd, tag);
+		sd = shadow_sd;
+	}
+	if (sd) {
+		*parent_sd = sd;
+		return 1;
+	}
+	return 0;
+}
+
+int sysfs_resolve_for_remove(struct kobject *kobj,
+				struct sysfs_dirent **parent_sd)
+{
+	struct sysfs_dirent *sd;
+	/* If dentry is a shadow directory find the shadow that is
+	 * stored under the same tag as kobj.  This allows removal
+	 * of dirents to function properly even if the value of
+	 * kobject_tag() has changed since we initially created
+	 * the dirents assoctated with kobj.
+	 */
+
+	sd = *parent_sd;
+	if (sysfs_type(sd) == SYSFS_SHADOW_DIR)
+		sd = sd->s_parent;
+	if (sd->s_flags & SYSFS_FLAG_SHADOWED) {
+		const void *tag;
+
+		tag = find_shadow_tag(kobj);
+		sd = find_shadow_sd(sd, tag);
+	}
+	if (sd) {
+		*parent_sd = sd;
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ *	sysfs_enable_shadowing - Automatically create shadows of a directory
+ *	@kobj:	object to automatically shadow
+ *
+ *	Once shadowing has been enabled on a directory the contents
+ *	of the directory become dependent upon context.
+ *
+ *	shadow_ops->current_tag() returns the context for the current
+ *	process.
+ *
+ *	shadow_ops->kobject_tag() returns the context that a given kobj
+ *	resides in.
+ *
+ *	Using those methods the sysfs code on shadowed directories
+ *	carefully stores the files so that when we lookup files
+ *	we get the proper answer for our context.
+ *
+ *	If the context of a kobject is changed it is expected that
+ *	the kobject will be renamed so the appopriate sysfs data structures
+ *	can be updated.
+ */
+int sysfs_enable_shadowing(struct kobject *kobj,
+	const struct shadow_dir_operations *shadow_ops)
+{
+	struct sysfs_dirent *sd;
+	struct dentry *dentry;
+	int err;
+
+	/* Find the dentry for the shadowed directory and
+	 * increase it's count.
+	 */
+	err = -ENOENT;
+	sd = kobj->sd;
+	dentry = sysfs_get_dentry(sd);
+	if (!dentry)
+		goto out;
+
+	mutex_lock(&sysfs_mutex);
+	err = -EINVAL;
+	/* We can only enable shadowing on empty directories
+	 * where shadowing is not already enabled.
+	 */
+	if (!sd->s_children && (sysfs_type(sd) == SYSFS_DIR) &&
+	    !(sd->s_flags & SYSFS_FLAG_REMOVED) &&
+	    !(sd->s_flags & SYSFS_FLAG_SHADOWED)) {
+		sd->s_flags |= SYSFS_FLAG_SHADOWED;
+		dentry->d_inode->i_private = (void *)shadow_ops;
+		err = 0;
+	}
+	mutex_unlock(&sysfs_mutex);
+out:
+	if (err)
+		dput(dentry);
+	return err;
+}
+
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 3e1cc06..530a830 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -544,7 +544,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);
 }
 
 
@@ -561,7 +561,7 @@ void sysfs_remove_file_from_group(struct kobject *kobj,
 
 	dir_sd = sysfs_get_dirent(kobj->sd, group);
 	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 4606f7c..9e928fd 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -17,16 +17,16 @@
 #include "sysfs.h"
 
 
-static void remove_files(struct sysfs_dirent *dir_sd,
+static void remove_files(struct kobject *kobj, struct sysfs_dirent *dir_sd,
 			 const struct attribute_group *grp)
 {
 	struct attribute *const* attr;
 
 	for (attr = grp->attrs; *attr; 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,
+static int create_files(struct kobject *kobj, struct sysfs_dirent *dir_sd,
 			const struct attribute_group *grp)
 {
 	struct attribute *const* attr;
@@ -35,7 +35,7 @@ static int create_files(struct sysfs_dirent *dir_sd,
 	for (attr = grp->attrs; *attr && !error; attr++)
 		error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
 	if (error)
-		remove_files(dir_sd, grp);
+		remove_files(kobj, dir_sd, grp);
 	return error;
 }
 
@@ -55,7 +55,7 @@ int sysfs_create_group(struct kobject * kobj,
 	} else
 		sd = kobj->sd;
 	sysfs_get(sd);
-	error = create_files(sd, grp);
+	error = create_files(kobj, sd, grp);
 	if (error) {
 		if (grp->name)
 			sysfs_remove_subdir(sd);
@@ -76,7 +76,7 @@ void sysfs_remove_group(struct kobject * kobj,
 	} else
 		sd = sysfs_get(dir_sd);
 
-	remove_files(sd, grp);
+	remove_files(kobj, sd, grp);
 	if (grp->name)
 		sysfs_remove_subdir(sd);
 
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 9671164..e31896e 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -187,17 +187,16 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode)
 	d_instantiate(dentry, 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 **pos, *sd;
 
-	if (!dir_sd)
-		return -ENOENT;
-
 	sysfs_addrm_start(&acxt, dir_sd);
+	if (!sysfs_resolve_for_remove(kobj, &acxt.parent_sd))
+		goto addrm_finish;
 
-	for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) {
+	for (pos = &acxt.parent_sd->s_children; *pos; pos = &(*pos)->s_sibling) {
 		sd = *pos;
 
 		if (!sysfs_type(sd))
@@ -209,7 +208,7 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
 			break;
 		}
 	}
-
+addrm_finish:
 	if (sysfs_addrm_finish(&acxt))
 		return 0;
 	return -ENOENT;
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index 4ce687f..e52d3ef 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -15,8 +15,11 @@ static int object_depth(struct sysfs_dirent *sd)
 {
 	int depth = 0;
 
-	for (; sd->s_parent; sd = sd->s_parent)
+	for (; sd->s_parent; sd = sd->s_parent) {
+		if (sysfs_type(sd) == SYSFS_SHADOW_DIR)
+			continue;
 		depth++;
+	}
 
 	return depth;
 }
@@ -25,17 +28,24 @@ static int object_path_length(struct sysfs_dirent * sd)
 {
 	int length = 1;
 
-	for (; sd->s_parent; sd = sd->s_parent)
+	for (; sd->s_parent; sd = sd->s_parent) {
+		if (sysfs_type(sd) == SYSFS_SHADOW_DIR)
+			continue;
 		length += strlen(sd->s_name) + 1;
+	}
 
 	return length;
 }
 
 static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length)
 {
+	int cur;
 	--length;
 	for (; sd->s_parent; sd = sd->s_parent) {
-		int cur = strlen(sd->s_name);
+		if (sysfs_type(sd) == SYSFS_SHADOW_DIR)
+			continue;
+
+		cur = strlen(sd->s_name);
 
 		/* back up enough to print this bus id with '/' */
 		length -= cur;
@@ -91,16 +101,20 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
 	target_sd = NULL;	/* reference is now owned by the symlink */
 
 	sysfs_addrm_start(&acxt, parent_sd);
+	error = -ENOENT;
+	if (!sysfs_resolve_for_create(target, &acxt.parent_sd))
+		goto addrm_finish;
 
-	if (!sysfs_find_dirent(parent_sd, name)) {
+	error = -EEXIST;
+	if (!sysfs_find_dirent(acxt.parent_sd, name)) {
+		error = 0;
 		sysfs_add_one(&acxt, sd);
 		sysfs_link_sibling(sd);
 	}
 
-	if (!sysfs_addrm_finish(&acxt)) {
-		error = -EEXIST;
+addrm_finish:
+	if (!sysfs_addrm_finish(&acxt))
 		goto out_put;
-	}
 
 	return 0;
 
@@ -119,7 +133,7 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
 
 void sysfs_remove_link(struct kobject * kobj, const char * name)
 {
-	sysfs_hash_and_remove(kobj->sd, name);
+	sysfs_hash_and_remove(kobj, kobj->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 b55e510..ddfcef2 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -58,6 +58,12 @@ extern struct kmem_cache *sysfs_dir_cachep;
 extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);
 extern void sysfs_link_sibling(struct sysfs_dirent *sd);
 extern void sysfs_unlink_sibling(struct sysfs_dirent *sd);
+
+extern int sysfs_resolve_for_create(struct kobject *kobj,
+				    struct sysfs_dirent **parent_sd);
+extern int sysfs_resolve_for_remove(struct kobject *kobj,
+				    struct sysfs_dirent **parent_sd);
+
 extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd);
 extern void sysfs_put_active(struct sysfs_dirent *sd);
 extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);
@@ -83,7 +89,8 @@ extern struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode,
 
 extern int sysfs_add_file(struct sysfs_dirent *dir_sd,
 			  const struct attribute *attr, int type);
-extern int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
+extern int sysfs_hash_and_remove(struct kobject *kobj,
+				 struct sysfs_dirent *dir_sd, const char *name);
 extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name);
 
 extern int sysfs_create_subdir(struct kobject *kobj, const char *name,
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index c16e4c5..7cda047 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -74,16 +74,23 @@ struct sysfs_ops {
 	ssize_t	(*store)(struct kobject *,struct attribute *,const char *, size_t);
 };
 
+struct shadow_dir_operations {
+	const void *(*current_tag)(void);
+	const void *(*kobject_tag)(struct kobject *kobj);
+};
+
 #define SYSFS_TYPE_MASK		0x00ff
 #define SYSFS_ROOT		0x0001
 #define SYSFS_DIR		0x0002
 #define SYSFS_KOBJ_ATTR 	0x0004
 #define SYSFS_KOBJ_BIN_ATTR	0x0008
 #define SYSFS_KOBJ_LINK 	0x0020
+#define SYSFS_SHADOW_DIR	0x0040
 #define SYSFS_COPY_NAME		(SYSFS_DIR | SYSFS_KOBJ_LINK)
 
 #define SYSFS_FLAG_MASK		~SYSFS_TYPE_MASK
 #define SYSFS_FLAG_REMOVED	0x0100
+#define SYSFS_FLAG_SHADOWED	0x0200
 
 #ifdef CONFIG_SYSFS
 
@@ -134,6 +141,8 @@ void sysfs_remove_file_from_group(struct kobject *kobj,
 
 void sysfs_notify(struct kobject * k, char *dir, char *attr);
 
+int sysfs_enable_shadowing(struct kobject *, const struct shadow_dir_operations *);
+
 extern int __must_check sysfs_init(void);
 
 #else /* CONFIG_SYSFS */
@@ -229,6 +238,12 @@ static inline void sysfs_notify(struct kobject * k, char *dir, char *attr)
 {
 }
 
+static inline int sysfs_enable_shadowing(struct kobject *kobj,
+				const struct shadow_dir_operations *shadow_ops)
+{
+	return 0;
+}
+
 static inline int __must_check sysfs_init(void)
 {
 	return 0;
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 3/4] sysfs: Implement sysfs_delete_link and sysfs_rename_link
       [not found]                       ` <m1zm1t2e92.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-19  4:46                         ` Eric W. Biederman
       [not found]                           ` <m1vech2e6o.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-21  6:36                         ` patch sysfs-implement-sysfs-manged-shadow-directory-support.patch " gregkh-l3A5Bk7waGM
  2007-07-22 19:47                         ` [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support Tejun Heo
  2 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-19  4:46 UTC (permalink / raw)
  To: Greg KH; +Cc: Linux Containers, Tejun Heo, Greg KH, Dave Hansen


When removing a symlink sysfs_remove_link does not provide enough
information to figure out which shadow directory the symlink falls in.
So I need sysfs_delete_link which is passed the target of the symlink
to delete.

Further half the time when we are removing a symlink the code is
actually renaming the symlink but not doing so explicitly because we
don't have a symlink rename method.  So I have added sysfs_rename_link
as well.

Both of these functions now have enough information to find a symlink
in a shadow directory.  The only restriction is that they must be
called before the target kobject is renamed or deleted.  If they are
called later I loose track of which tag the target kobject was marked
with and can no longer find the old symlink to remove it.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/sysfs/symlink.c    |   31 +++++++++++++++++++++++++++++++
 include/linux/sysfs.h |   18 ++++++++++++++++++
 2 files changed, 49 insertions(+), 0 deletions(-)

diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index e52d3ef..62b0aeb 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -126,6 +126,21 @@ addrm_finish:
 
 
 /**
+ *	sysfs_delete_link - remove symlink in object's directory.
+ *	@kobj:	object we're acting for.
+ *	@targ:	object we're pointing to.
+ *	@name:	name of the symlink to remove.
+ *
+ *	Unlike sysfs_remove_link sysfs_delete_link has enough information
+ *	to successfully delete symlinks in shadow directories.
+ */
+void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
+			const char *name)
+{
+	sysfs_hash_and_remove(targ, kobj->sd, name);
+}
+
+/**
  *	sysfs_remove_link - remove symlink in object's directory.
  *	@kobj:	object we're acting for.
  *	@name:	name of the symlink to remove.
@@ -136,6 +151,22 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)
 	sysfs_hash_and_remove(kobj, kobj->sd, name);
 }
 
+/**
+ *	sysfs_rename_link - rename symlink in object's directory.
+ *	@kobj:	object we're acting for.
+ *	@targ:	object we're pointing to.
+ *	@old:	previous name of the symlink.
+ *	@new:	new name of the symlink.
+ *
+ *	A helper function for the common rename symlink idiom.
+ */
+int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
+			const char *old, const char *new)
+{
+	sysfs_delete_link(kobj, targ, old);
+	return sysfs_create_link(kobj, targ, new);
+}
+
 static int sysfs_get_target_path(struct sysfs_dirent * parent_sd,
 				 struct sysfs_dirent * target_sd, char *path)
 {
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 7cda047..e195cb5 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -127,6 +127,13 @@ sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * n
 extern void
 sysfs_remove_link(struct kobject *, const char * name);
 
+extern int
+sysfs_rename_link(struct kobject *kobj, struct kobject *target,
+			const char *old_name, const char *new_name);
+
+extern void
+sysfs_delete_link(struct kobject *dir, struct kobject *targ, const char *name);
+
 int __must_check sysfs_create_bin_file(struct kobject *kobj,
 					struct bin_attribute *attr);
 void sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
@@ -202,6 +209,17 @@ static inline void sysfs_remove_link(struct kobject * k, const char * name)
 	;
 }
 
+static inline int
+sysfs_rename_link(struct kobject * k, struct kobject *t,
+			const char *old_name, const char * new_name)
+{
+	return 0;
+}
+
+static inline void
+sysfs_delete_link(struct kobject *k, struct kobject *t, const char *name)
+{
+}
 
 static inline int sysfs_create_bin_file(struct kobject * k, struct bin_attribute * a)
 {
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 4/4] driver core: Implement shadow directory support for device classes.
       [not found]                           ` <m1vech2e6o.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-19  4:47                             ` Eric W. Biederman
       [not found]                               ` <m1r6n52e5c.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-21  6:36                             ` patch sysfs-implement-sysfs_delete_link-and-sysfs_rename_link.patch " gregkh-l3A5Bk7waGM
  1 sibling, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-19  4:47 UTC (permalink / raw)
  To: Greg KH; +Cc: Linux Containers, Tejun Heo, Greg KH, Dave Hansen


This patch enables shadowing on every class directory if struct class
has shadow_ops.

In addition device_del and device_rename were modified to use
sysfs_delete_link and sysfs_rename_link respectively to ensure
when these operations happen on devices whos classes have
shadow operations that they work properly.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 drivers/base/class.c   |   30 ++++++++++++++++++++++++++----
 drivers/base/core.c    |   45 ++++++++++++++++++++++++---------------------
 include/linux/device.h |    2 ++
 3 files changed, 52 insertions(+), 25 deletions(-)

diff --git a/drivers/base/class.c b/drivers/base/class.c
index 4d22226..c981f75 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -134,6 +134,17 @@ static void remove_class_attrs(struct class * cls)
 	}
 }
 
+static int class_setup_shadowing(struct class *cls)
+{
+	const struct shadow_dir_operations *shadow_ops;
+
+	shadow_ops = cls->shadow_ops;
+	if (!shadow_ops)
+		return 0;
+
+	return sysfs_enable_shadowing(&cls->subsys.kobj, shadow_ops);
+}
+
 int class_register(struct class * cls)
 {
 	int error;
@@ -152,11 +163,22 @@ int class_register(struct class * cls)
 	subsys_set_kset(cls, class_subsys);
 
 	error = subsystem_register(&cls->subsys);
-	if (!error) {
-		error = add_class_attrs(class_get(cls));
-		class_put(cls);
-	}
+	if (error)
+		goto out;
+
+	error = class_setup_shadowing(cls);
+	if (error)
+		goto out_unregister;
+
+	error = add_class_attrs(cls);
+	if (error)
+		goto out_unregister;
+
+out:
 	return error;
+out_unregister:
+	subsystem_unregister(&cls->subsys);
+	goto out;
 }
 
 void class_unregister(struct class * cls)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 3599ab2..5b03842 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -639,8 +639,14 @@ static struct kobject * get_device_parent(struct device *dev,
 			return kobj;
 
 		/* or create a new class-directory at the parent device */
-		return kobject_kset_add_dir(&dev->class->class_dirs,
+		kobj = kobject_kset_add_dir(&dev->class->class_dirs,
 					    parent_kobj, dev->class->name);
+
+		/* If we created a new class-directory setup shadowing */
+		if (kobj && dev->class->shadow_ops)
+			sysfs_enable_shadowing(kobj, dev->class->shadow_ops);
+
+		return kobj;
 	}
 
 	if (parent)
@@ -937,8 +943,8 @@ void device_del(struct device * dev)
 		/* If this is not a "fake" compatible device, remove the
 		 * symlink from the class to the device. */
 		if (dev->kobj.parent != &dev->class->subsys.kobj)
-			sysfs_remove_link(&dev->class->subsys.kobj,
-					  dev->bus_id);
+			sysfs_delete_link(&dev->class->subsys.kobj,
+					  &dev->kobj, dev->bus_id);
 		if (parent) {
 #ifdef CONFIG_SYSFS_DEPRECATED
 			char *class_name = make_class_name(dev->class->name,
@@ -1236,6 +1242,13 @@ int device_rename(struct device *dev, char *new_name)
 	strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
 	strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
 
+	if (dev->class && (dev->kobj.parent != &dev->class->subsys.kobj)) {
+		error = sysfs_rename_link(&dev->class->subsys.kobj,
+			&dev->kobj, old_device_name, new_name);
+		if (error)
+			goto out;
+	}
+
 	error = kobject_rename(&dev->kobj, new_name);
 	if (error) {
 		strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);
@@ -1244,27 +1257,17 @@ int device_rename(struct device *dev, char *new_name)
 
 #ifdef CONFIG_SYSFS_DEPRECATED
 	if (old_class_name) {
+		error = -ENOMEM;
 		new_class_name = make_class_name(dev->class->name, &dev->kobj);
-		if (new_class_name) {
-			error = sysfs_create_link(&dev->parent->kobj,
-						  &dev->kobj, new_class_name);
-			if (error)
-				goto out;
-			sysfs_remove_link(&dev->parent->kobj, old_class_name);
-		}
-	}
-#endif
+		if (!new_class_name)
+			goto out;
 
-	if (dev->class) {
-		sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
-		error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
-					  dev->bus_id);
-		if (error) {
-			/* Uh... how to unravel this if restoring can fail? */
-			dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n",
-				__FUNCTION__, error);
-		}
+		error = sysfs_rename_link(&dev->parent->kobj, &dev->kobj,
+					  old_class_name, new_class_name);
+		if (error)
+			goto out;
 	}
+#endif
 out:
 	put_device(dev);
 
diff --git a/include/linux/device.h b/include/linux/device.h
index d9f0a57..ed31e43 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -200,6 +200,8 @@ struct class {
 
 	int	(*suspend)(struct device *, pm_message_t state);
 	int	(*resume)(struct device *);
+
+	const struct shadow_dir_operations *shadow_ops;
 };
 
 extern int __must_check class_register(struct class *);
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* patch driver-core-implement-shadow-directory-support-for-device-classes.patch added to gregkh-2.6 tree
       [not found]                               ` <m1r6n52e5c.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-21  6:36                                 ` gregkh-l3A5Bk7waGM
       [not found]                                   ` <20070721063634.9337314458DB-j1pC+zEt+uWoYr4blSSd5g@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: gregkh-l3A5Bk7waGM @ 2007-07-21  6:36 UTC (permalink / raw)
  To: greg-U8xfFu+wG4EAvxtiuMwx3w, benjamin.thery-6ktuUTfB/bM,
	containers-qjLDD68F18O7TbgM5vRIOg,
	ebiederm-aS9lmoZGLiVWk0Htik3J/w, gregkh-l3A5Bk7waGM,
	hansendc-r/Jw6+rmf7HQT0dZR+AlfA, htejun-Re5JQEeQqe8AvxtiuMwx3w


This is a note to let you know that I've just added the patch titled

     Subject: [PATCH 4/4] driver core: Implement shadow directory support for device classes.

to my gregkh-2.6 tree.  Its filename is

     driver-core-implement-shadow-directory-support-for-device-classes.patch

This tree can be found at 
    http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/


From ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org  Fri Jul 20 23:21:18 2007
From: ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org (Eric W. Biederman)
Date: Wed, 18 Jul 2007 22:47:27 -0600
Subject: [PATCH 4/4] driver core: Implement shadow directory support for device classes.
To: Greg KH <greg-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
Cc: Greg KH <gregkh-l3A5Bk7waGM@public.gmane.org>, Dave Hansen <hansendc-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>, Benjamin Thery <benjamin.thery-6ktuUTfB/bM@public.gmane.org>, Linux Containers <containers-qjLDD68F18O7TbgM5vRIOg@public.gmane.org>, Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Message-ID: <m1r6n52e5c.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>



This patch enables shadowing on every class directory if struct class
has shadow_ops.

In addition device_del and device_rename were modified to use
sysfs_delete_link and sysfs_rename_link respectively to ensure
when these operations happen on devices whos classes have
shadow operations that they work properly.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
Cc: Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>

---
 drivers/base/class.c   |   30 ++++++++++++++++++++++++++----
 drivers/base/core.c    |   45 ++++++++++++++++++++++++---------------------
 include/linux/device.h |    2 ++
 3 files changed, 52 insertions(+), 25 deletions(-)

--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -134,6 +134,17 @@ static void remove_class_attrs(struct cl
 	}
 }
 
+static int class_setup_shadowing(struct class *cls)
+{
+	const struct shadow_dir_operations *shadow_ops;
+
+	shadow_ops = cls->shadow_ops;
+	if (!shadow_ops)
+		return 0;
+
+	return sysfs_enable_shadowing(&cls->subsys.kobj, shadow_ops);
+}
+
 int class_register(struct class * cls)
 {
 	int error;
@@ -152,11 +163,22 @@ int class_register(struct class * cls)
 	subsys_set_kset(cls, class_subsys);
 
 	error = subsystem_register(&cls->subsys);
-	if (!error) {
-		error = add_class_attrs(class_get(cls));
-		class_put(cls);
-	}
+	if (error)
+		goto out;
+
+	error = class_setup_shadowing(cls);
+	if (error)
+		goto out_unregister;
+
+	error = add_class_attrs(cls);
+	if (error)
+		goto out_unregister;
+
+out:
 	return error;
+out_unregister:
+	subsystem_unregister(&cls->subsys);
+	goto out;
 }
 
 void class_unregister(struct class * cls)
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -645,8 +645,14 @@ static struct kobject * get_device_paren
 			return kobj;
 
 		/* or create a new class-directory at the parent device */
-		return kobject_kset_add_dir(&dev->class->class_dirs,
+		kobj = kobject_kset_add_dir(&dev->class->class_dirs,
 					    parent_kobj, dev->class->name);
+
+		/* If we created a new class-directory setup shadowing */
+		if (kobj && dev->class->shadow_ops)
+			sysfs_enable_shadowing(kobj, dev->class->shadow_ops);
+
+		return kobj;
 	}
 
 	if (parent)
@@ -844,8 +850,8 @@ int device_add(struct device *dev)
 		/* If this is not a "fake" compatible device, remove the
 		 * symlink from the class to the device. */
 		if (dev->kobj.parent != &dev->class->subsys.kobj)
-			sysfs_remove_link(&dev->class->subsys.kobj,
-					  dev->bus_id);
+			sysfs_delete_link(&dev->class->subsys.kobj,
+					  &dev->kobj, dev->bus_id);
 		if (parent && parent->bus) {
 #ifdef CONFIG_SYSFS_DEPRECATED
 			char *class_name = make_class_name(dev->class->name,
@@ -1243,6 +1249,13 @@ int device_rename(struct device *dev, ch
 	strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
 	strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
 
+	if (dev->class && (dev->kobj.parent != &dev->class->subsys.kobj)) {
+		error = sysfs_rename_link(&dev->class->subsys.kobj,
+			&dev->kobj, old_device_name, new_name);
+		if (error)
+			goto out;
+	}
+
 	error = kobject_rename(&dev->kobj, new_name);
 	if (error) {
 		strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);
@@ -1251,27 +1264,17 @@ int device_rename(struct device *dev, ch
 
 #ifdef CONFIG_SYSFS_DEPRECATED
 	if (old_class_name) {
+		error = -ENOMEM;
 		new_class_name = make_class_name(dev->class->name, &dev->kobj);
-		if (new_class_name) {
-			error = sysfs_create_link(&dev->parent->kobj,
-						  &dev->kobj, new_class_name);
-			if (error)
-				goto out;
-			sysfs_remove_link(&dev->parent->kobj, old_class_name);
-		}
-	}
-#endif
+		if (!new_class_name)
+			goto out;
 
-	if (dev->class) {
-		sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
-		error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
-					  dev->bus_id);
-		if (error) {
-			/* Uh... how to unravel this if restoring can fail? */
-			dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n",
-				__FUNCTION__, error);
-		}
+		error = sysfs_rename_link(&dev->parent->kobj, &dev->kobj,
+					  old_class_name, new_class_name);
+		if (error)
+			goto out;
 	}
+#endif
 out:
 	put_device(dev);
 
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -200,6 +200,8 @@ struct class {
 
 	int	(*suspend)(struct device *, pm_message_t state);
 	int	(*resume)(struct device *);
+
+	const struct shadow_dir_operations *shadow_ops;
 };
 
 extern int __must_check class_register(struct class *);


Patches currently in gregkh-2.6 which might be from greg-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org are

bad/pci-domain/pci-device-ensure-sysdata-initialised.patch
bad/pci-domain/pci-fix-the-x86-pci-domain-support-fix.patch
bad/relayfs/sysfs-update-relay-file-support-for-generic-relay-api.patch
bad/relayfs/relay-consolidate-relayfs-core-into-kernel-relay.c.patch
bad/relayfs/relay-relay-header-cleanup.patch
bad/relayfs/relayfs-remove-relayfs-in-favour-of-config_relay.patch
bad/relayfs/sysfs-add-__attr_relay-helper-for-relay-attributes.patch
bad/relayfs/sysfs-relay-channel-buffers-as-sysfs-attributes.patch
bad/usbip/usb-usbip-more-dead-code-fix.patch
bad/usbip/usb-usbip-build-fix.patch
bad/usbip/usb-usbip-warning-fixes.patch
bad/ndevfs.patch
bad/battery-class-driver.patch
bad/driver-model-convert-driver-model-to-mutexes.patch
bad/gpl_future-test.patch
bad/gregkh-debugfs_example.patch
bad/speakup-kconfig-fix.patch
bad/speakup-build-fix.patch
bad/pci-use-new-multi-phase-suspend-infrastructure.patch
bad/shot-accross-the-bow.patch
bad/no-more-non-gpl-modules.patch
bad/spi-device.patch
bad/ata_piix-multithread.patch
bad/uio-irq.patch
bad/pci-two-drivers-on-one-pci-device.patch
bad/pci-dynamic-id-cleanup.patch
bad/input-device.patch
bad/usb-stimulus.patch
driver/nozomi.patch
driver/kobject-put-kobject_actions-in-kobject.h.patch
driver/sysfs-implement-sysfs-manged-shadow-directory-support.patch
driver/sysfs-implement-sysfs_delete_link-and-sysfs_rename_link.patch
driver/sysfs-remove-first-pass-at-shadow-directory-support.patch
driver/driver-core-implement-shadow-directory-support-for-device-classes.patch
gregkh/gkh-version.patch
gregkh/sysfs-test.patch
gregkh/sysrq-u-laptop.patch
pci/pci_bridge-device.patch
pci/pci-piggy-bus.patch
pci/pci-move-prototypes-for-pci_bus_find_capability-to-include-linux-pci.h.patch
pci/pci-document-pci_iomap.patch
usb/usb-gotemp.patch
usb/kobject-put-kobject_actions-in-kobject.h.patch
usb/usb-add-the-concept-of-default-authorization-to-usb-hosts.patch
usb/usb-cleanup-usb_register_bus-and-hook-up-sysfs-group.patch
usb/usb-initialize-authorization-and-wusb-bits-in-usb-devices.patch
usb/usb-introduce-usb_device-authorization-bits.patch
usb/usb-usb_set_configuration-obeys-authorization.patch
usb/usb-usb.h-kernel-doc-additions.patch
HOWTO

^ permalink raw reply	[flat|nested] 79+ messages in thread

* patch sysfs-implement-sysfs-manged-shadow-directory-support.patch added to gregkh-2.6 tree
       [not found]                       ` <m1zm1t2e92.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-19  4:46                         ` [PATCH 3/4] sysfs: Implement sysfs_delete_link and sysfs_rename_link Eric W. Biederman
@ 2007-07-21  6:36                         ` gregkh-l3A5Bk7waGM
  2007-07-22 19:47                         ` [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support Tejun Heo
  2 siblings, 0 replies; 79+ messages in thread
From: gregkh-l3A5Bk7waGM @ 2007-07-21  6:36 UTC (permalink / raw)
  To: greg-U8xfFu+wG4EAvxtiuMwx3w, benjamin.thery-6ktuUTfB/bM,
	containers-qjLDD68F18O7TbgM5vRIOg,
	ebiederm-aS9lmoZGLiVWk0Htik3J/w, gregkh-l3A5Bk7waGM,
	hansendc-r/Jw6+rmf7HQT0dZR+AlfA, htejun-Re5JQEeQqe8AvxtiuMwx3w


This is a note to let you know that I've just added the patch titled

     Subject: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.

to my gregkh-2.6 tree.  Its filename is

     sysfs-implement-sysfs-manged-shadow-directory-support.patch

This tree can be found at 
    http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/


From ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org  Fri Jul 20 23:20:42 2007
From: ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org (Eric W. Biederman)
Date: Wed, 18 Jul 2007 22:45:13 -0600
Subject: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
To: Greg KH <greg-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
Cc: Greg KH <gregkh-l3A5Bk7waGM@public.gmane.org>, Dave Hansen <hansendc-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>, Benjamin Thery <benjamin.thery-6ktuUTfB/bM@public.gmane.org>, Linux Containers <containers-qjLDD68F18O7TbgM5vRIOg@public.gmane.org>, Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Message-ID: <m1zm1t2e92.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>



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 I want is for each network namespace to have it's own separate
set of directories.  /sys/class/net/, /sys/devices/virtual/net,
and /sys/ ... /net/, and in each set I want to name them
/sys/class/net/, sys/devices/virtual/net/ and /sys/ ... /net/ respectively.

I looked and the VFS actually allows that.  All that is needed is
for /sys/class/net to implement a follow link method to redirect
lookups to the real directory you want.

I am calling the concept of multiple directories all at the same path
in the filesystem shadow directories, the directory entry that
implements the follow_link method the shadow master, and the directories
that are the target of the follow link method shadow directories.

It turns out that just implementing a follow_link method is not
quite enough.  The existince of directories of the form /sys/ ... /net/
can depend on the presence or absence of hotplug hardware, which
means I need a simple race free way to create and destroy these
directories.

To achieve a race free design all shadow directories are created
and managed by sysfs itself.  The upper level code that knows what
shadow directories we need provides just two methods that enable
this:
  current_tag() - that returns a "void *" tag that identifies the context of
	the current process.
  kobject_tag(kobj) - that returns a "void *" tag that identifies the context
	a kobject should be in.
Everything else is left up to sysfs.

For the network namespace current_tag and kobject_tag are essentially
one line functions, and look to remain that.

The work needed in sysfs is more extensive.  At each directory or
symlink creation I need to check if the shadow directory it belongs
in exists and if it does not create it.  Likewise at each symlink
or directory removal I need to check if sysfs directory it is being
removed from is a shadow directory and if this is the last object
in the shadow directory and if so to remove the shadow directory
as well.

I also need a bunch of boiler plate that properly finds, creates, and
removes/frees the shadow directories.

Doing all of that in sysfs isn't bad it is just a bit tedious.  Being race
free is just a manner of ensure we have the directory inode mutex
and the sysfs mutex when we add or remove a shadow directory.  Trying to do
this race free anywhere besides in sysfs is very nasty, and requires unhealthy
amounts of information about how sysfs is implemented.

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
not potential users which makes it an uniteresting problem
to solve.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
Cc: Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>

---
 fs/sysfs/bin.c        |    2 
 fs/sysfs/dir.c        |  404 +++++++++++++++++++++++++++++++++++++++++---------
 fs/sysfs/file.c       |    4 
 fs/sysfs/group.c      |   12 -
 fs/sysfs/inode.c      |   11 -
 fs/sysfs/symlink.c    |   30 ++-
 fs/sysfs/sysfs.h      |    9 -
 include/linux/sysfs.h |   15 +
 8 files changed, 396 insertions(+), 91 deletions(-)

--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -248,7 +248,7 @@ int sysfs_create_bin_file(struct kobject
 
 void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr)
 {
-	if (sysfs_hash_and_remove(kobj->sd, attr->attr.name) < 0) {
+	if (sysfs_hash_and_remove(kobj, kobj->sd, attr->attr.name) < 0) {
 		printk(KERN_ERR "%s: "
 			"bad dentry or inode or no such file: \"%s\"\n",
 			__FUNCTION__, attr->attr.name);
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -14,12 +14,33 @@
 #include <asm/semaphore.h>
 #include "sysfs.h"
 
+static void sysfs_prune_shadow_sd(struct sysfs_dirent *sd);
+
 DEFINE_MUTEX(sysfs_mutex);
 spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED;
 
 static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED;
 static DEFINE_IDA(sysfs_ino_ida);
 
+static struct sysfs_dirent *find_shadow_sd(struct sysfs_dirent *parent_sd, const void *target)
+{
+	/* Find the shadow directory for the specified tag */
+	struct sysfs_dirent *sd;
+
+	for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
+		if (sd->s_name != target)
+			continue;
+		break;
+	}
+	return sd;
+}
+
+static const void *find_shadow_tag(struct kobject *kobj)
+{
+	/* Find the tag the current kobj is cached with */
+	return kobj->sd->s_parent->s_name;
+}
+
 /**
  *	sysfs_link_sibling - link sysfs_dirent into sibling list
  *	@sd: sysfs_dirent of interest
@@ -323,7 +344,8 @@ void release_sysfs_dirent(struct sysfs_d
 	if (sysfs_type(sd) & SYSFS_COPY_NAME)
 		kfree(sd->s_name);
 	kfree(sd->s_iattr);
-	sysfs_free_ino(sd->s_ino);
+	if (sysfs_type(sd) != SYSFS_SHADOW_DIR)
+		sysfs_free_ino(sd->s_ino);
 	kmem_cache_free(sysfs_dir_cachep, sd);
 
 	sd = parent_sd;
@@ -414,7 +436,8 @@ static void sysfs_attach_dentry(struct s
 	sd->s_dentry = dentry;
 	spin_unlock(&sysfs_assoc_lock);
 
-	d_rehash(dentry);
+	if (dentry->d_flags & DCACHE_UNHASHED)
+		d_rehash(dentry);
 }
 
 static int sysfs_ilookup_test(struct inode *inode, void *arg)
@@ -569,6 +592,10 @@ static void sysfs_drop_dentry(struct sys
 	spin_unlock(&dcache_lock);
 	spin_unlock(&sysfs_assoc_lock);
 
+	/* dentries for shadowed directories are pinned, unpin */
+	if ((sysfs_type(sd) == SYSFS_SHADOW_DIR) ||
+	    (sd->s_flags & SYSFS_FLAG_SHADOWED))
+		dput(dentry);
 	dput(dentry);
 
 	/* adjust nlink and update timestamp */
@@ -622,6 +649,7 @@ int sysfs_addrm_finish(struct sysfs_addr
 		acxt->removed = sd->s_sibling;
 		sd->s_sibling = NULL;
 
+		sysfs_prune_shadow_sd(sd->s_parent);
 		sysfs_drop_dentry(sd);
 		sysfs_deactivate(sd);
 		sysfs_put(sd);
@@ -687,6 +715,7 @@ static int create_dir(struct kobject *ko
 	umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
 	struct sysfs_addrm_cxt acxt;
 	struct sysfs_dirent *sd;
+	int err;
 
 	/* allocate */
 	sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
@@ -696,15 +725,21 @@ static int create_dir(struct kobject *ko
 
 	/* link in */
 	sysfs_addrm_start(&acxt, parent_sd);
+	err = -ENOENT;
+	if (!sysfs_resolve_for_create(kobj, &acxt.parent_sd))
+		goto addrm_finish;
 
-	if (!sysfs_find_dirent(parent_sd, name)) {
+	err = -EEXIST;
+	if (!sysfs_find_dirent(acxt.parent_sd, name)) {
 		sysfs_add_one(&acxt, sd);
 		sysfs_link_sibling(sd);
+		err = 0;
 	}
 
+addrm_finish:
 	if (!sysfs_addrm_finish(&acxt)) {
 		sysfs_put(sd);
-		return -EEXIST;
+		return err;
 	}
 
 	*p_sd = sd;
@@ -813,18 +848,56 @@ static struct dentry * sysfs_lookup(stru
 	return NULL;
 }
 
+static void *sysfs_shadow_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	struct sysfs_dirent *sd;
+	struct dentry *dest;
+
+	sd = dentry->d_fsdata;
+	dest = NULL;
+	if (sd->s_flags & SYSFS_FLAG_SHADOWED) {
+		const struct shadow_dir_operations *shadow_ops;
+		const void *tag;
+
+		mutex_lock(&sysfs_mutex);
+
+		shadow_ops = dentry->d_inode->i_private;
+		tag = shadow_ops->current_tag();
+
+		sd = find_shadow_sd(sd, tag);
+		if (sd)
+			dest = sd->s_dentry;
+		dget(dest);
+
+		mutex_unlock(&sysfs_mutex);
+	}
+	if (!dest)
+		dest = dget(dentry);
+	dput(nd->dentry);
+	nd->dentry = dest;
+
+	return NULL;
+}
+
+
 const struct inode_operations sysfs_dir_inode_operations = {
 	.lookup		= sysfs_lookup,
 	.setattr	= sysfs_setattr,
+	.follow_link	= sysfs_shadow_follow_link,
 };
 
+static void __remove_dir(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
+{
+	sysfs_unlink_sibling(sd);
+	sysfs_remove_one(acxt, sd);
+}
+
 static void remove_dir(struct sysfs_dirent *sd)
 {
 	struct sysfs_addrm_cxt acxt;
 
 	sysfs_addrm_start(&acxt, sd->s_parent);
-	sysfs_unlink_sibling(sd);
-	sysfs_remove_one(&acxt, sd);
+	__remove_dir(&acxt, sd);
 	sysfs_addrm_finish(&acxt);
 }
 
@@ -833,17 +906,11 @@ void sysfs_remove_subdir(struct sysfs_di
 	remove_dir(sd);
 }
 
-
-static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
+static void sysfs_empty_dir(struct sysfs_addrm_cxt *acxt,
+			    struct sysfs_dirent *dir_sd)
 {
-	struct sysfs_addrm_cxt acxt;
 	struct sysfs_dirent **pos;
 
-	if (!dir_sd)
-		return;
-
-	pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
-	sysfs_addrm_start(&acxt, dir_sd);
 	pos = &dir_sd->s_children;
 	while (*pos) {
 		struct sysfs_dirent *sd = *pos;
@@ -851,10 +918,39 @@ static void __sysfs_remove_dir(struct sy
 		if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) {
 			*pos = sd->s_sibling;
 			sd->s_sibling = NULL;
-			sysfs_remove_one(&acxt, sd);
+			sysfs_remove_one(acxt, sd);
 		} else
 			pos = &(*pos)->s_sibling;
 	}
+}
+
+static void sysfs_remove_shadows(struct sysfs_addrm_cxt * acxt,
+					struct sysfs_dirent *dir_sd)
+{
+	struct sysfs_dirent **pos;
+
+	pos = &dir_sd->s_children;
+	while (*pos) {
+		struct sysfs_dirent *sd = *pos;
+
+		sysfs_empty_dir(acxt, sd);
+		__remove_dir(acxt, sd);
+	}
+}
+
+static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
+{
+	struct sysfs_addrm_cxt acxt;
+
+	if (!dir_sd)
+		return;
+
+	pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
+	sysfs_addrm_start(&acxt, dir_sd);
+	if (sysfs_type(dir_sd) == SYSFS_DIR)
+		sysfs_empty_dir(&acxt, dir_sd);
+	else
+		sysfs_remove_shadows(&acxt, dir_sd);
 	sysfs_addrm_finish(&acxt);
 
 	remove_dir(dir_sd);
@@ -882,86 +978,75 @@ void sysfs_remove_dir(struct kobject * k
 
 int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
 {
+	struct dentry *old_dentry, *new_dentry, *parent;
+	struct sysfs_addrm_cxt acxt;
 	struct sysfs_dirent *sd;
-	struct dentry *parent = NULL;
-	struct dentry *old_dentry = NULL, *new_dentry = NULL;
-	struct sysfs_dirent *parent_sd;
-	const char *dup_name = NULL;
+	const char *dup_name;
 	int error;
 
-	if (!kobj->parent)
-		return -EINVAL;
+	dup_name = NULL;
+	new_dentry = NULL;
 
-	/* get dentries */
 	sd = kobj->sd;
-	old_dentry = sysfs_get_dentry(sd);
-	if (IS_ERR(old_dentry)) {
-		error = PTR_ERR(old_dentry);
-		goto out_dput;
-	}
-
-	parent_sd = kobj->parent->sd;
-	parent = sysfs_get_dentry(parent_sd);
-	if (IS_ERR(parent)) {
-		error = PTR_ERR(parent);
-		goto out_dput;
-	}
-
-	/* lock parent and get dentry for new name */
-	mutex_lock(&parent->d_inode->i_mutex);
+	sysfs_addrm_start(&acxt, sd->s_parent);
+	error = -ENOENT;
+	if (!sysfs_resolve_for_create(kobj, &acxt.parent_sd))
+		goto addrm_finish;
 
-	new_dentry = lookup_one_len(new_name, parent, strlen(new_name));
-	if (IS_ERR(new_dentry)) {
-		error = PTR_ERR(new_dentry);
-		goto out_unlock;
-	}
+	error = -EEXIST;
+	if (sysfs_find_dirent(acxt.parent_sd, new_name))
+		goto addrm_finish;
 
 	error = -EINVAL;
-	if (old_dentry == new_dentry)
-		goto out_unlock;
+	if ((sd->s_parent == acxt.parent_sd) &&
+	    (strcmp(new_name, sd->s_name) == 0))
+		goto addrm_finish;
+
+	old_dentry = sd->s_dentry;
+	parent = acxt.parent_sd->s_dentry;
+	if (old_dentry) {
+		old_dentry = sd->s_dentry;
+		parent = acxt.parent_sd->s_dentry;
+		new_dentry = lookup_one_len(new_name, parent, strlen(new_name));
+		if (IS_ERR(new_dentry)) {
+			error = PTR_ERR(new_dentry);
+			goto addrm_finish;
+		}
 
-	error = -EEXIST;
-	if (new_dentry->d_inode)
-		goto out_unlock;
+		error = -EINVAL;
+		if (old_dentry == new_dentry)
+			goto addrm_finish;
+	}
 
 	/* rename kobject and sysfs_dirent */
 	error = -ENOMEM;
 	new_name = dup_name = kstrdup(new_name, GFP_KERNEL);
 	if (!new_name)
-		goto out_drop;
+		goto addrm_finish;
 
 	error = kobject_set_name(kobj, "%s", new_name);
 	if (error)
-		goto out_drop;
+		goto addrm_finish;
 
 	dup_name = sd->s_name;
 	sd->s_name = new_name;
 
 	/* move under the new parent */
-	d_add(new_dentry, NULL);
-	d_move(sd->s_dentry, new_dentry);
-
-	mutex_lock(&sysfs_mutex);
-
 	sysfs_unlink_sibling(sd);
-	sysfs_get(parent_sd);
+	sysfs_get(acxt.parent_sd);
 	sysfs_put(sd->s_parent);
-	sd->s_parent = parent_sd;
+	sd->s_parent = acxt.parent_sd;
 	sysfs_link_sibling(sd);
 
-	mutex_unlock(&sysfs_mutex);
-
+	if (new_dentry) {
+		d_add(new_dentry, NULL);
+		d_move(old_dentry, new_dentry);
+	}
 	error = 0;
-	goto out_unlock;
+addrm_finish:
+	sysfs_addrm_finish(&acxt);
 
- out_drop:
-	d_drop(new_dentry);
- out_unlock:
-	mutex_unlock(&parent->d_inode->i_mutex);
- out_dput:
 	kfree(dup_name);
-	dput(parent);
-	dput(old_dentry);
 	dput(new_dentry);
 	return error;
 }
@@ -1098,8 +1183,11 @@ static int sysfs_readdir(struct file * f
 			i++;
 			/* fallthrough */
 		default:
-			mutex_lock(&sysfs_mutex);
+			/* If I am the shadow master return nothing. */
+			if (parent_sd->s_flags & SYSFS_FLAG_SHADOWED)
+				return 0;
 
+			mutex_lock(&sysfs_mutex);
 			pos = &parent_sd->s_children;
 			while (*pos != cursor)
 				pos = &(*pos)->s_sibling;
@@ -1188,3 +1276,185 @@ const struct file_operations sysfs_dir_o
 	.read		= generic_read_dir,
 	.readdir	= sysfs_readdir,
 };
+
+
+static void sysfs_prune_shadow_sd(struct sysfs_dirent *sd)
+{
+	struct sysfs_addrm_cxt acxt;
+
+	/* If a shadow directory goes empty remove it. */
+	if (sysfs_type(sd) != SYSFS_SHADOW_DIR)
+		return;
+
+	if (sd->s_children)
+		return;
+
+	sysfs_addrm_start(&acxt, sd->s_parent);
+
+	if (sd->s_flags & SYSFS_FLAG_REMOVED)
+		goto addrm_finish;
+
+	if (sd->s_children)
+		goto addrm_finish;
+
+	__remove_dir(&acxt, sd);
+addrm_finish:
+	sysfs_addrm_finish(&acxt);
+}
+
+static struct sysfs_dirent *add_shadow_sd(struct sysfs_dirent *parent_sd, const void *tag)
+{
+	struct sysfs_dirent *sd = NULL;
+	struct dentry *dir, *shadow;
+	struct inode *inode;
+
+	dir = parent_sd->s_dentry;
+	inode = dir->d_inode;
+
+	shadow = d_alloc(dir->d_parent, &dir->d_name);
+	if (!shadow)
+		goto out;
+
+	/* Since the shadow directory is reachable make it look
+	 * like it is actually hashed.
+	 */
+	shadow->d_hash.pprev = &shadow->d_hash.next;
+	shadow->d_hash.next = NULL;
+	shadow->d_flags &= ~DCACHE_UNHASHED;
+
+	sd = sysfs_new_dirent(tag, parent_sd->s_mode, SYSFS_SHADOW_DIR);
+	if (!sd)
+		goto error;
+
+	sd->s_elem.dir.kobj = parent_sd->s_elem.dir.kobj;
+	sd->s_parent = sysfs_get(parent_sd);
+
+	/* Use the inode number of the parent we are shadowing */
+	sysfs_free_ino(sd->s_ino);
+	sd->s_ino = parent_sd->s_ino;
+
+	inc_nlink(inode);
+	inc_nlink(dir->d_parent->d_inode);
+
+	sysfs_link_sibling(sd);
+	__iget(inode);
+	sysfs_instantiate(shadow, inode);
+	sysfs_attach_dentry(sd, shadow);
+out:
+	return sd;
+error:
+	dput(shadow);
+	goto out;
+}
+
+int sysfs_resolve_for_create(struct kobject *kobj,
+				struct sysfs_dirent **parent_sd)
+{
+	const struct shadow_dir_operations *shadow_ops;
+	struct sysfs_dirent *sd, *shadow_sd;
+
+	sd = *parent_sd;
+	if (sysfs_type(sd) == SYSFS_SHADOW_DIR)
+		sd = sd->s_parent;
+
+	if (sd->s_flags & SYSFS_FLAG_SHADOWED) {
+		const void *tag;
+
+		shadow_ops = sd->s_dentry->d_inode->i_private;
+		tag = shadow_ops->kobject_tag(kobj);
+
+		shadow_sd = find_shadow_sd(sd, tag);
+		if (!shadow_sd)
+			shadow_sd = add_shadow_sd(sd, tag);
+		sd = shadow_sd;
+	}
+	if (sd) {
+		*parent_sd = sd;
+		return 1;
+	}
+	return 0;
+}
+
+int sysfs_resolve_for_remove(struct kobject *kobj,
+				struct sysfs_dirent **parent_sd)
+{
+	struct sysfs_dirent *sd;
+	/* If dentry is a shadow directory find the shadow that is
+	 * stored under the same tag as kobj.  This allows removal
+	 * of dirents to function properly even if the value of
+	 * kobject_tag() has changed since we initially created
+	 * the dirents assoctated with kobj.
+	 */
+
+	sd = *parent_sd;
+	if (sysfs_type(sd) == SYSFS_SHADOW_DIR)
+		sd = sd->s_parent;
+	if (sd->s_flags & SYSFS_FLAG_SHADOWED) {
+		const void *tag;
+
+		tag = find_shadow_tag(kobj);
+		sd = find_shadow_sd(sd, tag);
+	}
+	if (sd) {
+		*parent_sd = sd;
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ *	sysfs_enable_shadowing - Automatically create shadows of a directory
+ *	@kobj:	object to automatically shadow
+ *
+ *	Once shadowing has been enabled on a directory the contents
+ *	of the directory become dependent upon context.
+ *
+ *	shadow_ops->current_tag() returns the context for the current
+ *	process.
+ *
+ *	shadow_ops->kobject_tag() returns the context that a given kobj
+ *	resides in.
+ *
+ *	Using those methods the sysfs code on shadowed directories
+ *	carefully stores the files so that when we lookup files
+ *	we get the proper answer for our context.
+ *
+ *	If the context of a kobject is changed it is expected that
+ *	the kobject will be renamed so the appopriate sysfs data structures
+ *	can be updated.
+ */
+int sysfs_enable_shadowing(struct kobject *kobj,
+	const struct shadow_dir_operations *shadow_ops)
+{
+	struct sysfs_dirent *sd;
+	struct dentry *dentry;
+	int err;
+
+	/* Find the dentry for the shadowed directory and
+	 * increase it's count.
+	 */
+	err = -ENOENT;
+	sd = kobj->sd;
+	dentry = sysfs_get_dentry(sd);
+	if (!dentry)
+		goto out;
+
+	mutex_lock(&sysfs_mutex);
+	err = -EINVAL;
+	/* We can only enable shadowing on empty directories
+	 * where shadowing is not already enabled.
+	 */
+	if (!sd->s_children && (sysfs_type(sd) == SYSFS_DIR) &&
+	    !(sd->s_flags & SYSFS_FLAG_REMOVED) &&
+	    !(sd->s_flags & SYSFS_FLAG_SHADOWED)) {
+		sd->s_flags |= SYSFS_FLAG_SHADOWED;
+		dentry->d_inode->i_private = (void *)shadow_ops;
+		err = 0;
+	}
+	mutex_unlock(&sysfs_mutex);
+out:
+	if (err)
+		dput(dentry);
+	return err;
+}
+
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -544,7 +544,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);
 }
 
 
@@ -561,7 +561,7 @@ void sysfs_remove_file_from_group(struct
 
 	dir_sd = sysfs_get_dirent(kobj->sd, group);
 	if (dir_sd) {
-		sysfs_hash_and_remove(dir_sd, attr->name);
+		sysfs_hash_and_remove(kobj, dir_sd, attr->name);
 		sysfs_put(dir_sd);
 	}
 }
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -17,16 +17,16 @@
 #include "sysfs.h"
 
 
-static void remove_files(struct sysfs_dirent *dir_sd,
+static void remove_files(struct kobject *kobj, struct sysfs_dirent *dir_sd,
 			 const struct attribute_group *grp)
 {
 	struct attribute *const* attr;
 
 	for (attr = grp->attrs; *attr; 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,
+static int create_files(struct kobject *kobj, struct sysfs_dirent *dir_sd,
 			const struct attribute_group *grp)
 {
 	struct attribute *const* attr;
@@ -35,7 +35,7 @@ static int create_files(struct sysfs_dir
 	for (attr = grp->attrs; *attr && !error; attr++)
 		error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
 	if (error)
-		remove_files(dir_sd, grp);
+		remove_files(kobj, dir_sd, grp);
 	return error;
 }
 
@@ -55,7 +55,7 @@ int sysfs_create_group(struct kobject * 
 	} else
 		sd = kobj->sd;
 	sysfs_get(sd);
-	error = create_files(sd, grp);
+	error = create_files(kobj, sd, grp);
 	if (error) {
 		if (grp->name)
 			sysfs_remove_subdir(sd);
@@ -76,7 +76,7 @@ void sysfs_remove_group(struct kobject *
 	} else
 		sd = sysfs_get(dir_sd);
 
-	remove_files(sd, grp);
+	remove_files(kobj, sd, grp);
 	if (grp->name)
 		sysfs_remove_subdir(sd);
 
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -187,17 +187,16 @@ void sysfs_instantiate(struct dentry *de
 	d_instantiate(dentry, 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 **pos, *sd;
 
-	if (!dir_sd)
-		return -ENOENT;
-
 	sysfs_addrm_start(&acxt, dir_sd);
+	if (!sysfs_resolve_for_remove(kobj, &acxt.parent_sd))
+		goto addrm_finish;
 
-	for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) {
+	for (pos = &acxt.parent_sd->s_children; *pos; pos = &(*pos)->s_sibling) {
 		sd = *pos;
 
 		if (!sysfs_type(sd))
@@ -209,7 +208,7 @@ int sysfs_hash_and_remove(struct sysfs_d
 			break;
 		}
 	}
-
+addrm_finish:
 	if (sysfs_addrm_finish(&acxt))
 		return 0;
 	return -ENOENT;
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -15,8 +15,11 @@ static int object_depth(struct sysfs_dir
 {
 	int depth = 0;
 
-	for (; sd->s_parent; sd = sd->s_parent)
+	for (; sd->s_parent; sd = sd->s_parent) {
+		if (sysfs_type(sd) == SYSFS_SHADOW_DIR)
+			continue;
 		depth++;
+	}
 
 	return depth;
 }
@@ -25,17 +28,24 @@ static int object_path_length(struct sys
 {
 	int length = 1;
 
-	for (; sd->s_parent; sd = sd->s_parent)
+	for (; sd->s_parent; sd = sd->s_parent) {
+		if (sysfs_type(sd) == SYSFS_SHADOW_DIR)
+			continue;
 		length += strlen(sd->s_name) + 1;
+	}
 
 	return length;
 }
 
 static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length)
 {
+	int cur;
 	--length;
 	for (; sd->s_parent; sd = sd->s_parent) {
-		int cur = strlen(sd->s_name);
+		if (sysfs_type(sd) == SYSFS_SHADOW_DIR)
+			continue;
+
+		cur = strlen(sd->s_name);
 
 		/* back up enough to print this bus id with '/' */
 		length -= cur;
@@ -91,16 +101,20 @@ int sysfs_create_link(struct kobject * k
 	target_sd = NULL;	/* reference is now owned by the symlink */
 
 	sysfs_addrm_start(&acxt, parent_sd);
+	error = -ENOENT;
+	if (!sysfs_resolve_for_create(target, &acxt.parent_sd))
+		goto addrm_finish;
 
-	if (!sysfs_find_dirent(parent_sd, name)) {
+	error = -EEXIST;
+	if (!sysfs_find_dirent(acxt.parent_sd, name)) {
+		error = 0;
 		sysfs_add_one(&acxt, sd);
 		sysfs_link_sibling(sd);
 	}
 
-	if (!sysfs_addrm_finish(&acxt)) {
-		error = -EEXIST;
+addrm_finish:
+	if (!sysfs_addrm_finish(&acxt))
 		goto out_put;
-	}
 
 	return 0;
 
@@ -119,7 +133,7 @@ int sysfs_create_link(struct kobject * k
 
 void sysfs_remove_link(struct kobject * kobj, const char * name)
 {
-	sysfs_hash_and_remove(kobj->sd, name);
+	sysfs_hash_and_remove(kobj, kobj->sd, name);
 }
 
 static int sysfs_get_target_path(struct sysfs_dirent * parent_sd,
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -58,6 +58,12 @@ extern struct kmem_cache *sysfs_dir_cach
 extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);
 extern void sysfs_link_sibling(struct sysfs_dirent *sd);
 extern void sysfs_unlink_sibling(struct sysfs_dirent *sd);
+
+extern int sysfs_resolve_for_create(struct kobject *kobj,
+				    struct sysfs_dirent **parent_sd);
+extern int sysfs_resolve_for_remove(struct kobject *kobj,
+				    struct sysfs_dirent **parent_sd);
+
 extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd);
 extern void sysfs_put_active(struct sysfs_dirent *sd);
 extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);
@@ -83,7 +89,8 @@ extern struct sysfs_dirent *sysfs_new_di
 
 extern int sysfs_add_file(struct sysfs_dirent *dir_sd,
 			  const struct attribute *attr, int type);
-extern int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
+extern int sysfs_hash_and_remove(struct kobject *kobj,
+				 struct sysfs_dirent *dir_sd, const char *name);
 extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name);
 
 extern int sysfs_create_subdir(struct kobject *kobj, const char *name,
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -74,16 +74,23 @@ struct sysfs_ops {
 	ssize_t	(*store)(struct kobject *,struct attribute *,const char *, size_t);
 };
 
+struct shadow_dir_operations {
+	const void *(*current_tag)(void);
+	const void *(*kobject_tag)(struct kobject *kobj);
+};
+
 #define SYSFS_TYPE_MASK		0x00ff
 #define SYSFS_ROOT		0x0001
 #define SYSFS_DIR		0x0002
 #define SYSFS_KOBJ_ATTR 	0x0004
 #define SYSFS_KOBJ_BIN_ATTR	0x0008
 #define SYSFS_KOBJ_LINK 	0x0020
+#define SYSFS_SHADOW_DIR	0x0040
 #define SYSFS_COPY_NAME		(SYSFS_DIR | SYSFS_KOBJ_LINK)
 
 #define SYSFS_FLAG_MASK		~SYSFS_TYPE_MASK
 #define SYSFS_FLAG_REMOVED	0x0100
+#define SYSFS_FLAG_SHADOWED	0x0200
 
 #ifdef CONFIG_SYSFS
 
@@ -134,6 +141,8 @@ void sysfs_remove_file_from_group(struct
 
 void sysfs_notify(struct kobject * k, char *dir, char *attr);
 
+int sysfs_enable_shadowing(struct kobject *, const struct shadow_dir_operations *);
+
 extern int __must_check sysfs_init(void);
 
 #else /* CONFIG_SYSFS */
@@ -229,6 +238,12 @@ static inline void sysfs_notify(struct k
 {
 }
 
+static inline int sysfs_enable_shadowing(struct kobject *kobj,
+				const struct shadow_dir_operations *shadow_ops)
+{
+	return 0;
+}
+
 static inline int __must_check sysfs_init(void)
 {
 	return 0;


Patches currently in gregkh-2.6 which might be from greg-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org are

bad/pci-domain/pci-device-ensure-sysdata-initialised.patch
bad/pci-domain/pci-fix-the-x86-pci-domain-support-fix.patch
bad/relayfs/sysfs-update-relay-file-support-for-generic-relay-api.patch
bad/relayfs/relay-consolidate-relayfs-core-into-kernel-relay.c.patch
bad/relayfs/relay-relay-header-cleanup.patch
bad/relayfs/relayfs-remove-relayfs-in-favour-of-config_relay.patch
bad/relayfs/sysfs-add-__attr_relay-helper-for-relay-attributes.patch
bad/relayfs/sysfs-relay-channel-buffers-as-sysfs-attributes.patch
bad/usbip/usb-usbip-more-dead-code-fix.patch
bad/usbip/usb-usbip-build-fix.patch
bad/usbip/usb-usbip-warning-fixes.patch
bad/ndevfs.patch
bad/battery-class-driver.patch
bad/driver-model-convert-driver-model-to-mutexes.patch
bad/gpl_future-test.patch
bad/gregkh-debugfs_example.patch
bad/speakup-kconfig-fix.patch
bad/speakup-build-fix.patch
bad/pci-use-new-multi-phase-suspend-infrastructure.patch
bad/shot-accross-the-bow.patch
bad/no-more-non-gpl-modules.patch
bad/spi-device.patch
bad/ata_piix-multithread.patch
bad/uio-irq.patch
bad/pci-two-drivers-on-one-pci-device.patch
bad/pci-dynamic-id-cleanup.patch
bad/input-device.patch
bad/usb-stimulus.patch
driver/nozomi.patch
driver/kobject-put-kobject_actions-in-kobject.h.patch
driver/sysfs-implement-sysfs-manged-shadow-directory-support.patch
driver/sysfs-implement-sysfs_delete_link-and-sysfs_rename_link.patch
driver/sysfs-remove-first-pass-at-shadow-directory-support.patch
driver/driver-core-implement-shadow-directory-support-for-device-classes.patch
gregkh/gkh-version.patch
gregkh/sysfs-test.patch
gregkh/sysrq-u-laptop.patch
pci/pci_bridge-device.patch
pci/pci-piggy-bus.patch
pci/pci-move-prototypes-for-pci_bus_find_capability-to-include-linux-pci.h.patch
pci/pci-document-pci_iomap.patch
usb/usb-gotemp.patch
usb/kobject-put-kobject_actions-in-kobject.h.patch
usb/usb-add-the-concept-of-default-authorization-to-usb-hosts.patch
usb/usb-cleanup-usb_register_bus-and-hook-up-sysfs-group.patch
usb/usb-initialize-authorization-and-wusb-bits-in-usb-devices.patch
usb/usb-introduce-usb_device-authorization-bits.patch
usb/usb-usb_set_configuration-obeys-authorization.patch
usb/usb-usb.h-kernel-doc-additions.patch
HOWTO

^ permalink raw reply	[flat|nested] 79+ messages in thread

* patch sysfs-implement-sysfs_delete_link-and-sysfs_rename_link.patch added to gregkh-2.6 tree
       [not found]                           ` <m1vech2e6o.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-19  4:47                             ` [PATCH 4/4] driver core: Implement shadow directory support for device classes Eric W. Biederman
@ 2007-07-21  6:36                             ` gregkh-l3A5Bk7waGM
  1 sibling, 0 replies; 79+ messages in thread
From: gregkh-l3A5Bk7waGM @ 2007-07-21  6:36 UTC (permalink / raw)
  To: greg-U8xfFu+wG4EAvxtiuMwx3w, benjamin.thery-6ktuUTfB/bM,
	containers-qjLDD68F18O7TbgM5vRIOg,
	ebiederm-aS9lmoZGLiVWk0Htik3J/w, gregkh-l3A5Bk7waGM,
	hansendc-r/Jw6+rmf7HQT0dZR+AlfA, htejun-Re5JQEeQqe8AvxtiuMwx3w


This is a note to let you know that I've just added the patch titled

     Subject: [PATCH 3/4] sysfs: Implement sysfs_delete_link and sysfs_rename_link

to my gregkh-2.6 tree.  Its filename is

     sysfs-implement-sysfs_delete_link-and-sysfs_rename_link.patch

This tree can be found at 
    http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/


From ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org  Fri Jul 20 23:21:06 2007
From: ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org (Eric W. Biederman)
Date: Wed, 18 Jul 2007 22:46:39 -0600
Subject: [PATCH 3/4] sysfs: Implement sysfs_delete_link and sysfs_rename_link
To: Greg KH <greg-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
Cc: Greg KH <gregkh-l3A5Bk7waGM@public.gmane.org>, Dave Hansen <hansendc-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>, Benjamin Thery <benjamin.thery-6ktuUTfB/bM@public.gmane.org>, Linux Containers <containers-qjLDD68F18O7TbgM5vRIOg@public.gmane.org>, Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Message-ID: <m1vech2e6o.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>



When removing a symlink sysfs_remove_link does not provide enough
information to figure out which shadow directory the symlink falls in.
So I need sysfs_delete_link which is passed the target of the symlink
to delete.

Further half the time when we are removing a symlink the code is
actually renaming the symlink but not doing so explicitly because we
don't have a symlink rename method.  So I have added sysfs_rename_link
as well.

Both of these functions now have enough information to find a symlink
in a shadow directory.  The only restriction is that they must be
called before the target kobject is renamed or deleted.  If they are
called later I loose track of which tag the target kobject was marked
with and can no longer find the old symlink to remove it.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
Cc: Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>

---
 fs/sysfs/symlink.c    |   31 +++++++++++++++++++++++++++++++
 include/linux/sysfs.h |   18 ++++++++++++++++++
 2 files changed, 49 insertions(+)

--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -126,6 +126,21 @@ addrm_finish:
 
 
 /**
+ *	sysfs_delete_link - remove symlink in object's directory.
+ *	@kobj:	object we're acting for.
+ *	@targ:	object we're pointing to.
+ *	@name:	name of the symlink to remove.
+ *
+ *	Unlike sysfs_remove_link sysfs_delete_link has enough information
+ *	to successfully delete symlinks in shadow directories.
+ */
+void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
+			const char *name)
+{
+	sysfs_hash_and_remove(targ, kobj->sd, name);
+}
+
+/**
  *	sysfs_remove_link - remove symlink in object's directory.
  *	@kobj:	object we're acting for.
  *	@name:	name of the symlink to remove.
@@ -136,6 +151,22 @@ void sysfs_remove_link(struct kobject * 
 	sysfs_hash_and_remove(kobj, kobj->sd, name);
 }
 
+/**
+ *	sysfs_rename_link - rename symlink in object's directory.
+ *	@kobj:	object we're acting for.
+ *	@targ:	object we're pointing to.
+ *	@old:	previous name of the symlink.
+ *	@new:	new name of the symlink.
+ *
+ *	A helper function for the common rename symlink idiom.
+ */
+int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
+			const char *old, const char *new)
+{
+	sysfs_delete_link(kobj, targ, old);
+	return sysfs_create_link(kobj, targ, new);
+}
+
 static int sysfs_get_target_path(struct sysfs_dirent * parent_sd,
 				 struct sysfs_dirent * target_sd, char *path)
 {
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -127,6 +127,13 @@ sysfs_create_link(struct kobject * kobj,
 extern void
 sysfs_remove_link(struct kobject *, const char * name);
 
+extern int
+sysfs_rename_link(struct kobject *kobj, struct kobject *target,
+			const char *old_name, const char *new_name);
+
+extern void
+sysfs_delete_link(struct kobject *dir, struct kobject *targ, const char *name);
+
 int __must_check sysfs_create_bin_file(struct kobject *kobj,
 					struct bin_attribute *attr);
 void sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
@@ -202,6 +209,17 @@ static inline void sysfs_remove_link(str
 	;
 }
 
+static inline int
+sysfs_rename_link(struct kobject * k, struct kobject *t,
+			const char *old_name, const char * new_name)
+{
+	return 0;
+}
+
+static inline void
+sysfs_delete_link(struct kobject *k, struct kobject *t, const char *name)
+{
+}
 
 static inline int sysfs_create_bin_file(struct kobject * k, struct bin_attribute * a)
 {


Patches currently in gregkh-2.6 which might be from greg-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org are

bad/pci-domain/pci-device-ensure-sysdata-initialised.patch
bad/pci-domain/pci-fix-the-x86-pci-domain-support-fix.patch
bad/relayfs/sysfs-update-relay-file-support-for-generic-relay-api.patch
bad/relayfs/relay-consolidate-relayfs-core-into-kernel-relay.c.patch
bad/relayfs/relay-relay-header-cleanup.patch
bad/relayfs/relayfs-remove-relayfs-in-favour-of-config_relay.patch
bad/relayfs/sysfs-add-__attr_relay-helper-for-relay-attributes.patch
bad/relayfs/sysfs-relay-channel-buffers-as-sysfs-attributes.patch
bad/usbip/usb-usbip-more-dead-code-fix.patch
bad/usbip/usb-usbip-build-fix.patch
bad/usbip/usb-usbip-warning-fixes.patch
bad/ndevfs.patch
bad/battery-class-driver.patch
bad/driver-model-convert-driver-model-to-mutexes.patch
bad/gpl_future-test.patch
bad/gregkh-debugfs_example.patch
bad/speakup-kconfig-fix.patch
bad/speakup-build-fix.patch
bad/pci-use-new-multi-phase-suspend-infrastructure.patch
bad/shot-accross-the-bow.patch
bad/no-more-non-gpl-modules.patch
bad/spi-device.patch
bad/ata_piix-multithread.patch
bad/uio-irq.patch
bad/pci-two-drivers-on-one-pci-device.patch
bad/pci-dynamic-id-cleanup.patch
bad/input-device.patch
bad/usb-stimulus.patch
driver/nozomi.patch
driver/kobject-put-kobject_actions-in-kobject.h.patch
driver/sysfs-implement-sysfs-manged-shadow-directory-support.patch
driver/sysfs-implement-sysfs_delete_link-and-sysfs_rename_link.patch
driver/sysfs-remove-first-pass-at-shadow-directory-support.patch
driver/driver-core-implement-shadow-directory-support-for-device-classes.patch
gregkh/gkh-version.patch
gregkh/sysfs-test.patch
gregkh/sysrq-u-laptop.patch
pci/pci_bridge-device.patch
pci/pci-piggy-bus.patch
pci/pci-move-prototypes-for-pci_bus_find_capability-to-include-linux-pci.h.patch
pci/pci-document-pci_iomap.patch
usb/usb-gotemp.patch
usb/kobject-put-kobject_actions-in-kobject.h.patch
usb/usb-add-the-concept-of-default-authorization-to-usb-hosts.patch
usb/usb-cleanup-usb_register_bus-and-hook-up-sysfs-group.patch
usb/usb-initialize-authorization-and-wusb-bits-in-usb-devices.patch
usb/usb-introduce-usb_device-authorization-bits.patch
usb/usb-usb_set_configuration-obeys-authorization.patch
usb/usb-usb.h-kernel-doc-additions.patch
HOWTO

^ permalink raw reply	[flat|nested] 79+ messages in thread

* patch sysfs-remove-first-pass-at-shadow-directory-support.patch added to gregkh-2.6 tree
       [not found]                   ` <m14pk13svx.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-19  4:45                     ` [PATCH 2/4] sysfs: Implement sysfs manged " Eric W. Biederman
@ 2007-07-21  6:36                     ` gregkh-l3A5Bk7waGM
  2007-07-22 18:35                     ` [PATCH 1/4] sysfs: Remove first pass at shadow directory support Tejun Heo
  2 siblings, 0 replies; 79+ messages in thread
From: gregkh-l3A5Bk7waGM @ 2007-07-21  6:36 UTC (permalink / raw)
  To: greg-U8xfFu+wG4EAvxtiuMwx3w, benjamin.thery-6ktuUTfB/bM,
	containers-qjLDD68F18O7TbgM5vRIOg,
	ebiederm-aS9lmoZGLiVWk0Htik3J/w, gregkh-l3A5Bk7waGM,
	hansendc-r/Jw6+rmf7HQT0dZR+AlfA, htejun-Re5JQEeQqe8AvxtiuMwx3w


This is a note to let you know that I've just added the patch titled

     Subject: [PATCH 1/4] sysfs: Remove first pass at shadow directory support

to my gregkh-2.6 tree.  Its filename is

     sysfs-remove-first-pass-at-shadow-directory-support.patch

This tree can be found at 
    http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/


From ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org  Fri Jul 20 23:20:07 2007
From: ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org (Eric W. Biederman)
Date: Wed, 18 Jul 2007 22:43:46 -0600
Subject: [PATCH 1/4] sysfs: Remove first pass at shadow directory support
To: Greg KH <greg-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
Cc: Greg KH <gregkh-l3A5Bk7waGM@public.gmane.org>, Dave Hansen <hansendc-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>, Benjamin Thery <benjamin.thery-6ktuUTfB/bM@public.gmane.org>, Linux Containers <containers-qjLDD68F18O7TbgM5vRIOg@public.gmane.org>, Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Message-ID: <m14pk13svx.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>



While shadow directories appear to be a good idea, the current scheme
of controlling their creation and destruction outside of sysfs appears
to be a locking and maintenance nightmare in the face of sysfs
directories dynamically coming and going.  Which can now occur for
directories containing network devices when CONFIG_SYSFS_DEPRECATED is
not set.

This patch removes everything from the initial shadow directory support
that allowed the shadow directory creation to be controlled at a higher
level.  So except for a few bits of sysfs_rename_dir everything from
commit b592fcfe7f06c15ec11774b5be7ce0de3aa86e73 is now gone.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>

---
 fs/sysfs/dir.c          |  167 ++++++------------------------------------------
 fs/sysfs/group.c        |    1 
 fs/sysfs/inode.c        |   10 --
 fs/sysfs/mount.c        |    2 
 fs/sysfs/sysfs.h        |    6 -
 include/linux/kobject.h |    5 -
 include/linux/sysfs.h   |   27 +------
 lib/kobject.c           |   44 +-----------
 8 files changed, 33 insertions(+), 229 deletions(-)

--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -569,9 +569,6 @@ static void sysfs_drop_dentry(struct sys
 	spin_unlock(&dcache_lock);
 	spin_unlock(&sysfs_assoc_lock);
 
-	/* dentries for shadowed inodes are pinned, unpin */
-	if (dentry && sysfs_is_shadowed_inode(dentry->d_inode))
-		dput(dentry);
 	dput(dentry);
 
 	/* adjust nlink and update timestamp */
@@ -723,19 +720,15 @@ int sysfs_create_subdir(struct kobject *
 /**
  *	sysfs_create_dir - create a directory for an object.
  *	@kobj:		object we're creating directory for. 
- *	@shadow_parent:	parent object.
  */
-int sysfs_create_dir(struct kobject *kobj,
-		     struct sysfs_dirent *shadow_parent_sd)
+int sysfs_create_dir(struct kobject * kobj)
 {
 	struct sysfs_dirent *parent_sd, *sd;
 	int error = 0;
 
 	BUG_ON(!kobj);
 
-	if (shadow_parent_sd)
-		parent_sd = shadow_parent_sd;
-	else if (kobj->parent)
+	if (kobj->parent)
 		parent_sd = kobj->parent->sd;
 	else if (sysfs_mount && sysfs_mount->mnt_sb)
 		parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
@@ -887,45 +880,44 @@ void sysfs_remove_dir(struct kobject * k
 	__sysfs_remove_dir(sd);
 }
 
-int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
-		     const char *new_name)
+int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
 {
-	struct sysfs_dirent *sd = kobj->sd;
-	struct dentry *new_parent = NULL;
+	struct sysfs_dirent *sd;
+	struct dentry *parent = NULL;
 	struct dentry *old_dentry = NULL, *new_dentry = NULL;
+	struct sysfs_dirent *parent_sd;
 	const char *dup_name = NULL;
 	int error;
 
+	if (!kobj->parent)
+		return -EINVAL;
+
 	/* get dentries */
+	sd = kobj->sd;
 	old_dentry = sysfs_get_dentry(sd);
 	if (IS_ERR(old_dentry)) {
 		error = PTR_ERR(old_dentry);
 		goto out_dput;
 	}
 
-	new_parent = sysfs_get_dentry(new_parent_sd);
-	if (IS_ERR(new_parent)) {
-		error = PTR_ERR(new_parent);
+	parent_sd = kobj->parent->sd;
+	parent = sysfs_get_dentry(parent_sd);
+	if (IS_ERR(parent)) {
+		error = PTR_ERR(parent);
 		goto out_dput;
 	}
 
-	/* lock new_parent and get dentry for new name */
-	mutex_lock(&new_parent->d_inode->i_mutex);
+	/* lock parent and get dentry for new name */
+	mutex_lock(&parent->d_inode->i_mutex);
 
-	new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
+	new_dentry = lookup_one_len(new_name, parent, strlen(new_name));
 	if (IS_ERR(new_dentry)) {
 		error = PTR_ERR(new_dentry);
 		goto out_unlock;
 	}
 
-	/* By allowing two different directories with the same
-	 * d_parent we allow this routine to move between different
-	 * shadows of the same directory
-	 */
 	error = -EINVAL;
-	if (old_dentry->d_parent->d_inode != new_parent->d_inode ||
-	    new_dentry->d_parent->d_inode != new_parent->d_inode ||
-	    old_dentry == new_dentry)
+	if (old_dentry == new_dentry)
 		goto out_unlock;
 
 	error = -EEXIST;
@@ -952,9 +944,9 @@ int sysfs_rename_dir(struct kobject *kob
 	mutex_lock(&sysfs_mutex);
 
 	sysfs_unlink_sibling(sd);
-	sysfs_get(new_parent_sd);
+	sysfs_get(parent_sd);
 	sysfs_put(sd->s_parent);
-	sd->s_parent = new_parent_sd;
+	sd->s_parent = parent_sd;
 	sysfs_link_sibling(sd);
 
 	mutex_unlock(&sysfs_mutex);
@@ -965,10 +957,10 @@ int sysfs_rename_dir(struct kobject *kob
  out_drop:
 	d_drop(new_dentry);
  out_unlock:
-	mutex_unlock(&new_parent->d_inode->i_mutex);
+	mutex_unlock(&parent->d_inode->i_mutex);
  out_dput:
 	kfree(dup_name);
-	dput(new_parent);
+	dput(parent);
 	dput(old_dentry);
 	dput(new_dentry);
 	return error;
@@ -1189,121 +1181,6 @@ static loff_t sysfs_dir_lseek(struct fil
 	return offset;
 }
 
-
-/**
- *	sysfs_make_shadowed_dir - Setup so a directory can be shadowed
- *	@kobj:	object we're creating shadow of.
- */
-
-int sysfs_make_shadowed_dir(struct kobject *kobj,
-	void * (*follow_link)(struct dentry *, struct nameidata *))
-{
-	struct dentry *dentry;
-	struct inode *inode;
-	struct inode_operations *i_op;
-
-	/* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */
-	dentry = sysfs_get_dentry(kobj->sd);
-	if (IS_ERR(dentry))
-		return PTR_ERR(dentry);
-
-	inode = dentry->d_inode;
-	if (inode->i_op != &sysfs_dir_inode_operations) {
-		dput(dentry);
-		return -EINVAL;
-	}
-
-	i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
-	if (!i_op)
-		return -ENOMEM;
-
-	memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op));
-	i_op->follow_link = follow_link;
-
-	/* Locking of inode->i_op?
-	 * Since setting i_op is a single word write and they
-	 * are atomic we should be ok here.
-	 */
-	inode->i_op = i_op;
-	return 0;
-}
-
-/**
- *	sysfs_create_shadow_dir - create a shadow directory for an object.
- *	@kobj:	object we're creating directory for.
- *
- *	sysfs_make_shadowed_dir must already have been called on this
- *	directory.
- */
-
-struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj)
-{
-	struct sysfs_dirent *parent_sd = kobj->sd->s_parent;
-	struct dentry *dir, *parent, *shadow;
-	struct inode *inode;
-	struct sysfs_dirent *sd;
-	struct sysfs_addrm_cxt acxt;
-
-	dir = sysfs_get_dentry(kobj->sd);
-	if (IS_ERR(dir)) {
-		sd = (void *)dir;
-		goto out;
-	}
-	parent = dir->d_parent;
-
-	inode = dir->d_inode;
-	sd = ERR_PTR(-EINVAL);
-	if (!sysfs_is_shadowed_inode(inode))
-		goto out_dput;
-
-	shadow = d_alloc(parent, &dir->d_name);
-	if (!shadow)
-		goto nomem;
-
-	sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR);
-	if (!sd)
-		goto nomem;
-	sd->s_elem.dir.kobj = kobj;
-
-	sysfs_addrm_start(&acxt, parent_sd);
-
-	/* add but don't link into children list */
-	sysfs_add_one(&acxt, sd);
-
-	/* attach and instantiate dentry */
-	sysfs_attach_dentry(sd, shadow);
-	d_instantiate(shadow, igrab(inode));
-	inc_nlink(inode);	/* tj: synchronization? */
-
-	sysfs_addrm_finish(&acxt);
-
-	dget(shadow);		/* Extra count - pin the dentry in core */
-
-	goto out_dput;
-
- nomem:
-	dput(shadow);
-	sd = ERR_PTR(-ENOMEM);
- out_dput:
-	dput(dir);
- out:
-	return sd;
-}
-
-/**
- *	sysfs_remove_shadow_dir - remove an object's directory.
- *	@shadow_sd: sysfs_dirent of shadow directory
- *
- *	The only thing special about this is that we remove any files in
- *	the directory before we remove the directory, and we've inlined
- *	what used to be sysfs_rmdir() below, instead of calling separately.
- */
-
-void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd)
-{
-	__sysfs_remove_dir(shadow_sd);
-}
-
 const struct file_operations sysfs_dir_operations = {
 	.open		= sysfs_dir_open,
 	.release	= sysfs_dir_close,
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -13,7 +13,6 @@
 #include <linux/dcache.h>
 #include <linux/namei.h>
 #include <linux/err.h>
-#include <linux/fs.h>
 #include <asm/semaphore.h>
 #include "sysfs.h"
 
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -34,16 +34,6 @@ static const struct inode_operations sys
 	.setattr	= sysfs_setattr,
 };
 
-void sysfs_delete_inode(struct inode *inode)
-{
-	/* Free the shadowed directory inode operations */
-	if (sysfs_is_shadowed_inode(inode)) {
-		kfree(inode->i_op);
-		inode->i_op = NULL;
-	}
-	return generic_delete_inode(inode);
-}
-
 int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
 {
 	struct inode * inode = dentry->d_inode;
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -21,7 +21,7 @@ struct kmem_cache *sysfs_dir_cachep;
 
 static const struct super_operations sysfs_ops = {
 	.statfs		= simple_statfs,
-	.drop_inode	= sysfs_delete_inode,
+	.drop_inode	= generic_delete_inode,
 };
 
 struct sysfs_dirent sysfs_root = {
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -70,7 +70,6 @@ extern void sysfs_remove_one(struct sysf
 			     struct sysfs_dirent *sd);
 extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
 
-extern void sysfs_delete_inode(struct inode *inode);
 extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd);
 extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode);
 
@@ -121,8 +120,3 @@ static inline void sysfs_put(struct sysf
 	if (sd && atomic_dec_and_test(&sd->s_count))
 		release_sysfs_dirent(sd);
 }
-
-static inline int sysfs_is_shadowed_inode(struct inode *inode)
-{
-	return S_ISDIR(inode->i_mode) && inode->i_op->follow_link;
-}
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -83,14 +83,9 @@ extern void kobject_init(struct kobject 
 extern void kobject_cleanup(struct kobject *);
 
 extern int __must_check kobject_add(struct kobject *);
-extern int __must_check kobject_shadow_add(struct kobject *kobj,
-					   struct sysfs_dirent *shadow_parent);
 extern void kobject_del(struct kobject *);
 
 extern int __must_check kobject_rename(struct kobject *, const char *new_name);
-extern int __must_check kobject_shadow_rename(struct kobject *kobj,
-					      struct sysfs_dirent *new_parent,
-					      const char *new_name);
 extern int __must_check kobject_move(struct kobject *, struct kobject *);
 
 extern int __must_check kobject_register(struct kobject *);
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -17,9 +17,6 @@
 
 struct kobject;
 struct module;
-struct nameidata;
-struct dentry;
-struct sysfs_dirent;
 
 /* FIXME
  * The *owner field is no longer used, but leave around
@@ -94,14 +91,13 @@ extern int sysfs_schedule_callback(struc
 		void (*func)(void *), void *data, struct module *owner);
 
 extern int __must_check
-sysfs_create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent_sd);
+sysfs_create_dir(struct kobject *);
 
 extern void
 sysfs_remove_dir(struct kobject *);
 
 extern int __must_check
-sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
-		 const char *new_name);
+sysfs_rename_dir(struct kobject *kobj, const char *new_name);
 
 extern int __must_check
 sysfs_move_dir(struct kobject *, struct kobject *);
@@ -138,12 +134,6 @@ void sysfs_remove_file_from_group(struct
 
 void sysfs_notify(struct kobject * k, char *dir, char *attr);
 
-
-extern int sysfs_make_shadowed_dir(struct kobject *kobj,
-	void * (*follow_link)(struct dentry *, struct nameidata *));
-extern struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj);
-extern void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd);
-
 extern int __must_check sysfs_init(void);
 
 #else /* CONFIG_SYSFS */
@@ -154,8 +144,7 @@ static inline int sysfs_schedule_callbac
 	return -ENOSYS;
 }
 
-static inline int sysfs_create_dir(struct kobject *kobj,
-				   struct sysfs_dirent *shadow_parent_sd)
+static inline int sysfs_create_dir(struct kobject * kobj)
 {
 	return 0;
 }
@@ -165,9 +154,7 @@ static inline void sysfs_remove_dir(stru
 	;
 }
 
-static inline int sysfs_rename_dir(struct kobject *kobj,
-				   struct sysfs_dirent *new_parent_sd,
-				   const char *new_name)
+static inline int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
 {
 	return 0;
 }
@@ -242,12 +229,6 @@ static inline void sysfs_notify(struct k
 {
 }
 
-static inline int sysfs_make_shadowed_dir(struct kobject *kobj,
-	void * (*follow_link)(struct dentry *, struct nameidata *))
-{
-	return 0;
-}
-
 static inline int __must_check sysfs_init(void)
 {
 	return 0;
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -46,11 +46,11 @@ static int populate_dir(struct kobject *
 	return error;
 }
 
-static int create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
+static int create_dir(struct kobject * kobj)
 {
 	int error = 0;
 	if (kobject_name(kobj)) {
-		error = sysfs_create_dir(kobj, shadow_parent);
+		error = sysfs_create_dir(kobj);
 		if (!error) {
 			if ((error = populate_dir(kobj)))
 				sysfs_remove_dir(kobj);
@@ -201,12 +201,11 @@ static void unlink(struct kobject * kobj
 }
 
 /**
- *	kobject_shadow_add - add an object to the hierarchy.
+ *	kobject_add - add an object to the hierarchy.
  *	@kobj:	object.
- *	@shadow_parent: sysfs directory to add to.
  */
 
-int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
+int kobject_add(struct kobject * kobj)
 {
 	int error = 0;
 	struct kobject * parent;
@@ -238,7 +237,7 @@ int kobject_shadow_add(struct kobject *k
 		kobj->parent = parent;
 	}
 
-	error = create_dir(kobj, shadow_parent);
+	error = create_dir(kobj);
 	if (error) {
 		/* unlink does the kobject_put() for us */
 		unlink(kobj);
@@ -260,16 +259,6 @@ int kobject_shadow_add(struct kobject *k
 }
 
 /**
- *	kobject_add - add an object to the hierarchy.
- *	@kobj:	object.
- */
-int kobject_add(struct kobject * kobj)
-{
-	return kobject_shadow_add(kobj, NULL);
-}
-
-
-/**
  *	kobject_register - initialize and add an object.
  *	@kobj:	object in question.
  */
@@ -382,7 +371,7 @@ int kobject_rename(struct kobject * kobj
 	/* Note : if we want to send the new name alone, not the full path,
 	 * we could probably use kobject_name(kobj); */
 
-	error = sysfs_rename_dir(kobj, kobj->parent->sd, new_name);
+	error = sysfs_rename_dir(kobj, new_name);
 
 	/* This function is mostly/only used for network interface.
 	 * Some hotplug package track interfaces by their name and
@@ -399,27 +388,6 @@ out:
 }
 
 /**
- *	kobject_rename - change the name of an object
- *	@kobj:	object in question.
- *	@new_parent: object's new parent
- *	@new_name: object's new name
- */
-
-int kobject_shadow_rename(struct kobject *kobj,
-			  struct sysfs_dirent *new_parent, const char *new_name)
-{
-	int error = 0;
-
-	kobj = kobject_get(kobj);
-	if (!kobj)
-		return -EINVAL;
-	error = sysfs_rename_dir(kobj, new_parent, new_name);
-	kobject_put(kobj);
-
-	return error;
-}
-
-/**
  *	kobject_move - move object to another parent
  *	@kobj:	object in question.
  *	@new_parent: object's new parent (can be NULL)


Patches currently in gregkh-2.6 which might be from greg-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org are

bad/pci-domain/pci-device-ensure-sysdata-initialised.patch
bad/pci-domain/pci-fix-the-x86-pci-domain-support-fix.patch
bad/relayfs/sysfs-update-relay-file-support-for-generic-relay-api.patch
bad/relayfs/relay-consolidate-relayfs-core-into-kernel-relay.c.patch
bad/relayfs/relay-relay-header-cleanup.patch
bad/relayfs/relayfs-remove-relayfs-in-favour-of-config_relay.patch
bad/relayfs/sysfs-add-__attr_relay-helper-for-relay-attributes.patch
bad/relayfs/sysfs-relay-channel-buffers-as-sysfs-attributes.patch
bad/usbip/usb-usbip-more-dead-code-fix.patch
bad/usbip/usb-usbip-build-fix.patch
bad/usbip/usb-usbip-warning-fixes.patch
bad/ndevfs.patch
bad/battery-class-driver.patch
bad/driver-model-convert-driver-model-to-mutexes.patch
bad/gpl_future-test.patch
bad/gregkh-debugfs_example.patch
bad/speakup-kconfig-fix.patch
bad/speakup-build-fix.patch
bad/pci-use-new-multi-phase-suspend-infrastructure.patch
bad/shot-accross-the-bow.patch
bad/no-more-non-gpl-modules.patch
bad/spi-device.patch
bad/ata_piix-multithread.patch
bad/uio-irq.patch
bad/pci-two-drivers-on-one-pci-device.patch
bad/pci-dynamic-id-cleanup.patch
bad/input-device.patch
bad/usb-stimulus.patch
driver/nozomi.patch
driver/kobject-put-kobject_actions-in-kobject.h.patch
driver/sysfs-implement-sysfs-manged-shadow-directory-support.patch
driver/sysfs-implement-sysfs_delete_link-and-sysfs_rename_link.patch
driver/sysfs-remove-first-pass-at-shadow-directory-support.patch
driver/driver-core-implement-shadow-directory-support-for-device-classes.patch
gregkh/gkh-version.patch
gregkh/sysfs-test.patch
gregkh/sysrq-u-laptop.patch
pci/pci_bridge-device.patch
pci/pci-piggy-bus.patch
pci/pci-move-prototypes-for-pci_bus_find_capability-to-include-linux-pci.h.patch
pci/pci-document-pci_iomap.patch
usb/usb-gotemp.patch
usb/kobject-put-kobject_actions-in-kobject.h.patch
usb/usb-add-the-concept-of-default-authorization-to-usb-hosts.patch
usb/usb-cleanup-usb_register_bus-and-hook-up-sysfs-group.patch
usb/usb-initialize-authorization-and-wusb-bits-in-usb-devices.patch
usb/usb-introduce-usb_device-authorization-bits.patch
usb/usb-usb_set_configuration-obeys-authorization.patch
usb/usb-usb.h-kernel-doc-additions.patch
HOWTO

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: patch driver-core-implement-shadow-directory-support-for-device-classes.patch added to gregkh-2.6 tree
       [not found]                                   ` <20070721063634.9337314458DB-j1pC+zEt+uWoYr4blSSd5g@public.gmane.org>
@ 2007-07-21 10:00                                     ` Eric W. Biederman
  0 siblings, 0 replies; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-21 10:00 UTC (permalink / raw)
  To: gregkh-l3A5Bk7waGM
  Cc: containers-qjLDD68F18O7TbgM5vRIOg, greg-U8xfFu+wG4EAvxtiuMwx3w,
	htejun-Re5JQEeQqe8AvxtiuMwx3w, hansendc-r/Jw6+rmf7HQT0dZR+AlfA

<gregkh-l3A5Bk7waGM@public.gmane.org> writes:

> This is a note to let you know that I've just added the patch titled
>
>      Subject: [PATCH 4/4] driver core: Implement shadow directory support for
> device classes.
>
> to my gregkh-2.6 tree.  Its filename is
>
>      driver-core-implement-shadow-directory-support-for-device-classes.patch
>
> This tree can be found at 
>     http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/

Hip hip hooray.  The patches finally apply!!!!


Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 1/4] sysfs: Remove first pass at shadow directory support
       [not found]                   ` <m14pk13svx.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-19  4:45                     ` [PATCH 2/4] sysfs: Implement sysfs manged " Eric W. Biederman
  2007-07-21  6:36                     ` patch sysfs-remove-first-pass-at-shadow-directory-support.patch added to gregkh-2.6 tree gregkh-l3A5Bk7waGM
@ 2007-07-22 18:35                     ` Tejun Heo
       [not found]                       ` <46A3A36F.9070904-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2 siblings, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-22 18:35 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Hello,

Hope my late review isn't too late.

Eric W. Biederman wrote:
> While shadow directories appear to be a good idea, the current scheme
> of controlling their creation and destruction outside of sysfs appears
> to be a locking and maintenance nightmare in the face of sysfs
> directories dynamically coming and going.

Yeah, shadow directory was a real PITA while restructuring sysfs.  I
tried hard to keep it working but, without test case and detailed
documentation, I'm pretty sure I broke something.

My feeling was that it was merged too early and implementation was too
tightly coupled with other more regular paths.  Anyways, glad shadow
dirs are getting some loving care.  If properly done, we should be able
to simplify sysfs_get_dentry(), removal logic and save a pointer in
sysfs_dirent.

> Which can now occur for
> directories containing network devices when CONFIG_SYSFS_DEPRECATED is
> not set.

Shadow directories were always pinned - both the shadowed one and
shadows.  Well, that was the theory at least.

> -int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
> -		     const char *new_name)
> +int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
>  {
> -	struct sysfs_dirent *sd = kobj->sd;
> -	struct dentry *new_parent = NULL;
> +	struct sysfs_dirent *sd;
> +	struct dentry *parent = NULL;
>  	struct dentry *old_dentry = NULL, *new_dentry = NULL;
> +	struct sysfs_dirent *parent_sd;
>  	const char *dup_name = NULL;
>  	int error;
>  
> +	if (!kobj->parent)
> +		return -EINVAL;

Please don't do this.  The goal is to decouple sysfs and kobj.

>  	/* get dentries */
> +	sd = kobj->sd;
>  	old_dentry = sysfs_get_dentry(sd);
>  	if (IS_ERR(old_dentry)) {
>  		error = PTR_ERR(old_dentry);
>  		goto out_dput;
>  	}
>  
> -	new_parent = sysfs_get_dentry(new_parent_sd);
> -	if (IS_ERR(new_parent)) {
> -		error = PTR_ERR(new_parent);
> +	parent_sd = kobj->parent->sd;
> +	parent = sysfs_get_dentry(parent_sd);
> +	if (IS_ERR(parent)) {
> +		error = PTR_ERR(parent);
>  		goto out_dput;

You can simply do parent = old_dentry->d_parent.  parent is guaranteed
to be there as long as we hold old_dentry.  In the original code,
new_parent needed to be looked because new_parent wasn't necessarily
old_dentry's parent.

> @@ -965,10 +957,10 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
>   out_drop:
>  	d_drop(new_dentry);
>   out_unlock:
> -	mutex_unlock(&new_parent->d_inode->i_mutex);
> +	mutex_unlock(&parent->d_inode->i_mutex);
>   out_dput:
>  	kfree(dup_name);
> -	dput(new_parent);
> +	dput(parent);

So, dput(parent) can go away too.

> diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
> index f318b73..4606f7c 100644
> --- a/fs/sysfs/group.c
> +++ b/fs/sysfs/group.c
> @@ -13,7 +13,6 @@
>  #include <linux/dcache.h>
>  #include <linux/namei.h>
>  #include <linux/err.h>
> -#include <linux/fs.h>
>  #include <asm/semaphore.h>
>  #include "sysfs.h"

Can you explain this one a bit?

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 1/4] sysfs: Remove first pass at shadow directory support
       [not found]                       ` <46A3A36F.9070904-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2007-07-22 19:17                         ` Eric W. Biederman
  0 siblings, 0 replies; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-22 19:17 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:

> Hello,
>
> Hope my late review isn't too late.
>
> Eric W. Biederman wrote:
>> While shadow directories appear to be a good idea, the current scheme
>> of controlling their creation and destruction outside of sysfs appears
>> to be a locking and maintenance nightmare in the face of sysfs
>> directories dynamically coming and going.
>
> Yeah, shadow directory was a real PITA while restructuring sysfs.  I
> tried hard to keep it working but, without test case and detailed
> documentation, I'm pretty sure I broke something.
>
> My feeling was that it was merged too early and implementation was too
> tightly coupled with other more regular paths.  

It's a problem because sysfs has this tendency especially before your
cleanups to be tightly coupled.

But yes the original implementation was probably factored at the wrong
level, not giving sysfs enough responsibility.  Which became apparent
when the single objects started living all over the sysfs tree.

> Anyways, glad shadow
> dirs are getting some loving care.  If properly done, we should be able
> to simplify sysfs_get_dentry(), removal logic and save a pointer in
> sysfs_dirent.

Hopefully.  The logic in sysfs_resolve_for_create (i.e. which shadow
dir do you intend to create something is tricky with the current locking
logic).

>> Which can now occur for
>> directories containing network devices when CONFIG_SYSFS_DEPRECATED is
>> not set.
>
> Shadow directories were always pinned - both the shadowed one and
> shadows.  Well, that was the theory at least.

Yes.  The difference I was referring to was:
/sys/class/net/  used to be the only directory I needed to shadow.

Now there is one net/ in each networking device and several other
little things.

>> -int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent
> *new_parent_sd,
>> -		     const char *new_name)
>> +int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
>>  {
>> -	struct sysfs_dirent *sd = kobj->sd;
>> -	struct dentry *new_parent = NULL;
>> +	struct sysfs_dirent *sd;
>> +	struct dentry *parent = NULL;
>>  	struct dentry *old_dentry = NULL, *new_dentry = NULL;
>> +	struct sysfs_dirent *parent_sd;
>>  	const char *dup_name = NULL;
>>  	int error;
>>  
>> +	if (!kobj->parent)
>> +		return -EINVAL;
>
> Please don't do this.  The goal is to decouple sysfs and kobj.

I have no problem moving that test back to a higher level.
My practical goal of this first patch was to remove the original
shadow dir work so I had a clean slate to start with.  I got
tired and perhaps didn't do as clean a break here as I could
have.

Do you mind an incremental patch to move the kobj->parent test?

As long as we don't break git-bisect support I would really prefer
to just build on top of the patches that are there.

It has been a major hair pulling exercise to get everything to get
everything to work in the presence of other parallel changes in sysfs.
I only had to relearn the locking and organization rules 3 times.  I
really don't want to repeat it but I am happy to incrementally improve
things.

>>  	/* get dentries */
>> +	sd = kobj->sd;
>>  	old_dentry = sysfs_get_dentry(sd);
>>  	if (IS_ERR(old_dentry)) {
>>  		error = PTR_ERR(old_dentry);
>>  		goto out_dput;
>>  	}
>>  
>> -	new_parent = sysfs_get_dentry(new_parent_sd);
>> -	if (IS_ERR(new_parent)) {
>> -		error = PTR_ERR(new_parent);
>> +	parent_sd = kobj->parent->sd;
>> +	parent = sysfs_get_dentry(parent_sd);
>> +	if (IS_ERR(parent)) {
>> +		error = PTR_ERR(parent);
>>  		goto out_dput;
>
> You can simply do parent = old_dentry->d_parent.  parent is guaranteed
> to be there as long as we hold old_dentry.  In the original code,
> new_parent needed to be looked because new_parent wasn't necessarily
> old_dentry's parent.

Yes.  This part is probably the ugliest, and least well factored part
of this patchset. sysfs_rename_dir wasn't something I could completely
revert to it's pre shadow directory state as that was no longer
available.  What do you think of sysfs_rename_dir after the second patch in
the patchset?

I still think I have the limitation that new_parent and old_parent may
be separate. (Although clearly not at this point in the patch series).
I seem to remember trying to minimize the flux in sysfs_rename_dir and
eventually giving up.  Having found a path that seemed to be good enough.

>> @@ -965,10 +957,10 @@ int sysfs_rename_dir(struct kobject *kobj, struct
> sysfs_dirent *new_parent_sd,
>>   out_drop:
>>  	d_drop(new_dentry);
>>   out_unlock:
>> -	mutex_unlock(&new_parent->d_inode->i_mutex);
>> +	mutex_unlock(&parent->d_inode->i_mutex);
>>   out_dput:
>>  	kfree(dup_name);
>> -	dput(new_parent);
>> +	dput(parent);
>
> So, dput(parent) can go away too.

I actually managed to remove sysfs_get_dentry entirely from
sysfs_rename_dir and to use sysfs_addrm_start.

>> diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
>> index f318b73..4606f7c 100644
>> --- a/fs/sysfs/group.c
>> +++ b/fs/sysfs/group.c
>> @@ -13,7 +13,6 @@
>>  #include <linux/dcache.h>
>>  #include <linux/namei.h>
>>  #include <linux/err.h>
>> -#include <linux/fs.h>
>>  #include <asm/semaphore.h>
>>  #include "sysfs.h"
>
> Can you explain this one a bit?

This include was added by the original shadow directory support
and with it the original shadow directory support removed the include
became unnecessary.  I forget the exact details.

But so I could catch subtle things like that is why my patchset is
structured as first a removal pass and then the new stuff.

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                       ` <m1zm1t2e92.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-19  4:46                         ` [PATCH 3/4] sysfs: Implement sysfs_delete_link and sysfs_rename_link Eric W. Biederman
  2007-07-21  6:36                         ` patch sysfs-implement-sysfs-manged-shadow-directory-support.patch " gregkh-l3A5Bk7waGM
@ 2007-07-22 19:47                         ` Tejun Heo
       [not found]                           ` <46A3B449.3090409-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2 siblings, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-22 19:47 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Hello,

Eric W. Biederman wrote:
> diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
> +static struct sysfs_dirent *find_shadow_sd(struct sysfs_dirent
*parent_sd, const void *target)
> +{
> +	/* Find the shadow directory for the specified tag */
> +	struct sysfs_dirent *sd;
> +
> +	for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
> +		if (sd->s_name != target)
> +			continue;

This is way too cryptic and, plus, no comment.  This kind of stuff can
cause a lot of confusion later when other people wanna work on the
code.  Please move s_name into sysfs_elem_* which need s_name and
create sysfs_elem_shadow which doesn't have ->name but has ->tag.

> +static const void *find_shadow_tag(struct kobject *kobj)
> +{
> +	/* Find the tag the current kobj is cached with */
> +	return kobj->sd->s_parent->s_name;
> +}

Please don't use kobj inside sysfs.  Use sysfs_dirent instead.

> @@ -414,7 +436,8 @@ static void sysfs_attach_dentry(struct
sysfs_dirent *sd, struct dentry *dentry)
>  	sd->s_dentry = dentry;
>  	spin_unlock(&sysfs_assoc_lock);
>
> -	d_rehash(dentry);
> +	if (dentry->d_flags & DCACHE_UNHASHED)
> +		d_rehash(dentry);

I think we can use some comment for subtle things like this.
DCACHE_UNHASHED is being tested without holding dcache_lock which also
can use some comment.

> @@ -569,6 +592,10 @@ static void sysfs_drop_dentry(struct sysfs_dirent
*sd)
>  	spin_unlock(&dcache_lock);
>  	spin_unlock(&sysfs_assoc_lock);
>
> +	/* dentries for shadowed directories are pinned, unpin */
> +	if ((sysfs_type(sd) == SYSFS_SHADOW_DIR) ||
> +	    (sd->s_flags & SYSFS_FLAG_SHADOWED))
> +		dput(dentry);
>  	dput(dentry);
>
>  	/* adjust nlink and update timestamp */
> @@ -622,6 +649,7 @@ int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
>  		acxt->removed = sd->s_sibling;
>  		sd->s_sibling = NULL;
>
> +		sysfs_prune_shadow_sd(sd->s_parent);
>  		sysfs_drop_dentry(sd);
>  		sysfs_deactivate(sd);
>  		sysfs_put(sd);
> @@ -687,6 +715,7 @@ static int create_dir(struct kobject *kobj, struct
sysfs_dirent *parent_sd,
>  	umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
>  	struct sysfs_addrm_cxt acxt;
>  	struct sysfs_dirent *sd;
> +	int err;
>
>  	/* allocate */
>  	sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
> @@ -696,15 +725,21 @@ static int create_dir(struct kobject *kobj,
struct sysfs_dirent *parent_sd,
>
>  	/* link in */
>  	sysfs_addrm_start(&acxt, parent_sd);
> +	err = -ENOENT;
> +	if (!sysfs_resolve_for_create(kobj, &acxt.parent_sd))
> +		goto addrm_finish;
>
> -	if (!sysfs_find_dirent(parent_sd, name)) {
> +	err = -EEXIST;
> +	if (!sysfs_find_dirent(acxt.parent_sd, name)) {
>  		sysfs_add_one(&acxt, sd);
>  		sysfs_link_sibling(sd);
> +		err = 0;
>  	}
>
> +addrm_finish:
>  	if (!sysfs_addrm_finish(&acxt)) {
>  		sysfs_put(sd);
> -		return -EEXIST;
> +		return err;
>  	}
>
>  	*p_sd = sd;
> @@ -813,18 +848,56 @@ static struct dentry * sysfs_lookup(struct inode
*dir, struct dentry *dentry,
>  	return NULL;
>  }
>
> +static void *sysfs_shadow_follow_link(struct dentry *dentry, struct
nameidata *nd)
> +{
> +	struct sysfs_dirent *sd;
> +	struct dentry *dest;
> +
> +	sd = dentry->d_fsdata;
> +	dest = NULL;
> +	if (sd->s_flags & SYSFS_FLAG_SHADOWED) {

sd->s_flags should be protected by sysfs_mutex.  Please don't depend
on inode locking for synchronization internal to sysfs.

> +static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
> +{
> +	struct sysfs_addrm_cxt acxt;
> +
> +	if (!dir_sd)
> +		return;
> +
> +	pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
> +	sysfs_addrm_start(&acxt, dir_sd);
> +	if (sysfs_type(dir_sd) == SYSFS_DIR)
> +		sysfs_empty_dir(&acxt, dir_sd);
> +	else
> +		sysfs_remove_shadows(&acxt, dir_sd);

Care to explain this a bit?

>  	sysfs_addrm_finish(&acxt);
>
>  	remove_dir(dir_sd);
> @@ -882,86 +978,75 @@ void sysfs_remove_dir(struct kobject * kobj)
>
>  int sysfs_rename_dir(struct kobject * kobj, const char *new_name)

This rename modification is painful.  Please explain why we need to
rename nodes between shadows?  Can't we just create new ones?  Also,
please add some comment when performing black magic.

> @@ -1098,8 +1183,11 @@ static int sysfs_readdir(struct file * filp,
void * dirent, filldir_t filldir)
>  			i++;
>  			/* fallthrough */
>  		default:
> -			mutex_lock(&sysfs_mutex);
> +			/* If I am the shadow master return nothing. */
> +			if (parent_sd->s_flags & SYSFS_FLAG_SHADOWED)

s_flags protection?

> @@ -1188,3 +1276,185 @@ const struct file_operations
sysfs_dir_operations = {
>  	.read		= generic_read_dir,
>  	.readdir	= sysfs_readdir,
>  };
> +
> +
> +static void sysfs_prune_shadow_sd(struct sysfs_dirent *sd)

Please put this before sysfs_addrm_finish().  That's the only place
this function is used.

> +static struct sysfs_dirent *add_shadow_sd(struct sysfs_dirent
*parent_sd, const void *tag)
> +{
> +	struct sysfs_dirent *sd = NULL;
> +	struct dentry *dir, *shadow;
> +	struct inode *inode;
> +
> +	dir = parent_sd->s_dentry;
> +	inode = dir->d_inode;
> +
> +	shadow = d_alloc(dir->d_parent, &dir->d_name);
> +	if (!shadow)
> +		goto out;
> +
> +	/* Since the shadow directory is reachable make it look
> +	 * like it is actually hashed.
> +	 */
> +	shadow->d_hash.pprev = &shadow->d_hash.next;
> +	shadow->d_hash.next = NULL;
> +	shadow->d_flags &= ~DCACHE_UNHASHED;
> +
> +	sd = sysfs_new_dirent(tag, parent_sd->s_mode, SYSFS_SHADOW_DIR);
> +	if (!sd)
> +		goto error;
> +
> +	sd->s_elem.dir.kobj = parent_sd->s_elem.dir.kobj;
> +	sd->s_parent = sysfs_get(parent_sd);
> +
> +	/* Use the inode number of the parent we are shadowing */
> +	sysfs_free_ino(sd->s_ino);
> +	sd->s_ino = parent_sd->s_ino;
> +
> +	inc_nlink(inode);
> +	inc_nlink(dir->d_parent->d_inode);
> +
> +	sysfs_link_sibling(sd);
> +	__iget(inode);
> +	sysfs_instantiate(shadow, inode);
> +	sysfs_attach_dentry(sd, shadow);
> +out:
> +	return sd;
> +error:
> +	dput(shadow);
> +	goto out;
> +}

Can we just add sd here and resolve the rest the same way as other
nodes such that each shadow has its own dentry and inode?  Am I
missing something?  Also, why do we need the intermediate shadowed sd
at all?  Can't we do the following?

* non-shadowed case

 parent_sd - sd

* shadowed case

 parent_sd - sd0
	     sd1
	     sd2

I think we can reduce considerable special case handlings if we do
like the above including the implicit shadow creation, parent pruning
and symlink tricks.  After all, it's just multiple siblings sharing a
name which needs some extra context to look up the correct one.  We
wouldn't even need 'shadow' at all.

Sorry but I don't think the current approach is the correct one.  It's
too painful and too much complexity is scattered all over the place.
I'm afraid this implementation is going to be a maintenance nightmare.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                           ` <46A3B449.3090409-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2007-07-22 20:25                             ` Greg KH
       [not found]                               ` <20070722202508.GA18018-l3A5Bk7waGM@public.gmane.org>
  2007-07-22 22:07                             ` Eric W. Biederman
  1 sibling, 1 reply; 79+ messages in thread
From: Greg KH @ 2007-07-22 20:25 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Dave Hansen, Eric W. Biederman

On Mon, Jul 23, 2007 at 04:47:21AM +0900, Tejun Heo wrote:
> Sorry but I don't think the current approach is the correct one.  It's
> too painful and too much complexity is scattered all over the place.
> I'm afraid this implementation is going to be a maintenance nightmare.

In looking over this again, and due to the fact that there are no
in-kernel users of this code, I'm going to drop the other patches in
this series and only keep the first one that removes the current
implementation.

Eric, is that ok?  It gives you time to revisit these changes.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                           ` <46A3B449.3090409-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2007-07-22 20:25                             ` Greg KH
@ 2007-07-22 22:07                             ` Eric W. Biederman
  1 sibling, 0 replies; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-22 22:07 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:

> Hello,
>
> Eric W. Biederman wrote:
>> diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
>> +static struct sysfs_dirent *find_shadow_sd(struct sysfs_dirent
> *parent_sd, const void *target)
>> +{
>> +	/* Find the shadow directory for the specified tag */
>> +	struct sysfs_dirent *sd;
>> +
>> +	for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
>> +		if (sd->s_name != target)
>> +			continue;
>
> This is way too cryptic and, plus, no comment.  This kind of stuff can
> cause a lot of confusion later when other people wanna work on the
> code.  Please move s_name into sysfs_elem_* which need s_name and
> create sysfs_elem_shadow which doesn't have ->name but has ->tag.

I'm been staring at this to long to know.  I just know the name
is more or less reasonable and following how it is called tends
to show what it is used for.

In one sense the name is very much the tag.  So I don't feel
bad about using it that way.  In another sense if we can cleanup
the code by having the s_name field be a string that would
be an improvement and be appreciated.

>> +static const void *find_shadow_tag(struct kobject *kobj)
>> +{
>> +	/* Find the tag the current kobj is cached with */
>> +	return kobj->sd->s_parent->s_name;
>> +}
>
> Please don't use kobj inside sysfs.  Use sysfs_dirent instead.

The interface to sysfs is kobjects and names, so I'm limited
in what I can do.

Where this is used I know a directory and a name I want to
remove.  What I don't necessarily know is which shadow of that
directory I want to remove from without looking at the kobject.

sysfs_delete_link is a good code path to follow to understand
this.

>> @@ -414,7 +436,8 @@ static void sysfs_attach_dentry(struct
> sysfs_dirent *sd, struct dentry *dentry)
>>  	sd->s_dentry = dentry;
>>  	spin_unlock(&sysfs_assoc_lock);
>>
>> -	d_rehash(dentry);
>> +	if (dentry->d_flags & DCACHE_UNHASHED)
>> +		d_rehash(dentry);
>
> I think we can use some comment for subtle things like this.
> DCACHE_UNHASHED is being tested without holding dcache_lock which also
> can use some comment.

Basically this is a test to see if we have already been placed in
the dcache.  I'm trying to remember my reasoning 

>> @@ -569,6 +592,10 @@ static void sysfs_drop_dentry(struct sysfs_dirent
> *sd)
>>  	spin_unlock(&dcache_lock);
>>  	spin_unlock(&sysfs_assoc_lock);
>>
>> +	/* dentries for shadowed directories are pinned, unpin */
>> +	if ((sysfs_type(sd) == SYSFS_SHADOW_DIR) ||
>> +	    (sd->s_flags & SYSFS_FLAG_SHADOWED))
>> +		dput(dentry);
>>  	dput(dentry);
>>
>>  	/* adjust nlink and update timestamp */
>> @@ -622,6 +649,7 @@ int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
>>  		acxt->removed = sd->s_sibling;
>>  		sd->s_sibling = NULL;
>>
>> +		sysfs_prune_shadow_sd(sd->s_parent);
>>  		sysfs_drop_dentry(sd);
>>  		sysfs_deactivate(sd);
>>  		sysfs_put(sd);
>> @@ -687,6 +715,7 @@ static int create_dir(struct kobject *kobj, struct
> sysfs_dirent *parent_sd,
>>  	umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
>>  	struct sysfs_addrm_cxt acxt;
>>  	struct sysfs_dirent *sd;
>> +	int err;
>>
>>  	/* allocate */
>>  	sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
>> @@ -696,15 +725,21 @@ static int create_dir(struct kobject *kobj,
> struct sysfs_dirent *parent_sd,
>>
>>  	/* link in */
>>  	sysfs_addrm_start(&acxt, parent_sd);
>> +	err = -ENOENT;
>> +	if (!sysfs_resolve_for_create(kobj, &acxt.parent_sd))
>> +		goto addrm_finish;
>>
>> -	if (!sysfs_find_dirent(parent_sd, name)) {
>> +	err = -EEXIST;
>> +	if (!sysfs_find_dirent(acxt.parent_sd, name)) {
>>  		sysfs_add_one(&acxt, sd);
>>  		sysfs_link_sibling(sd);
>> +		err = 0;
>>  	}
>>
>> +addrm_finish:
>>  	if (!sysfs_addrm_finish(&acxt)) {
>>  		sysfs_put(sd);
>> -		return -EEXIST;
>> +		return err;
>>  	}
>>
>>  	*p_sd = sd;
>> @@ -813,18 +848,56 @@ static struct dentry * sysfs_lookup(struct inode
> *dir, struct dentry *dentry,
>>  	return NULL;
>>  }
>>
>> +static void *sysfs_shadow_follow_link(struct dentry *dentry, struct
> nameidata *nd)
>> +{
>> +	struct sysfs_dirent *sd;
>> +	struct dentry *dest;
>> +
>> +	sd = dentry->d_fsdata;
>> +	dest = NULL;
>> +	if (sd->s_flags & SYSFS_FLAG_SHADOWED) {
>
> sd->s_flags should be protected by sysfs_mutex.  Please don't depend
> on inode locking for synchronization internal to sysfs.

Basically this is a set once bit.  That is never expected to be cleared.
And is never expected to show up until it is set.  So that is minor.

I was hoping to avoid taking the sysfs_mutex for non-shadow directories
while always having the same code.

Whatever moving the sysfs_mutex up just a little bit in that function
is trivial if it is important.  As is potentially having two copies
of the directory operations.

>> +static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
>> +{
>> +	struct sysfs_addrm_cxt acxt;
>> +
>> +	if (!dir_sd)
>> +		return;
>> +
>> +	pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
>> +	sysfs_addrm_start(&acxt, dir_sd);
>> +	if (sysfs_type(dir_sd) == SYSFS_DIR)
>> +		sysfs_empty_dir(&acxt, dir_sd);
>> +	else
>> +		sysfs_remove_shadows(&acxt, dir_sd);
>
> Care to explain this a bit?

Hmm.  It looks like in all of the thrashing of sysfs I got my
tested goofed up.  It should say:

	if (!(dir_sd->s_flags & SYSFS_FLAG_SHAODWED))
		sysfs_empty_dir(&acxt, dir_sd);
	else
		sysfs_remove_shadows(&acxt, dir_sd);

The logic is if this is an ordinary directory just empty it.
However if this directory has shadows empty each shadow.
Because we need to delete them all.

>>  	sysfs_addrm_finish(&acxt);
>>
>>  	remove_dir(dir_sd);
>> @@ -882,86 +978,75 @@ void sysfs_remove_dir(struct kobject * kobj)
>>
>>  int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
>
> This rename modification is painful.  Please explain why we need to
> rename nodes between shadows?  Can't we just create new ones?  Also,
> please add some comment when performing black magic.

Well the context is more in the changelog.  Although something in the
code might help.

Are you looking at just the diff or the applied patch?
It may just be that the diff looks horrible.  I don't see
deep black magic in there that needs an explicit comment.

Please look at sysfs_rename_dir.  While the shadow logic may be
overkill I think it would probably be worth moving rename dir in a
direction where we don't require the dentries to be in cache and
we can use sysfs_addrm_start in any event.

Which is the bulk of what I have done there.

>> @@ -1098,8 +1183,11 @@ static int sysfs_readdir(struct file * filp,
> void * dirent, filldir_t filldir)
>>  			i++;
>>  			/* fallthrough */
>>  		default:
>> -			mutex_lock(&sysfs_mutex);
>> +			/* If I am the shadow master return nothing. */
>> +			if (parent_sd->s_flags & SYSFS_FLAG_SHADOWED)
>
> s_flags protection?

sysfs_mutex?  And the set once property.
Basically the check here is just a sanity check and I don't
think we will ever get there.


>> @@ -1188,3 +1276,185 @@ const struct file_operations
> sysfs_dir_operations = {
>>  	.read		= generic_read_dir,
>>  	.readdir	= sysfs_readdir,
>>  };
>> +
>> +
>> +static void sysfs_prune_shadow_sd(struct sysfs_dirent *sd)
>
> Please put this before sysfs_addrm_finish().  That's the only place
> this function is used.

Sure.  I was also calling it in sysfs_move_dir but that case was
to much of a pain and I wasn't really using it so I removed it.

>> +static struct sysfs_dirent *add_shadow_sd(struct sysfs_dirent
> *parent_sd, const void *tag)
>> +{
>> +	struct sysfs_dirent *sd = NULL;
>> +	struct dentry *dir, *shadow;
>> +	struct inode *inode;
>> +
>> +	dir = parent_sd->s_dentry;
>> +	inode = dir->d_inode;
>> +
>> +	shadow = d_alloc(dir->d_parent, &dir->d_name);
>> +	if (!shadow)
>> +		goto out;
>> +
>> +	/* Since the shadow directory is reachable make it look
>> +	 * like it is actually hashed.
>> +	 */
>> +	shadow->d_hash.pprev = &shadow->d_hash.next;
>> +	shadow->d_hash.next = NULL;
>> +	shadow->d_flags &= ~DCACHE_UNHASHED;
>> +
>> +	sd = sysfs_new_dirent(tag, parent_sd->s_mode, SYSFS_SHADOW_DIR);
>> +	if (!sd)
>> +		goto error;
>> +
>> +	sd->s_elem.dir.kobj = parent_sd->s_elem.dir.kobj;
>> +	sd->s_parent = sysfs_get(parent_sd);
>> +
>> +	/* Use the inode number of the parent we are shadowing */
>> +	sysfs_free_ino(sd->s_ino);
>> +	sd->s_ino = parent_sd->s_ino;
>> +
>> +	inc_nlink(inode);
>> +	inc_nlink(dir->d_parent->d_inode);
>> +
>> +	sysfs_link_sibling(sd);
>> +	__iget(inode);
>> +	sysfs_instantiate(shadow, inode);
>> +	sysfs_attach_dentry(sd, shadow);
>> +out:
>> +	return sd;
>> +error:
>> +	dput(shadow);
>> +	goto out;
>> +}
>
> Can we just add sd here and resolve the rest the same way as other
> nodes such that each shadow has its own dentry and inode?  Am I
> missing something?  Also, why do we need the intermediate shadowed sd
> at all?  Can't we do the following?

Sharing the struct inode means when we switch from one shadow to another
we keep the same inode lock.  Which means we can resolve which shadow we
are working with inside of sysfs_addrm_start, because we don't have to
drop and reacquire the locks.

I do the hashed but not in the dcache dentry so that I don't confuse
the VFS with multiple dentries of the same name as children on the same
dentry.  Currently they are locked in cache to simplify things.


>
> * non-shadowed case
>
>  parent_sd - sd
>
> * shadowed case
>
>  parent_sd - sd0
> 	     sd1
> 	     sd2
>
> I think we can reduce considerable special case handlings if we do
> like the above including the implicit shadow creation, parent pruning
> and symlink tricks.  After all, it's just multiple siblings sharing a
> name which needs some extra context to look up the correct one.  We
> wouldn't even need 'shadow' at all.

I disagree. Or at least I don't see what you are suggesting.
Currently I see sysfs_resolve_for_create and sysfs_resolve_for_remove 
(the implicit shadow directory creation/finding) as fundamental
complexity of the problem.  We may be able to simplify the
implementation of those to a small extent but I don't see those code
paths going away.

The big problem I have is I don't know which directories I will need
to shadow.  Currently on my test system I have:
/sys/class/net
/sys/devices/pci0000:00/0000:00:1c.5/0000:04:00.0/net
/sys/devices/virtual/net

But hotpluging a new pci device could add yet another directory.
So the only code which actually has a clue which directories
I need to handle is the sysfs/kobject layer I can't handle it
externally.  And adding to my fun my network namespaces (the tags)
are created and destroyed asynchronously to the devices coming
in and going.  That is why I have the implicit creation, because
I don't know what is happening.

So while I think changing how exactly I use sysfs_dirents may
simplify some things I don't see things getting much simpler.


Originally things worked out more nicely because we had the
dcache in the form you suggest and the sysfs_dirent tree in the
current form.  But we were always looking at the dcache when we
really cared.  So things were a little nicer and there were one
or two fewer special cases.  But the code was effectively the same.

Now things are a little worse because we don't use the dcache
tree for anything.  So getting the full path name has a special
case.


What do I have to deal with.
- readdir knows it can return the inode number.
- readdir needs to only return one entry for a shadow.

- When I move a network device between namespaces I need sysfs
  to follow.  In particular as I recall we have kobject attributes
  added by individual devices that I need to preserve.  Which
  strongly suggests doing something a rename to switch contexts
  is what is needed.

  So for the rename I need to get sd->parent_sd is the old directory.

  Now perhaps I should be calling something besides device_rename
  while I move a network device between namespaces and I should have a
  completely different code path.  But that doesn't feel correct to
  me.

- The dcache can only hold one entry with a given name so I need to
  use a magic follow_link to switch to the proper name.

- Implicit directory creation is essential because I don't know which
  directories I will be shadowing a priori.


> Sorry but I don't think the current approach is the correct one.  It's
> too painful and too much complexity is scattered all over the place.
> I'm afraid this implementation is going to be a maintenance
> nightmare.

Frankly.  The tightly coupled sysfs + kobject debacle of a user
interface adds a lot of complexity to maintaining a stable interface
to user space.  And if something should pay it should be the sysfs
code itself not the other pieces of the kernel that are stuck with
sysfs.  So I will happily argue that my interface to the upper levels
is correct or very close to it.  

At the same time. If we can find a way to do this with less complexity
in sysfs I'm all for it.  I just don't see it yet.

To some extent the ideal user space interface would be one where 
we have multiple different mounts of sysfs.  At mount time each
one calling shadow_ops->current_tag() and only displaying one tag
in that sysfs mount instance.  Given the current coupling of
everything that still looks noticeably harder to implement then what
I have done so far.

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                               ` <20070722202508.GA18018-l3A5Bk7waGM@public.gmane.org>
@ 2007-07-22 22:19                                 ` Eric W. Biederman
       [not found]                                   ` <m17iosw075.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-22 22:19 UTC (permalink / raw)
  To: Greg KH; +Cc: Linux Containers, Greg KH, Tejun Heo, Dave Hansen

Greg KH <gregkh-l3A5Bk7waGM@public.gmane.org> writes:

> On Mon, Jul 23, 2007 at 04:47:21AM +0900, Tejun Heo wrote:
>> Sorry but I don't think the current approach is the correct one.  It's
>> too painful and too much complexity is scattered all over the place.
>> I'm afraid this implementation is going to be a maintenance nightmare.
>
> In looking over this again, and due to the fact that there are no
> in-kernel users of this code, I'm going to drop the other patches in
> this series and only keep the first one that removes the current
> implementation.
>
> Eric, is that ok?  It gives you time to revisit these changes.

Greg a big part of the reason I don't have internal kernel users
is keeping up with changes of sysfs has meant I haven't had time
to clean up and submit the patches for the users.  With a little
luck I will have users by 2.6.24.  I am in the process of cleaning
up those patches right now.  So I can send the off to Dave Miller.

So please can we try and at least keep these sysfs patches in a
development tree so that people will see them.

Further while there are a few little nits I think mostly Tejun is 
mostly objecting to the fundamental complexity of the problem rather
then to things that can be fixed by a cleaner implementation.

If it didn't take me a week every time I had to update this code
after Tejun changes the locking rules in fs/sysfs/dir.c or if there
was someone I could delegate the work of maintaining this code to
I probably would not mind dropping the patches for a little bit.  As
it stands I am having horrible nightmares about how the internals
of sysfs will be completely different if you drop the last 3 patches
by the time I come back and I will need to spend several more weeks
just catching up.

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                   ` <m17iosw075.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-23  3:52                                     ` Tejun Heo
       [not found]                                       ` <46A425F9.1030008-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2007-07-26  8:00                                     ` Tejun Heo
  1 sibling, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-23  3:52 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> Further while there are a few little nits I think mostly Tejun is 
> mostly objecting to the fundamental complexity of the problem rather
> then to things that can be fixed by a cleaner implementation.

Oh well, I don't think so but I might be wrong.

> If it didn't take me a week every time I had to update this code
> after Tejun changes the locking rules in fs/sysfs/dir.c or if there
> was someone I could delegate the work of maintaining this code to
> I probably would not mind dropping the patches for a little bit.  As
> it stands I am having horrible nightmares about how the internals
> of sysfs will be completely different if you drop the last 3 patches
> by the time I come back and I will need to spend several more weeks
> just catching up.

Yeah, sysfs has gone through a lot of changes but I think most of
internal restructuring is complete now.  What's left is removing kobj
completely from sysfs internals and interface.

We kind of share the pain here although yours seems much worse than
mine.  Shadow directories have been major pain in the ass while
restructuring sysfs and I basically had to shoot in the dark because
there was no in-kernel user.  I guess the blame falls on the timing.

I'll give a shot at the no intermediate shadowed directory
implementation.  I think things will fit a lot easier that way but I
really dunno till I try.  I'll try to post prototype early.

As long as the current shadow implementation doesn't get into mainline.
 I'm okay with it staying in Greg's tree until this is resolved.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                       ` <46A425F9.1030008-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2007-07-24  7:26                                         ` Greg KH
  2007-07-30  7:09                                         ` Tejun Heo
  1 sibling, 0 replies; 79+ messages in thread
From: Greg KH @ 2007-07-24  7:26 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Dave Hansen, Eric W. Biederman

On Mon, Jul 23, 2007 at 12:52:25PM +0900, Tejun Heo wrote:
> Eric W. Biederman wrote:
> > Further while there are a few little nits I think mostly Tejun is 
> > mostly objecting to the fundamental complexity of the problem rather
> > then to things that can be fixed by a cleaner implementation.
> 
> Oh well, I don't think so but I might be wrong.
> 
> > If it didn't take me a week every time I had to update this code
> > after Tejun changes the locking rules in fs/sysfs/dir.c or if there
> > was someone I could delegate the work of maintaining this code to
> > I probably would not mind dropping the patches for a little bit.  As
> > it stands I am having horrible nightmares about how the internals
> > of sysfs will be completely different if you drop the last 3 patches
> > by the time I come back and I will need to spend several more weeks
> > just catching up.
> 
> Yeah, sysfs has gone through a lot of changes but I think most of
> internal restructuring is complete now.  What's left is removing kobj
> completely from sysfs internals and interface.
> 
> We kind of share the pain here although yours seems much worse than
> mine.  Shadow directories have been major pain in the ass while
> restructuring sysfs and I basically had to shoot in the dark because
> there was no in-kernel user.  I guess the blame falls on the timing.
> 
> I'll give a shot at the no intermediate shadowed directory
> implementation.  I think things will fit a lot easier that way but I
> really dunno till I try.  I'll try to post prototype early.
> 
> As long as the current shadow implementation doesn't get into mainline.
>  I'm okay with it staying in Greg's tree until this is resolved.

Don't worry, I will not be sending it on to Linus unless you give the ok
to do so :)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                   ` <m17iosw075.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-23  3:52                                     ` Tejun Heo
@ 2007-07-26  8:00                                     ` Tejun Heo
       [not found]                                       ` <46A85485.40502-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  1 sibling, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-26  8:00 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Dave Hansen

Hello,

Okay, some questions.

* What do you think about not allowing duplicate names across different
tags?  ie. there's only one ethX anywhere but it's visible only in a
specific namespace (and maybe in the default global one).  Or does
everyone need its own eth0.  If this is acceptable, the problem becomes
_much_ simpler.

* I think we can do away with the magic tag and use a pointer to
vfsmount instead.  So, a process which wants to be in certain namespace
can bind-mount /sysfs to its own /sysfs and make needed sysfs nodes
bound to the mount.  Does this sound okay?  Such process should probably
be in its own chrooted environment to function properly.

* I haven't really followed the containers thread.  Do people generally
agree on including it in mainline when we have all the fancy
virtualization stuff?

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [Devel] Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                       ` <46A85485.40502-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2007-07-27 10:58                                         ` Kirill Korotaev
  2007-07-27 20:59                                         ` Carl-Daniel Hailfinger
  2007-07-30 15:36                                         ` Eric W. Biederman
  2 siblings, 0 replies; 79+ messages in thread
From: Kirill Korotaev @ 2007-07-27 10:58 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Dave Hansen, Eric W. Biederman

Tejun Heo wrote:
> Hello,
> 
> Okay, some questions.
> 
> * What do you think about not allowing duplicate names across different
> tags?  ie. there's only one ethX anywhere but it's visible only in a
> specific namespace (and maybe in the default global one).  Or does
> everyone need its own eth0.  If this is acceptable, the problem becomes
> _much_ simpler.

at least on checkpoint/restart names should be restored as is
and conflicts are unavoidable.
this includes ifindex as well by the way.

> * I think we can do away with the magic tag and use a pointer to
> vfsmount instead.  So, a process which wants to be in certain namespace
> can bind-mount /sysfs to its own /sysfs and make needed sysfs nodes
> bound to the mount.  Does this sound okay?  Such process should probably
> be in its own chrooted environment to function properly.
> 
> * I haven't really followed the containers thread.  Do people generally
> agree on including it in mainline when we have all the fancy
> virtualization stuff?

Thanks,
Kirill

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                       ` <46A85485.40502-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2007-07-27 10:58                                         ` [Devel] " Kirill Korotaev
@ 2007-07-27 20:59                                         ` Carl-Daniel Hailfinger
  2007-07-30 15:36                                         ` Eric W. Biederman
  2 siblings, 0 replies; 79+ messages in thread
From: Carl-Daniel Hailfinger @ 2007-07-27 20:59 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Dave Hansen, Eric W. Biederman

Hi,

On 26.07.2007 10:00, Tejun Heo wrote:
> Okay, some questions.
> 
> * What do you think about not allowing duplicate names across different
> tags?  ie. there's only one ethX anywhere but it's visible only in a
> specific namespace (and maybe in the default global one).  Or does
> everyone need its own eth0.  If this is acceptable, the problem becomes
> _much_ simpler.

Duplicating names across different namespaces (eth0 for everyone) is a
feature which allows me to use a very similar configurations for
different namespaces.
There's also a security argument saying that one namespace shouldn't be
able to infer information about other namespaces. If an interface name
must not be reused across namespaces you can enumerate the obvious
interface name list from any namespace and find out which interface
names are used by other namespaces. I'm not suggesting that this
argument is valid, but it needs to be considered and if we decide it is
invalid, we should document why.

Regards,
Carl-Daniel

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                       ` <46A425F9.1030008-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2007-07-24  7:26                                         ` Greg KH
@ 2007-07-30  7:09                                         ` Tejun Heo
       [not found]                                           ` <46AD8E92.7080002-l3A5Bk7waGM@public.gmane.org>
  1 sibling, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-30  7:09 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Hello, Eric.

Tejun Heo wrote:
> Eric W. Biederman wrote:
>> Further while there are a few little nits I think mostly Tejun is 
>> mostly objecting to the fundamental complexity of the problem rather
>> then to things that can be fixed by a cleaner implementation.
> 
> Oh well, I don't think so but I might be wrong.

And I'm wrong.  Mine didn't turn out to be much cleaner than yours.
What I did was (still broken)...

* No shadower/shadowee.  Each dentry is tagged.
* dentries of tagged sd's are taken out of dcache and always go through
->lookup() where the correct sd is looked up considering the current tag.

Tagging and adding new entries could be done rather cleanly but shooting
down existing dentries on rename/move turned out to be a mess.  Things
will be much simpler if no sysfs dentry is hashed on dcache and always
go through ->lookup() but that will hurt big machines.

The basic problem here is that dcache layer doesn't allow different
views and sysfs shadow is trying to work behind its back.  I don't think
this is a viable approach.  Both implementations bend too many rules and
 are too fragile.  It will be a genuine pain in the ass to maintain.

Sorry that I can't come up with an alternative but NACK.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                           ` <46AD8E92.7080002-l3A5Bk7waGM@public.gmane.org>
@ 2007-07-30 12:41                                             ` Kirill Korotaev
       [not found]                                               ` <46ADDC7F.1090306-3ImXcnM4P+0@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Kirill Korotaev @ 2007-07-30 12:41 UTC (permalink / raw)
  To: Tejun Heo
  Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen, Eric W. Biederman

Tejun Heo wrote:
> Hello, Eric.
> 
> Tejun Heo wrote:
> 
>>Eric W. Biederman wrote:
>>
>>>Further while there are a few little nits I think mostly Tejun is 
>>>mostly objecting to the fundamental complexity of the problem rather
>>>then to things that can be fixed by a cleaner implementation.
>>
>>Oh well, I don't think so but I might be wrong.
> 
> 
> And I'm wrong.  Mine didn't turn out to be much cleaner than yours.
> What I did was (still broken)...
> 
> * No shadower/shadowee.  Each dentry is tagged.
> * dentries of tagged sd's are taken out of dcache and always go through
> ->lookup() where the correct sd is looked up considering the current tag.
> 
> Tagging and adding new entries could be done rather cleanly but shooting
> down existing dentries on rename/move turned out to be a mess.  Things
> will be much simpler if no sysfs dentry is hashed on dcache and always
> go through ->lookup() but that will hurt big machines.
> 
> The basic problem here is that dcache layer doesn't allow different
> views and sysfs shadow is trying to work behind its back.  I don't think
> this is a viable approach.  Both implementations bend too many rules and
>  are too fragile.  It will be a genuine pain in the ass to maintain.
> 
> Sorry that I can't come up with an alternative but NACK.

Imho then OpenOVZ approach with multiple sysfs trees is better.
it allows to use cached dentries with moultiple sysfs mounts
each having different view.
It also allows to hide hw-related entries and events from the containers
and has quite little modifications in the code.

Thanks,
Kirill

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                               ` <46ADDC7F.1090306-3ImXcnM4P+0@public.gmane.org>
@ 2007-07-30 13:06                                                 ` Tejun Heo
       [not found]                                                   ` <46ADE24E.8020502-l3A5Bk7waGM@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-30 13:06 UTC (permalink / raw)
  To: Kirill Korotaev
  Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen, Eric W. Biederman

Hello, Kirill.

Kirill Korotaev wrote:
> Imho then OpenOVZ approach with multiple sysfs trees is better.
> it allows to use cached dentries with moultiple sysfs mounts
> each having different view.
> It also allows to hide hw-related entries and events from the containers
> and has quite little modifications in the code.

I thought something like supermount plus some twists or fuse based sysfs
proxy would fit better.  Dunno whether or how uevent and polling stuff
can work that way tho.  Note that sysfs no longer keeps dentries and
inodes pinned.  It might make the shared dentry stuff harder.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                                   ` <46ADE24E.8020502-l3A5Bk7waGM@public.gmane.org>
@ 2007-07-30 13:57                                                     ` Kirill Korotaev
       [not found]                                                       ` <46ADEE35.8000109-3ImXcnM4P+0@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Kirill Korotaev @ 2007-07-30 13:57 UTC (permalink / raw)
  To: Tejun Heo
  Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen, Eric W. Biederman

Tejun Heo wrote:
> Hello, Kirill.
> 
> Kirill Korotaev wrote:
> 
>>Imho then OpenOVZ approach with multiple sysfs trees is better.
>>it allows to use cached dentries with moultiple sysfs mounts
>>each having different view.
>>It also allows to hide hw-related entries and events from the containers
>>and has quite little modifications in the code.
> 
> 
> I thought something like supermount plus some twists or fuse based sysfs
> proxy would fit better.  Dunno whether or how uevent and polling stuff
> can work that way tho.  Note that sysfs no longer keeps dentries and
> inodes pinned.  It might make the shared dentry stuff harder.

We simply don't share sysfs dentries/inodes between containers.
It's not that frequently used time critical fs to be super-optimized... :)
I don't like the idea with fuse, since sysfs exports kernel-related stuff,
so doing it via user-space would be pain.

Thanks,
Kirill

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                                       ` <46ADEE35.8000109-3ImXcnM4P+0@public.gmane.org>
@ 2007-07-30 14:04                                                         ` Tejun Heo
       [not found]                                                           ` <46ADF003.3010100-l3A5Bk7waGM@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-30 14:04 UTC (permalink / raw)
  To: Kirill Korotaev
  Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen, Eric W. Biederman

Kirill Korotaev wrote:
> Tejun Heo wrote:
>> I thought something like supermount plus some twists or fuse based sysfs
>> proxy would fit better.  Dunno whether or how uevent and polling stuff
>> can work that way tho.  Note that sysfs no longer keeps dentries and
>> inodes pinned.  It might make the shared dentry stuff harder.
> 
> We simply don't share sysfs dentries/inodes between containers.
> It's not that frequently used time critical fs to be super-optimized... :)

OIC, dentries and inodes are not shared.  Good then.  Agreed that sysfs
doesn't need to be super-optimized as long as big machines aren't
penalized too much (both memory and cpu cycle wise).

> I don't like the idea with fuse, since sysfs exports kernel-related stuff,
> so doing it via user-space would be pain.

Yeah, it would be cumbersome to setup but it's also fast and easy to toy
with for prototypes at least.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                       ` <46A85485.40502-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2007-07-27 10:58                                         ` [Devel] " Kirill Korotaev
  2007-07-27 20:59                                         ` Carl-Daniel Hailfinger
@ 2007-07-30 15:36                                         ` Eric W. Biederman
  2 siblings, 0 replies; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-30 15:36 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Dave Hansen

Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:

> Hello,
>
> Okay, some questions.
>
> * What do you think about not allowing duplicate names across different
> tags?  ie. there's only one ethX anywhere but it's visible only in a
> specific namespace (and maybe in the default global one).  Or does
> everyone need its own eth0.  If this is acceptable, the problem becomes
> _much_ simpler.

I agree, and unfortunately this is the problem I am really trying to solve.
Everyone namespace has it's own loopback interface.

> * I think we can do away with the magic tag and use a pointer to
> vfsmount instead.  So, a process which wants to be in certain namespace
> can bind-mount /sysfs to its own /sysfs and make needed sysfs nodes
> bound to the mount.  Does this sound okay?  Such process should probably
> be in its own chrooted environment to function properly.

That would actually be preferable.

> * I haven't really followed the containers thread.  Do people generally
> agree on including it in mainline when we have all the fancy
> virtualization stuff?

Generally.  Assuming all of the i's are dotted and all of the t's crossed.

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                                           ` <46ADF003.3010100-l3A5Bk7waGM@public.gmane.org>
@ 2007-07-30 15:51                                                             ` Eric W. Biederman
       [not found]                                                               ` <m1ps29vqin.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-30 15:51 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Tejun Heo <teheo-l3A5Bk7waGM@public.gmane.org> writes:

> Kirill Korotaev wrote:
>> Tejun Heo wrote:
>>> I thought something like supermount plus some twists or fuse based sysfs
>>> proxy would fit better.  Dunno whether or how uevent and polling stuff
>>> can work that way tho.  Note that sysfs no longer keeps dentries and
>>> inodes pinned.  It might make the shared dentry stuff harder.
>> 
>> We simply don't share sysfs dentries/inodes between containers.
>> It's not that frequently used time critical fs to be super-optimized... :)
>
> OIC, dentries and inodes are not shared.  Good then.  Agreed that sysfs
> doesn't need to be super-optimized as long as big machines aren't
> penalized too much (both memory and cpu cycle wise).
>
>> I don't like the idea with fuse, since sysfs exports kernel-related stuff,
>> so doing it via user-space would be pain.
>
> Yeah, it would be cumbersome to setup but it's also fast and easy to toy
> with for prototypes at least.

How close are we to the point where we can get mount sysfs multiple
times and get multiple dentry trees with different super blocks?

That really does sound like the right way to go.  Especially as it
simplifies the monitoring of containers.  If you want to watch what
the view looks like in some container your bind mount his sysfs and
look at that.

If we can do that the dcache side at least will be beautiful.  And
with a little care we may be able to reduce the work to a special case
in lookup, some extra handling to mark directories as belonging only
to a certain mount of sysfs.

If we can find something that is stupid and simple I'm all for that.

To reach the no-kobj utopia we may also need a special device_migrate
that is a super set of device_rename (because sometimes we need to
rename devices when we move them between namespaces).

So are we close to having a sysfs that we can have multiple super
blocks for?

I'm on a sysctl tangent, but I should be able to look at that in
just a little bit.

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                                               ` <m1ps29vqin.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31  3:24                                                                 ` Eric W. Biederman
       [not found]                                                                   ` <m1k5shuugc.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31  3:51                                                                 ` [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support Tejun Heo
  1 sibling, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31  3:24 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


Ugh.  I need to step back and carefully define what I'm seeing but it
looks like the current sysfs locking is wrong.

I'm starting to find little inconsistencies all over the place
such as:

Which lock actually protects sd->s_children?
- It isn't sysfs_mutex.  (see sysfs_lookup)
- It isn't inode->i_mutex (we only get it if we happen to have the inode
  in core)

At first glance sysfs_assoc_lock looks just as bad.

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                                                   ` <m1k5shuugc.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31  3:41                                                                     ` Tejun Heo
       [not found]                                                                       ` <46AEAF79.6080404-l3A5Bk7waGM@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-31  3:41 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Hello,

Eric W. Biederman wrote:
> Ugh.  I need to step back and carefully define what I'm seeing but it
> looks like the current sysfs locking is wrong.
> 
> I'm starting to find little inconsistencies all over the place
> such as:
> 
> Which lock actually protects sd->s_children?
> - It isn't sysfs_mutex.  (see sysfs_lookup)
> - It isn't inode->i_mutex (we only get it if we happen to have the inode
>   in core)

Yeah, I missed two places while converting to sysfs_mutex.
sysfs_lookup() and rename().  I'm about to post patch to fix it.

> At first glance sysfs_assoc_lock looks just as bad.

I think sysfs_assoc_lock is okay.  It's tricky tho.  Why do you think
it's bad?

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                                               ` <m1ps29vqin.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31  3:24                                                                 ` Eric W. Biederman
@ 2007-07-31  3:51                                                                 ` Tejun Heo
  1 sibling, 0 replies; 79+ messages in thread
From: Tejun Heo @ 2007-07-31  3:51 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Hello,

Eric W. Biederman wrote:
> How close are we to the point where we can get mount sysfs multiple
> times and get multiple dentry trees with different super blocks?

Yeah, that sounds much better.  We only have to pay attention to getting
sysfs_dirent tree correct.  The rest can be done by just looking up the
correct sysfs_dirent in sysfs_lookup().  We would still need to pin all
shadows to keep sysfs_get_dentry() working.

> That really does sound like the right way to go.  Especially as it
> simplifies the monitoring of containers.  If you want to watch what
> the view looks like in some container your bind mount his sysfs and
> look at that.
> 
> If we can do that the dcache side at least will be beautiful.  And
> with a little care we may be able to reduce the work to a special case
> in lookup, some extra handling to mark directories as belonging only
> to a certain mount of sysfs.
> 
> If we can find something that is stupid and simple I'm all for that.

Amen.

> To reach the no-kobj utopia we may also need a special device_migrate
> that is a super set of device_rename (because sometimes we need to
> rename devices when we move them between namespaces).

One thing I'm curious about is which semantic is appropriate behavior
when a node is migrated from one namespace to another - renaming or
deactivation followed by activation in new name space.  I guess it
doesn't really matter.

> So are we close to having a sysfs that we can have multiple super
> blocks for?

Sorry but I dunno.  It sounds much more appealing than other approaches tho.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                                                       ` <46AEAF79.6080404-l3A5Bk7waGM@public.gmane.org>
@ 2007-07-31  4:02                                                                         ` Eric W. Biederman
       [not found]                                                                           ` <m1fy35uso4.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31  4:02 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Tejun Heo <teheo-l3A5Bk7waGM@public.gmane.org> writes:

> Hello,
>
> Eric W. Biederman wrote:
>> Ugh.  I need to step back and carefully define what I'm seeing but it
>> looks like the current sysfs locking is wrong.
>> 
>> I'm starting to find little inconsistencies all over the place
>> such as:
>> 
>> Which lock actually protects sd->s_children?
>> - It isn't sysfs_mutex.  (see sysfs_lookup)
>> - It isn't inode->i_mutex (we only get it if we happen to have the inode
>>   in core)
>
> Yeah, I missed two places while converting to sysfs_mutex.
> sysfs_lookup() and rename().  I'm about to post patch to fix it.

Yes.  Make certain to get the name change under sysfs_mutex
while you are at it.

What do we use inode->i_mutex for?  I think we might be able
to kill that.

I'm starting to wonder if we can completely remove sysfs
from grabbing inode->i_mutex.

>> At first glance sysfs_assoc_lock looks just as bad.
>
> I think sysfs_assoc_lock is okay.  It's tricky tho.  Why do you think
> it's bad?

I'm still looking.  I just have a weird vibe so far.  sysfs_get_dentry
is really nasty with respect to locking.

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                                                           ` <m1fy35uso4.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31  4:28                                                                             ` Tejun Heo
       [not found]                                                                               ` <46AEBA87.6000400-l3A5Bk7waGM@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-31  4:28 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> What do we use inode->i_mutex for?  I think we might be able
> to kill that.
> 
> I'm starting to wonder if we can completely remove sysfs
> from grabbing inode->i_mutex.

i_mutex is grabbed when dentry and inode locking requires it.  It's not
used to protect sysfs internal data structure anymore.  I don't think we
can remove i_mutex grabbing without violating dentry/inode locking rules.

>>> At first glance sysfs_assoc_lock looks just as bad.
>> I think sysfs_assoc_lock is okay.  It's tricky tho.  Why do you think
>> it's bad?
> 
> I'm still looking.  I just have a weird vibe so far.  sysfs_get_dentry
> is really nasty with respect to locking.

Yes, sysfs_get_dentry() is pretty hairy.  I wish I could use
path_lookup() there but can't allocate memory for path name because
looking up must succeed when it's called from removal path if dentry
already exists.  Also, lookup_one_len_kern() bypasses security checks
and there's no equivalent path_lookup() like function which does that.

Locking rule aruond sysfs_assoc_lock is tricky.  It's mainly used to
avoid race condition between sysfs_d_iput() vs. dentry creation, node
removal, etc.  As long as sysfs_assoc_lock is held, sd->s_dentry can be
dereferenced but you also need dcache_lock to determine whether the
dentry is alive (dentry->d_inode != NULL) or in the process of being
killed.  There were two or three race conditions around dentry
reclamation in the past and several discussion threads about them.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                                                               ` <46AEBA87.6000400-l3A5Bk7waGM@public.gmane.org>
@ 2007-07-31  7:59                                                                                 ` Eric W. Biederman
       [not found]                                                                                   ` <m1bqdtt34l.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31  7:59 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Tejun Heo <teheo-l3A5Bk7waGM@public.gmane.org> writes:

> Eric W. Biederman wrote:
>> What do we use inode->i_mutex for?  I think we might be able
>> to kill that.
>> 
>> I'm starting to wonder if we can completely remove sysfs
>> from grabbing inode->i_mutex.
>
> i_mutex is grabbed when dentry and inode locking requires it.  It's not
> used to protect sysfs internal data structure anymore.  I don't think we
> can remove i_mutex grabbing without violating dentry/inode locking rules.

Not entirely no.  I think we can remove i_mutex from protecting dentry
tree modifications.

>>>> At first glance sysfs_assoc_lock looks just as bad.
>>> I think sysfs_assoc_lock is okay.  It's tricky tho.  Why do you think
>>> it's bad?
>> 
>> I'm still looking.  I just have a weird vibe so far.  sysfs_get_dentry
>> is really nasty with respect to locking.
>
> Yes, sysfs_get_dentry() is pretty hairy.  I wish I could use
> path_lookup() there but can't allocate memory for path name because
> looking up must succeed when it's called from removal path if dentry
> already exists.  Also, lookup_one_len_kern() bypasses security checks
> and there's no equivalent path_lookup() like function which does that.

We can use d_hash_and_lookup and that helps a lot.  I have attached
my in-progress rewrite of sysfs_get_dentry.  It's a little less
efficient but a whole lot easier to maintain.

> Locking rule aruond sysfs_assoc_lock is tricky.  It's mainly used to
> avoid race condition between sysfs_d_iput() vs. dentry creation, node
> removal, etc.  As long as sysfs_assoc_lock is held, sd->s_dentry can be
> dereferenced but you also need dcache_lock to determine whether the
> dentry is alive (dentry->d_inode != NULL) or in the process of being
> killed.  There were two or three race conditions around dentry
> reclamation in the past and several discussion threads about them.

I think I have figured out how to safely remove s_dentry entirely from
sysfs_dirent and that winds up removing a lot of subtle and nasty locking.
I'm hoping to have a good patch series after another couple of hours of
work.

struct dentry *__sysfs_get_dentry(struct sysfs_dirent *sd, int create)
{
	struct sysfs_dirent *cur;
	struct dentry *parent_dentry, *dentry;
	struct qstr name;
	struct inode *inode;

	parent_dentry = NULL;
	dentry = dget(sysfs_sb->s_root);

	do {
		/* Find the first ancestor I have not looked up */
		cur = sd;
		while (cur->s_parent != dentry->d_fsdata)
			cur = cur->s_parent;

		/* look it up */
		dput(parent_dentry);
		parent_dentry = dentry;
		name.name = cur->s_name;
		name.len = strlen(cur->s_name);
		dentry = d_hash_and_lookup(parent_dentry, &name);
		if (dentry)
			continue;
		if (!create)
			goto out;
		dentry = d_alloc(parent_dentry, &name);
		if (!dentry) {
			dentry = ERR_PTR(-ENOMEM);
			goto out;
		}
		inode = sysfs_get_inode(cur);
		if (!inode) {
			dput(dentry);
			dentry = ERR_PTR(-ENOMEM);
			goto out;
		}
		d_instantiate(dentry, inode);
		sysfs_attach_dentry(cur, dentry);
	} while (cur != sd);

out:	
	dput(parent_dentry);
	return dentry;
}

struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
{
	struct dentry *dentry;

	mutex_lock(&sysfs_mutex);
	dentry = __sysfs_get_dentry(sd, 1);
	mutex_unlock(&sysfs_mutex);
	return dentry;
}

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                                                                   ` <m1bqdtt34l.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31  8:14                                                                                     ` Tejun Heo
       [not found]                                                                                       ` <46AEEF75.2030101-l3A5Bk7waGM@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-31  8:14 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> I think I have figured out how to safely remove s_dentry entirely from
> sysfs_dirent and that winds up removing a lot of subtle and nasty locking.
> I'm hoping to have a good patch series after another couple of hours of
> work.

Great.  Yeah, open coding lookup seems much better idea than checking
whether tree changed while sysfs_mutex was releated.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support.
       [not found]                                                                                       ` <46AEEF75.2030101-l3A5Bk7waGM@public.gmane.org>
@ 2007-07-31  8:15                                                                                         ` Tejun Heo
       [not found]                                                                                           ` <46AEEFA6.4000901-l3A5Bk7waGM@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-31  8:15 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Tejun Heo wrote:
> Eric W. Biederman wrote:
>> I think I have figured out how to safely remove s_dentry entirely from
>> sysfs_dirent and that winds up removing a lot of subtle and nasty locking.
>> I'm hoping to have a good patch series after another couple of hours of
>> work.
> 
> Great.  Yeah, open coding lookup seems much better idea than checking
> whether tree changed while sysfs_mutex was releated.

s/related/released/

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* [PATCH 0/14] sysfs cleanups
       [not found]                                                                                           ` <46AEEFA6.4000901-l3A5Bk7waGM@public.gmane.org>
@ 2007-07-31 10:16                                                                                             ` Eric W. Biederman
       [not found]                                                                                               ` <m14pjkubd2.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:16 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


Ok.  I don't know how alert I am at the moment (it's way past my bed
time) but I have been digging in and cleaning up sysfs.  I'm not quite
to the point of supporting multiple mounts and shadow directories
again but the locking is looking much simpler and cleaner.  So with a
little luck this will be a better base to build on.

If something looks horrible please holler.

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* [PATCH 01/14] sysfs: Remove first pass at shadow directory support
       [not found]                                                                                               ` <m14pjkubd2.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:18                                                                                                 ` Eric W. Biederman
       [not found]                                                                                                   ` <m1zm1cswp0.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:18 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


While shadow directories appear to be a good idea, the current scheme
of controlling their creation and destruction outside of sysfs appears
to be a locking and maintenance nightmare in the face of sysfs directories
dynamically coming and going.  Which can now occur for directories containing
network devices when CONFIG_SYSFS_DEPRECATED is not set.

This patch removes everything from the initial shadow directory support
that allowed the shadow directory creation to be controlled at a higher
level.  So except for a few bits of sysfs_rename_dir everything from
commit b592fcfe7f06c15ec11774b5be7ce0de3aa86e73 is now gone.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
I have sanitized my changes to sysfs_rename_dir since last time I posted
this patch.

 fs/sysfs/dir.c          |  155 ++--------------------------------------------
 fs/sysfs/group.c        |    1 -
 fs/sysfs/inode.c        |   10 ---
 fs/sysfs/mount.c        |    2 +-
 fs/sysfs/sysfs.h        |    6 --
 include/linux/kobject.h |    5 --
 include/linux/sysfs.h   |   27 +-------
 lib/kobject.c           |   44 ++------------
 8 files changed, 18 insertions(+), 232 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 048e605..40b9efe 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -569,9 +569,6 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd)
 	spin_unlock(&dcache_lock);
 	spin_unlock(&sysfs_assoc_lock);
 
-	/* dentries for shadowed inodes are pinned, unpin */
-	if (dentry && sysfs_is_shadowed_inode(dentry->d_inode))
-		dput(dentry);
 	dput(dentry);
 
 	/* adjust nlink and update timestamp */
@@ -723,19 +720,15 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name,
 /**
  *	sysfs_create_dir - create a directory for an object.
  *	@kobj:		object we're creating directory for. 
- *	@shadow_parent:	parent object.
  */
-int sysfs_create_dir(struct kobject *kobj,
-		     struct sysfs_dirent *shadow_parent_sd)
+int sysfs_create_dir(struct kobject * kobj)
 {
 	struct sysfs_dirent *parent_sd, *sd;
 	int error = 0;
 
 	BUG_ON(!kobj);
 
-	if (shadow_parent_sd)
-		parent_sd = shadow_parent_sd;
-	else if (kobj->parent)
+	if (kobj->parent)
 		parent_sd = kobj->parent->sd;
 	else if (sysfs_mount && sysfs_mount->mnt_sb)
 		parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
@@ -887,8 +880,7 @@ void sysfs_remove_dir(struct kobject * kobj)
 	__sysfs_remove_dir(sd);
 }
 
-int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
-		     const char *new_name)
+int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
 {
 	struct sysfs_dirent *sd = kobj->sd;
 	struct dentry *new_parent = NULL;
@@ -903,11 +895,7 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
 		goto out_dput;
 	}
 
-	new_parent = sysfs_get_dentry(new_parent_sd);
-	if (IS_ERR(new_parent)) {
-		error = PTR_ERR(new_parent);
-		goto out_dput;
-	}
+	new_parent = dget(old_dentry->d_parent);
 
 	/* lock new_parent and get dentry for new name */
 	mutex_lock(&new_parent->d_inode->i_mutex);
@@ -918,14 +906,8 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
 		goto out_unlock;
 	}
 
-	/* By allowing two different directories with the same
-	 * d_parent we allow this routine to move between different
-	 * shadows of the same directory
-	 */
 	error = -EINVAL;
-	if (old_dentry->d_parent->d_inode != new_parent->d_inode ||
-	    new_dentry->d_parent->d_inode != new_parent->d_inode ||
-	    old_dentry == new_dentry)
+	if (old_dentry == new_dentry)
 		goto out_unlock;
 
 	error = -EEXIST;
@@ -942,23 +924,15 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
 	if (error)
 		goto out_drop;
 
+	mutex_lock(&sysfs_mutex);
 	dup_name = sd->s_name;
 	sd->s_name = new_name;
+	mutex_unlock(&sysfs_mutex);
 
 	/* move under the new parent */
 	d_add(new_dentry, NULL);
 	d_move(sd->s_dentry, new_dentry);
 
-	mutex_lock(&sysfs_mutex);
-
-	sysfs_unlink_sibling(sd);
-	sysfs_get(new_parent_sd);
-	sysfs_put(sd->s_parent);
-	sd->s_parent = new_parent_sd;
-	sysfs_link_sibling(sd);
-
-	mutex_unlock(&sysfs_mutex);
-
 	error = 0;
 	goto out_unlock;
 
@@ -1189,121 +1163,6 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
 	return offset;
 }
 
-
-/**
- *	sysfs_make_shadowed_dir - Setup so a directory can be shadowed
- *	@kobj:	object we're creating shadow of.
- */
-
-int sysfs_make_shadowed_dir(struct kobject *kobj,
-	void * (*follow_link)(struct dentry *, struct nameidata *))
-{
-	struct dentry *dentry;
-	struct inode *inode;
-	struct inode_operations *i_op;
-
-	/* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */
-	dentry = sysfs_get_dentry(kobj->sd);
-	if (IS_ERR(dentry))
-		return PTR_ERR(dentry);
-
-	inode = dentry->d_inode;
-	if (inode->i_op != &sysfs_dir_inode_operations) {
-		dput(dentry);
-		return -EINVAL;
-	}
-
-	i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
-	if (!i_op)
-		return -ENOMEM;
-
-	memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op));
-	i_op->follow_link = follow_link;
-
-	/* Locking of inode->i_op?
-	 * Since setting i_op is a single word write and they
-	 * are atomic we should be ok here.
-	 */
-	inode->i_op = i_op;
-	return 0;
-}
-
-/**
- *	sysfs_create_shadow_dir - create a shadow directory for an object.
- *	@kobj:	object we're creating directory for.
- *
- *	sysfs_make_shadowed_dir must already have been called on this
- *	directory.
- */
-
-struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj)
-{
-	struct sysfs_dirent *parent_sd = kobj->sd->s_parent;
-	struct dentry *dir, *parent, *shadow;
-	struct inode *inode;
-	struct sysfs_dirent *sd;
-	struct sysfs_addrm_cxt acxt;
-
-	dir = sysfs_get_dentry(kobj->sd);
-	if (IS_ERR(dir)) {
-		sd = (void *)dir;
-		goto out;
-	}
-	parent = dir->d_parent;
-
-	inode = dir->d_inode;
-	sd = ERR_PTR(-EINVAL);
-	if (!sysfs_is_shadowed_inode(inode))
-		goto out_dput;
-
-	shadow = d_alloc(parent, &dir->d_name);
-	if (!shadow)
-		goto nomem;
-
-	sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR);
-	if (!sd)
-		goto nomem;
-	sd->s_elem.dir.kobj = kobj;
-
-	sysfs_addrm_start(&acxt, parent_sd);
-
-	/* add but don't link into children list */
-	sysfs_add_one(&acxt, sd);
-
-	/* attach and instantiate dentry */
-	sysfs_attach_dentry(sd, shadow);
-	d_instantiate(shadow, igrab(inode));
-	inc_nlink(inode);	/* tj: synchronization? */
-
-	sysfs_addrm_finish(&acxt);
-
-	dget(shadow);		/* Extra count - pin the dentry in core */
-
-	goto out_dput;
-
- nomem:
-	dput(shadow);
-	sd = ERR_PTR(-ENOMEM);
- out_dput:
-	dput(dir);
- out:
-	return sd;
-}
-
-/**
- *	sysfs_remove_shadow_dir - remove an object's directory.
- *	@shadow_sd: sysfs_dirent of shadow directory
- *
- *	The only thing special about this is that we remove any files in
- *	the directory before we remove the directory, and we've inlined
- *	what used to be sysfs_rmdir() below, instead of calling separately.
- */
-
-void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd)
-{
-	__sysfs_remove_dir(shadow_sd);
-}
-
 const struct file_operations sysfs_dir_operations = {
 	.open		= sysfs_dir_open,
 	.release	= sysfs_dir_close,
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index f318b73..4606f7c 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -13,7 +13,6 @@
 #include <linux/dcache.h>
 #include <linux/namei.h>
 #include <linux/err.h>
-#include <linux/fs.h>
 #include <asm/semaphore.h>
 #include "sysfs.h"
 
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 10d1b52..9671164 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -34,16 +34,6 @@ static const struct inode_operations sysfs_inode_operations ={
 	.setattr	= sysfs_setattr,
 };
 
-void sysfs_delete_inode(struct inode *inode)
-{
-	/* Free the shadowed directory inode operations */
-	if (sysfs_is_shadowed_inode(inode)) {
-		kfree(inode->i_op);
-		inode->i_op = NULL;
-	}
-	return generic_delete_inode(inode);
-}
-
 int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
 {
 	struct inode * inode = dentry->d_inode;
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index fbc7b65..0c016e1 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -21,7 +21,7 @@ struct kmem_cache *sysfs_dir_cachep;
 
 static const struct super_operations sysfs_ops = {
 	.statfs		= simple_statfs,
-	.drop_inode	= sysfs_delete_inode,
+	.drop_inode	= generic_delete_inode,
 };
 
 struct sysfs_dirent sysfs_root = {
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 6b8c8d7..b55e510 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -70,7 +70,6 @@ extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt,
 			     struct sysfs_dirent *sd);
 extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
 
-extern void sysfs_delete_inode(struct inode *inode);
 extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd);
 extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode);
 
@@ -121,8 +120,3 @@ static inline void sysfs_put(struct sysfs_dirent * sd)
 	if (sd && atomic_dec_and_test(&sd->s_count))
 		release_sysfs_dirent(sd);
 }
-
-static inline int sysfs_is_shadowed_inode(struct inode *inode)
-{
-	return S_ISDIR(inode->i_mode) && inode->i_op->follow_link;
-}
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index aa2fe22..7108a3e 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -80,14 +80,9 @@ extern void kobject_init(struct kobject *);
 extern void kobject_cleanup(struct kobject *);
 
 extern int __must_check kobject_add(struct kobject *);
-extern int __must_check kobject_shadow_add(struct kobject *kobj,
-					   struct sysfs_dirent *shadow_parent);
 extern void kobject_del(struct kobject *);
 
 extern int __must_check kobject_rename(struct kobject *, const char *new_name);
-extern int __must_check kobject_shadow_rename(struct kobject *kobj,
-					      struct sysfs_dirent *new_parent,
-					      const char *new_name);
 extern int __must_check kobject_move(struct kobject *, struct kobject *);
 
 extern int __must_check kobject_register(struct kobject *);
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index be8228e..c16e4c5 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -17,9 +17,6 @@
 
 struct kobject;
 struct module;
-struct nameidata;
-struct dentry;
-struct sysfs_dirent;
 
 /* FIXME
  * The *owner field is no longer used, but leave around
@@ -94,14 +91,13 @@ extern int sysfs_schedule_callback(struct kobject *kobj,
 		void (*func)(void *), void *data, struct module *owner);
 
 extern int __must_check
-sysfs_create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent_sd);
+sysfs_create_dir(struct kobject *);
 
 extern void
 sysfs_remove_dir(struct kobject *);
 
 extern int __must_check
-sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
-		 const char *new_name);
+sysfs_rename_dir(struct kobject *kobj, const char *new_name);
 
 extern int __must_check
 sysfs_move_dir(struct kobject *, struct kobject *);
@@ -138,12 +134,6 @@ void sysfs_remove_file_from_group(struct kobject *kobj,
 
 void sysfs_notify(struct kobject * k, char *dir, char *attr);
 
-
-extern int sysfs_make_shadowed_dir(struct kobject *kobj,
-	void * (*follow_link)(struct dentry *, struct nameidata *));
-extern struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj);
-extern void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd);
-
 extern int __must_check sysfs_init(void);
 
 #else /* CONFIG_SYSFS */
@@ -154,8 +144,7 @@ static inline int sysfs_schedule_callback(struct kobject *kobj,
 	return -ENOSYS;
 }
 
-static inline int sysfs_create_dir(struct kobject *kobj,
-				   struct sysfs_dirent *shadow_parent_sd)
+static inline int sysfs_create_dir(struct kobject * kobj)
 {
 	return 0;
 }
@@ -165,9 +154,7 @@ static inline void sysfs_remove_dir(struct kobject * k)
 	;
 }
 
-static inline int sysfs_rename_dir(struct kobject *kobj,
-				   struct sysfs_dirent *new_parent_sd,
-				   const char *new_name)
+static inline int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
 {
 	return 0;
 }
@@ -242,12 +229,6 @@ static inline void sysfs_notify(struct kobject * k, char *dir, char *attr)
 {
 }
 
-static inline int sysfs_make_shadowed_dir(struct kobject *kobj,
-	void * (*follow_link)(struct dentry *, struct nameidata *))
-{
-	return 0;
-}
-
 static inline int __must_check sysfs_init(void)
 {
 	return 0;
diff --git a/lib/kobject.c b/lib/kobject.c
index 4b08e0f..2fc9fc6 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -44,11 +44,11 @@ static int populate_dir(struct kobject * kobj)
 	return error;
 }
 
-static int create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
+static int create_dir(struct kobject * kobj)
 {
 	int error = 0;
 	if (kobject_name(kobj)) {
-		error = sysfs_create_dir(kobj, shadow_parent);
+		error = sysfs_create_dir(kobj);
 		if (!error) {
 			if ((error = populate_dir(kobj)))
 				sysfs_remove_dir(kobj);
@@ -157,12 +157,11 @@ static void unlink(struct kobject * kobj)
 }
 
 /**
- *	kobject_shadow_add - add an object to the hierarchy.
+ *	kobject_add - add an object to the hierarchy.
  *	@kobj:	object.
- *	@shadow_parent: sysfs directory to add to.
  */
 
-int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
+int kobject_add(struct kobject * kobj)
 {
 	int error = 0;
 	struct kobject * parent;
@@ -194,7 +193,7 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
 		kobj->parent = parent;
 	}
 
-	error = create_dir(kobj, shadow_parent);
+	error = create_dir(kobj);
 	if (error) {
 		/* unlink does the kobject_put() for us */
 		unlink(kobj);
@@ -216,16 +215,6 @@ int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
 }
 
 /**
- *	kobject_add - add an object to the hierarchy.
- *	@kobj:	object.
- */
-int kobject_add(struct kobject * kobj)
-{
-	return kobject_shadow_add(kobj, NULL);
-}
-
-
-/**
  *	kobject_register - initialize and add an object.
  *	@kobj:	object in question.
  */
@@ -338,7 +327,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name)
 	/* Note : if we want to send the new name alone, not the full path,
 	 * we could probably use kobject_name(kobj); */
 
-	error = sysfs_rename_dir(kobj, kobj->parent->sd, new_name);
+	error = sysfs_rename_dir(kobj, new_name);
 
 	/* This function is mostly/only used for network interface.
 	 * Some hotplug package track interfaces by their name and
@@ -355,27 +344,6 @@ out:
 }
 
 /**
- *	kobject_rename - change the name of an object
- *	@kobj:	object in question.
- *	@new_parent: object's new parent
- *	@new_name: object's new name
- */
-
-int kobject_shadow_rename(struct kobject *kobj,
-			  struct sysfs_dirent *new_parent, const char *new_name)
-{
-	int error = 0;
-
-	kobj = kobject_get(kobj);
-	if (!kobj)
-		return -EINVAL;
-	error = sysfs_rename_dir(kobj, new_parent, new_name);
-	kobject_put(kobj);
-
-	return error;
-}
-
-/**
  *	kobject_move - move object to another parent
  *	@kobj:	object in question.
  *	@new_parent: object's new parent (can be NULL)
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 02/14] sysfs: In sysfs_lookup protect s_parent with sysfs_mutex
       [not found]                                                                                                   ` <m1zm1cswp0.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:20                                                                                                     ` Eric W. Biederman
       [not found]                                                                                                       ` <m1vec0swmi.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:20 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


It turns out we have been being silly and have failed to
protect ourselves against races between sysfs_lookup
and operations that modify the sysfs directory like sysfs_readdir
and create_dir.

So this patch modifies sysfs_lookup to grab sysfs_mutex before
walking the parent->s_children list.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/sysfs/dir.c |   15 +++++++++------
 1 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 40b9efe..b27a38c 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -756,11 +756,13 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 				struct nameidata *nd)
 {
 	struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
+	struct dentry *result = NULL;
 	struct sysfs_dirent * sd;
 	struct bin_attribute *bin_attr;
 	struct inode *inode;
 	int found = 0;
 
+	mutex_lock(&sysfs_mutex);
 	for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
 		if (sysfs_type(sd) &&
 		    !strcmp(sd->s_name, dentry->d_name.name)) {
@@ -771,14 +773,14 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 
 	/* no such entry */
 	if (!found)
-		return NULL;
+		goto out;
 
 	/* attach dentry and inode */
 	inode = sysfs_get_inode(sd);
-	if (!inode)
-		return ERR_PTR(-ENOMEM);
-
-	mutex_lock(&sysfs_mutex);
+	if (!inode) {
+		result = ERR_PTR(-ENOMEM);
+		goto out;
+	}
 
 	if (inode->i_state & I_NEW) {
 		/* initialize inode according to type */
@@ -808,9 +810,10 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 	sysfs_instantiate(dentry, inode);
 	sysfs_attach_dentry(sd, dentry);
 
+out:
 	mutex_unlock(&sysfs_mutex);
 
-	return NULL;
+	return result;
 }
 
 const struct inode_operations sysfs_dir_inode_operations = {
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 03/14] sysfs: Move all of inode initialization into sysfs_init_inode
       [not found]                                                                                                       ` <m1vec0swmi.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:22                                                                                                         ` Eric W. Biederman
       [not found]                                                                                                           ` <m1r6moswhr.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:36                                                                                                         ` [PATCH 02/14] sysfs: In sysfs_lookup protect s_parent with sysfs_mutex Tejun Heo
  1 sibling, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:22 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


Besides being a good general cleanup the ultimate effect
of this patch is that sysfs_get_inode now gives you a
usable inode that doesn't need any further initialization
to be useful.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

---
 fs/sysfs/dir.c   |   37 -------------------------------------
 fs/sysfs/inode.c |   48 +++++++++++++++++++++++++++++++++++++++++++++---
 fs/sysfs/mount.c |    5 -----
 3 files changed, 45 insertions(+), 45 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index b27a38c..834ed74 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -741,24 +741,12 @@ int sysfs_create_dir(struct kobject * kobj)
 	return error;
 }
 
-static int sysfs_count_nlink(struct sysfs_dirent *sd)
-{
-	struct sysfs_dirent *child;
-	int nr = 0;
-
-	for (child = sd->s_children; child; child = child->s_sibling)
-		if (sysfs_type(child) == SYSFS_DIR)
-			nr++;
-	return nr + 2;
-}
-
 static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 				struct nameidata *nd)
 {
 	struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
 	struct dentry *result = NULL;
 	struct sysfs_dirent * sd;
-	struct bin_attribute *bin_attr;
 	struct inode *inode;
 	int found = 0;
 
@@ -782,31 +770,6 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 		goto out;
 	}
 
-	if (inode->i_state & I_NEW) {
-		/* initialize inode according to type */
-		switch (sysfs_type(sd)) {
-		case SYSFS_DIR:
-			inode->i_op = &sysfs_dir_inode_operations;
-			inode->i_fop = &sysfs_dir_operations;
-			inode->i_nlink = sysfs_count_nlink(sd);
-			break;
-		case SYSFS_KOBJ_ATTR:
-			inode->i_size = PAGE_SIZE;
-			inode->i_fop = &sysfs_file_operations;
-			break;
-		case SYSFS_KOBJ_BIN_ATTR:
-			bin_attr = sd->s_elem.bin_attr.bin_attr;
-			inode->i_size = bin_attr->size;
-			inode->i_fop = &bin_fops;
-			break;
-		case SYSFS_KOBJ_LINK:
-			inode->i_op = &sysfs_symlink_inode_operations;
-			break;
-		default:
-			BUG();
-		}
-	}
-
 	sysfs_instantiate(dentry, inode);
 	sysfs_attach_dentry(sd, dentry);
 
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 9671164..e832a5d 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -123,8 +123,22 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
  */
 static struct lock_class_key sysfs_inode_imutex_key;
 
+static int sysfs_count_nlink(struct sysfs_dirent *sd)
+{
+	struct sysfs_dirent *child;
+	int nr = 0;
+
+	for (child = sd->s_children; child; child = child->s_sibling)
+		if (sysfs_type(child) == SYSFS_DIR)
+			nr++;
+
+	return nr + 2;
+}
+
 static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
 {
+	struct bin_attribute *bin_attr;
+
 	inode->i_blocks = 0;
 	inode->i_mapping->a_ops = &sysfs_aops;
 	inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
@@ -140,6 +154,37 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
 		set_inode_attr(inode, sd->s_iattr);
 	} else
 		set_default_inode_attr(inode, sd->s_mode);
+
+
+	/* initialize inode according to type */
+	switch (sysfs_type(sd)) {
+	case SYSFS_ROOT:
+		inode->i_op = &sysfs_dir_inode_operations;
+		inode->i_fop = &sysfs_dir_operations;
+		inc_nlink(inode); /* directory, account for "." */
+		break;
+	case SYSFS_DIR:
+		inode->i_op = &sysfs_dir_inode_operations;
+		inode->i_fop = &sysfs_dir_operations;
+		inode->i_nlink = sysfs_count_nlink(sd);
+		break;
+	case SYSFS_KOBJ_ATTR:
+		inode->i_size = PAGE_SIZE;
+		inode->i_fop = &sysfs_file_operations;
+		break;
+	case SYSFS_KOBJ_BIN_ATTR:
+		bin_attr = sd->s_elem.bin_attr.bin_attr;
+		inode->i_size = bin_attr->size;
+		inode->i_fop = &bin_fops;
+		break;
+	case SYSFS_KOBJ_LINK:
+		inode->i_op = &sysfs_symlink_inode_operations;
+		break;
+	default:
+		BUG();
+	}
+
+	unlock_new_inode(inode);
 }
 
 /**
@@ -181,9 +226,6 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode)
 {
 	BUG_ON(!dentry || dentry->d_inode);
 
-	if (inode->i_state & I_NEW)
-		unlock_new_inode(inode);
-
 	d_instantiate(dentry, inode);
 }
 
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 0c016e1..919eaaf 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -50,11 +50,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
 		return -ENOMEM;
 	}
 
-	inode->i_op = &sysfs_dir_inode_operations;
-	inode->i_fop = &sysfs_dir_operations;
-	inc_nlink(inode); /* directory, account for "." */
-	unlock_new_inode(inode);
-
 	/* instantiate and link root dentry */
 	root = d_alloc_root(inode);
 	if (!root) {
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 04/14] sysfs: Remove unnecessary variable found from sysfs_lookup
       [not found]                                                                                                           ` <m1r6moswhr.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:24                                                                                                             ` Eric W. Biederman
       [not found]                                                                                                               ` <m1myxcswfr.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:43                                                                                                             ` [PATCH 03/14] sysfs: Move all of inode initialization into sysfs_init_inode Tejun Heo
  1 sibling, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:24 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


The subject says it all.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/sysfs/dir.c |    7 ++-----
 1 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 834ed74..8430633 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -748,19 +748,16 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 	struct dentry *result = NULL;
 	struct sysfs_dirent * sd;
 	struct inode *inode;
-	int found = 0;
 
 	mutex_lock(&sysfs_mutex);
 	for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
 		if (sysfs_type(sd) &&
-		    !strcmp(sd->s_name, dentry->d_name.name)) {
-			found = 1;
+		    !strcmp(sd->s_name, dentry->d_name.name))
 			break;
-		}
 	}
 
 	/* no such entry */
-	if (!found)
+	if (!sd)
 		goto out;
 
 	/* attach dentry and inode */
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 05/14] sysfs: Remove sysfs_instantiate
       [not found]                                                                                                               ` <m1myxcswfr.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:25                                                                                                                 ` Eric W. Biederman
       [not found]                                                                                                                   ` <m1ir80swdl.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:45                                                                                                                 ` [PATCH 04/14] sysfs: Remove unnecessary variable found from sysfs_lookup Tejun Heo
  1 sibling, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:25 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


Now that sysfs_get_inode is dropping the inode lock
we no longer have a need for sysfs_instantiate.  So
kill it and just use d_instantiate instead.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/sysfs/dir.c   |    2 +-
 fs/sysfs/inode.c |   17 -----------------
 fs/sysfs/sysfs.h |    1 -
 3 files changed, 1 insertions(+), 19 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 8430633..6933f36 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -767,7 +767,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 		goto out;
 	}
 
-	sysfs_instantiate(dentry, inode);
+	d_instantiate(dentry, inode);
 	sysfs_attach_dentry(sd, dentry);
 
 out:
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index e832a5d..f55d9da 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -212,23 +212,6 @@ struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
 	return inode;
 }
 
-/**
- *	sysfs_instantiate - instantiate dentry
- *	@dentry: dentry to be instantiated
- *	@inode: inode associated with @sd
- *
- *	Unlock @inode if locked and instantiate @dentry with @inode.
- *
- *	LOCKING:
- *	None.
- */
-void sysfs_instantiate(struct dentry *dentry, struct inode *inode)
-{
-	BUG_ON(!dentry || dentry->d_inode);
-
-	d_instantiate(dentry, inode);
-}
-
 int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
 {
 	struct sysfs_addrm_cxt acxt;
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index b55e510..3b4b989 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -71,7 +71,6 @@ extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt,
 extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
 
 extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd);
-extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode);
 
 extern void release_sysfs_dirent(struct sysfs_dirent * sd);
 extern struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                   ` <m1ir80swdl.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:27                                                                                                                     ` Eric W. Biederman
       [not found]                                                                                                                       ` <m1ejioswai.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:44                                                                                                                     ` [PATCH 05/14] sysfs: Remove sysfs_instantiate Tejun Heo
  1 sibling, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:27 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


Currently sysfs_get_dentry is very hairy and requires all kinds
of locking magic.  This patch rewrites sysfs_get_dentry to
not use the cached sd->s_dentry, and instead simply lookup
and create dcache entries.

This lays the foundation for removing s_dentry and the
current hairy sysfs_assoc_lock logic.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/sysfs/dir.c |  117 +++++++++++++++++++++++--------------------------------
 1 files changed, 49 insertions(+), 68 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 6933f36..f22d60c 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -20,6 +20,8 @@ spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED;
 static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED;
 static DEFINE_IDA(sysfs_ino_ida);
 
+static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry);
+
 /**
  *	sysfs_link_sibling - link sysfs_dirent into sibling list
  *	@sd: sysfs_dirent of interest
@@ -66,10 +68,10 @@ void sysfs_unlink_sibling(struct sysfs_dirent *sd)
  *	sysfs_get_dentry - get dentry for the given sysfs_dirent
  *	@sd: sysfs_dirent of interest
  *
- *	Get dentry for @sd.  Dentry is looked up if currently not
- *	present.  This function climbs sysfs_dirent tree till it
- *	reaches a sysfs_dirent with valid dentry attached and descends
- *	down from there looking up dentry for each step.
+ *	Get dentry for @sd.
+ *
+ *	This function descends the sysfs dentry tree from the root
+ *	populating it if necessary until it reaches the dentry for @sd.
  *
  *	LOCKING:
  *	Kernel thread context (may sleep)
@@ -77,85 +79,58 @@ void sysfs_unlink_sibling(struct sysfs_dirent *sd)
  *	RETURNS:
  *	Pointer to found dentry on success, ERR_PTR() value on error.
  */
-struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
+struct dentry *__sysfs_get_dentry(struct sysfs_dirent *sd, int create)
 {
 	struct sysfs_dirent *cur;
 	struct dentry *parent_dentry, *dentry;
-	int i, depth;
-
-	/* Find the first parent which has valid s_dentry and get the
-	 * dentry.
-	 */
-	mutex_lock(&sysfs_mutex);
- restart0:
-	spin_lock(&sysfs_assoc_lock);
- restart1:
-	spin_lock(&dcache_lock);
-
-	dentry = NULL;
-	depth = 0;
-	cur = sd;
-	while (!cur->s_dentry || !cur->s_dentry->d_inode) {
-		if (cur->s_flags & SYSFS_FLAG_REMOVED) {
-			dentry = ERR_PTR(-ENOENT);
-			depth = 0;
-			break;
-		}
-		cur = cur->s_parent;
-		depth++;
-	}
-	if (!IS_ERR(dentry))
-		dentry = dget_locked(cur->s_dentry);
+	struct qstr name;
+	struct inode *inode;
 
-	spin_unlock(&dcache_lock);
-	spin_unlock(&sysfs_assoc_lock);
+	parent_dentry = NULL;
+	dentry = dget(sysfs_sb->s_root);
 
-	/* from the found dentry, look up depth times */
-	while (depth--) {
-		/* find and get depth'th ancestor */
-		for (cur = sd, i = 0; cur && i < depth; i++)
+	do {
+		/* Find the first ancestor I have not looked up */
+		cur = sd;
+		while (cur->s_parent != dentry->d_fsdata)
 			cur = cur->s_parent;
 
-		/* This can happen if tree structure was modified due
-		 * to move/rename.  Restart.
-		 */
-		if (i != depth) {
-			dput(dentry);
-			goto restart0;
-		}
-
-		sysfs_get(cur);
-
-		mutex_unlock(&sysfs_mutex);
-
 		/* look it up */
-		parent_dentry = dentry;
-		dentry = lookup_one_len_kern(cur->s_name, parent_dentry,
-					     strlen(cur->s_name));
 		dput(parent_dentry);
-
-		if (IS_ERR(dentry)) {
-			sysfs_put(cur);
-			return dentry;
+		parent_dentry = dentry;
+		name.name = cur->s_name;
+		name.len = strlen(cur->s_name);
+		dentry = d_hash_and_lookup(parent_dentry, &name);
+		if (dentry)
+			continue;
+		if (!create)
+			goto out;
+		dentry = d_alloc(parent_dentry, &name);
+		if (!dentry) {
+			dentry = ERR_PTR(-ENOMEM);
+			goto out;
 		}
-
-		mutex_lock(&sysfs_mutex);
-		spin_lock(&sysfs_assoc_lock);
-
-		/* This, again, can happen if tree structure has
-		 * changed and we looked up the wrong thing.  Restart.
-		 */
-		if (cur->s_dentry != dentry) {
+		inode = sysfs_get_inode(cur);
+		if (!inode) {
 			dput(dentry);
-			sysfs_put(cur);
-			goto restart1;
+			dentry = ERR_PTR(-ENOMEM);
+			goto out;
 		}
+		d_instantiate(dentry, inode);
+		sysfs_attach_dentry(cur, dentry);
+	} while (cur != sd);
 
-		spin_unlock(&sysfs_assoc_lock);
+out:
+	dput(parent_dentry);
+	return dentry;
+}
 
-		sysfs_put(cur);
-	}
+struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
+{
+	struct dentry *dentry;
 
+	mutex_lock(&sysfs_mutex);
+	dentry = __sysfs_get_dentry(sd, 1);
 	mutex_unlock(&sysfs_mutex);
 	return dentry;
 }
@@ -750,6 +725,12 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 	struct inode *inode;
 
 	mutex_lock(&sysfs_mutex);
+
+	/* Guard against races with sysfs_get_dentry */
+	result = d_hash_and_lookup(dentry->d_parent, &dentry->d_name);
+	if (result)
+		goto out;
+
 	for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
 		if (sysfs_type(sd) &&
 		    !strcmp(sd->s_name, dentry->d_name.name))
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 07/14] vfs: Remove lookup_one_len_kern
       [not found]                                                                                                                       ` <m1ejioswai.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:28                                                                                                                         ` Eric W. Biederman
       [not found]                                                                                                                           ` <m1abtcsw8w.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:59                                                                                                                         ` [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry Tejun Heo
  1 sibling, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:28 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


Now that sysfs no longer uses lookup_one_len_kern the function has
no users so remove it from the kernel.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/namei.c            |   46 +++++++++++-----------------------------------
 include/linux/namei.h |    1 -
 2 files changed, 11 insertions(+), 36 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index a83160a..69d3304 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1273,7 +1273,12 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags,
 	return err;
 }
 
-static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry *base, struct nameidata *nd)
+/*
+ * Restricted form of lookup. Doesn't follow links, single-component only,
+ * needs parent already locked. Doesn't follow mounts.
+ * SMP-safe.
+ */
+static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd)
 {
 	struct dentry *dentry;
 	struct inode *inode;
@@ -1281,6 +1286,11 @@ static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry
 
 	inode = base->d_inode;
 
+	err = permission(inode, MAY_EXEC, nd);
+	dentry = ERR_PTR(err);
+	if (err)
+		goto out;
+
 	/*
 	 * See if the low-level filesystem might want
 	 * to use its own hash..
@@ -1308,29 +1318,6 @@ out:
 	return dentry;
 }
 
-/*
- * Restricted form of lookup. Doesn't follow links, single-component only,
- * needs parent already locked. Doesn't follow mounts.
- * SMP-safe.
- */
-static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd)
-{
-	struct dentry *dentry;
-	struct inode *inode;
-	int err;
-
-	inode = base->d_inode;
-
-	err = permission(inode, MAY_EXEC, nd);
-	dentry = ERR_PTR(err);
-	if (err)
-		goto out;
-
-	dentry = __lookup_hash_kern(name, base, nd);
-out:
-	return dentry;
-}
-
 static struct dentry *lookup_hash(struct nameidata *nd)
 {
 	return __lookup_hash(&nd->last, nd->dentry, nd);
@@ -1369,17 +1356,6 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
 	return __lookup_hash(&this, base, NULL);
 }
 
-struct dentry *lookup_one_len_kern(const char *name, struct dentry *base, int len)
-{
-	int err;
-	struct qstr this;
-
-	err = __lookup_one_len(name, &this, base, len);
-	if (err)
-		return ERR_PTR(err);
-	return __lookup_hash_kern(&this, base, NULL);
-}
-
 int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags,
 			    struct nameidata *nd)
 {
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 6c38efb..36e5690 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -82,7 +82,6 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);
 extern void release_open_intent(struct nameidata *);
 
 extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
-extern struct dentry *lookup_one_len_kern(const char *, struct dentry *, int);
 
 extern int follow_down(struct vfsmount **, struct dentry **);
 extern int follow_up(struct vfsmount **, struct dentry **);
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 08/14] sysfs: Perform renames under sysfs_mutex
       [not found]                                                                                                                           ` <m1abtcsw8w.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:29                                                                                                                             ` Eric W. Biederman
       [not found]                                                                                                                               ` <m16440sw6d.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:29 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


This modifies sysfs_rename_dir to use sysfs_addrm_start/sysfs_addrm_finish
making it more like the rest of the sysfs directory manipulation functions.

This moves the entire rename operation inside of sysfs_mutex removing
the need to grab i_mutex, and incidentally this kills one s_dentry use.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/sysfs/dir.c |   46 +++++++++++++++++-----------------------------
 1 files changed, 17 insertions(+), 29 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index f22d60c..8e614d3 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -827,7 +827,7 @@ void sysfs_remove_dir(struct kobject * kobj)
 int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
 {
 	struct sysfs_dirent *sd = kobj->sd;
-	struct dentry *new_parent = NULL;
+	struct sysfs_addrm_cxt acxt;
 	struct dentry *old_dentry = NULL, *new_dentry = NULL;
 	const char *dup_name = NULL;
 	int error;
@@ -836,59 +836,47 @@ int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
 	old_dentry = sysfs_get_dentry(sd);
 	if (IS_ERR(old_dentry)) {
 		error = PTR_ERR(old_dentry);
-		goto out_dput;
+		goto out;
 	}
 
-	new_parent = dget(old_dentry->d_parent);
-
-	/* lock new_parent and get dentry for new name */
-	mutex_lock(&new_parent->d_inode->i_mutex);
-
-	new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
-	if (IS_ERR(new_dentry)) {
-		error = PTR_ERR(new_dentry);
-		goto out_unlock;
-	}
+	sysfs_addrm_start(&acxt, sd->s_parent);
 
 	error = -EINVAL;
-	if (old_dentry == new_dentry)
-		goto out_unlock;
+	if (strcmp(new_name, sd->s_name) == 0)
+		goto addrm_finish;
 
 	error = -EEXIST;
-	if (new_dentry->d_inode)
-		goto out_unlock;
+	if (sysfs_find_dirent(acxt.parent_sd, new_name))
+		goto addrm_finish;
+
+	new_dentry = d_alloc_name(old_dentry->d_parent, new_name);
+	if (!new_dentry)
+		goto addrm_finish;
 
 	/* rename kobject and sysfs_dirent */
 	error = -ENOMEM;
 	new_name = dup_name = kstrdup(new_name, GFP_KERNEL);
 	if (!new_name)
-		goto out_drop;
+		goto addrm_finish;
 
 	error = kobject_set_name(kobj, "%s", new_name);
 	if (error)
-		goto out_drop;
+		goto addrm_finish;
 
-	mutex_lock(&sysfs_mutex);
 	dup_name = sd->s_name;
 	sd->s_name = new_name;
-	mutex_unlock(&sysfs_mutex);
 
 	/* move under the new parent */
 	d_add(new_dentry, NULL);
-	d_move(sd->s_dentry, new_dentry);
+	d_move(old_dentry, new_dentry);
 
 	error = 0;
-	goto out_unlock;
-
- out_drop:
-	d_drop(new_dentry);
- out_unlock:
-	mutex_unlock(&new_parent->d_inode->i_mutex);
- out_dput:
+addrm_finish:
+	sysfs_addrm_finish(&acxt);
 	kfree(dup_name);
-	dput(new_parent);
 	dput(old_dentry);
 	dput(new_dentry);
+out:
 	return error;
 }
 
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 09/14] sysfs: Move all of sysfs_move_dir under sysfs_mutex
       [not found]                                                                                                                               ` <m16440sw6d.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:33                                                                                                                                 ` Eric W. Biederman
       [not found]                                                                                                                                   ` <m11weosvzz.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 11:06                                                                                                                                 ` [PATCH 08/14] sysfs: Perform renames " Tejun Heo
  1 sibling, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:33 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


This patch modifies sysfs_move_dir to perform all of it's
operations under the sysfs_mutex.  By looking for conflicts
using sysfs_find_dirent we accidentally moving something
onto a name that already exists but just not in the dcache
right now.

Two s_dentry usages are killed.

And it has probably become unnecessary to grab i_mutex at
all but I'm not brave enough to do that just yet.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/sysfs/dir.c |   24 +++++++++++++-----------
 1 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 8e614d3..ed2e6f3 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -897,7 +897,7 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
 		error = PTR_ERR(old_dentry);
 		goto out_dput;
 	}
-	old_parent = sd->s_parent->s_dentry;
+	old_parent = old_dentry->d_parent;
 
 	new_parent = sysfs_get_dentry(new_parent_sd);
 	if (IS_ERR(new_parent)) {
@@ -915,29 +915,31 @@ again:
 		mutex_unlock(&old_parent->d_inode->i_mutex);
 		goto again;
 	}
+	mutex_lock(&sysfs_mutex);
 
-	new_dentry = lookup_one_len(kobj->name, new_parent, strlen(kobj->name));
-	if (IS_ERR(new_dentry)) {
-		error = PTR_ERR(new_dentry);
+	error = -EEXIST;
+	if (sysfs_find_dirent(new_parent_sd, kobj->name))
 		goto out_unlock;
-	} else
-		error = 0;
+
+	error = -ENOMEM;
+	new_dentry = d_alloc_name(new_parent, kobj->name);
+	if (!new_dentry)
+		goto out_unlock;
+
+	error = 0;
 	d_add(new_dentry, NULL);
-	d_move(sd->s_dentry, new_dentry);
+	d_move(old_dentry, new_dentry);
 	dput(new_dentry);
 
 	/* Remove from old parent's list and insert into new parent's list. */
-	mutex_lock(&sysfs_mutex);
-
 	sysfs_unlink_sibling(sd);
 	sysfs_get(new_parent_sd);
 	sysfs_put(sd->s_parent);
 	sd->s_parent = new_parent_sd;
 	sysfs_link_sibling(sd);
 
-	mutex_unlock(&sysfs_mutex);
-
  out_unlock:
+	mutex_unlock(&sysfs_mutex);
 	mutex_unlock(&new_parent->d_inode->i_mutex);
 	mutex_unlock(&old_parent->d_inode->i_mutex);
  out_dput:
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* Re: [PATCH 02/14] sysfs: In sysfs_lookup protect s_parent with sysfs_mutex
       [not found]                                                                                                       ` <m1vec0swmi.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:22                                                                                                         ` [PATCH 03/14] sysfs: Move all of inode initialization into sysfs_init_inode Eric W. Biederman
@ 2007-07-31 10:36                                                                                                         ` Tejun Heo
       [not found]                                                                                                           ` <46AF10B7.3070600-l3A5Bk7waGM@public.gmane.org>
  1 sibling, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 10:36 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> It turns out we have been being silly and have failed to
> protect ourselves against races between sysfs_lookup
> and operations that modify the sysfs directory like sysfs_readdir
> and create_dir.
> 
> So this patch modifies sysfs_lookup to grab sysfs_mutex before
> walking the parent->s_children list.

Updated portion of #01 and #02 are identical to the cleanup patches I
just posted.  :-)

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* [PATCH 10/14] sysfs: Rework sysfs_drop_dentry
       [not found]                                                                                                                                   ` <m11weosvzz.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:37                                                                                                                                     ` Eric W. Biederman
       [not found]                                                                                                                                       ` <m1wswgrh8x.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 11:09                                                                                                                                     ` [PATCH 09/14] sysfs: Move all of sysfs_move_dir under sysfs_mutex Tejun Heo
  1 sibling, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:37 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


This modifies sysfs_drop_dentry so it no longers needs the
sysfs_assoc_lock and it's assorted challenges. 

The principal idea is that __sysfs_get_dentry when not creating dentry
will return a dentry for the sysfs_dirent if there is one in the
dcache.   If we do get a dentry we can drop it and force it out
of the cache.

For good measure I am also calling shrink_dcache_parent which will
force all of the child dentries out of the dcache as well if it
is a directory.

This is essentially and adaption of proc_flush_task from procfs
to handle the similar problems of sysfs.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/sysfs/dir.c |   34 ++++++++++++----------------------
 1 files changed, 12 insertions(+), 22 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index ed2e6f3..f8de6fb 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -516,35 +516,25 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
  *	parent on entry to this function such that it can't be looked
  *	up anymore.
  *
- *	@sd->s_dentry which is protected with sysfs_assoc_lock points
- *	to the currently associated dentry but we're not holding a
- *	reference to it and racing with dput().  Grab dcache_lock and
- *	verify dentry before dropping it.  If @sd->s_dentry is NULL or
- *	dput() beats us, no need to bother.
+ *	We find the dentry for @sd by probing the dcache while holding
+ *	sysfs_mutex to keep it from changing until we are done.
  */
 static void sysfs_drop_dentry(struct sysfs_dirent *sd)
 {
 	struct dentry *dentry = NULL;
 	struct inode *inode;
 
-	/* We're not holding a reference to ->s_dentry dentry but the
-	 * field will stay valid as long as sysfs_assoc_lock is held.
-	 */
-	spin_lock(&sysfs_assoc_lock);
-	spin_lock(&dcache_lock);
-
-	/* drop dentry if it's there and dput() didn't kill it yet */
-	if (sd->s_dentry && sd->s_dentry->d_inode) {
-		dentry = dget_locked(sd->s_dentry);
-		spin_lock(&dentry->d_lock);
-		__d_drop(dentry);
-		spin_unlock(&dentry->d_lock);
+	/* Remove a dentry for a sd from the dcache if present */
+	mutex_lock(&sysfs_mutex);
+	dentry = __sysfs_get_dentry(sd, 0);
+	if (IS_ERR(dentry))
+		dentry = NULL;
+	if (dentry) {
+		shrink_dcache_parent(dentry);
+		d_drop(dentry);
+		dput(dentry);
 	}
-
-	spin_unlock(&dcache_lock);
-	spin_unlock(&sysfs_assoc_lock);
-
-	dput(dentry);
+	mutex_unlock(&sysfs_mutex);
 
 	/* adjust nlink and update timestamp */
 	inode = ilookup(sysfs_sb, sd->s_ino);
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 11/14] sysfs: Remove s_dentry form sysfs_dirent.
       [not found]                                                                                                                                       ` <m1wswgrh8x.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:39                                                                                                                                         ` Eric W. Biederman
       [not found]                                                                                                                                           ` <m1sl74rh6e.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 11:17                                                                                                                                         ` [PATCH 10/14] sysfs: Rework sysfs_drop_dentry Tejun Heo
  1 sibling, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:39 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


After the last round of refactoring nothing is really using
using s_dirent so remove it.  Which makes the code easier to work
with and follow.  And with a little luck makes it easier to
support multiple dentry trees for sysfs.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/sysfs/dir.c   |   26 +-------------------------
 fs/sysfs/mount.c |    1 -
 fs/sysfs/sysfs.h |    1 -
 3 files changed, 1 insertions(+), 27 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index f8de6fb..c17e601 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -310,22 +310,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
 {
 	struct sysfs_dirent * sd = dentry->d_fsdata;
 
-	if (sd) {
-		/* sd->s_dentry is protected with sysfs_assoc_lock.
-		 * This allows sysfs_drop_dentry() to dereference it.
-		 */
-		spin_lock(&sysfs_assoc_lock);
-
-		/* The dentry might have been deleted or another
-		 * lookup could have happened updating sd->s_dentry to
-		 * point the new dentry.  Ignore if it isn't pointing
-		 * to this dentry.
-		 */
-		if (sd->s_dentry == dentry)
-			sd->s_dentry = NULL;
-		spin_unlock(&sysfs_assoc_lock);
-		sysfs_put(sd);
-	}
+	sysfs_put(sd);
 	iput(inode);
 }
 
@@ -373,9 +358,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
  *	@sd: target sysfs_dirent
  *	@dentry: dentry to associate
  *
- *	Associate @sd with @dentry.  This is protected by
- *	sysfs_assoc_lock to avoid race with sysfs_d_iput().
- *
  *	LOCKING:
  *	mutex_lock(sysfs_mutex)
  */
@@ -383,12 +365,6 @@ static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry)
 {
 	dentry->d_op = &sysfs_dentry_ops;
 	dentry->d_fsdata = sysfs_get(sd);
-
-	/* protect sd->s_dentry against sysfs_d_iput */
-	spin_lock(&sysfs_assoc_lock);
-	sd->s_dentry = dentry;
-	spin_unlock(&sysfs_assoc_lock);
-
 	d_rehash(dentry);
 }
 
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 919eaaf..3f652be 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -57,7 +57,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
 		iput(inode);
 		return -ENOMEM;
 	}
-	sysfs_root.s_dentry = root;
 	root->d_fsdata = &sysfs_root;
 	sb->s_root = root;
 	return 0;
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 3b4b989..60af864 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -37,7 +37,6 @@ struct sysfs_dirent {
 	unsigned int		s_flags;
 	umode_t			s_mode;
 	ino_t			s_ino;
-	struct dentry		* s_dentry;
 	struct iattr		* s_iattr;
 	atomic_t		s_event;
 };
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 12/14] sysfs: Make sysfs_mount static
       [not found]                                                                                                                                           ` <m1sl74rh6e.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:40                                                                                                                                             ` Eric W. Biederman
       [not found]                                                                                                                                               ` <m1odhsrh46.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 11:18                                                                                                                                             ` [PATCH 11/14] sysfs: Remove s_dentry form sysfs_dirent Tejun Heo
  1 sibling, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:40 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


This patch modifies the users of sysfs_mount to use sysfs_root instead
(which is what they are looking for).  It then makes sysfs_mount
static to keep people from using it by accident.

The net result is slightly faster and clearer code.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/sysfs/dir.c     |    4 +---
 fs/sysfs/mount.c   |    2 +-
 fs/sysfs/symlink.c |    7 +++----
 fs/sysfs/sysfs.h   |    1 -
 4 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index c17e601..1611cbd 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -671,10 +671,8 @@ int sysfs_create_dir(struct kobject * kobj)
 
 	if (kobj->parent)
 		parent_sd = kobj->parent->sd;
-	else if (sysfs_mount && sysfs_mount->mnt_sb)
-		parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
 	else
-		return -EFAULT;
+		parent_sd = &sysfs_root;
 
 	error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
 	if (!error)
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 3f652be..0ad731b 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -15,7 +15,7 @@
 /* Random magic number */
 #define SYSFS_MAGIC 0x62656572
 
-struct vfsmount *sysfs_mount;
+static struct vfsmount *sysfs_mount;
 struct super_block * sysfs_sb = NULL;
 struct kmem_cache *sysfs_dir_cachep;
 
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index 4ce687f..2b542dc 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -60,10 +60,9 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
 
 	BUG_ON(!name);
 
-	if (!kobj) {
-		if (sysfs_mount && sysfs_mount->mnt_sb)
-			parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
-	} else
+	if (!kobj)
+		parent_sd = &sysfs_root;
+	else
 		parent_sd = kobj->sd;
 
 	error = -EFAULT;
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 60af864..265a16a 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -50,7 +50,6 @@ struct sysfs_addrm_cxt {
 	int			cnt;
 };
 
-extern struct vfsmount * sysfs_mount;
 extern struct sysfs_dirent sysfs_root;
 extern struct kmem_cache *sysfs_dir_cachep;
 
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 13/14] sysfs: Simplify readdir.
       [not found]                                                                                                                                               ` <m1odhsrh46.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:42                                                                                                                                                 ` Eric W. Biederman
       [not found]                                                                                                                                                   ` <m1k5sgrh1h.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 11:19                                                                                                                                                 ` [PATCH 12/14] sysfs: Make sysfs_mount static Tejun Heo
  1 sibling, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:42 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


At some point someone wrote sysfs_readdir to insert a cursor
into the list of sysfs_dirents to ensure that sysfs_readdir would
restart properly.  That works but it is complex code and tends
to be expensive.

The same effect can be achived by keeping the sysfs_dirents in
inode order and using the inode number as the f_pos.  Then
when we restart we just have to find the first dirent whose inode
number is equal or greater then the last sysfs_dirent we attempted
to return.

Removing the sysfs directory cursor also allows the removal of
all of the mysterious checks for sysfs_type(sd) != 0.   Which
were nonbovious checks to see if a cursor was in a directory list.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/sysfs/dir.c   |  178 ++++++++++++++----------------------------------------
 fs/sysfs/inode.c |    2 -
 2 files changed, 45 insertions(+), 135 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 1611cbd..f9be856 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -35,10 +35,20 @@ static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry);
 void sysfs_link_sibling(struct sysfs_dirent *sd)
 {
 	struct sysfs_dirent *parent_sd = sd->s_parent;
+	struct sysfs_dirent **pos;
 
 	BUG_ON(sd->s_sibling);
-	sd->s_sibling = parent_sd->s_children;
-	parent_sd->s_children = sd;
+
+	/* Store directory entries in order by ino.  This allows
+	 * readdir to properly restart without having to add a
+	 * cursor into the s_children list.
+	 */
+	for (pos = &parent_sd->s_children; *pos; pos = &(*pos)->s_sibling) {
+		if (sd->s_ino < (*pos)->s_ino)
+			break;
+	}
+	sd->s_sibling = *pos;
+	*pos = sd;
 }
 
 /**
@@ -590,7 +600,7 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
 	struct sysfs_dirent *sd;
 
 	for (sd = parent_sd->s_children; sd; sd = sd->s_sibling)
-		if (sysfs_type(sd) && !strcmp(sd->s_name, name))
+		if (!strcmp(sd->s_name, name))
 			return sd;
 	return NULL;
 }
@@ -696,8 +706,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 		goto out;
 
 	for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
-		if (sysfs_type(sd) &&
-		    !strcmp(sd->s_name, dentry->d_name.name))
+		if (!strcmp(sd->s_name, dentry->d_name.name))
 			break;
 	}
 
@@ -756,7 +765,7 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
 	while (*pos) {
 		struct sysfs_dirent *sd = *pos;
 
-		if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) {
+		if (sysfs_type(sd) != SYSFS_DIR) {
 			*pos = sd->s_sibling;
 			sd->s_sibling = NULL;
 			sysfs_remove_one(&acxt, sd);
@@ -913,37 +922,6 @@ again:
 	return error;
 }
 
-static int sysfs_dir_open(struct inode *inode, struct file *file)
-{
-	struct dentry * dentry = file->f_path.dentry;
-	struct sysfs_dirent * parent_sd = dentry->d_fsdata;
-	struct sysfs_dirent * sd;
-
-	sd = sysfs_new_dirent("_DIR_", 0, 0);
-	if (sd) {
-		mutex_lock(&sysfs_mutex);
-		sd->s_parent = sysfs_get(parent_sd);
-		sysfs_link_sibling(sd);
-		mutex_unlock(&sysfs_mutex);
-	}
-
-	file->private_data = sd;
-	return sd ? 0 : -ENOMEM;
-}
-
-static int sysfs_dir_close(struct inode *inode, struct file *file)
-{
-	struct sysfs_dirent * cursor = file->private_data;
-
-	mutex_lock(&sysfs_mutex);
-	sysfs_unlink_sibling(cursor);
-	mutex_unlock(&sysfs_mutex);
-
-	release_sysfs_dirent(cursor);
-
-	return 0;
-}
-
 /* Relationship between s_mode and the DT_xxx types */
 static inline unsigned char dt_type(struct sysfs_dirent *sd)
 {
@@ -954,117 +932,51 @@ 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 *cursor = filp->private_data;
-	struct sysfs_dirent **pos;
+	struct sysfs_dirent *pos;
 	ino_t ino;
-	int i = filp->f_pos;
 
-	switch (i) {
-		case 0:
-			ino = parent_sd->s_ino;
-			if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
-				break;
+	if (filp->f_pos == 0) {
+		ino = parent_sd->s_ino;
+		if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0)
 			filp->f_pos++;
-			i++;
-			/* fallthrough */
-		case 1:
-			if (parent_sd->s_parent)
-				ino = parent_sd->s_parent->s_ino;
-			else
-				ino = parent_sd->s_ino;
-			if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
-				break;
+	}
+	if (filp->f_pos == 1) {
+		if (parent_sd->s_parent)
+			ino = parent_sd->s_parent->s_ino;
+		else
+			ino = parent_sd->s_ino;
+		if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0)
 			filp->f_pos++;
-			i++;
-			/* fallthrough */
-		default:
-			mutex_lock(&sysfs_mutex);
-
-			pos = &parent_sd->s_children;
-			while (*pos != cursor)
-				pos = &(*pos)->s_sibling;
-
-			/* unlink cursor */
-			*pos = cursor->s_sibling;
-
-			if (filp->f_pos == 2)
-				pos = &parent_sd->s_children;
-
-			for ( ; *pos; pos = &(*pos)->s_sibling) {
-				struct sysfs_dirent *next = *pos;
-				const char * name;
-				int len;
-
-				if (!sysfs_type(next))
-					continue;
-
-				name = next->s_name;
-				len = strlen(name);
-				ino = next->s_ino;
-
-				if (filldir(dirent, name, len, filp->f_pos, ino,
-						 dt_type(next)) < 0)
-					break;
-
-				filp->f_pos++;
-			}
+	}
+	if ((filp->f_pos > 1) && (filp->f_pos < UINT_MAX)) {
+		mutex_lock(&sysfs_mutex);
 
-			/* put cursor back in */
-			cursor->s_sibling = *pos;
-			*pos = cursor;
+		/* Skip the dentries we have already reported */
+		pos = parent_sd->s_children;
+		while (pos && (filp->f_pos > pos->s_ino))
+			pos = pos->s_sibling;
 
-			mutex_unlock(&sysfs_mutex);
-	}
-	return 0;
-}
+		for ( ; pos; pos = pos->s_sibling) {
+			const char * name;
+			int len;
 
-static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
-{
-	struct dentry * dentry = file->f_path.dentry;
+			name = pos->s_name;
+			len = strlen(name);
+			filp->f_pos = ino = pos->s_ino;
 
-	switch (origin) {
-		case 1:
-			offset += file->f_pos;
-		case 0:
-			if (offset >= 0)
+			if (filldir(dirent, name, len, filp->f_pos, ino,
+					 dt_type(pos)) < 0)
 				break;
-		default:
-			return -EINVAL;
-	}
-	if (offset != file->f_pos) {
-		mutex_lock(&sysfs_mutex);
-
-		file->f_pos = offset;
-		if (file->f_pos >= 2) {
-			struct sysfs_dirent *sd = dentry->d_fsdata;
-			struct sysfs_dirent *cursor = file->private_data;
-			struct sysfs_dirent **pos;
-			loff_t n = file->f_pos - 2;
-
-			sysfs_unlink_sibling(cursor);
-
-			pos = &sd->s_children;
-			while (n && *pos) {
-				struct sysfs_dirent *next = *pos;
-				if (sysfs_type(next))
-					n--;
-				pos = &(*pos)->s_sibling;
-			}
-
-			cursor->s_sibling = *pos;
-			*pos = cursor;
 		}
-
+		if (!pos)
+			filp->f_pos = UINT_MAX;
 		mutex_unlock(&sysfs_mutex);
 	}
-
-	return offset;
+	return 0;
 }
 
+
 const struct file_operations sysfs_dir_operations = {
-	.open		= sysfs_dir_open,
-	.release	= sysfs_dir_close,
-	.llseek		= sysfs_dir_lseek,
 	.read		= generic_read_dir,
 	.readdir	= sysfs_readdir,
 };
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index f55d9da..e212c69 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -225,8 +225,6 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
 	for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) {
 		sd = *pos;
 
-		if (!sysfs_type(sd))
-			continue;
 		if (!strcmp(sd->s_name, name)) {
 			*pos = sd->s_sibling;
 			sd->s_sibling = NULL;
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 14/14] sysfs: In sysfs_lookup don't open code sysfs_find_dirent
       [not found]                                                                                                                                                   ` <m1k5sgrh1h.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:42                                                                                                                                                     ` Eric W. Biederman
       [not found]                                                                                                                                                       ` <m1fy34rh08.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 11:36                                                                                                                                                     ` [PATCH 13/14] sysfs: Simplify readdir Tejun Heo
  1 sibling, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:42 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen


This is a small cleanup patch that makes the code just
a little bit cleaner.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/sysfs/dir.c |    5 +----
 1 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index f9be856..66d418a 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -705,10 +705,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 	if (result)
 		goto out;
 
-	for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
-		if (!strcmp(sd->s_name, dentry->d_name.name))
-			break;
-	}
+	sd = sysfs_find_dirent(parent_sd, dentry->d_name.name);
 
 	/* no such entry */
 	if (!sd)
-- 
1.5.1.1.181.g2de0

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* Re: [PATCH 03/14] sysfs: Move all of inode initialization into sysfs_init_inode
       [not found]                                                                                                           ` <m1r6moswhr.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:24                                                                                                             ` [PATCH 04/14] sysfs: Remove unnecessary variable found from sysfs_lookup Eric W. Biederman
@ 2007-07-31 10:43                                                                                                             ` Tejun Heo
  1 sibling, 0 replies; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 10:43 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> Besides being a good general cleanup the ultimate effect
> of this patch is that sysfs_get_inode now gives you a
> usable inode that doesn't need any further initialization
> to be useful.
> 
> Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

I generally like it.  The only nits are that I think we're better off
keeping the function in fs/sysfs/dir.c as all the interesting parts are
there anyway and sysfs_instantiate() can just die.  The function is just
a remnant of days where inode initialization was scattered all over the
place.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 05/14] sysfs: Remove sysfs_instantiate
       [not found]                                                                                                                   ` <m1ir80swdl.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:27                                                                                                                     ` [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry Eric W. Biederman
@ 2007-07-31 10:44                                                                                                                     ` Tejun Heo
  1 sibling, 0 replies; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 10:44 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> Now that sysfs_get_inode is dropping the inode lock
> we no longer have a need for sysfs_instantiate.  So
> kill it and just use d_instantiate instead.
> 
> Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Oh, here it is.  Forget the second nit in my previous comment.  Yeap,
this looks good.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 04/14] sysfs: Remove unnecessary variable found from sysfs_lookup
       [not found]                                                                                                               ` <m1myxcswfr.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:25                                                                                                                 ` [PATCH 05/14] sysfs: Remove sysfs_instantiate Eric W. Biederman
@ 2007-07-31 10:45                                                                                                                 ` Tejun Heo
  1 sibling, 0 replies; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 10:45 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> The subject says it all.
> 
> Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

I happen to have just posted the same patch.  :-)

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 02/14] sysfs: In sysfs_lookup protect s_parent with sysfs_mutex
       [not found]                                                                                                           ` <46AF10B7.3070600-l3A5Bk7waGM@public.gmane.org>
@ 2007-07-31 10:45                                                                                                             ` Eric W. Biederman
       [not found]                                                                                                               ` <m1bqdsrgvy.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 10:45 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Tejun Heo <teheo-l3A5Bk7waGM@public.gmane.org> writes:

> Eric W. Biederman wrote:
>> It turns out we have been being silly and have failed to
>> protect ourselves against races between sysfs_lookup
>> and operations that modify the sysfs directory like sysfs_readdir
>> and create_dir.
>> 
>> So this patch modifies sysfs_lookup to grab sysfs_mutex before
>> walking the parent->s_children list.
>
> Updated portion of #01 and #02 are identical to the cleanup patches I
> just posted.  :-)

I'm not surprised.  I will have to see what you have done after I have
slept.

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 02/14] sysfs: In sysfs_lookup protect s_parent with sysfs_mutex
       [not found]                                                                                                               ` <m1bqdsrgvy.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 10:47                                                                                                                 ` Tejun Heo
  0 siblings, 0 replies; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 10:47 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> Tejun Heo <teheo-l3A5Bk7waGM@public.gmane.org> writes:
> 
>> Eric W. Biederman wrote:
>>> It turns out we have been being silly and have failed to
>>> protect ourselves against races between sysfs_lookup
>>> and operations that modify the sysfs directory like sysfs_readdir
>>> and create_dir.
>>>
>>> So this patch modifies sysfs_lookup to grab sysfs_mutex before
>>> walking the parent->s_children list.
>> Updated portion of #01 and #02 are identical to the cleanup patches I
>> just posted.  :-)
> 
> I'm not surprised.  I will have to see what you have done after I have
> slept.

Good night.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                       ` <m1ejioswai.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:28                                                                                                                         ` [PATCH 07/14] vfs: Remove lookup_one_len_kern Eric W. Biederman
@ 2007-07-31 10:59                                                                                                                         ` Tejun Heo
       [not found]                                                                                                                           ` <46AF15F6.6010202-l3A5Bk7waGM@public.gmane.org>
  1 sibling, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 10:59 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> Currently sysfs_get_dentry is very hairy and requires all kinds
> of locking magic.  This patch rewrites sysfs_get_dentry to
> not use the cached sd->s_dentry, and instead simply lookup
> and create dcache entries.

I wanted to kill sd->s_dentry from the beginning.  The obstacle was
actually the shadow directory support, ironic.

> +	struct qstr name;
> +	struct inode *inode;
>  
> +	parent_dentry = NULL;
> +	dentry = dget(sysfs_sb->s_root);
>  
> +	do {
> +		/* Find the first ancestor I have not looked up */
> +		cur = sd;
> +		while (cur->s_parent != dentry->d_fsdata)
>  			cur = cur->s_parent;
>  
>  		/* look it up */
>  		dput(parent_dentry);

Shouldn't this be done after looking up the child?

> +		parent_dentry = dentry;
> +		name.name = cur->s_name;
> +		name.len = strlen(cur->s_name);
> +		dentry = d_hash_and_lookup(parent_dentry, &name);
> +		if (dentry)
> +			continue;
> +		if (!create)
> +			goto out;

Probably missing dentry = NULL?

> +		dentry = d_alloc(parent_dentry, &name);
> +		if (!dentry) {
> +			dentry = ERR_PTR(-ENOMEM);
> +			goto out;
>  		}
> +		inode = sysfs_get_inode(cur);
> +		if (!inode) {
>  			dput(dentry);
> +			dentry = ERR_PTR(-ENOMEM);
> +			goto out;
>  		}
> +		d_instantiate(dentry, inode);
> +		sysfs_attach_dentry(cur, dentry);
> +	} while (cur != sd);
>  
> +out:
> +	dput(parent_dentry);
> +	return dentry;
> +}
>  
> @@ -750,6 +725,12 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
>  	struct inode *inode;
>  
>  	mutex_lock(&sysfs_mutex);
> +
> +	/* Guard against races with sysfs_get_dentry */
> +	result = d_hash_and_lookup(dentry->d_parent, &dentry->d_name);
> +	if (result)
> +		goto out;
> +

Hmmm... This is tricky but probably better than the previous hairy
sysfs_get_dentry().  I think it would be worthwhile to comment about
creating dentry/inode behind vfs's back in __sysfs_get_dentry().

One thing I'm worried about is that dentry can now be looked up without
holding i_mutex.  In sysfs proper, there's no synchronization problem
but I'm not sure whether we're willing to cross that line set by vfs.
It might come back and bite our asses hard later.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 08/14] sysfs: Perform renames under sysfs_mutex
       [not found]                                                                                                                               ` <m16440sw6d.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:33                                                                                                                                 ` [PATCH 09/14] sysfs: Move all of sysfs_move_dir " Eric W. Biederman
@ 2007-07-31 11:06                                                                                                                                 ` Tejun Heo
       [not found]                                                                                                                                   ` <46AF17A1.2010203-l3A5Bk7waGM@public.gmane.org>
  1 sibling, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 11:06 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> This modifies sysfs_rename_dir to use sysfs_addrm_start/sysfs_addrm_finish
> making it more like the rest of the sysfs directory manipulation functions.
> 
> This moves the entire rename operation inside of sysfs_mutex removing
> the need to grab i_mutex, and incidentally this kills one s_dentry use.
> 
> Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Looks good.

Acked-by: Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 09/14] sysfs: Move all of sysfs_move_dir under sysfs_mutex
       [not found]                                                                                                                                   ` <m11weosvzz.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:37                                                                                                                                     ` [PATCH 10/14] sysfs: Rework sysfs_drop_dentry Eric W. Biederman
@ 2007-07-31 11:09                                                                                                                                     ` Tejun Heo
  1 sibling, 0 replies; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 11:09 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> This patch modifies sysfs_move_dir to perform all of it's
> operations under the sysfs_mutex.  By looking for conflicts
> using sysfs_find_dirent we accidentally moving something
> onto a name that already exists but just not in the dcache
> right now.
> 
> Two s_dentry usages are killed.
> 
> And it has probably become unnecessary to grab i_mutex at
> all but I'm not brave enough to do that just yet.
> 
> Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Acked-by: Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 08/14] sysfs: Perform renames under sysfs_mutex
       [not found]                                                                                                                                   ` <46AF17A1.2010203-l3A5Bk7waGM@public.gmane.org>
@ 2007-07-31 11:10                                                                                                                                     ` Tejun Heo
  0 siblings, 0 replies; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 11:10 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Tejun Heo wrote:
> Eric W. Biederman wrote:
>> This modifies sysfs_rename_dir to use sysfs_addrm_start/sysfs_addrm_finish
>> making it more like the rest of the sysfs directory manipulation functions.
>>
>> This moves the entire rename operation inside of sysfs_mutex removing
>> the need to grab i_mutex, and incidentally this kills one s_dentry use.
>>
>> Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
> 
> Looks good.
> 
> Acked-by: Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> 

Just one afterthought.  addrm_start/finish are basically used as wrapper
to lock both sysfs_mutex and i_mutex.  It might be better to just open
code them.  sysfs_move_dir() has to open code locking anyway and IMHO
it's better to keep rename and move look similar.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 10/14] sysfs: Rework sysfs_drop_dentry
       [not found]                                                                                                                                       ` <m1wswgrh8x.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:39                                                                                                                                         ` [PATCH 11/14] sysfs: Remove s_dentry form sysfs_dirent Eric W. Biederman
@ 2007-07-31 11:17                                                                                                                                         ` Tejun Heo
  1 sibling, 0 replies; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 11:17 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> This modifies sysfs_drop_dentry so it no longers needs the
> sysfs_assoc_lock and it's assorted challenges. 
> 
> The principal idea is that __sysfs_get_dentry when not creating dentry
> will return a dentry for the sysfs_dirent if there is one in the
> dcache.   If we do get a dentry we can drop it and force it out
> of the cache.
> 
> For good measure I am also calling shrink_dcache_parent which will
> force all of the child dentries out of the dcache as well if it
> is a directory.

I don't think we need this as we drop all sd's recursively anyway.  Can
we drop it?

Other than that, looks good.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 11/14] sysfs: Remove s_dentry form sysfs_dirent.
       [not found]                                                                                                                                           ` <m1sl74rh6e.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:40                                                                                                                                             ` [PATCH 12/14] sysfs: Make sysfs_mount static Eric W. Biederman
@ 2007-07-31 11:18                                                                                                                                             ` Tejun Heo
  1 sibling, 0 replies; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 11:18 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> After the last round of refactoring nothing is really using
> using s_dirent so remove it.  Which makes the code easier to work
> with and follow.  And with a little luck makes it easier to
> support multiple dentry trees for sysfs.
> 
> Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Hooray, Acked-by: Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 12/14] sysfs: Make sysfs_mount static
       [not found]                                                                                                                                               ` <m1odhsrh46.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:42                                                                                                                                                 ` [PATCH 13/14] sysfs: Simplify readdir Eric W. Biederman
@ 2007-07-31 11:19                                                                                                                                                 ` Tejun Heo
  1 sibling, 0 replies; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 11:19 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> This patch modifies the users of sysfs_mount to use sysfs_root instead
> (which is what they are looking for).  It then makes sysfs_mount
> static to keep people from using it by accident.
> 
> The net result is slightly faster and clearer code.
> 
> Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Acked-by: Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                           ` <46AF15F6.6010202-l3A5Bk7waGM@public.gmane.org>
@ 2007-07-31 11:23                                                                                                                             ` Eric W. Biederman
       [not found]                                                                                                                               ` <m11weorf3l.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 11:23 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Tejun Heo <teheo-l3A5Bk7waGM@public.gmane.org> writes:

> Eric W. Biederman wrote:
>> Currently sysfs_get_dentry is very hairy and requires all kinds
>> of locking magic.  This patch rewrites sysfs_get_dentry to
>> not use the cached sd->s_dentry, and instead simply lookup
>> and create dcache entries.
>
> I wanted to kill sd->s_dentry from the beginning.  The obstacle was
> actually the shadow directory support, ironic.
>
>> +	struct qstr name;
>> +	struct inode *inode;
>>  
>> +	parent_dentry = NULL;
>> +	dentry = dget(sysfs_sb->s_root);
>>  
>> +	do {
>> +		/* Find the first ancestor I have not looked up */
>> +		cur = sd;
>> +		while (cur->s_parent != dentry->d_fsdata)
>>  			cur = cur->s_parent;
>>  
>>  		/* look it up */
>>  		dput(parent_dentry);
>
> Shouldn't this be done after looking up the child?
Yes and that is what this is.  Delaying it a little longer
made the conditionals easier to write and verify for correctness.

>> +		parent_dentry = dentry;
>> +		name.name = cur->s_name;
>> +		name.len = strlen(cur->s_name);
>> +		dentry = d_hash_and_lookup(parent_dentry, &name);
>> +		if (dentry)
>> +			continue;
>> +		if (!create)
>> +			goto out;
>
> Probably missing dentry = NULL?
d_hash_and_lookup sets dentry, and we can't get here if (dentry != NULL)

>> +		dentry = d_alloc(parent_dentry, &name);
>> +		if (!dentry) {
>> +			dentry = ERR_PTR(-ENOMEM);
>> +			goto out;
>>  		}
>> +		inode = sysfs_get_inode(cur);
>> +		if (!inode) {
>>  			dput(dentry);
>> +			dentry = ERR_PTR(-ENOMEM);
>> +			goto out;
>>  		}
>> +		d_instantiate(dentry, inode);
>> +		sysfs_attach_dentry(cur, dentry);
>> +	} while (cur != sd);
>>  
>> +out:
>> +	dput(parent_dentry);
>> +	return dentry;
>> +}
>>  
>> @@ -750,6 +725,12 @@ static struct dentry * sysfs_lookup(struct inode *dir,
> struct dentry *dentry,
>>  	struct inode *inode;
>>  
>>  	mutex_lock(&sysfs_mutex);
>> +
>> +	/* Guard against races with sysfs_get_dentry */
>> +	result = d_hash_and_lookup(dentry->d_parent, &dentry->d_name);
>> +	if (result)
>> +		goto out;
>> +
>
> Hmmm... This is tricky but probably better than the previous hairy
> sysfs_get_dentry().  I think it would be worthwhile to comment about
> creating dentry/inode behind vfs's back in __sysfs_get_dentry().

Yes. Good point.  That is sufficiently non-intuitive and non-obvious
to deserve a comment.

> One thing I'm worried about is that dentry can now be looked up without
> holding i_mutex.  In sysfs proper, there's no synchronization problem
> but I'm not sure whether we're willing to cross that line set by vfs.
> It might come back and bite our asses hard later.

It's a reasonable concern.  I'm wondering if there are any precedents
set by distributed filesystems.  Because in a sense that is what
we are.

As for crossing that line I don't know what to say it makes the
code a lot cleaner, and if we are merged into the kernel at
least it will be visible if someone rewrites the vfs.

If sysfs_mutex nested the other way things would be easier,
and we could grab all of the i_mutexes we wanted.  I wonder if we can
be annoying in sysfs_lookup and treat that as the lock inversion
case using mutex_trylock etc.  And have sysfs_mutex be on the
outside for the rest of the cases?

Anyway back to bed with me.  I've been dreaming up to many silly
ways to abuse the dcache...

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                               ` <m11weorf3l.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 11:34                                                                                                                                 ` Tejun Heo
       [not found]                                                                                                                                   ` <46AF1E57.3030209-l3A5Bk7waGM@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 11:34 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
>>> +	do {
>>> +		/* Find the first ancestor I have not looked up */
>>> +		cur = sd;
>>> +		while (cur->s_parent != dentry->d_fsdata)
>>>  			cur = cur->s_parent;
>>>  
>>>  		/* look it up */
>>>  		dput(parent_dentry);
>> Shouldn't this be done after looking up the child?
> Yes and that is what this is.  Delaying it a little longer
> made the conditionals easier to write and verify for correctness.

Right, missed the next line.

>>> +		parent_dentry = dentry;
>>> +		name.name = cur->s_name;
>>> +		name.len = strlen(cur->s_name);
>>> +		dentry = d_hash_and_lookup(parent_dentry, &name);
>>> +		if (dentry)
>>> +			continue;
>>> +		if (!create)
>>> +			goto out;
>> Probably missing dentry = NULL?
> d_hash_and_lookup sets dentry, and we can't get here if (dentry != NULL)

Yes.

>> One thing I'm worried about is that dentry can now be looked up without
>> holding i_mutex.  In sysfs proper, there's no synchronization problem
>> but I'm not sure whether we're willing to cross that line set by vfs.
>> It might come back and bite our asses hard later.
> 
> It's a reasonable concern.  I'm wondering if there are any precedents
> set by distributed filesystems.  Because in a sense that is what
> we are.

Yeah, that's the weird thing about sysfs.  sysfs interface acts as a
different access point to the filesystem making it virtually distributed.

> As for crossing that line I don't know what to say it makes the
> code a lot cleaner, and if we are merged into the kernel at
> least it will be visible if someone rewrites the vfs.
> 
> If sysfs_mutex nested the other way things would be easier,
> and we could grab all of the i_mutexes we wanted.  I wonder if we can
> be annoying in sysfs_lookup and treat that as the lock inversion
> case using mutex_trylock etc.  And have sysfs_mutex be on the
> outside for the rest of the cases?

The problem with treating sysfs_lookup as inversion case is that vfs
layer grabs i_mutex outside of sysfs_lookup.  Releasing i_mutex from
inside sysfs_lookup would be a hacky layering violation.

Then again, the clean up which can come from the new sysfs_looukp_dentry
is very significant.  I'll think about it a bit more.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 13/14] sysfs: Simplify readdir.
       [not found]                                                                                                                                                   ` <m1k5sgrh1h.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  2007-07-31 10:42                                                                                                                                                     ` [PATCH 14/14] sysfs: In sysfs_lookup don't open code sysfs_find_dirent Eric W. Biederman
@ 2007-07-31 11:36                                                                                                                                                     ` Tejun Heo
  1 sibling, 0 replies; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 11:36 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> At some point someone wrote sysfs_readdir to insert a cursor
> into the list of sysfs_dirents to ensure that sysfs_readdir would
> restart properly.  That works but it is complex code and tends
> to be expensive.
> 
> The same effect can be achived by keeping the sysfs_dirents in
> inode order and using the inode number as the f_pos.  Then
> when we restart we just have to find the first dirent whose inode
> number is equal or greater then the last sysfs_dirent we attempted
> to return.
> 
> Removing the sysfs directory cursor also allows the removal of
> all of the mysterious checks for sysfs_type(sd) != 0.   Which
> were nonbovious checks to see if a cursor was in a directory list.
> 
> Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Great, Acked-by: Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 14/14] sysfs: In sysfs_lookup don't open code sysfs_find_dirent
       [not found]                                                                                                                                                       ` <m1fy34rh08.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-07-31 11:38                                                                                                                                                         ` Tejun Heo
       [not found]                                                                                                                                                           ` <46AF1F28.3000101-l3A5Bk7waGM@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 11:38 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Eric W. Biederman wrote:
> This is a small cleanup patch that makes the code just
> a little bit cleaner.
> 
> Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Acked-by: Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

I think this series of patches need wider review than Linux Containers
mailing list.  Please cc LKML, cornelia.huck-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org and
stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz@public.gmane.org when posting the next round.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                                   ` <46AF1E57.3030209-l3A5Bk7waGM@public.gmane.org>
@ 2007-07-31 14:16                                                                                                                                     ` Tejun Heo
       [not found]                                                                                                                                       ` <20070731141613.GC13674-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-07-31 14:16 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

On Tue, Jul 31, 2007 at 08:34:47PM +0900, Tejun Heo wrote:
> > If sysfs_mutex nested the other way things would be easier,
> > and we could grab all of the i_mutexes we wanted.  I wonder if we can
> > be annoying in sysfs_lookup and treat that as the lock inversion
> > case using mutex_trylock etc.  And have sysfs_mutex be on the
> > outside for the rest of the cases?
> 
> The problem with treating sysfs_lookup as inversion case is that vfs
> layer grabs i_mutex outside of sysfs_lookup.  Releasing i_mutex from
> inside sysfs_lookup would be a hacky layering violation.
> 
> Then again, the clean up which can come from the new sysfs_looukp_dentry
> is very significant.  I'll think about it a bit more.

How about something like this?  __sysfs_get_dentry() never creates any
dentry, it just looks up existing ones.  sysfs_get_dentry() calls
__sysfs_get_dentry() and if it fails, it builds a path string and look
up using regular vfs_path_lookup().  Once in the creation path,
sysfs_get_dentry() is allowed to fail, so allocating path buf is fine.

It still needs to retry when vfs_path_lookup() returns -ENOENT or the
wrong dentry but things are much simpler now.  It doesn't violate any
VFS locking rule while maintaining all the benefits of
sysfs_get_dentry() cleanup.

Something like LOOKUP_KERNEL is needed to ignore security checks;
otherwise, we'll need to resurrect lookup_one_len_kern() and open code
look up.

The patch is on top of all your patches and is in barely working form.

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 66d418a..0a6e036 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -81,20 +81,19 @@ void sysfs_unlink_sibling(struct sysfs_dirent *sd)
  *	Get dentry for @sd.
  *
  *	This function descends the sysfs dentry tree from the root
- *	populating it if necessary until it reaches the dentry for @sd.
+ *	until it reaches the dentry for @sd.
  *
  *	LOCKING:
- *	Kernel thread context (may sleep)
+ *	mutex_lock(sysfs_mutex)
  *
  *	RETURNS:
- *	Pointer to found dentry on success, ERR_PTR() value on error.
+ *	Pointer to found dentry on success, NULL if doesn't exist.
  */
-struct dentry *__sysfs_get_dentry(struct sysfs_dirent *sd, int create)
+struct dentry *__sysfs_get_dentry(struct sysfs_dirent *sd)
 {
 	struct sysfs_dirent *cur;
 	struct dentry *parent_dentry, *dentry;
 	struct qstr name;
-	struct inode *inode;
 
 	parent_dentry = NULL;
 	dentry = dget(sysfs_sb->s_root);
@@ -111,26 +110,8 @@ struct dentry *__sysfs_get_dentry(struct sysfs_dirent *sd, int create)
 		name.name = cur->s_name;
 		name.len = strlen(cur->s_name);
 		dentry = d_hash_and_lookup(parent_dentry, &name);
-		if (dentry)
-			continue;
-		if (!create)
-			goto out;
-		dentry = d_alloc(parent_dentry, &name);
-		if (!dentry) {
-			dentry = ERR_PTR(-ENOMEM);
-			goto out;
-		}
-		inode = sysfs_get_inode(cur);
-		if (!inode) {
-			dput(dentry);
-			dentry = ERR_PTR(-ENOMEM);
-			goto out;
-		}
-		d_instantiate(dentry, inode);
-		sysfs_attach_dentry(cur, dentry);
-	} while (cur != sd);
+	} while (dentry && cur != sd);
 
-out:
 	dput(parent_dentry);
 	return dentry;
 }
@@ -138,10 +119,52 @@ out:
 struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
 {
 	struct dentry *dentry;
+	struct nameidata nd;
+	char *path_buf;
+	int len, rc;
+	
+	mutex_lock(&sysfs_mutex);
+	dentry = __sysfs_get_dentry(sd);
+	mutex_unlock(&sysfs_mutex);
+
+	if (dentry)
+		return dentry;
+
+	/* Look up failed.  This means that the dentry associated with
+	 * @sd currently doesn't exist and we're allowed to fail.
+	 * Let's allocate path buffer and look up like a sane person.
+	 */
+	path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
+	if (!path_buf)
+		return ERR_PTR(-ENOMEM);
 
+ retry:
 	mutex_lock(&sysfs_mutex);
-	dentry = __sysfs_get_dentry(sd, 1);
+	/* XXX - clean up */
+	len = object_path_length(sd);
+	BUG_ON(len > PATH_MAX);
+	path_buf[len - 1] = '\0';
+	fill_object_path(sd, path_buf, len);
 	mutex_unlock(&sysfs_mutex);
+
+	/* XXX - we need a flag to override security check or need to
+	 * open code lookup.  The former is far better, IMHO.
+	 */
+	rc = vfs_path_lookup(sysfs_mount->mnt_root, sysfs_mount,
+			     path_buf + 1, 0, &nd);
+	dentry = nd.dentry;
+
+	/* renamed/moved beneath us? */
+	if (rc == -ENOENT)
+		goto retry;
+	if (rc == 0 && dentry->d_fsdata != sd) {
+		dput(dentry);
+		goto retry;
+	}
+	if (rc && rc != -ENOENT)
+		dentry = ERR_PTR(rc);
+
+	kfree(path_buf);
 	return dentry;
 }
 
@@ -512,7 +535,7 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd)
 
 	/* Remove a dentry for a sd from the dcache if present */
 	mutex_lock(&sysfs_mutex);
-	dentry = __sysfs_get_dentry(sd, 0);
+	dentry = __sysfs_get_dentry(sd);
 	if (IS_ERR(dentry))
 		dentry = NULL;
 	if (dentry) {
@@ -700,11 +723,6 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 
 	mutex_lock(&sysfs_mutex);
 
-	/* Guard against races with sysfs_get_dentry */
-	result = d_hash_and_lookup(dentry->d_parent, &dentry->d_name);
-	if (result)
-		goto out;
-
 	sd = sysfs_find_dirent(parent_sd, dentry->d_name.name);
 
 	/* no such entry */
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 0ad731b..3f652be 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -15,7 +15,7 @@
 /* Random magic number */
 #define SYSFS_MAGIC 0x62656572
 
-static struct vfsmount *sysfs_mount;
+struct vfsmount *sysfs_mount;
 struct super_block * sysfs_sb = NULL;
 struct kmem_cache *sysfs_dir_cachep;
 
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index 2b542dc..336823c 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -21,7 +21,7 @@ static int object_depth(struct sysfs_dirent *sd)
 	return depth;
 }
 
-static int object_path_length(struct sysfs_dirent * sd)
+int object_path_length(struct sysfs_dirent * sd)
 {
 	int length = 1;
 
@@ -31,7 +31,7 @@ static int object_path_length(struct sysfs_dirent * sd)
 	return length;
 }
 
-static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length)
+void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length)
 {
 	--length;
 	for (; sd->s_parent; sd = sd->s_parent) {
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 265a16a..86704ef 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -51,6 +51,7 @@ struct sysfs_addrm_cxt {
 };
 
 extern struct sysfs_dirent sysfs_root;
+extern struct vfsmount *sysfs_mount;
 extern struct kmem_cache *sysfs_dir_cachep;
 
 extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);
@@ -89,6 +90,9 @@ extern void sysfs_remove_subdir(struct sysfs_dirent *sd);
 
 extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
 
+extern int object_path_length(struct sysfs_dirent * sd);
+extern void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length);
+
 extern spinlock_t sysfs_assoc_lock;
 extern struct mutex sysfs_mutex;
 extern struct super_block * sysfs_sb;

^ permalink raw reply related	[flat|nested] 79+ messages in thread

* Re: [PATCH 14/14] sysfs: In sysfs_lookup don't open code sysfs_find_dirent
       [not found]                                                                                                                                                           ` <46AF1F28.3000101-l3A5Bk7waGM@public.gmane.org>
@ 2007-07-31 16:01                                                                                                                                                             ` Eric W. Biederman
  0 siblings, 0 replies; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 16:01 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Tejun Heo <teheo-l3A5Bk7waGM@public.gmane.org> writes:

> Eric W. Biederman wrote:
>> This is a small cleanup patch that makes the code just
>> a little bit cleaner.
>> 
>> Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
>
> Acked-by: Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>
> I think this series of patches need wider review than Linux Containers
> mailing list.  Please cc LKML, cornelia.huck-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org and
> stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz@public.gmane.org when posting the next round.

Sure.  I was just Cc'ing those I could think of and I was tired.

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                                       ` <20070731141613.GC13674-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org>
@ 2007-07-31 19:24                                                                                                                                         ` Eric W. Biederman
  2007-08-01  9:22                                                                                                                                         ` Eric W. Biederman
  1 sibling, 0 replies; 79+ messages in thread
From: Eric W. Biederman @ 2007-07-31 19:24 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Linux Containers, Greg KH, Greg KH, Dave Hansen

Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:

> On Tue, Jul 31, 2007 at 08:34:47PM +0900, Tejun Heo wrote:
>> > If sysfs_mutex nested the other way things would be easier,
>> > and we could grab all of the i_mutexes we wanted.  I wonder if we can
>> > be annoying in sysfs_lookup and treat that as the lock inversion
>> > case using mutex_trylock etc.  And have sysfs_mutex be on the
>> > outside for the rest of the cases?
>> 
>> The problem with treating sysfs_lookup as inversion case is that vfs
>> layer grabs i_mutex outside of sysfs_lookup.  Releasing i_mutex from
>> inside sysfs_lookup would be a hacky layering violation.
>> 
>> Then again, the clean up which can come from the new sysfs_looukp_dentry
>> is very significant.  I'll think about it a bit more.
>
> How about something like this?  __sysfs_get_dentry() never creates any
> dentry, it just looks up existing ones.  sysfs_get_dentry() calls
> __sysfs_get_dentry() and if it fails, it builds a path string and look
> up using regular vfs_path_lookup().  Once in the creation path,
> sysfs_get_dentry() is allowed to fail, so allocating path buf is fine.
>
> It still needs to retry when vfs_path_lookup() returns -ENOENT or the
> wrong dentry but things are much simpler now.  It doesn't violate any
> VFS locking rule while maintaining all the benefits of
> sysfs_get_dentry() cleanup.
>
> Something like LOOKUP_KERNEL is needed to ignore security checks;
> otherwise, we'll need to resurrect lookup_one_len_kern() and open code
> look up.
>
> The patch is on top of all your patches and is in barely working form.

Thanks.  I need to look some more.  I've got a case where __sysfs_get_dentry
called from sysfs_drop_dentry is not successfully walking of the sysfs_dirent
tree to the initial root directory.  (This is with deleted sysfs_dirents but
that expected from the context).

I haven't yet had a chance to dig in and see what is going on yet.

Your patch doesn't touch that part of my logic so I don't know yet what
is going on.

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                                       ` <20070731141613.GC13674-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org>
  2007-07-31 19:24                                                                                                                                         ` Eric W. Biederman
@ 2007-08-01  9:22                                                                                                                                         ` Eric W. Biederman
       [not found]                                                                                                                                           ` <m1fy33pq1r.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  1 sibling, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-08-01  9:22 UTC (permalink / raw)
  Cc: htejun-Re5JQEeQqe8AvxtiuMwx3w, Greg KH, Greg KH,
	cornelia.huck-tA70FqPdS9bQT0dZR+AlfA,
	stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
	satyam-wEGCiKHe2LqWVfeAwA7xHQ, Linux Containers, Dave Hansen

Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:

> On Tue, Jul 31, 2007 at 08:34:47PM +0900, Tejun Heo wrote:
>> > If sysfs_mutex nested the other way things would be easier,
>> > and we could grab all of the i_mutexes we wanted.  I wonder if we can
>> > be annoying in sysfs_lookup and treat that as the lock inversion
>> > case using mutex_trylock etc.  And have sysfs_mutex be on the
>> > outside for the rest of the cases?
>> 
>> The problem with treating sysfs_lookup as inversion case is that vfs
>> layer grabs i_mutex outside of sysfs_lookup.  Releasing i_mutex from
>> inside sysfs_lookup would be a hacky layering violation.
>> 
>> Then again, the clean up which can come from the new sysfs_looukp_dentry
>> is very significant.  I'll think about it a bit more.
>
> How about something like this?  __sysfs_get_dentry() never creates any
> dentry, it just looks up existing ones.  sysfs_get_dentry() calls
> __sysfs_get_dentry() and if it fails, it builds a path string and look
> up using regular vfs_path_lookup().  Once in the creation path,
> sysfs_get_dentry() is allowed to fail, so allocating path buf is fine.
>
> It still needs to retry when vfs_path_lookup() returns -ENOENT or the
> wrong dentry but things are much simpler now.  It doesn't violate any
> VFS locking rule while maintaining all the benefits of
> sysfs_get_dentry() cleanup.
>
> Something like LOOKUP_KERNEL is needed to ignore security checks;
> otherwise, we'll need to resurrect lookup_one_len_kern() and open code
> look up.
>
> The patch is on top of all your patches and is in barely working form.

I will look a little more and see.  But right now it looks like the
real problem with locking is that we use sysfs_mutex to lock the
sysfs_dirent s_children list.

Instead it really looks like we should use i_mutex from the appropriate
inode.  Or is there a real performance problem with forcing the directory
inodes in core when we modify the directories?

Using i_mutex to lock the s_children list. Allows us to make sysfs_mutex
come before i_mutex, and it removes the need for an additional lock in
sysfs_lookup.  So generally it looks like the right thing to do and
it should noticeably simplify the sysfs locking.

Was this an oversight or is there some good reason we aren't using
i_mutex to lock the s_children list?

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                                           ` <m1fy33pq1r.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-08-01 10:02                                                                                                                                             ` Tejun Heo
       [not found]                                                                                                                                               ` <46B05A1D.5000703-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-08-01 10:02 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Greg KH, Greg KH, cornelia.huck-tA70FqPdS9bQT0dZR+AlfA,
	stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
	satyam-wEGCiKHe2LqWVfeAwA7xHQ, Linux Containers, Dave Hansen

Hello, Eric.

Eric W. Biederman wrote:
> I will look a little more and see.  But right now it looks like the
> real problem with locking is that we use sysfs_mutex to lock the
> sysfs_dirent s_children list.
> 
> Instead it really looks like we should use i_mutex from the appropriate
> inode.  Or is there a real performance problem with forcing the directory
> inodes in core when we modify the directories?

I don't think there is any performance problem.  Problems with using
i_mutex were...

* It was messy.  I don't remember all the details now but IIRC symlink
walk code was pretty complex.

* And more importantly, inodes are reclaimable and might or might not be
there.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                                               ` <46B05A1D.5000703-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2007-08-01 17:07                                                                                                                                                 ` Eric W. Biederman
       [not found]                                                                                                                                                   ` <m1vebznpyc.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-08-01 17:07 UTC (permalink / raw)
  To: Tejun Heo
  Cc: Greg KH, Greg KH, cornelia.huck-tA70FqPdS9bQT0dZR+AlfA,
	stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
	satyam-wEGCiKHe2LqWVfeAwA7xHQ, Linux Containers, Dave Hansen

Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:

> Hello, Eric.
>
> Eric W. Biederman wrote:
>> I will look a little more and see.  But right now it looks like the
>> real problem with locking is that we use sysfs_mutex to lock the
>> sysfs_dirent s_children list.
>> 
>> Instead it really looks like we should use i_mutex from the appropriate
>> inode.  Or is there a real performance problem with forcing the directory
>> inodes in core when we modify the directories?
>
> I don't think there is any performance problem.  Problems with using
> i_mutex were...
>
> * It was messy.  I don't remember all the details now but IIRC symlink
> walk code was pretty complex.
>
> * And more importantly, inodes are reclaimable and might or might not be
> there.

Yes.  But we can always force inodes into the cache when we need them.
When I complete it I will have to show you a patch using the inode lock
for locking directory modifications.  From what I can tell so far it allows
me to fix the weird lock order problems and generally simplify the locking.

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                                                   ` <m1vebznpyc.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-08-01 17:20                                                                                                                                                     ` Tejun Heo
       [not found]                                                                                                                                                       ` <46B0C0E6.5030008-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-08-01 17:20 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Greg KH, Greg KH, cornelia.huck-tA70FqPdS9bQT0dZR+AlfA,
	stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
	satyam-wEGCiKHe2LqWVfeAwA7xHQ, Linux Containers, Dave Hansen

Eric W. Biederman wrote:
> Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
> 
>> Hello, Eric.
>>
>> Eric W. Biederman wrote:
>>> I will look a little more and see.  But right now it looks like the
>>> real problem with locking is that we use sysfs_mutex to lock the
>>> sysfs_dirent s_children list.
>>>
>>> Instead it really looks like we should use i_mutex from the appropriate
>>> inode.  Or is there a real performance problem with forcing the directory
>>> inodes in core when we modify the directories?
>> I don't think there is any performance problem.  Problems with using
>> i_mutex were...
>>
>> * It was messy.  I don't remember all the details now but IIRC symlink
>> walk code was pretty complex.
>>
>> * And more importantly, inodes are reclaimable and might or might not be
>> there.
> 
> Yes.  But we can always force inodes into the cache when we need them.
> When I complete it I will have to show you a patch using the inode lock
> for locking directory modifications.  From what I can tell so far it allows
> me to fix the weird lock order problems and generally simplify the locking.

Hmmm... I think we can live with a bit of complexity in
sysfs_get_dentry().  It's very well localized and not even long.  I have
been trying hard to untangle sysfs internals from vfs and have a bit of
resistance against going back.  But, then again, if we can achieve
something better and simpler, why not?

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                                                       ` <46B0C0E6.5030008-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2007-08-01 17:40                                                                                                                                                         ` Eric W. Biederman
       [not found]                                                                                                                                                           ` <m1ir7znog9.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-08-01 17:40 UTC (permalink / raw)
  To: Tejun Heo
  Cc: Greg KH, Greg KH, cornelia.huck-tA70FqPdS9bQT0dZR+AlfA,
	stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
	satyam-wEGCiKHe2LqWVfeAwA7xHQ, Linux Containers, Dave Hansen

Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:

> Hmmm... I think we can live with a bit of complexity in
> sysfs_get_dentry().  It's very well localized and not even long.  I have
> been trying hard to untangle sysfs internals from vfs and have a bit of
> resistance against going back.  But, then again, if we can achieve
> something better and simpler, why not?

Right now my real challenge is untangling sysfs_move_dir.  In the
case of multiple mounts of the sysfs tree.

My practical problem is that I need to hold a lock for the sysfs
dirents and while that lock is held I need to call sysfs_get_dentry
for the destination directory once for each superblock.

It might be that some kind of reader-writer lock strategy is what
I need to untangle this mess.  Rather then making changing to i_mutex.
All I know is at the moment it is taking a lot of code reading and
brain storm to come of with something that is easy to maintain.

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                                                           ` <m1ir7znog9.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-08-01 17:51                                                                                                                                                             ` Tejun Heo
       [not found]                                                                                                                                                               ` <46B0C817.7060106-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Tejun Heo @ 2007-08-01 17:51 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Greg KH, Greg KH, cornelia.huck-tA70FqPdS9bQT0dZR+AlfA,
	stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
	satyam-wEGCiKHe2LqWVfeAwA7xHQ, Linux Containers, Dave Hansen

Eric W. Biederman wrote:
> Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
> 
>> Hmmm... I think we can live with a bit of complexity in
>> sysfs_get_dentry().  It's very well localized and not even long.  I have
>> been trying hard to untangle sysfs internals from vfs and have a bit of
>> resistance against going back.  But, then again, if we can achieve
>> something better and simpler, why not?
> 
> Right now my real challenge is untangling sysfs_move_dir.  In the
> case of multiple mounts of the sysfs tree.

OIC.  Yeah, I guess moving a sd with multiple dentries attached could be
pretty difficult.

> My practical problem is that I need to hold a lock for the sysfs
> dirents and while that lock is held I need to call sysfs_get_dentry
> for the destination directory once for each superblock.
> 
> It might be that some kind of reader-writer lock strategy is what
> I need to untangle this mess.  Rather then making changing to i_mutex.
> All I know is at the moment it is taking a lot of code reading and
> brain storm to come of with something that is easy to maintain.

Just in case, sysfs used to have sysfs_rename_rwsem to protect
move/rename against tree walking, which became unnecessary after i_mutex
-> sysfs_mutex conversion.  Move/rename can use stupid big fat locks if
that helps.

Good luck.

-- 
tejun

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                                                               ` <46B0C817.7060106-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2007-08-02  8:28                                                                                                                                                                 ` Cornelia Huck
       [not found]                                                                                                                                                                   ` <20070802102819.183720a4-XQvu0L+U/CiXI4yAdoq52KN5r0PSdgG1zG2AekJRRhI@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Cornelia Huck @ 2007-08-02  8:28 UTC (permalink / raw)
  To: Tejun Heo
  Cc: Greg KH, Greg KH, stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
	Eric W. Biederman, satyam-wEGCiKHe2LqWVfeAwA7xHQ,
	Linux Containers, Dave Hansen

On Thu, 02 Aug 2007 02:51:19 +0900,
Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> Eric W. Biederman wrote:
> > My practical problem is that I need to hold a lock for the sysfs
> > dirents and while that lock is held I need to call sysfs_get_dentry
> > for the destination directory once for each superblock.
> > 
> > It might be that some kind of reader-writer lock strategy is what
> > I need to untangle this mess.  Rather then making changing to i_mutex.
> > All I know is at the moment it is taking a lot of code reading and
> > brain storm to come of with something that is easy to maintain.
> 
> Just in case, sysfs used to have sysfs_rename_rwsem to protect
> move/rename against tree walking, which became unnecessary after i_mutex
> -> sysfs_mutex conversion.  Move/rename can use stupid big fat locks if
> that helps.

I second that. Reintroduction of sysfs_rename_rwsem or something
similar may be the best way to avoid headaches.

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                                                                   ` <20070802102819.183720a4-XQvu0L+U/CiXI4yAdoq52KN5r0PSdgG1zG2AekJRRhI@public.gmane.org>
@ 2007-08-03 19:29                                                                                                                                                                     ` Eric W. Biederman
       [not found]                                                                                                                                                                       ` <m1tzrgl8mo.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
  0 siblings, 1 reply; 79+ messages in thread
From: Eric W. Biederman @ 2007-08-03 19:29 UTC (permalink / raw)
  To: Cornelia Huck
  Cc: Tejun Heo, Greg KH, Greg KH,
	stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
	satyam-wEGCiKHe2LqWVfeAwA7xHQ, Linux Containers, Dave Hansen

Cornelia Huck <cornelia.huck-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org> writes:

> On Thu, 02 Aug 2007 02:51:19 +0900,
> Tejun Heo <htejun-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>
>> Eric W. Biederman wrote:
>> > My practical problem is that I need to hold a lock for the sysfs
>> > dirents and while that lock is held I need to call sysfs_get_dentry
>> > for the destination directory once for each superblock.
>> > 
>> > It might be that some kind of reader-writer lock strategy is what
>> > I need to untangle this mess.  Rather then making changing to i_mutex.
>> > All I know is at the moment it is taking a lot of code reading and
>> > brain storm to come of with something that is easy to maintain.
>> 
>> Just in case, sysfs used to have sysfs_rename_rwsem to protect
>> move/rename against tree walking, which became unnecessary after i_mutex
>> -> sysfs_mutex conversion.  Move/rename can use stupid big fat locks if
>> that helps.
>
> I second that. Reintroduction of sysfs_rename_rwsem or something
> similar may be the best way to avoid headaches.

I guess I haven't looked at that because we already have a big fact
lock we just have an ordering problem in taking that lock.  Introducing
another lock just because of that doesn't quite feel right.

I currently have two practical solutions on the table.

- Make the s_sibling list walk RCU safe so it does not require us to
  grab the sysfs_mutex.  This works but is a bit complicated.

- Just kill all of the dentries in sysfs_move_dir and sysfs_rename_dir.
  The semantics are that no one can be using the device at the time
  of a rename or a move (as I read the callers) so dropping the dentries
  and making it look like a delete/add pair to the users should be
  acceptable and a whole lot simpler.

Eric

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry
       [not found]                                                                                                                                                                       ` <m1tzrgl8mo.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
@ 2007-08-06 15:06                                                                                                                                                                         ` Cornelia Huck
  0 siblings, 0 replies; 79+ messages in thread
From: Cornelia Huck @ 2007-08-06 15:06 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: satyam-wEGCiKHe2LqWVfeAwA7xHQ, Tejun Heo, Greg KH, Greg KH,
	stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
	Linux-YRGon0hq2jhQetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Containers,
	Dave Hansen

On Fri, 03 Aug 2007 13:29:19 -0600,
ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org (Eric W. Biederman) wrote:

> I currently have two practical solutions on the table.
> 
> - Make the s_sibling list walk RCU safe so it does not require us to
>   grab the sysfs_mutex.  This works but is a bit complicated.

But it would be nice, I guess :)

> 
> - Just kill all of the dentries in sysfs_move_dir and sysfs_rename_dir.
>   The semantics are that no one can be using the device at the time
>   of a rename or a move (as I read the callers) so dropping the dentries
>   and making it look like a delete/add pair to the users should be
>   acceptable and a whole lot simpler.

Hm, I'm not sure I understand you here. What do you mean by "using the
device"? Do you mean dropping the sysfs_dirents? Or am I just confused?

^ permalink raw reply	[flat|nested] 79+ messages in thread

end of thread, other threads:[~2007-08-06 15:06 UTC | newest]

Thread overview: 79+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <4676C798.2090404@bull.net>
     [not found] ` <1182446577.8138.29.camel@localhost>
     [not found]   ` <m1odj9dofp.fsf@ebiederm.dsl.xmission.com>
     [not found]     ` <20070621211637.GB10583@suse.de>
     [not found]       ` <m1fy4ldldm.fsf@ebiederm.dsl.xmission.com>
     [not found]         ` <20070622001328.GA14113@suse.de>
     [not found]           ` <m1tzt0cujt.fsf_-_@ebiederm.dsl.xmission.com>
     [not found]             ` <20070625212339.GA13398@kroah.com>
     [not found]               ` <20070625212339.GA13398-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
2007-07-19  4:43                 ` [PATCH 1/4] sysfs: Remove first pass at shadow directory support Eric W. Biederman
     [not found]                   ` <m14pk13svx.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-19  4:45                     ` [PATCH 2/4] sysfs: Implement sysfs manged " Eric W. Biederman
     [not found]                       ` <m1zm1t2e92.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-19  4:46                         ` [PATCH 3/4] sysfs: Implement sysfs_delete_link and sysfs_rename_link Eric W. Biederman
     [not found]                           ` <m1vech2e6o.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-19  4:47                             ` [PATCH 4/4] driver core: Implement shadow directory support for device classes Eric W. Biederman
     [not found]                               ` <m1r6n52e5c.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-21  6:36                                 ` patch driver-core-implement-shadow-directory-support-for-device-classes.patch added to gregkh-2.6 tree gregkh-l3A5Bk7waGM
     [not found]                                   ` <20070721063634.9337314458DB-j1pC+zEt+uWoYr4blSSd5g@public.gmane.org>
2007-07-21 10:00                                     ` Eric W. Biederman
2007-07-21  6:36                             ` patch sysfs-implement-sysfs_delete_link-and-sysfs_rename_link.patch " gregkh-l3A5Bk7waGM
2007-07-21  6:36                         ` patch sysfs-implement-sysfs-manged-shadow-directory-support.patch " gregkh-l3A5Bk7waGM
2007-07-22 19:47                         ` [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support Tejun Heo
     [not found]                           ` <46A3B449.3090409-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2007-07-22 20:25                             ` Greg KH
     [not found]                               ` <20070722202508.GA18018-l3A5Bk7waGM@public.gmane.org>
2007-07-22 22:19                                 ` Eric W. Biederman
     [not found]                                   ` <m17iosw075.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-23  3:52                                     ` Tejun Heo
     [not found]                                       ` <46A425F9.1030008-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2007-07-24  7:26                                         ` Greg KH
2007-07-30  7:09                                         ` Tejun Heo
     [not found]                                           ` <46AD8E92.7080002-l3A5Bk7waGM@public.gmane.org>
2007-07-30 12:41                                             ` Kirill Korotaev
     [not found]                                               ` <46ADDC7F.1090306-3ImXcnM4P+0@public.gmane.org>
2007-07-30 13:06                                                 ` Tejun Heo
     [not found]                                                   ` <46ADE24E.8020502-l3A5Bk7waGM@public.gmane.org>
2007-07-30 13:57                                                     ` Kirill Korotaev
     [not found]                                                       ` <46ADEE35.8000109-3ImXcnM4P+0@public.gmane.org>
2007-07-30 14:04                                                         ` Tejun Heo
     [not found]                                                           ` <46ADF003.3010100-l3A5Bk7waGM@public.gmane.org>
2007-07-30 15:51                                                             ` Eric W. Biederman
     [not found]                                                               ` <m1ps29vqin.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31  3:24                                                                 ` Eric W. Biederman
     [not found]                                                                   ` <m1k5shuugc.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31  3:41                                                                     ` Tejun Heo
     [not found]                                                                       ` <46AEAF79.6080404-l3A5Bk7waGM@public.gmane.org>
2007-07-31  4:02                                                                         ` Eric W. Biederman
     [not found]                                                                           ` <m1fy35uso4.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31  4:28                                                                             ` Tejun Heo
     [not found]                                                                               ` <46AEBA87.6000400-l3A5Bk7waGM@public.gmane.org>
2007-07-31  7:59                                                                                 ` Eric W. Biederman
     [not found]                                                                                   ` <m1bqdtt34l.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31  8:14                                                                                     ` Tejun Heo
     [not found]                                                                                       ` <46AEEF75.2030101-l3A5Bk7waGM@public.gmane.org>
2007-07-31  8:15                                                                                         ` Tejun Heo
     [not found]                                                                                           ` <46AEEFA6.4000901-l3A5Bk7waGM@public.gmane.org>
2007-07-31 10:16                                                                                             ` [PATCH 0/14] sysfs cleanups Eric W. Biederman
     [not found]                                                                                               ` <m14pjkubd2.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:18                                                                                                 ` [PATCH 01/14] sysfs: Remove first pass at shadow directory support Eric W. Biederman
     [not found]                                                                                                   ` <m1zm1cswp0.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:20                                                                                                     ` [PATCH 02/14] sysfs: In sysfs_lookup protect s_parent with sysfs_mutex Eric W. Biederman
     [not found]                                                                                                       ` <m1vec0swmi.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:22                                                                                                         ` [PATCH 03/14] sysfs: Move all of inode initialization into sysfs_init_inode Eric W. Biederman
     [not found]                                                                                                           ` <m1r6moswhr.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:24                                                                                                             ` [PATCH 04/14] sysfs: Remove unnecessary variable found from sysfs_lookup Eric W. Biederman
     [not found]                                                                                                               ` <m1myxcswfr.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:25                                                                                                                 ` [PATCH 05/14] sysfs: Remove sysfs_instantiate Eric W. Biederman
     [not found]                                                                                                                   ` <m1ir80swdl.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:27                                                                                                                     ` [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry Eric W. Biederman
     [not found]                                                                                                                       ` <m1ejioswai.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:28                                                                                                                         ` [PATCH 07/14] vfs: Remove lookup_one_len_kern Eric W. Biederman
     [not found]                                                                                                                           ` <m1abtcsw8w.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:29                                                                                                                             ` [PATCH 08/14] sysfs: Perform renames under sysfs_mutex Eric W. Biederman
     [not found]                                                                                                                               ` <m16440sw6d.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:33                                                                                                                                 ` [PATCH 09/14] sysfs: Move all of sysfs_move_dir " Eric W. Biederman
     [not found]                                                                                                                                   ` <m11weosvzz.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:37                                                                                                                                     ` [PATCH 10/14] sysfs: Rework sysfs_drop_dentry Eric W. Biederman
     [not found]                                                                                                                                       ` <m1wswgrh8x.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:39                                                                                                                                         ` [PATCH 11/14] sysfs: Remove s_dentry form sysfs_dirent Eric W. Biederman
     [not found]                                                                                                                                           ` <m1sl74rh6e.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:40                                                                                                                                             ` [PATCH 12/14] sysfs: Make sysfs_mount static Eric W. Biederman
     [not found]                                                                                                                                               ` <m1odhsrh46.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:42                                                                                                                                                 ` [PATCH 13/14] sysfs: Simplify readdir Eric W. Biederman
     [not found]                                                                                                                                                   ` <m1k5sgrh1h.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:42                                                                                                                                                     ` [PATCH 14/14] sysfs: In sysfs_lookup don't open code sysfs_find_dirent Eric W. Biederman
     [not found]                                                                                                                                                       ` <m1fy34rh08.fsf_-_-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 11:38                                                                                                                                                         ` Tejun Heo
     [not found]                                                                                                                                                           ` <46AF1F28.3000101-l3A5Bk7waGM@public.gmane.org>
2007-07-31 16:01                                                                                                                                                             ` Eric W. Biederman
2007-07-31 11:36                                                                                                                                                     ` [PATCH 13/14] sysfs: Simplify readdir Tejun Heo
2007-07-31 11:19                                                                                                                                                 ` [PATCH 12/14] sysfs: Make sysfs_mount static Tejun Heo
2007-07-31 11:18                                                                                                                                             ` [PATCH 11/14] sysfs: Remove s_dentry form sysfs_dirent Tejun Heo
2007-07-31 11:17                                                                                                                                         ` [PATCH 10/14] sysfs: Rework sysfs_drop_dentry Tejun Heo
2007-07-31 11:09                                                                                                                                     ` [PATCH 09/14] sysfs: Move all of sysfs_move_dir under sysfs_mutex Tejun Heo
2007-07-31 11:06                                                                                                                                 ` [PATCH 08/14] sysfs: Perform renames " Tejun Heo
     [not found]                                                                                                                                   ` <46AF17A1.2010203-l3A5Bk7waGM@public.gmane.org>
2007-07-31 11:10                                                                                                                                     ` Tejun Heo
2007-07-31 10:59                                                                                                                         ` [PATCH 06/14] sysfs: Rewrite sysfs_get_dentry Tejun Heo
     [not found]                                                                                                                           ` <46AF15F6.6010202-l3A5Bk7waGM@public.gmane.org>
2007-07-31 11:23                                                                                                                             ` Eric W. Biederman
     [not found]                                                                                                                               ` <m11weorf3l.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 11:34                                                                                                                                 ` Tejun Heo
     [not found]                                                                                                                                   ` <46AF1E57.3030209-l3A5Bk7waGM@public.gmane.org>
2007-07-31 14:16                                                                                                                                     ` Tejun Heo
     [not found]                                                                                                                                       ` <20070731141613.GC13674-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org>
2007-07-31 19:24                                                                                                                                         ` Eric W. Biederman
2007-08-01  9:22                                                                                                                                         ` Eric W. Biederman
     [not found]                                                                                                                                           ` <m1fy33pq1r.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-08-01 10:02                                                                                                                                             ` Tejun Heo
     [not found]                                                                                                                                               ` <46B05A1D.5000703-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2007-08-01 17:07                                                                                                                                                 ` Eric W. Biederman
     [not found]                                                                                                                                                   ` <m1vebznpyc.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-08-01 17:20                                                                                                                                                     ` Tejun Heo
     [not found]                                                                                                                                                       ` <46B0C0E6.5030008-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2007-08-01 17:40                                                                                                                                                         ` Eric W. Biederman
     [not found]                                                                                                                                                           ` <m1ir7znog9.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-08-01 17:51                                                                                                                                                             ` Tejun Heo
     [not found]                                                                                                                                                               ` <46B0C817.7060106-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2007-08-02  8:28                                                                                                                                                                 ` Cornelia Huck
     [not found]                                                                                                                                                                   ` <20070802102819.183720a4-XQvu0L+U/CiXI4yAdoq52KN5r0PSdgG1zG2AekJRRhI@public.gmane.org>
2007-08-03 19:29                                                                                                                                                                     ` Eric W. Biederman
     [not found]                                                                                                                                                                       ` <m1tzrgl8mo.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-08-06 15:06                                                                                                                                                                         ` Cornelia Huck
2007-07-31 10:44                                                                                                                     ` [PATCH 05/14] sysfs: Remove sysfs_instantiate Tejun Heo
2007-07-31 10:45                                                                                                                 ` [PATCH 04/14] sysfs: Remove unnecessary variable found from sysfs_lookup Tejun Heo
2007-07-31 10:43                                                                                                             ` [PATCH 03/14] sysfs: Move all of inode initialization into sysfs_init_inode Tejun Heo
2007-07-31 10:36                                                                                                         ` [PATCH 02/14] sysfs: In sysfs_lookup protect s_parent with sysfs_mutex Tejun Heo
     [not found]                                                                                                           ` <46AF10B7.3070600-l3A5Bk7waGM@public.gmane.org>
2007-07-31 10:45                                                                                                             ` Eric W. Biederman
     [not found]                                                                                                               ` <m1bqdsrgvy.fsf-T1Yj925okcoyDheHMi7gv2pdwda3JcWeAL8bYrjMMd8@public.gmane.org>
2007-07-31 10:47                                                                                                                 ` Tejun Heo
2007-07-31  3:51                                                                 ` [PATCH 2/4] sysfs: Implement sysfs manged shadow directory support Tejun Heo
2007-07-26  8:00                                     ` Tejun Heo
     [not found]                                       ` <46A85485.40502-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2007-07-27 10:58                                         ` [Devel] " Kirill Korotaev
2007-07-27 20:59                                         ` Carl-Daniel Hailfinger
2007-07-30 15:36                                         ` Eric W. Biederman
2007-07-22 22:07                             ` Eric W. Biederman
2007-07-21  6:36                     ` patch sysfs-remove-first-pass-at-shadow-directory-support.patch added to gregkh-2.6 tree gregkh-l3A5Bk7waGM
2007-07-22 18:35                     ` [PATCH 1/4] sysfs: Remove first pass at shadow directory support Tejun Heo
     [not found]                       ` <46A3A36F.9070904-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2007-07-22 19:17                         ` Eric W. Biederman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.