From 641e6f30a095f3752ed84fd9d279382f5d3ef4c1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 16 Mar 2006 15:44:26 -0800 Subject: [PATCH] sysfs: sysfs_remove_dir() needs to invalidate the dentry When calling sysfs_remove_dir() don't allow any further sysfs functions to work for this kobject anymore. This fixes a nasty USB cdc-acm oops on disconnect. Many thanks to Bob Copeland and Paul Fulghum for taking the time to track this down. Cc: Bob Copeland Cc: Paul Fulghum Cc: Maneesh Soni Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/sysfs/dir.c') diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 49bd219275d..cfd290d3d6b 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -302,6 +302,7 @@ void sysfs_remove_dir(struct kobject * kobj) * Drop reference from dget() on entrance. */ dput(dentry); + kobj->dentry = NULL; } int sysfs_rename_dir(struct kobject * kobj, const char *new_name) -- cgit v1.2.3-70-g09d2 From c516865cfbac0d862d4888df91793ad1e74ffd58 Mon Sep 17 00:00:00 2001 From: Maneesh Soni Date: Thu, 9 Mar 2006 19:40:14 +0530 Subject: [PATCH] sysfs: fix problem with duplicate sysfs directories and files The following patch checks for existing sysfs_dirent before preparing new one while creating sysfs directories and files. Signed-off-by: Maneesh Soni Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 32 +++++++++++++++++++++++++++++++- fs/sysfs/file.c | 6 ++++-- fs/sysfs/symlink.c | 5 +++-- fs/sysfs/sysfs.h | 1 + 4 files changed, 39 insertions(+), 5 deletions(-) (limited to 'fs/sysfs/dir.c') diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index cfd290d3d6b..bea1f4c02b9 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -50,6 +50,32 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd, return sd; } +/** + * + * Return -EEXIST if there is already a sysfs element with the same name for + * the same parent. + * + * called with parent inode's i_mutex held + */ +int sysfs_dirent_exist(struct sysfs_dirent *parent_sd, + const unsigned char *new) +{ + struct sysfs_dirent * sd; + + list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { + if (sd->s_element) { + const unsigned char *existing = sysfs_get_name(sd); + if (strcmp(existing, new)) + continue; + else + return -EEXIST; + } + } + + return 0; +} + + int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, void * element, umode_t mode, int type) { @@ -102,7 +128,11 @@ static int create_dir(struct kobject * k, struct dentry * p, mutex_lock(&p->d_inode->i_mutex); *d = lookup_one_len(n, p, strlen(n)); if (!IS_ERR(*d)) { - error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR); + if (sysfs_dirent_exist(p->d_fsdata, n)) + error = -EEXIST; + else + error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, + SYSFS_DIR); if (!error) { error = sysfs_create(*d, mode, init_dir); if (!error) { diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index e21f4022feb..5e83e724678 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -361,10 +361,12 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type) { struct sysfs_dirent * parent_sd = dir->d_fsdata; umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; - int error = 0; + int error = -EEXIST; mutex_lock(&dir->d_inode->i_mutex); - error = sysfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type); + if (!sysfs_dirent_exist(parent_sd, attr->name)) + error = sysfs_make_dirent(parent_sd, NULL, (void *)attr, + mode, type); mutex_unlock(&dir->d_inode->i_mutex); return error; diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index e38d6338a20..fe23f47f6e4 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -82,12 +82,13 @@ exit1: int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name) { struct dentry * dentry = kobj->dentry; - int error = 0; + int error = -EEXIST; BUG_ON(!kobj || !kobj->dentry || !name); mutex_lock(&dentry->d_inode->i_mutex); - error = sysfs_add_link(dentry, name, target); + if (!sysfs_dirent_exist(dentry->d_fsdata, name)) + error = sysfs_add_link(dentry, name, target); mutex_unlock(&dentry->d_inode->i_mutex); return error; } diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 3f8953e0e5d..cf11d5b789d 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -5,6 +5,7 @@ extern kmem_cache_t *sysfs_dir_cachep; extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); +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); -- cgit v1.2.3-70-g09d2 From 832c57e9afa7a263bb2f8ee6d04d527ef6709aae Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 16 Mar 2006 11:23:21 -0700 Subject: [PATCH] sysfs: don't export dir symbols These functions should only be used by the kobject core, and if any driver tries to use them, bad things happen. Unexport them to try to prevent this from happening. Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'fs/sysfs/dir.c') diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index bea1f4c02b9..9ee95686444 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -510,7 +510,3 @@ struct file_operations sysfs_dir_operations = { .read = generic_read_dir, .readdir = sysfs_readdir, }; - -EXPORT_SYMBOL_GPL(sysfs_create_dir); -EXPORT_SYMBOL_GPL(sysfs_remove_dir); -EXPORT_SYMBOL_GPL(sysfs_rename_dir); -- cgit v1.2.3-70-g09d2