<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
From: Maneesh Soni &lt;maneesh@in.ibm.com&gt;

o This patch uses the sysfs_dirent based tree while removing sysfs files
  and directories. This avoids holding dcache_lock by not using dentry 
  based vfs tree. Thus simplyfying the removal logic in sysfs.

o It uses two helper routines sysfs_get_name(), to get the name for
  sysfs element and sysfs_drop_dentry() to delete the dentry given a
  sysfs_dirent.

Signed-off-by: Andrew Morton &lt;akpm@osdl.org&gt;
---

 25-akpm/fs/sysfs/dir.c   |   48 +++++-------------------
 25-akpm/fs/sysfs/inode.c |   92 +++++++++++++++++++++++++++++++++--------------
 25-akpm/fs/sysfs/sysfs.h |   17 ++++++++
 3 files changed, 94 insertions(+), 63 deletions(-)

diff -puN fs/sysfs/dir.c~sysfs-backing-store-use-sysfs_dirent-tree-in-removal fs/sysfs/dir.c
--- 25/fs/sysfs/dir.c~sysfs-backing-store-use-sysfs_dirent-tree-in-removal	2004-08-15 13:42:12.177150192 -0700
+++ 25-akpm/fs/sysfs/dir.c	2004-08-15 13:42:12.186148824 -0700
@@ -19,7 +19,7 @@ static void sysfs_d_iput(struct dentry *
 	if (sd) {
 		BUG_ON(sd-&gt;s_dentry != dentry);
 		sd-&gt;s_dentry = NULL;
-		release_sysfs_dirent(sd);
+		sysfs_put(sd);
 	}
 	iput(inode);
 }
