Re: Bug creating USB endpoints in 2.6.20.x (kernel bug 8198)

Tejun Heo <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
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

-------------------------------------------------------------------------
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/

_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
sysfs-debug.patch (text/x-patch, 7.5 KB)
---
 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.