Chris Rankin wrote:
> Will this patch apply against 2.6.20.x? I haven't tried triggering this 
> problem on 2.6.21.x yet.

Okay, here's patch against 2.6.20.11.  Let's hope we're not chasing
something which is already fixed.

-- 
tejun
---
 fs/sysfs/dir.c        |   57 +++++++++++++++++++++++++++++++++++++++++++++++---
 fs/sysfs/file.c       |   32 ++++++++++++++++++++++++++--
 fs/sysfs/symlink.c    |    7 ++++--
 fs/sysfs/sysfs.h      |   24 +++++++++++++++++++--
 include/linux/sysfs.h |    1 
 5 files changed, 112 insertions(+), 9 deletions(-)

Index: tree0/fs/sysfs/dir.c
===================================================================
--- tree0.orig/fs/sysfs/dir.c
+++ tree0/fs/sysfs/dir.c
@@ -11,6 +11,9 @@
 #include <linux/namei.h>
 #include "sysfs.h"
 
+static char sysfs_trace_path[PATH_MAX];
+module_param_string(sysfs_trace_path, sysfs_trace_path, PATH_MAX, 0644);
+
 DECLARE_RWSEM(sysfs_rename_sem);
 
 static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
@@ -76,9 +79,53 @@ int sysfs_dirent_exist(struct sysfs_dire
 	return 0;
 }
 
+void sysfs_trace_create(struct dentry *parent, const char *last_component,
+			struct sysfs_dirent *sd)
+{
+	char *buf, *path, *c;
+	int len;
+
+	buf = kmalloc(PATH_MAX, GFP_KERNEL);
+	if (!buf) {
+		printk("sysfs_trace: OOPS no memory\n");
+		return;
+	}
+
+	path = d_path(parent, sysfs_mount, buf, PATH_MAX);
+	if (IS_ERR(path)) {
+		printk("sysfs_trace: OOPS d_path error %d\n",
+		       (int)PTR_ERR(path));
+		goto out_free;
+	}
+
+	c = sysfs_trace_path;
+	if (strncmp(c, "/sys/", 5) == 0)
+		c += 4;
+
+	len = strlen(path);
+	if (strncmp(c, path, len))
+		goto out_free;
+
+	/* only the last component should be remaining */
+	c += len;
+	if (*c++ != '/')
+		goto out_free;
+
+	if (strcmp(c, last_component))
+		goto out_free;
+
+	printk("sysfs_trace: CREATE %s pid=%u comm=%s",
+	       sysfs_trace_path, current->pid, current->comm);
+	dump_stack();
+	sd->s_trace = 1;
+
+ out_free:
+	kfree(buf);
+}
 
 int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