@@ -61,7 +61,7 @@ int sysfs_make_dirent(struct sysfs_diren
 	sd-&gt;s_mode = mode;
 	sd-&gt;s_type = type;
 	sd-&gt;s_dentry = dentry;
-	dentry-&gt;d_fsdata = sd;
+	dentry-&gt;d_fsdata = sysfs_get(sd);
 	dentry-&gt;d_op = &amp;sysfs_dentry_ops;
 
 	return 0;
@@ -146,6 +146,7 @@ static void remove_dir(struct dentry * d
 	d_delete(d);
 	sd = d-&gt;d_fsdata;
  	list_del_init(&amp;sd-&gt;s_sibling);
+	sysfs_put(sd);
 	if (d-&gt;d_inode)
 		simple_rmdir(parent-&gt;d_inode,d);
 
@@ -173,49 +174,22 @@ void sysfs_remove_subdir(struct dentry *
 
 void sysfs_remove_dir(struct kobject * kobj)
 {
-	struct list_head * node;
 	struct dentry * dentry = dget(kobj-&gt;dentry);
+	struct sysfs_dirent * parent_sd = dentry-&gt;d_fsdata;
+	struct sysfs_dirent * sd, * tmp;
 
 	if (!dentry)
 		return;
 
 	pr_debug("sysfs %s: removing dir\n",dentry-&gt;d_name.name);
 	down(&amp;dentry-&gt;d_inode-&gt;i_sem);
-
-	spin_lock(&amp;dcache_lock);
-restart:
-	node = dentry-&gt;d_subdirs.next;
-	while (node != &amp;dentry-&gt;d_subdirs) {
-		struct dentry * d = list_entry(node,struct dentry,d_child);
-
-		node = node-&gt;next;
-		pr_debug(" o %s (%d): ",d-&gt;d_name.name,atomic_read(&amp;d-&gt;d_count));
-		if (!d_unhashed(d) &amp;&amp; (d-&gt;d_inode)) {
-			struct sysfs_dirent * sd = d-&gt;d_fsdata;
-			d = dget_locked(d);
-			pr_debug("removing");
-
-			/**
-			 * Unlink and unhash.
-			 */
-			__d_drop(d);
-			spin_unlock(&amp;dcache_lock);
-			/* release the target kobject in case of 
-			 * a symlink
-			 */
-			if (S_ISLNK(d-&gt;d_inode-&gt;i_mode))
-				kobject_put(sd-&gt;s_element);
-			
-			list_del_init(&amp;sd-&gt;s_sibling);
-			simple_unlink(dentry-&gt;d_inode,d);
-			dput(d);
-			pr_debug(" done\n");
-			spin_lock(&amp;dcache_lock);
-			/* re-acquired dcache_lock, need to restart */
-			goto restart;
-		}
+	list_for_each_entry_safe(sd, tmp, &amp;parent_sd-&gt;s_children, s_sibling) {
+		if (!sd-&gt;s_element)
+			continue;
+		list_del_init(&amp;sd-&gt;s_sibling);
+		sysfs_drop_dentry(sd, dentry);
+		sysfs_put(sd);
 	}
-	spin_unlock(&amp;dcache_lock);
 	up(&amp;dentry-&gt;d_inode-&gt;i_sem);
 
 	remove_dir(dentry);
diff -puN fs/sysfs/inode.c~sysfs-backing-store-use-sysfs_dirent-tree-in-removal fs/sysfs/inode.c
--- 25/fs/sysfs/inode.c~sysfs-backing-store-use-sysfs_dirent-tree-in-removal	2004-08-15 13:42:12.179149888 -0700
+++ 25-akpm/fs/sysfs/inode.c	2004-08-15 13:42:12.187148672 -0700
@@ -31,8 +31,8 @@ struct inode * sysfs_new_inode(mode_t mo
 	struct inode * inode = new_inode(sysfs_sb);
 	if (inode) {
 		inode-&gt;i_mode = mode;
-		inode-&gt;i_uid = current-&gt;fsuid;
-		inode-&gt;i_gid = current-&gt;fsgid;
+		inode-&gt;i_uid = 0;
+		inode-&gt;i_gid = 0;
 		inode-&gt;i_blksize = PAGE_CACHE_SIZE;
 		inode-&gt;i_blocks = 0;
 		inode-&gt;i_atime = inode-&gt;i_mtime = inode-&gt;i_ctime = CURRENT_TIME;
@@ -68,7 +68,8 @@ int sysfs_create(struct dentry * dentry,
 		error = init(inode);
 	if (!error) {
 		d_instantiate(dentry, inode);
-		dget(dentry); /* Extra count - pin the dentry in core */
+		if (S_ISDIR(mode))
+			dget(dentry);  /* pin only directory dentry in core */
 	} else
 		iput(inode);
  Done:
@@ -90,35 +91,74 @@ struct dentry * sysfs_get_dentry(struct 
 	return lookup_hash(&amp;qstr,parent);
 }
 
+/*
+ * Get the name for corresponding element represented by the given sysfs_dirent
+ */
+const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
+{
+	struct attribute * attr;
+	struct bin_attribute * bin_attr;
+	struct sysfs_symlink  * sl;
+
+	if (!sd || !sd-&gt;s_element)
+		BUG();
+
+	switch (sd-&gt;s_type) {
+		case SYSFS_DIR:
+			/* Always have a dentry so use that */
+			return sd-&gt;s_dentry-&gt;d_name.name;
+
+		case SYSFS_KOBJ_ATTR:
+			attr = sd-&gt;s_element;
+			return attr-&gt;name;
+
+		case SYSFS_KOBJ_BIN_ATTR:
+			bin_attr = sd-&gt;s_element;
+			return bin_attr-&gt;attr.name;
+
+		case SYSFS_KOBJ_LINK:
+			sl = sd-&gt;s_element;
+			return sl-&gt;link_name;
+	}
+	return NULL;
+}
+
+
+/*
+ * Unhashes the dentry corresponding to given sysfs_dirent
+ * Called with parent inode's i_sem held.
+ */
+void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
+{
+	struct dentry * dentry = sd-&gt;s_dentry;
+
+	if (dentry) {
+		spin_lock(&amp;dcache_lock);
+		if (!(d_unhashed(dentry) &amp;&amp; dentry-&gt;d_inode)) {
+			dget_locked(dentry);
+			__d_drop(dentry);
+			spin_unlock(&amp;dcache_lock);
+			simple_unlink(parent-&gt;d_inode, dentry);
+		} else
+			spin_unlock(&amp;dcache_lock);
+	}
+}
+
 void sysfs_hash_and_remove(struct dentry * dir, const char * name)
 {
-	struct dentry * victim;
 	struct sysfs_dirent * sd;
+	struct sysfs_dirent * parent_sd = dir-&gt;d_fsdata;
 
 	down(&amp;dir-&gt;d_inode-&gt;i_sem);
-	victim = sysfs_get_dentry(dir,name);
-	if (!IS_ERR(victim)) {
-		/* make sure dentry is really there */
-		if (victim-&gt;d_inode &amp;&amp; 
-		    (victim-&gt;d_parent-&gt;d_inode == dir-&gt;d_inode)) {
-			pr_debug("sysfs: Removing %s (%d)\n", victim-&gt;d_name.name,
-				 atomic_read(&amp;victim-&gt;d_count));
-
-			sd = victim-&gt;d_fsdata;
-			d_drop(victim);
-			/* release the target kobject in case of 
-			 * a symlink
-			 */
-			if (S_ISLNK(victim-&gt;d_inode-&gt;i_mode))
-				kobject_put(sd-&gt;s_element);
+	list_for_each_entry(sd, &amp;parent_sd-&gt;s_children, s_sibling) {
+		if (!sd-&gt;s_element)
+			continue;
+		if (!strcmp(sysfs_get_name(sd), name)) {
 			list_del_init(&amp;sd-&gt;s_sibling);
-			simple_unlink(dir-&gt;d_inode,victim);
-		} else
-			d_drop(victim);
-		/*
-		 * Drop reference from sysfs_get_dentry() above.
-		 */
-		dput(victim);
+			sysfs_drop_dentry(sd, dir);
+			sysfs_put(sd);
+			break;
+		}
 	}
 	up(&amp;dir-&gt;d_inode-&gt;i_sem);
 }
diff -puN fs/sysfs/sysfs.h~sysfs-backing-store-use-sysfs_dirent-tree-in-removal fs/sysfs/sysfs.h
--- 25/fs/sysfs/sysfs.h~sysfs-backing-store-use-sysfs_dirent-tree-in-removal	2004-08-15 13:42:12.180149736 -0700
+++ 25-akpm/fs/sysfs/sysfs.h	2004-08-15 13:42:12.187148672 -0700
@@ -14,6 +14,8 @@ extern void sysfs_hash_and_remove(struct
 extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **);
 extern void sysfs_remove_subdir(struct dentry *);
 
+extern const unsigned char * sysfs_get_name(struct sysfs_dirent *sd);
+extern void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent);
 extern int sysfs_readlink(struct dentry *, char __user *, int );
 extern int sysfs_follow_link(struct dentry *, struct nameidata *);
 extern struct rw_semaphore sysfs_rename_sem;
@@ -70,3 +72,18 @@ static inline void release_sysfs_dirent(
 	kfree(sd);
 }
 
+static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd)
+{
+	if (sd) {
+		WARN_ON(!atomic_read(&amp;sd-&gt;s_count));
+		atomic_inc(&amp;sd-&gt;s_count);
+	}
+	return sd;
+}
+
+static inline void sysfs_put(struct sysfs_dirent * sd)
+{
+	if (atomic_dec_and_test(&amp;sd-&gt;s_count))
+		release_sysfs_dirent(sd);
+}
+
_
</pre></body></html>