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