-			void * element, umode_t mode, int type)
+		      void * element, umode_t mode, int type,
+		      struct sysfs_dirent **psd)
 {
 	struct sysfs_dirent * sd;
 
@@ -89,6 +136,8 @@ int sysfs_make_dirent(struct sysfs_diren
 	sd->s_mode = mode;
 	sd->s_type = type;
 	sd->s_dentry = dentry;
+	if (psd)
+		*psd = sd;
 	if (dentry) {
 		dentry->d_fsdata = sysfs_get(sd);
 		dentry->d_op = &sysfs_dentry_ops;
@@ -125,6 +174,7 @@ static int create_dir(struct kobject * k
 {
 	int error;
 	umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
+	struct sysfs_dirent *sd;
 
 	mutex_lock(&p->d_inode->i_mutex);
 	*d = lookup_one_len(n, p, strlen(n));
@@ -133,8 +183,10 @@ static int create_dir(struct kobject * k
   			error = -EEXIST;
   		else
 			error = sysfs_make_dirent(p->d_fsdata, *d, k, mode,
-								SYSFS_DIR);
+						  SYSFS_DIR, &sd);
+
 		if (!error) {
+			sysfs_trace_create(p, n, sd);
 			error = sysfs_create(*d, mode, init_dir);
 			if (!error) {
 				inc_nlink(p->d_inode);
@@ -143,7 +195,6 @@ static int create_dir(struct kobject * k
 			}
 		}
 		if (error && (error != -EEXIST)) {
-			struct sysfs_dirent *sd = (*d)->d_fsdata;
 			if (sd) {
  				list_del_init(&sd->s_sibling);
 				sysfs_put(sd);
Index: tree0/fs/sysfs/file.c
===================================================================
--- tree0.orig/fs/sysfs/file.c
+++ tree0/fs/sysfs/file.c
@@ -316,6 +316,18 @@ static int check_perm(struct inode * ino
 		file->private_data = buffer;
 	} else
 		error = -ENOMEM;
+
+	{
+		struct sysfs_dirent *sd = file->f_path.dentry->d_fsdata;
+
+		if (sd->s_trace) {
+			printk("sysfs_trace: OPEN s_count=%d pid=%u comm=%s",
+			       atomic_read(&sd->s_count), current->pid,
+			       current->comm);
+			dump_stack();
+		}
+	}
+
 	goto Done;
 
  Einval:
@@ -342,6 +354,17 @@ static int sysfs_release(struct inode * 
 	struct module * owner = attr->owner;
 	struct sysfs_buffer * buffer = filp->private_data;
 
+	{
+		struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata;
+
+		if (sd->s_trace) {
+			printk("sysfs_trace: CLOSE s_count=%d pid=%u comm=%s",
+			       atomic_read(&sd->s_count), current->pid,
+			       current->comm);
+			dump_stack();
+		}
+	}
+
 	if (kobj) 
 		kobject_put(kobj);
 	/* After this point, attr should not be accessed. */
@@ -352,6 +375,7 @@ static int sysfs_release(struct inode * 
 			free_page((unsigned long)buffer->page);
 		kfree(buffer);
 	}
+
 	return 0;
 }
 
@@ -443,9 +467,13 @@ int sysfs_add_file(struct dentry * dir, 
 	int error = -EEXIST;
 
 	mutex_lock(&dir->d_inode->i_mutex);
-	if (!sysfs_dirent_exist(parent_sd, attr->name))
+	if (!sysfs_dirent_exist(parent_sd, attr->name)) {
+		struct sysfs_dirent *sd;
 		error = sysfs_make_dirent(parent_sd, NULL, (void *)attr,
-					  mode, type);
+					  mode, type, &sd);
+		if (!error)
+			sysfs_trace_create(dir, attr->name, sd);
+	}
 	mutex_unlock(&dir->d_inode->i_mutex);
 
 	return error;
Index: tree0/fs/sysfs/symlink.c
===================================================================
--- tree0.orig/fs/sysfs/symlink.c
+++ tree0/fs/sysfs/symlink.c
@@ -48,6 +48,7 @@ static int sysfs_add_link(struct dentry 
 {
 	struct sysfs_dirent * parent_sd = parent->d_fsdata;
 	struct sysfs_symlink * sl;
+	struct sysfs_dirent *sd;
 	int error = 0;
 
 	error = -ENOMEM;
@@ -63,9 +64,11 @@ static int sysfs_add_link(struct dentry 
 	sl->target_kobj = kobject_get(target);
 
 	error = sysfs_make_dirent(parent_sd, NULL, sl, S_IFLNK|S_IRWXUGO,
-				SYSFS_KOBJ_LINK);
-	if (!error)
+				  SYSFS_KOBJ_LINK, &sd);
+	if (!error) {
+		sysfs_trace_create(parent, name, sd);
 		return 0;
+	}
 
 	kobject_put(target);
 	kfree(sl->link_name);
Index: tree0/fs/sysfs/sysfs.h
===================================================================
--- tree0.orig/fs/sysfs/sysfs.h
+++ tree0/fs/sysfs/sysfs.h
@@ -7,7 +7,10 @@ extern int sysfs_create(struct dentry *,
 
 extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *);
 extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *,
-				umode_t, int);
+			     umode_t, int, struct sysfs_dirent **);
+extern void sysfs_trace_create(struct dentry *dentry,
+			       const char *last_component,
+			       struct sysfs_dirent *sd);
 
 extern int sysfs_add_file(struct dentry *, const struct attribute *, int);
 extern int sysfs_hash_and_remove(struct dentry * dir, const char * name);
@@ -69,8 +72,15 @@ static inline struct kobject *sysfs_get_
 	return kobj;
 }
 
+#include <linux/sched.h>
 static inline void release_sysfs_dirent(struct sysfs_dirent * sd)
 {
+	if (sd->s_trace) {
+		printk("sysfs_trace: RELEASE pid=%u comm=%s",
+		       current->pid, current->comm);
+		dump_stack();
+	}
+
 	if (sd->s_type & SYSFS_KOBJ_LINK) {
 		struct sysfs_symlink * sl = sd->s_element;
 		kfree(sl->link_name);
@@ -86,13 +96,23 @@ static inline struct sysfs_dirent * sysf
 	if (sd) {
 		WARN_ON(!atomic_read(&sd->s_count));
 		atomic_inc(&sd->s_count);
+		if (sd->s_trace) {
+			printk("sysfs_trace: GET s_count=%d pid=%u comm=%s",
+			       atomic_read(&sd->s_count), current->pid, current->comm);
+			dump_stack();
+		}
 	}
 	return sd;
 }
 
 static inline void sysfs_put(struct sysfs_dirent * sd)
 {
-	if (atomic_dec_and_test(&sd->s_count))
+	if (atomic_dec_and_test(&sd->s_count)) {
 		release_sysfs_dirent(sd);
+	} else if (sd->s_trace) {
+		printk("sysfs_trace: PUT s_count=%d pid=%u comm=%s",
+		       atomic_read(&sd->s_count), current->pid, current->comm);
+		dump_stack();
+	}
 }
 
Index: tree0/include/linux/sysfs.h
===================================================================
--- tree0.orig/include/linux/sysfs.h
+++ tree0/include/linux/sysfs.h
@@ -76,6 +76,7 @@ struct sysfs_dirent {
 	struct dentry		* s_dentry;
 	struct iattr		* s_iattr;
 	atomic_t		s_event;
+	int			s_trace:1;
 };
 
 #define SYSFS_ROOT		0x0001
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to