Sysfs cleanups
Subsystems (3)
cover Sysfs cleanups
The following patch series cleans up sysfs to the point where itq is generally a good citizen of the vfs layer. The big theme is lazy synchronization from the sysfs data structures to the vfs data structures using the same techniques as most other distributed filesystems.
This allows the complete removal of i_mutex from the sysfs code, the death of lookup_one_noperm, and probably a few other weird cases that slip my tongue.
Included in this is the latest version of my work that merges sysfs_move_dir and sysfs_rename_dir to simplify maitenance of.
I have been running these patches for several months so there should be no really nasty surprises in here.
drivers/base/core.c | 18 +- fs/namei.c | 22 -- fs/sysfs/dir.c | 565 ++++++++++++++----------------------------------- fs/sysfs/file.c | 47 +---- fs/sysfs/inode.c | 154 ++++++++------ fs/sysfs/mount.c | 20 +- fs/sysfs/symlink.c | 71 +++---- fs/sysfs/sysfs.h | 25 +-- include/linux/namei.h | 1 - include/linux/sysfs.h | 9 + 10 files changed, 325 insertions(+), 607 deletions(-)
Eric
Quoted 6 lines · Eric W. Biederman
The following patch series cleans up sysfs to the point where itq is generally a good citizen of the vfs layer. The big theme is lazy synchronization from the sysfs data structures to the vfs data structures using the same techniques as most other distributed filesystems.
Hm, I only seem to have gotten patch 0/20, none of the actual patches. Did I somehow miss them?
confused,
greg k-h
Quoted 8 lines · Greg KH
Quoted 6 lines · Eric W. Biederman
The following patch series cleans up sysfs to the point where itq is generally a good citizen of the vfs layer. The big theme is lazy synchronization from the sysfs data structures to the vfs data structures using the same techniques as most other distributed filesystems.
Quoted 4 lines
Hm, I only seem to have gotten patch 0/20, none of the actual patches. Did I somehow miss them?
confused,
Me too.
git-send-email ran. I got copies of the mail sent. But fsdevel and linux-kernel appears not to have received them. Hopefully I can figure out what went wrong shortly. My apologies if anyone receives several copies.
Eric
PATCH 1/20 sysfs: Implement sysfs_rename_link
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Because of rename ordering problems we occassionally give false warnings about invalid sysfs operations, so implement a helper function for this common sysfs idiom.
This is a stripped down version of an earlier patch that also added sysfs_delete_link.
--- fs/sysfs/symlink.c | 16 ++++++++++++++++ include/linux/sysfs.h | 9 +++++++++ 2 files changed, 25 insertions(+), 0 deletions(-)
fs/sysfs/symlink.c +16 -0
@@ -122,6 +122,22 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)sysfs_hash_and_remove (parent_sd, name); } +/** +* sysfs_rename_link - rename symlink in object's directory. +* @kobj: object we're acting for. +* @targ: object we're pointing to. +* @old: previous name of the symlink. +* @new: new name of the symlink. +* +* A helper function for the common rename symlink idiom. +*/ +int sysfs_rename_link (struct kobject *kobj,struct kobject *targ, +const char *old,const char *new) +{ +sysfs_remove_link (kobj, old); +return sysfs_create_link (kobj, targ, new); +} +static int sysfs_get_target_path (struct sysfs_dirent *parent_sd,struct sysfs_dirent *target_sd,char *path) {
include/linux/sysfs.h +9 -0
@@ -109,6 +109,9 @@ int __must_check sysfs_create_link_nowarn(struct kobject *kobj, const char *name);void sysfs_remove_link (struct kobject *kobj,const char *name); +int sysfs_rename_link (struct kobject *kobj,struct kobject *target, +const char *old_name,const char *new_name); +int __must_check sysfs_create_group (struct kobject *kobj,const struct attribute_group *grp); int sysfs_update_group(struct kobject *kobj,
@@ -202,6 +205,12 @@ static inline void sysfs_remove_link(struct kobject *kobj, const char *name) { } +static inline int sysfs_rename_link (struct kobject *k,struct kobject *t, +const char *old_name,const char *new_name) +{ +return 0 ; +} +static inline int sysfs_create_group (struct kobject *kobj,const struct attribute_group *grp) {
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 2/20 driver core: Use sysfs_rename_link in device_rename
From: Eric W. Biederman <[email protected]>
Don't open code the renaming of symlinks in sysfs instead use the new helper function sysfs_rename_link
--- drivers/base/core.c | 18 ++++++------------ 1 files changed, 6 insertions(+), 12 deletions(-)
drivers/base/core.c +6 -12
@@ -1490,22 +1490,16 @@ int device_rename(struct device *dev, char *new_name)if (old_class_name) { new_class_name =make_class_name (dev->class->name, &dev->kobj);if (new_class_name) { - error =sysfs_create_link_nowarn (&dev->parent->kobj, - &dev->kobj, - new_class_name); -if (error) - goto out; -sysfs_remove_link (&dev->parent->kobj, old_class_name); + error =sysfs_rename_link (&dev->parent->kobj, + &dev->kobj, + old_class_name, + new_class_name); } }#else if (dev->class) { - error =sysfs_create_link_nowarn (&dev->class->p->class_subsys.kobj, - &dev->kobj,dev_name (dev)); -if (error) - goto out; -sysfs_remove_link (&dev->class->p->class_subsys.kobj, - old_device_name); + error =sysfs_rename_link (&dev->class->p->class_subsys.kobj, + &dev->kobj, old_device_name, new_name); }#endif
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 3/20 sysfs: Remove now unnecessary error reporting suppression.
From: Eric W. Biederman <[email protected]>
Now that we use sysfs_rename_link in the places we previously used sysfs_create_link_nowarn we can remove sysfs_create_link_nowarn and all it's supporting infrastructure.
--- fs/sysfs/dir.c | 54 +++++++++++---------------------------------------- fs/sysfs/symlink.c | 42 ++++++++------------------------------- fs/sysfs/sysfs.h | 1 - 3 files changed, 21 insertions(+), 76 deletions(-)
fs/sysfs/dir.c +12 -42
@@ -397,43 +397,6 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, }/** -* __sysfs_add_one - add sysfs_dirent to parent without warning -* @acxt: addrm context to use -* @sd: sysfs_dirent to be added -* -* Get @acxt->parent_sd and set sd->s_parent to it and increment -* nlink of parent inode if @sd is a directory and link into the -* children list of the parent. -* -* This function should be called between calls to -* sysfs_addrm_start() and sysfs_addrm_finish() and should be -* passed the same @acxt as passed to sysfs_addrm_start(). -* -* LOCKING: -* Determined by sysfs_addrm_start(). -* -* RETURNS: -* 0 on success, -EEXIST if entry with the given name already -* exists. -*/ -int __sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) -{ -if (sysfs_find_dirent (acxt->parent_sd, sd->s_name)) -return -EEXIST ; - - sd->s_parent =sysfs_get (acxt->parent_sd); - -if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) -inc_nlink (acxt->parent_inode); - - acxt->cnt++; - -sysfs_link_sibling (sd); - -return 0 ; -} - -/** * sysfs_pathname - return full path to sysfs dirent * @sd: sysfs_dirent whose path we want * @path: caller allocated buffer
@@ -475,10 +438,7 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)*/ int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) { -int ret; - - ret =__sysfs_add_one (acxt, sd); -if (ret == -EEXIST ) { +if (sysfs_find_dirent (acxt->parent_sd, sd->s_name)) {char *path =kzalloc (PATH_MAX ,GFP_KERNEL ); WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n",
@@ -486,9 +446,19 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)strcat (strcat (sysfs_pathname (acxt->parent_sd, path),"/" ), sd->s_name));kfree (path); +return -EEXIST ; } -return ret; + sd->s_parent =sysfs_get (acxt->parent_sd); + +if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) +inc_nlink (acxt->parent_inode); + + acxt->cnt++; + +sysfs_link_sibling (sd); + +return 0 ; }/**
fs/sysfs/symlink.c +9 -33
60 lines not on this page · raw message
fs/sysfs/sysfs.h +0 -1
@@ -108,7 +108,6 @@ struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);void sysfs_put_active_two (struct sysfs_dirent *sd);void sysfs_addrm_start (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *parent_sd); -int __sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd);int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd);void sysfs_remove_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd);void sysfs_addrm_finish (struct sysfs_addrm_cxt *acxt);
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 4/20 sysfs: Handle the general case of removing of directories with subdirectories
From: Eric W. Biederman <[email protected]>
Modify sysfs to properly remove directories containing attributes and subdirectories. The code is relatively simple and means we don't have to worry about what might use this logic.
In a quick survey I have only found /sys/dev/char and /sys/dev/block that are removing non-enmpty directories today (and they are exclusively filled with symlinks). So only removing empty directories does not appear to be an option.
I don't hold sysfs_mutex across the entire operation as that is unneeded for coherence at the sysfs level and some level of coordination is expected at the upper layers.
--- fs/sysfs/dir.c | 54 ++++++++++++++++++++++++++---------------------------- 1 files changed, 26 insertions(+), 28 deletions(-)
fs/sysfs/dir.c +25 -27
@@ -732,43 +732,41 @@ const struct inode_operations sysfs_dir_inode_operations = { .setattr = sysfs_setattr, }; -static void remove_dir (struct sysfs_dirent *sd) +static struct sysfs_dirent *sysfs_get_one (struct sysfs_dirent *dir_sd) { -struct sysfs_addrm_cxt acxt; - -sysfs_addrm_start (&acxt, sd->s_parent); -sysfs_remove_one (&acxt, sd); -sysfs_addrm_finish (&acxt); -} - -void sysfs_remove_subdir (struct sysfs_dirent *sd) -{ -remove_dir (sd); +struct sysfs_dirent *sd = dir_sd; +mutex_lock (&sysfs_mutex); +while ((sysfs_type (sd) ==SYSFS_DIR ) && sd->s_dir.children) + sd = sd->s_dir.children; +if (sd != dir_sd) +sysfs_get (sd); +else + sd =NULL ; +mutex_unlock (&sysfs_mutex); +return sd; } - -static void __sysfs_remove_dir (struct sysfs_dirent *dir_sd) +static void remove_dir (struct sysfs_dirent *dir_sd) {struct sysfs_addrm_cxt acxt; -struct sysfs_dirent **pos; - -if (!dir_sd) -return ; +struct sysfs_dirent *sd;pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name); -sysfs_addrm_start (&acxt, dir_sd); - pos = &dir_sd->s_dir.children; -while (*pos) { -struct sysfs_dirent *sd = *pos; -if (sysfs_type (sd) !=SYSFS_DIR ) -sysfs_remove_one (&acxt, sd); -else - pos = &(*pos)->s_sibling; +while ((sd =sysfs_get_one (dir_sd))) { +sysfs_addrm_start (&acxt, sd->s_parent); +sysfs_remove_one (&acxt, sd); +sysfs_addrm_finish (&acxt); +sysfs_put (sd); } +sysfs_addrm_start (&acxt, dir_sd->s_parent); +sysfs_remove_one (&acxt, dir_sd);sysfs_addrm_finish (&acxt); +} -remove_dir (dir_sd); +void sysfs_remove_subdir (struct sysfs_dirent *sd) +{ +remove_dir (sd); }/**
@@ -788,7 +786,7 @@ void sysfs_remove_dir(struct kobject * kobj) kobj->sd =NULL ;spin_unlock (&sysfs_assoc_lock); -__sysfs_remove_dir (sd); +remove_dir (sd); }int sysfs_rename_dir (struct kobject * kobj,const char *new_name)
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 5/20 sysfs: Rename sysfs_d_iput to sysfs_dentry_iput
From: Eric W. Biederman <[email protected]>
Using dentry instead of d in the function name is what several other filesystems are doing and it seems to be a more readable convention.
--- fs/sysfs/dir.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
fs/sysfs/dir.c +2 -2
@@ -294,7 +294,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) goto repeat; } -static void sysfs_d_iput (struct dentry * dentry,struct inode * inode) +static void sysfs_dentry_iput (struct dentry * dentry,struct inode * inode) {struct sysfs_dirent * sd = dentry->d_fsdata;
@@ -303,7 +303,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) }static const struct dentry_operations sysfs_dentry_ops = { - .d_iput = sysfs_d_iput, + .d_iput = sysfs_dentry_iput, };struct sysfs_dirent *sysfs_new_dirent (const char *name,umode_t mode,int type)
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 6/20 sysfs: Use dentry_ops instead of directly playing with the dcache
From: Eric W. Biederman <[email protected]>
Calling d_drop unconditionally when a sysfs_dirent is deleted has the potential to leak mounts, so instead implement dentry delete and revalidate operations that cause sysfs dentries to be removed at the appropriate time.
--- fs/sysfs/dir.c | 73 +++++++++++++++++++++++++++++++++++-------------------- 1 files changed, 46 insertions(+), 27 deletions(-)
fs/sysfs/dir.c +46 -27
@@ -294,6 +294,46 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) goto repeat; } +static int sysfs_dentry_delete (struct dentry *dentry) +{ +struct sysfs_dirent *sd = dentry->d_fsdata; +return !!(sd->s_flags &SYSFS_FLAG_REMOVED ); +} + +static int sysfs_dentry_revalidate (struct dentry *dentry,struct nameidata *nd) +{ +struct sysfs_dirent *sd = dentry->d_fsdata; +int is_dir; + +mutex_lock (&sysfs_mutex); + +/* The sysfs dirent has been deleted */ +if (sd->s_flags &SYSFS_FLAG_REMOVED ) + goto out_bad; + +mutex_unlock (&sysfs_mutex); +out_valid: +return 1 ; +out_bad: +/* Remove the dentry from the dcache hashes. +* If this is a deleted dentry we use d_drop instead of d_delete +* so sysfs doesn't need to cope with negative dentries. +*/ + is_dir = (sysfs_type (sd) ==SYSFS_DIR ); +mutex_unlock (&sysfs_mutex); +if (is_dir) { +/* If we have submounts we must allow the vfs caches +* to lie about the state of the filesystem to prevent +* leaks and other nasty things. +*/ +if (have_submounts (dentry)) + goto out_valid; +shrink_dcache_parent (dentry); + } +d_drop (dentry); +return 0 ; +} +static void sysfs_dentry_iput (struct dentry * dentry,struct inode * inode) {struct sysfs_dirent * sd = dentry->d_fsdata;
@@ -303,6 +343,8 @@ static void sysfs_dentry_iput(struct dentry * dentry, struct inode * inode) }static const struct dentry_operations sysfs_dentry_ops = { + .d_revalidate = sysfs_dentry_revalidate, + .d_delete = sysfs_dentry_delete, .d_iput = sysfs_dentry_iput, };
@@ -493,44 +535,21 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) }/** -* sysfs_drop_dentry - drop dentry for the specified sysfs_dirent +* sysfs_dec_nlink - Decrement link count for the specified sysfs_dirent * @sd: target sysfs_dirent * -* Drop dentry for @sd. @sd must have been unlinked from its +* Decrement nlink for @sd. @sd must have been unlinked from its * parent on entry to this function such that it can't be looked * up anymore. */ -static void sysfs_drop_dentry (struct sysfs_dirent *sd) +static void sysfs_dec_nlink (struct sysfs_dirent *sd) {struct inode *inode; -struct dentry *dentry; inode =ilookup (sysfs_sb, sd->s_ino);if (!inode)return ; -/* Drop any existing dentries associated with sd. -* -* For the dentry to be properly freed we need to grab a -* reference to the dentry under the dcache lock, unhash it, -* and then put it. The playing with the dentry count allows -* dput to immediately free the dentry if it is not in use. -*/ -repeat: -spin_lock (&dcache_lock); -list_for_each_entry (dentry, &inode->i_dentry, d_alias) { -if (d_unhashed (dentry)) -continue ; -dget_locked (dentry); -spin_lock (&dentry->d_lock); -__d_drop (dentry); -spin_unlock (&dentry->d_lock); -spin_unlock (&dcache_lock); -dput (dentry); - goto repeat; - } -spin_unlock (&dcache_lock); -/* adjust nlink and update timestamp */ mutex_lock (&inode->i_mutex);
@@ -577,7 +596,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) acxt->removed = sd->s_sibling; sd->s_sibling =NULL ; -sysfs_drop_dentry (sd); +sysfs_dec_nlink (sd);sysfs_deactivate (sd);unmap_bin_file (sd);sysfs_put (sd);
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 7/20 sysfs: Simplify sysfs_chmod_file semantics
From: Eric W. Biederman <[email protected]>
Currently every caller of sysfs_chmod_file happens at either file creation time to set a non-default mode or in response to a specific user requested space change in policy. Making timestamps of when the chmod happens and notification of a file changing mode uninteresting.
Remove the unnecessary time stamp and filesystem change notification, and removes the last of the explicit inotify and donitfy support from sysfs.
--- fs/sysfs/file.c | 10 +--------- 1 files changed, 1 insertions(+), 9 deletions(-)
fs/sysfs/file.c +1 -9
@@ -602,17 +602,9 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)mutex_lock (&inode->i_mutex); newattrs.ia_mode = (mode &S_IALLUGO ) | (inode->i_mode & ~S_IALLUGO ); - newattrs.ia_valid =ATTR_MODE |ATTR_CTIME ; - newattrs.ia_ctime =current_fs_time (inode->i_sb); + newattrs.ia_valid =ATTR_MODE ; rc =sysfs_setattr (victim, &newattrs); -if (rc ==0 ) { -fsnotify_change (victim, newattrs.ia_valid); -mutex_lock (&sysfs_mutex); - victim_sd->s_mode = newattrs.ia_mode; -mutex_unlock (&sysfs_mutex); - } -mutex_unlock (&inode->i_mutex); out:dput (victim);
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 8/20 sysfs: Optimize just changing the sysfs file mode.
From: Eric W. Biederman <[email protected]>
Don't allocate a struct iattr for the sysfs dentry if just the mode changes because we have a field for that on the sysfs_dirent, and we can trigger that case with sysfs_chmod_file.
--- fs/sysfs/inode.c | 22 ++++++++++++++-------- 1 files changed, 14 insertions(+), 8 deletions(-)
fs/sysfs/inode.c +14 -8
@@ -60,12 +60,16 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)return error; iattr->ia_valid &= ~ATTR_SIZE ;/* ignore size changes */ +if (iattr->ia_valid &ATTR_MODE ) { +if (!in_group_p (inode->i_gid) && !capable (CAP_FSETID )) + iattr->ia_mode &= ~S_ISGID ; + } error =inode_setattr (inode, iattr);if (error)return error; -if (!sd_iattr) { +if (!sd_iattr && (ia_valid & ~ATTR_MODE )) {/* setting attributes for the first time, allocate now */ sd_iattr =kzalloc (sizeof (struct iattr ),GFP_KERNEL );if (!sd_iattr)
@@ -78,6 +82,13 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) sd->s_iattr = sd_iattr; } +if (ia_valid &ATTR_MODE ) + sd->s_mode = iattr->ia_mode; + +/* If we don't need the extra attributes leave */ +if (!sd_iattr) +return 0 ; +/* attributes were changed atleast once in past */ if (ia_valid &ATTR_UID )
@@ -93,13 +104,8 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)if (ia_valid &ATTR_CTIME ) sd_iattr->ia_ctime =timespec_trunc (iattr->ia_ctime, inode->i_sb->s_time_gran); -if (ia_valid &ATTR_MODE ) { -umode_t mode = iattr->ia_mode; - -if (!in_group_p (inode->i_gid) && !capable (CAP_FSETID )) - mode &= ~S_ISGID ; - sd_iattr->ia_mode = sd->s_mode = mode; - } +if (ia_valid &ATTR_MODE ) + sd_iattr->ia_mode = iattr->ia_mode;return error; }
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 9/20 sysfs: Simplify iattr assignments
From: Eric W. Biederman <[email protected]>
The granularity of sysfs time when we keep it is 1 ns. Which when passed to timestamp_trunc results in a nop. So remove the unnecessary function call making sysfs_setattr slightly easier to read.
--- fs/sysfs/inode.c | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-)
fs/sysfs/inode.c +3 -6
@@ -96,14 +96,11 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)if (ia_valid &ATTR_GID ) sd_iattr->ia_gid = iattr->ia_gid;if (ia_valid &ATTR_ATIME ) - sd_iattr->ia_atime =timespec_trunc (iattr->ia_atime, - inode->i_sb->s_time_gran); + sd_iattr->ia_atime = iattr->ia_atime;if (ia_valid &ATTR_MTIME ) - sd_iattr->ia_mtime =timespec_trunc (iattr->ia_mtime, - inode->i_sb->s_time_gran); + sd_iattr->ia_mtime = iattr->ia_mtime;if (ia_valid &ATTR_CTIME ) - sd_iattr->ia_ctime =timespec_trunc (iattr->ia_ctime, - inode->i_sb->s_time_gran); + sd_iattr->ia_ctime = iattr->ia_ctime;if (ia_valid &ATTR_MODE ) sd_iattr->ia_mode = iattr->ia_mode;
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 10/20 sysfs: Fix locking and factor out sysfs_sd_setattr
From: Eric W. Biederman <[email protected]>
Cleanly separate the work that is specific to setting the attributes of a sysfs_dirent from what is needed to update the attributes of a vfs inode.
Additionally grab the sysfs_mutex to keep any nasties from surprising us when updating the sysfs_dirent.
--- fs/sysfs/inode.c | 52 ++++++++++++++++++++++++++++++---------------------- fs/sysfs/sysfs.h | 1 + 2 files changed, 31 insertions(+), 22 deletions(-)
fs/sysfs/inode.c +30 -22
@@ -42,33 +42,12 @@ int __init sysfs_inode_init(void)return bdi_init (&sysfs_backing_dev_info); } -int sysfs_setattr (struct dentry * dentry,struct iattr * iattr) +int sysfs_sd_setattr (struct sysfs_dirent *sd,struct iattr * iattr) { -struct inode * inode = dentry->d_inode; -struct sysfs_dirent * sd = dentry->d_fsdata;struct iattr * sd_iattr;unsigned int ia_valid = iattr->ia_valid; -int error; - -if (!sd) -return -EINVAL ; sd_iattr = sd->s_iattr; - - error =inode_change_ok (inode, iattr); -if (error) -return error; - - iattr->ia_valid &= ~ATTR_SIZE ;/* ignore size changes */ -if (iattr->ia_valid &ATTR_MODE ) { -if (!in_group_p (inode->i_gid) && !capable (CAP_FSETID )) - iattr->ia_mode &= ~S_ISGID ; - } - - error =inode_setattr (inode, iattr); -if (error) -return error; -if (!sd_iattr && (ia_valid & ~ATTR_MODE )) {/* setting attributes for the first time, allocate now */ sd_iattr =kzalloc (sizeof (struct iattr ),GFP_KERNEL );
@@ -103,6 +82,35 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) sd_iattr->ia_ctime = iattr->ia_ctime;if (ia_valid &ATTR_MODE ) sd_iattr->ia_mode = iattr->ia_mode; +return 0 ; +} + +int sysfs_setattr (struct dentry * dentry,struct iattr * iattr) +{ +struct inode * inode = dentry->d_inode; +struct sysfs_dirent * sd = dentry->d_fsdata; +int error; + +if (!sd) +return -EINVAL ; + + error =inode_change_ok (inode, iattr); +if (error) +return error; + + iattr->ia_valid &= ~ATTR_SIZE ;/* ignore size changes */ +if (iattr->ia_valid &ATTR_MODE ) { +if (!in_group_p (inode->i_gid) && !capable (CAP_FSETID )) + iattr->ia_mode &= ~S_ISGID ; + } + + error =inode_setattr (inode, iattr); +if (error) +return error; + +mutex_lock (&sysfs_mutex); + error =sysfs_sd_setattr (sd, iattr); +mutex_unlock (&sysfs_mutex);return error; }
fs/sysfs/sysfs.h +1 -0
@@ -146,6 +146,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd)*/ struct inode *sysfs_get_inode (struct sysfs_dirent *sd);void sysfs_delete_inode (struct inode *inode); +int sysfs_sd_setattr (struct sysfs_dirent *sd,struct iattr *iattr);int sysfs_setattr (struct dentry *dentry,struct iattr *iattr);int sysfs_hash_and_remove (struct sysfs_dirent *dir_sd,const char *name);int sysfs_inode_init (void );
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 11/20 sysfs: Update s_iattr on link and unlink.
From: Eric W. Biederman <[email protected]>
Currently sysfs updates the timestamps on the vfs directory inode when we create or remove a directory entry but doesn't update the cached copy on the sysfs_dirent, fix that oversight.
--- fs/sysfs/dir.c | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-)
fs/sysfs/dir.c +14 -0
@@ -480,6 +480,8 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)*/ int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) { +struct iattr *ps_iattr; +if (sysfs_find_dirent (acxt->parent_sd, sd->s_name)) {char *path =kzalloc (PATH_MAX ,GFP_KERNEL ); WARN(1, KERN_WARNING
@@ -500,6 +502,11 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)sysfs_link_sibling (sd); +/* Update timestamps on the parent */ + ps_iattr = acxt->parent_sd->s_iattr; +if (ps_iattr) + ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; +return 0 ; }
@@ -520,10 +527,17 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)*/ void sysfs_remove_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) { +struct iattr *ps_iattr; +BUG_ON (sd->s_flags &SYSFS_FLAG_REMOVED );sysfs_unlink_sibling (sd); +/* Update timestamps on the parent */ + ps_iattr = acxt->parent_sd->s_iattr; +if (ps_iattr) + ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; + sd->s_flags |=SYSFS_FLAG_REMOVED ; sd->s_sibling = acxt->removed; acxt->removed = sd;
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 12/20 sysfs: Nicely indent sysfs_symlink_inode_operations
From: Eric W. Biederman <[email protected]>
Lining up the functions in sysfs_symlink_inode_operations follows the pattern in the rest of sysfs and makes things slightly more readable.
--- fs/sysfs/symlink.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-)
fs/sysfs/symlink.c +3 -3
@@ -198,9 +198,9 @@ static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *co }const struct inode_operations sysfs_symlink_inode_operations = { - .readlink = generic_readlink, - .follow_link = sysfs_follow_link, - .put_link = sysfs_put_link, + .readlink = generic_readlink, + .follow_link = sysfs_follow_link, + .put_link = sysfs_put_link, };
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 13/20 sysfs: Implement sysfs_getattr & sysfs_permission
From: Eric W. Biederman <[email protected]>
With the implementation of sysfs_getattr and sysfs_permission sysfs becomes able to lazily propogate inode attribute changes
from the sysfs_dirents to the vfs inodes. This paves the way
for deleting significant chunks of now unnecessary code.
--- fs/sysfs/dir.c | 2 + fs/sysfs/inode.c | 54 ++++++++++++++++++++++++++++++++++++++++----------- fs/sysfs/symlink.c | 3 ++ fs/sysfs/sysfs.h | 2 + 4 files changed, 49 insertions(+), 12 deletions(-)
fs/sysfs/dir.c +2 -0
@@ -763,6 +763,8 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,const struct inode_operations sysfs_dir_inode_operations = { .lookup = sysfs_lookup, .setattr = sysfs_setattr, + .getattr = sysfs_getattr, + .permission = sysfs_permission, };static struct sysfs_dirent *sysfs_get_one (struct sysfs_dirent *dir_sd)
fs/sysfs/inode.c +42 -12
89 lines not on this page · raw message
fs/sysfs/symlink.c +3 -0
@@ -201,6 +201,9 @@ const struct inode_operations sysfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = sysfs_follow_link, .put_link = sysfs_put_link, + .setattr = sysfs_setattr, + .getattr = sysfs_getattr, + .permission = sysfs_permission, };
fs/sysfs/sysfs.h +2 -0
@@ -148,6 +148,8 @@ struct inode *sysfs_get_inode(struct sysfs_dirent *sd);void sysfs_delete_inode (struct inode *inode);int sysfs_sd_setattr (struct sysfs_dirent *sd,struct iattr *iattr);int sysfs_setattr (struct dentry *dentry,struct iattr *iattr); +int sysfs_getattr (struct vfsmount *mnt,struct dentry *dentry,struct kstat *stat); +int sysfs_permission (struct inode *inode,int mask);int sysfs_hash_and_remove (struct sysfs_dirent *dir_sd,const char *name);int sysfs_inode_init (void );
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 14/20 sysfs: In sysfs_chmod_file lazily propagate the mode change.
From: Eric W. Biederman <[email protected]>
Now that sysfs_getattr and sysfs_permission refresh the vfs inode there is no need to immediatly push the mode change into the vfs cache. Reducing the amount of work needed and simplifying the locking.
--- fs/sysfs/file.c | 31 ++++++++----------------------- 1 files changed, 8 insertions(+), 23 deletions(-)
fs/sysfs/file.c +8 -23
@@ -577,38 +577,23 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);*/ int sysfs_chmod_file (struct kobject *kobj,struct attribute *attr,mode_t mode) { -struct sysfs_dirent *victim_sd =NULL ; -struct dentry *victim =NULL ; -struct inode * inode; +struct sysfs_dirent *sd;struct iattr newattrs;int rc; - rc = -ENOENT ; - victim_sd =sysfs_get_dirent (kobj->sd, attr->name); -if (!victim_sd) - goto out; +mutex_lock (&sysfs_mutex); -mutex_lock (&sysfs_rename_mutex); - victim =sysfs_get_dentry (victim_sd); -mutex_unlock (&sysfs_rename_mutex); -if (IS_ERR (victim)) { - rc =PTR_ERR (victim); - victim =NULL ; + rc = -ENOENT ; + sd =sysfs_find_dirent (kobj->sd, attr->name); +if (!sd) goto out; - } - - inode = victim->d_inode; -mutex_lock (&inode->i_mutex); - - newattrs.ia_mode = (mode &S_IALLUGO ) | (inode->i_mode & ~S_IALLUGO ); + newattrs.ia_mode = (mode &S_IALLUGO ) | (sd->s_mode & ~S_IALLUGO ); newattrs.ia_valid =ATTR_MODE ; - rc =sysfs_setattr (victim, &newattrs); + rc =sysfs_sd_setattr (sd, &newattrs); -mutex_unlock (&inode->i_mutex); out: -dput (victim); -sysfs_put (victim_sd); +mutex_unlock (&sysfs_mutex);return rc; }EXPORT_SYMBOL_GPL (sysfs_chmod_file);
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 15/20 sysfs: Kill sysfs_addrm_start and sysfs_addrm_finish
From: Eric W. Biederman <[email protected]>
With lazy inode updates and dentry operations bringing everything into sync on demand there is no longer any need to immediately update the vfs or grab i_mutex to protect those updates as we make changes to sysfs.
So stop updating the vfs inodes and move what remains of sysfs_addrm_start and sysfs_addrm_finsih (just barely more than taking the sysfs_mutex) into sysfs_add_one and sysfs_remove_one.
--- fs/sysfs/dir.c | 192 +++++++--------------------------------------------- fs/sysfs/file.c | 6 +-- fs/sysfs/inode.c | 16 ++--- fs/sysfs/symlink.c | 6 +-- fs/sysfs/sysfs.h | 17 +---- 5 files changed, 34 insertions(+), 203 deletions(-)
fs/sysfs/dir.c +25 -167
@@ -382,62 +382,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)return NULL ; } -static int sysfs_ilookup_test (struct inode *inode,void *arg) -{ -struct sysfs_dirent *sd = arg; -return inode->i_ino == sd->s_ino; -} - -/** -* sysfs_addrm_start - prepare for sysfs_dirent add/remove -* @acxt: pointer to sysfs_addrm_cxt to be used -* @parent_sd: parent sysfs_dirent -* -* This function is called when the caller is about to add or -* remove sysfs_dirent under @parent_sd. This function acquires -* sysfs_mutex, grabs inode for @parent_sd if available and lock -* i_mutex of it. @acxt is used to keep and pass context to -* other addrm functions. -* -* LOCKING: -* Kernel thread context (may sleep). sysfs_mutex is locked on -* return. i_mutex of parent inode is locked on return if -* available. -*/ -void sysfs_addrm_start (struct sysfs_addrm_cxt *acxt, -struct sysfs_dirent *parent_sd) -{ -struct inode *inode; - -memset (acxt,0 ,sizeof (*acxt)); - acxt->parent_sd = parent_sd; - -/* Lookup parent inode. inode initialization is protected by -* sysfs_mutex, so inode existence can be determined by -* looking up inode while holding sysfs_mutex. -*/ -mutex_lock (&sysfs_mutex); - - inode =ilookup5 (sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test, - parent_sd); -if (inode) { -WARN_ON (inode->i_state &I_NEW ); - -/* parent inode available */ - acxt->parent_inode = inode; - -/* sysfs_mutex is below i_mutex in lock hierarchy. -* First, trylock i_mutex. If fails, unlock -* sysfs_mutex and lock them in order. -*/ -if (!mutex_trylock (&inode->i_mutex)) { -mutex_unlock (&sysfs_mutex); -mutex_lock (&inode->i_mutex); -mutex_lock (&sysfs_mutex); - } - } -} -/** * sysfs_pathname - return full path to sysfs dirent * @sd: sysfs_dirent whose path we want
@@ -460,161 +404,83 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)/** * sysfs_add_one - add sysfs_dirent to parent -* @acxt: addrm context to use +* @parent_sd: directory to add @sd into * @sd: sysfs_dirent to be added * -* Get @acxt->parent_sd and set sd->s_parent to it and increment +* Get @parent_sd and set sd->s_parent to it and increment * nlink of parent inode if @sd is a directory and link into the * children list of the parent. * -* This function should be called between calls to -* sysfs_addrm_start() and sysfs_addrm_finish() and should be -* passed the same @acxt as passed to sysfs_addrm_start(). -* * LOCKING: -* Determined by sysfs_addrm_start(). +* Kernel thread context (may sleep). Grabs sysfs_mutex. * * RETURNS: * 0 on success, -EEXIST if entry with the given name already * exists. */ -int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) +int sysfs_add_one (struct sysfs_dirent *parent_sd,struct sysfs_dirent *sd) {struct iattr *ps_iattr; -if (sysfs_find_dirent (acxt->parent_sd, sd->s_name)) { -char *path =kzalloc (PATH_MAX ,GFP_KERNEL ); +mutex_lock (&sysfs_mutex); +if (sysfs_find_dirent (parent_sd, sd->s_name)) { +char *path; +mutex_unlock (&sysfs_mutex); + + path =kzalloc (PATH_MAX ,GFP_KERNEL );WARN (1 ,KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n" , (path ==NULL ) ? sd->s_name : -strcat (strcat (sysfs_pathname (acxt->parent_sd, path),"/" ), +strcat (strcat (sysfs_pathname (parent_sd, path),"/" ), sd->s_name));kfree (path);return -EEXIST ; } - sd->s_parent =sysfs_get (acxt->parent_sd); - -if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) -inc_nlink (acxt->parent_inode); - - acxt->cnt++; - + sd->s_parent =sysfs_get (parent_sd);sysfs_link_sibling (sd);/* Update timestamps on the parent */ - ps_iattr = acxt->parent_sd->s_iattr; + ps_iattr = parent_sd->s_iattr;if (ps_iattr) ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; +mutex_unlock (&sysfs_mutex);return 0 ; }/** * sysfs_remove_one - remove sysfs_dirent from parent -* @acxt: addrm context to use * @sd: sysfs_dirent to be removed * * Mark @sd removed and drop nlink of parent inode if @sd is a * directory. @sd is unlinked from the children list. * -* This function should be called between calls to -* sysfs_addrm_start() and sysfs_addrm_finish() and should be -* passed the same @acxt as passed to sysfs_addrm_start(). -* * LOCKING: -* Determined by sysfs_addrm_start(). +* Kernel thread context (may sleep). Grabs sysfs_mutex. */ -void sysfs_remove_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) +void sysfs_remove_one (struct sysfs_dirent *sd) {struct iattr *ps_iattr;BUG_ON (sd->s_flags &SYSFS_FLAG_REMOVED ); +mutex_lock (&sysfs_mutex); +sysfs_unlink_sibling (sd);/* Update timestamps on the parent */ - ps_iattr = acxt->parent_sd->s_iattr; + ps_iattr = sd->s_parent->s_iattr;if (ps_iattr) ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; sd->s_flags |=SYSFS_FLAG_REMOVED ; - sd->s_sibling = acxt->removed; - acxt->removed = sd; - -if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) -drop_nlink (acxt->parent_inode); - - acxt->cnt++; -} -/** -* sysfs_dec_nlink - Decrement link count for the specified sysfs_dirent -* @sd: target sysfs_dirent -* -* Decrement nlink for @sd. @sd must have been unlinked from its -* parent on entry to this function such that it can't be looked -* up anymore. -*/ -static void sysfs_dec_nlink (struct sysfs_dirent *sd) -{ -struct inode *inode; - - inode =ilookup (sysfs_sb, sd->s_ino); -if (!inode) -return ; - -/* adjust nlink and update timestamp */ -mutex_lock (&inode->i_mutex); - - inode->i_ctime =CURRENT_TIME ; -drop_nlink (inode); -if (sysfs_type (sd) ==SYSFS_DIR ) -drop_nlink (inode); - -mutex_unlock (&inode->i_mutex); - -iput (inode); -} - -/** -* sysfs_addrm_finish - finish up sysfs_dirent add/remove -* @acxt: addrm context to finish up -* -* Finish up sysfs_dirent add/remove. Resources acquired by -* sysfs_addrm_start() are released and removed sysfs_dirents are -* cleaned up. Timestamps on the parent inode are updated. -* -* LOCKING: -* All mutexes acquired by sysfs_addrm_start() are released. -*/ -void sysfs_addrm_finish (struct sysfs_addrm_cxt *acxt) -{ -/* release resources acquired by sysfs_addrm_start() */ mutex_unlock (&sysfs_mutex); -if (acxt->parent_inode) { -struct inode *inode = acxt->parent_inode; -/* if added/removed, update timestamps on the parent */ -if (acxt->cnt) - inode->i_ctime = inode->i_mtime =CURRENT_TIME ; - -mutex_unlock (&inode->i_mutex); -iput (inode); - } - -/* kill removed sysfs_dirents */ -while (acxt->removed) { -struct sysfs_dirent *sd = acxt->removed; - - acxt->removed = sd->s_sibling; - sd->s_sibling =NULL ; - -sysfs_dec_nlink (sd); -sysfs_deactivate (sd); -unmap_bin_file (sd); -sysfs_put (sd); - } +sysfs_deactivate (sd); +unmap_bin_file (sd); +sysfs_put (sd); }/**
@@ -673,7 +539,6 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, const char *name, struct sysfs_dirent **p_sd) { umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; -struct sysfs_addrm_cxt acxt;struct sysfs_dirent *sd;int rc;
@@ -684,10 +549,8 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, sd->s_dir.kobj = kobj;/* link in */ -sysfs_addrm_start (&acxt, parent_sd); - rc =sysfs_add_one (&acxt, sd); -sysfs_addrm_finish (&acxt); + rc =sysfs_add_one (parent_sd, sd);if (rc ==0 ) *p_sd = sd;else
@@ -783,20 +646,15 @@ static struct sysfs_dirent *sysfs_get_one(struct sysfs_dirent *dir_sd)static void remove_dir (struct sysfs_dirent *dir_sd) { -struct sysfs_addrm_cxt acxt;struct sysfs_dirent *sd;pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name);while ((sd =sysfs_get_one (dir_sd))) { -sysfs_addrm_start (&acxt, sd->s_parent); -sysfs_remove_one (&acxt, sd); -sysfs_addrm_finish (&acxt); +sysfs_remove_one (sd);sysfs_put (sd); } -sysfs_addrm_start (&acxt, dir_sd->s_parent); -sysfs_remove_one (&acxt, dir_sd); -sysfs_addrm_finish (&acxt); +sysfs_remove_one (dir_sd); }void sysfs_remove_subdir (struct sysfs_dirent *sd)
fs/sysfs/file.c +1 -5
@@ -499,7 +499,6 @@ int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, const struct attribute *attr, int type, mode_t amode) { umode_t mode = (amode & S_IALLUGO) | S_IFREG; -struct sysfs_addrm_cxt acxt;struct sysfs_dirent *sd;int rc;
@@ -508,10 +507,7 @@ int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,return -ENOMEM ; sd->s_attr.attr = (void *)attr; -sysfs_addrm_start (&acxt, dir_sd); - rc =sysfs_add_one (&acxt, sd); -sysfs_addrm_finish (&acxt); - + rc =sysfs_add_one (dir_sd, sd);if (rc)sysfs_put (sd);
fs/sysfs/inode.c +5 -11
@@ -263,23 +263,17 @@ void sysfs_delete_inode(struct inode *inode)int sysfs_hash_and_remove (struct sysfs_dirent *dir_sd,const char *name) { -struct sysfs_addrm_cxt acxt;struct sysfs_dirent *sd;if (!dir_sd)return -ENOENT ; -sysfs_addrm_start (&acxt, dir_sd); - - sd =sysfs_find_dirent (dir_sd, name); -if (sd) -sysfs_remove_one (&acxt, sd); - -sysfs_addrm_finish (&acxt); - -if (sd) + sd =sysfs_get_dirent (dir_sd, name); +if (sd) { +sysfs_remove_one (sd); +sysfs_put (sd);return 0 ; -else + }else return -ENOENT ; }
fs/sysfs/symlink.c +1 -5
@@ -31,7 +31,6 @@ int sysfs_create_link(struct kobject *kobj, struct kobject *target,struct sysfs_dirent *parent_sd =NULL ;struct sysfs_dirent *target_sd =NULL ;struct sysfs_dirent *sd =NULL ; -struct sysfs_addrm_cxt acxt;int error;BUG_ON (!name);
@@ -65,10 +64,7 @@ int sysfs_create_link(struct kobject *kobj, struct kobject *target, sd->s_symlink.target_sd = target_sd; target_sd =NULL ;/* reference is now owned by the symlink */ -sysfs_addrm_start (&acxt, parent_sd); - error =sysfs_add_one (&acxt, sd); -sysfs_addrm_finish (&acxt); - + error =sysfs_add_one (parent_sd, sd);if (error) goto out_put;
fs/sysfs/sysfs.h +2 -15
@@ -77,16 +77,6 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd) }/* -* Context structure to be used while adding/removing nodes. -*/ -struct sysfs_addrm_cxt { -struct sysfs_dirent *parent_sd; -struct inode *parent_inode; -struct sysfs_dirent *removed; -int cnt; -}; - -/* * mount.c */ extern struct sysfs_dirent sysfs_root;
@@ -106,11 +96,8 @@ extern const struct inode_operations sysfs_dir_inode_operations;struct dentry *sysfs_get_dentry (struct sysfs_dirent *sd);struct sysfs_dirent *sysfs_get_active_two (struct sysfs_dirent *sd);void sysfs_put_active_two (struct sysfs_dirent *sd); -void sysfs_addrm_start (struct sysfs_addrm_cxt *acxt, -struct sysfs_dirent *parent_sd); -int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd); -void sysfs_remove_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd); -void sysfs_addrm_finish (struct sysfs_addrm_cxt *acxt); +int sysfs_add_one (struct sysfs_dirent *parent_sd,struct sysfs_dirent *sd); +void sysfs_remove_one (struct sysfs_dirent *sd);struct sysfs_dirent *sysfs_find_dirent (struct sysfs_dirent *parent_sd,const unsigned char *name);
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 16/20 sysfs: Propagate renames to the vfs on demand
From: Eric W. Biederman <[email protected]>
By teaching sysfs_revalidate to hide a dentry for a sysfs_dirent if the sysfs_dirent has been renamed, and by teaching sysfs_lookup to return the original dentry if the sysfs dirent has been renamed. I can show the results of renames correctly without having to update the dcache during the directory rename.
This massively simplifies the rename logic allowing a lot of weird sysfs special cases to be removed along with a lot of now unnecesary helper code.
--- fs/namei.c | 22 ------- fs/sysfs/dir.c | 156 ++++++++++--------------------------------------- fs/sysfs/inode.c | 12 ---- fs/sysfs/sysfs.h | 1 - include/linux/namei.h | 1 - 5 files changed, 32 insertions(+), 160 deletions(-)
fs/namei.c +0 -22
@@ -1260,28 +1260,6 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)return __lookup_hash (&this, base,NULL ); } -/** -* lookup_one_noperm - bad hack for sysfs -* @name: pathname component to lookup -* @base: base directory to lookup from -* -* This is a variant of lookup_one_len that doesn't perform any permission -* checks. It's a horrible hack to work around the braindead sysfs -* architecture and should not be used anywhere else. -* -* DON'T USE THIS FUNCTION EVER, thanks. -*/ -struct dentry *lookup_one_noperm (const char *name,struct dentry *base) -{ -int err; -struct qstr this; - - err =__lookup_one_len (name, &this, base,strlen (name)); -if (err) -return ERR_PTR (err); -return __lookup_hash (&this, base,NULL ); -} -int user_path_at (int dfd,const char __user *name,unsigned flags,struct path *path) {
fs/sysfs/dir.c +32 -124
238 lines not on this page · raw message
fs/sysfs/inode.c +0 -12
@@ -132,17 +132,6 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) inode->i_ctime = iattr->ia_ctime; } - -/* -* sysfs has a different i_mutex lock order behavior for i_mutex than other -* filesystems; sysfs i_mutex is called in many places with subsystem locks -* held. At the same time, many of the VFS locking rules do not apply to -* sysfs at all (cross directory rename for example). To untangle this mess -* (which gives false positives in lockdep), we're giving sysfs inodes their -* own class for i_mutex. -*/ -static struct lock_class_key sysfs_inode_imutex_key; -static int sysfs_count_nlink (struct sysfs_dirent *sd) {struct sysfs_dirent *child;
@@ -190,7 +179,6 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) inode->i_mapping->a_ops = &sysfs_aops; inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; inode->i_op = &sysfs_inode_operations; -lockdep_set_class (&inode->i_mutex, &sysfs_inode_imutex_key);set_default_inode_attr (inode, sd->s_mode);sysfs_refresh_inode (sd, inode);
fs/sysfs/sysfs.h +0 -1
@@ -87,7 +87,6 @@ extern struct kmem_cache *sysfs_dir_cachep;* dir.c */ extern struct mutex sysfs_mutex; -extern struct mutex sysfs_rename_mutex;extern spinlock_t sysfs_assoc_lock;extern const struct file_operations sysfs_dir_operations;
include/linux/namei.h +0 -1
@@ -76,7 +76,6 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);extern void release_open_intent (struct nameidata *);extern struct dentry *lookup_one_len (const char *,struct dentry *,int ); -extern struct dentry *lookup_one_noperm (const char *,struct dentry *);extern int follow_down (struct vfsmount **,struct dentry **);extern int follow_up (struct vfsmount **,struct dentry **);
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 17/20 sysfs: Merge sysfs_rename_dir and sysfs_move_dir
From: Eric W. Biederman <[email protected]>
These two functions do 90% of the same work and it doesn't significantly obfuscate the function to allow both the parent dir and the name to change at the same time. So merge them together to simplify maintenance, and increase testing.
--- fs/sysfs/dir.c | 66 +++++++++++++++++++++++-------------------------------- 1 files changed, 28 insertions(+), 38 deletions(-)
fs/sysfs/dir.c +28 -38
@@ -660,30 +660,42 @@ void sysfs_remove_dir(struct kobject * kobj)remove_dir (sd); } -int sysfs_rename_dir (struct kobject * kobj,const char *new_name) +static int sysfs_mv_dir (struct sysfs_dirent *sd, +struct sysfs_dirent *new_parent_sd,const char *new_name) { -struct sysfs_dirent *sd = kobj->sd;const char *dup_name =NULL ;int error;mutex_lock (&sysfs_mutex); error =0 ; -if (strcmp (sd->s_name, new_name) ==0 ) +if ((sd->s_parent == new_parent_sd) && + (strcmp (sd->s_name, new_name) ==0 )) goto out;/* nothing to rename */ error = -EEXIST ; -if (sysfs_find_dirent (sd->s_parent, new_name)) +if (sysfs_find_dirent (new_parent_sd, new_name)) goto out;/* rename sysfs_dirent */ - error = -ENOMEM ; - new_name = dup_name =kstrdup (new_name,GFP_KERNEL ); -if (!new_name) - goto out; +if (strcmp (sd->s_name, new_name) !=0 ) { + error = -ENOMEM ; + new_name = dup_name =kstrdup (new_name,GFP_KERNEL ); +if (!new_name) + goto out; + + dup_name = sd->s_name; + sd->s_name = new_name; + } - dup_name = sd->s_name; - sd->s_name = new_name; +/* Remove from old parent's list and insert into new parent's list. */ +if (sd->s_parent != new_parent_sd) { +sysfs_unlink_sibling (sd); +sysfs_get (new_parent_sd); +sysfs_put (sd->s_parent); + sd->s_parent = new_parent_sd; +sysfs_link_sibling (sd); + } error =0 ; out:
@@ -692,36 +704,14 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)return error; } -int sysfs_move_dir (struct kobject *kobj,struct kobject *new_parent_kobj) +int sysfs_rename_dir (struct kobject * kobj,const char *new_name) { -struct sysfs_dirent *sd = kobj->sd; -struct sysfs_dirent *new_parent_sd; -int error; - -BUG_ON (!sd->s_parent); - -mutex_lock (&sysfs_mutex); - new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; - - error =0 ; -if (sd->s_parent == new_parent_sd) - goto out;/* nothing to move */ - - error = -EEXIST ; -if (sysfs_find_dirent (new_parent_sd, sd->s_name)) - goto out; - -/* Remove from old parent's list and insert into new parent's list. */ -sysfs_unlink_sibling (sd); -sysfs_get (new_parent_sd); -sysfs_put (sd->s_parent); - sd->s_parent = new_parent_sd; -sysfs_link_sibling (sd); +return sysfs_mv_dir (kobj->sd, kobj->sd->s_parent, new_name); +} - error =0 ; -out: -mutex_unlock (&sysfs_mutex); -return error; +int sysfs_move_dir (struct kobject *kobj,struct kobject *new_parent_kobj) +{ +return sysfs_mv_dir (kobj->sd, new_parent_kobj->sd, kobj->sd->s_name); }/* Relationship between s_mode and the DT_xxx types */
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 18/20 sysfs: Pass super_block to sysfs_get_inode
From: Eric W. Biederman <[email protected]>
Currently sysfs_get_inode magically returns an inode on sysfs_sb. Make the super_block parameter explicit and the code becomes clearer.
--- fs/sysfs/dir.c | 2 +- fs/sysfs/inode.c | 5 +++-- fs/sysfs/mount.c | 2 +- fs/sysfs/sysfs.h | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-)
fs/sysfs/dir.c +1 -1
@@ -579,7 +579,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, }/* attach dentry and inode */ - inode =sysfs_get_inode (sd); + inode =sysfs_get_inode (dir->i_sb, sd);if (!inode) { ret =ERR_PTR (-ENOMEM ); goto out_unlock;
fs/sysfs/inode.c +3 -2
@@ -210,6 +210,7 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)/** * sysfs_get_inode - get inode for sysfs_dirent +* @sb: super block * @sd: sysfs_dirent to allocate inode for * * Get inode for @sd. If such inode doesn't exist, a new inode
@@ -222,11 +223,11 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)* RETURNS: * Pointer to allocated inode on success, NULL on failure. */ -struct inode *sysfs_get_inode (struct sysfs_dirent *sd) +struct inode *sysfs_get_inode (struct super_block *sb,struct sysfs_dirent *sd) {struct inode *inode; - inode =iget_locked (sysfs_sb, sd->s_ino); + inode =iget_locked (sb, sd->s_ino);if (inode && (inode->i_state &I_NEW ))sysfs_init_inode (sd, inode);
fs/sysfs/mount.c +1 -1
@@ -54,7 +54,7 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)/* get root inode, initialize and unlock it */ mutex_lock (&sysfs_mutex); - inode =sysfs_get_inode (&sysfs_root); + inode =sysfs_get_inode (sb, &sysfs_root);mutex_unlock (&sysfs_mutex);if (!inode) {pr_debug ("sysfs: could not get root inode\n" );
fs/sysfs/sysfs.h +1 -1
@@ -130,7 +130,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd)/* * inode.c */ -struct inode *sysfs_get_inode (struct sysfs_dirent *sd); +struct inode *sysfs_get_inode (struct super_block *sb,struct sysfs_dirent *sd);void sysfs_delete_inode (struct inode *inode);int sysfs_sd_setattr (struct sysfs_dirent *sd,struct iattr *iattr);int sysfs_setattr (struct dentry *dentry,struct iattr *iattr);
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 19/20 sysfs: Kill unused sysfs_sb variable.
From: Eric W. Biederman <[email protected]>
Now that there are no more users we can remove
the sysfs_sb variable.
--- fs/sysfs/mount.c | 2 -- fs/sysfs/sysfs.h | 1 - 2 files changed, 0 insertions(+), 3 deletions(-)
fs/sysfs/mount.c +0 -2
@@ -23,7 +23,6 @@static struct vfsmount *sysfs_mount; -struct super_block * sysfs_sb =NULL ;struct kmem_cache *sysfs_dir_cachep;static const struct super_operations sysfs_ops = {
@@ -50,7 +49,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_magic =SYSFS_MAGIC ; sb->s_op = &sysfs_ops; sb->s_time_gran =1 ; - sysfs_sb = sb;/* get root inode, initialize and unlock it */ mutex_lock (&sysfs_mutex);
fs/sysfs/sysfs.h +0 -1
@@ -80,7 +80,6 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd)* mount.c */ extern struct sysfs_dirent sysfs_root; -extern struct super_block *sysfs_sb;extern struct kmem_cache *sysfs_dir_cachep;/*
Signature · 1 line
1.6.1.2.350.g88cc
PATCH 20/20 sysfs: Normalize error handling in sysfs_fill_inode
From: Eric W. Biederman <[email protected]>
Use a single error exit path instead of doing whatever is the required cleanup at each point we find the error. Ultimately this should make the code more maintainable.
--- fs/sysfs/mount.c | 16 +++++++++++----- 1 files changed, 11 insertions(+), 5 deletions(-)
fs/sysfs/mount.c +11 -5
@@ -41,8 +41,9 @@ struct sysfs_dirent sysfs_root = {static int sysfs_fill_super (struct super_block *sb,void *data,int silent) { -struct inode *inode; -struct dentry *root; +struct inode *inode =NULL ; +struct dentry *root =NULL ; +int error; sb->s_blocksize =PAGE_CACHE_SIZE ; sb->s_blocksize_bits =PAGE_CACHE_SHIFT ;
@@ -51,24 +52,29 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_time_gran =1 ;/* get root inode, initialize and unlock it */ + error = -ENOMEM ;mutex_lock (&sysfs_mutex); inode =sysfs_get_inode (sb, &sysfs_root);mutex_unlock (&sysfs_mutex);if (!inode) {pr_debug ("sysfs: could not get root inode\n" ); -return -ENOMEM ; + goto err_out; }/* instantiate and link root dentry */ + error = -ENOMEM ; root =d_alloc_root (inode);if (!root) {pr_debug ("%s: could not get root dentry!\n" ,__func__); -iput (inode); -return -ENOMEM ; + goto err_out; } root->d_fsdata = &sysfs_root; sb->s_root = root;return 0 ; +err_out: +dput (root); +iput (inode); +return error; } static int sysfs_get_sb(struct file_system_type *fs_type,
Signature · 1 line
1.6.1.2.350.g88cc
Re: [PATCH 20/20] sysfs: Normalize error handling in sysfs_fill_inode
Quoted 7 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Use a single error exit path instead of doing whatever is the required cleanup at each point we find the error. Ultimately this should make the code more maintainable.
Signed-off-by Eric W. Biederman <[email protected]>
For 0018-0020,
Thanks.
Signature · 1 line
tejun
Re: [PATCH 20/20] sysfs: Normalize error handling in sysfs_fill_inode
Quoted 7 lines · Tejun Heo
Quoted 6 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Use a single error exit path instead of doing whatever is the required cleanup at each point we find the error. Ultimately this should make the code more maintainable.
Quoted 5 lines
Quoted 1 line
Signed-off-by Eric W. Biederman <[email protected]>For 0018-0020,
Acked-by Tejun Heo <[email protected]>
Thanks for taking the time to review these patches.
Eric
Re: [PATCH 17/20] sysfs: Merge sysfs_rename_dir and sysfs_move_dir
In reply to Eric W. BiedermanQuoted 8 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
These two functions do 90% of the same work and it doesn't significantly obfuscate the function to allow both the parent dir and the name to change at the same time. So merge them together to simplify maintenance, and increase testing.
Signed-off-by Eric W. Biederman <[email protected]>
Signature · 1 line
tejun
Re: [PATCH 16/20] sysfs: Propagate renames to the vfs on demand
In reply to Eric W. BiedermanQuoted 9 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
By teaching
sysfs_revalidateto hide a dentry for asysfs_direntif thesysfs_direnthas been renamed, and by teachingsysfs_lookupto return the original dentry if the sysfs dirent has been renamed. I can show the results of renames correctly without having to update the dcache during the directory rename.
Quoted 5 lines
This massively simplifies the rename logic allowing a lot of weird sysfs special cases to be removed along with a lot of now unnecesary helper code.
Signed-off-by Eric W. Biederman <[email protected]>
It's probably a good idea to cc Al Viro?
Quoted 16 lines
fs/sysfs/dir.c +8
-0@@ -311,6 +270,14 @@ static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd)if (sd->s_flags &SYSFS_FLAG_REMOVED ) goto out_bad; +/* The sysfs dirent has been moved? */ +if (dentry->d_parent->d_fsdata != sd->s_parent) + goto out_bad; + +/* The sysfs dirent has been renamed */ +if (strcmp (dentry->d_name.name, sd->s_name) !=0 ) + goto out_bad; +mutex_unlock (&sysfs_mutex); out_valid:return 1 ;
fs/sysfs/dir.c out_bad: · line 290
Quoted 6 lines
fs/sysfs/dir.c +3
-0@@ -318,6 +285,12 @@ out_bad:/* Remove the dentry from the dcache hashes. * If this is a deleted dentry we use d_drop instead of d_delete * so sysfs doesn't need to cope with negative dentries. +* +* If this is a dentry that has simply been renamed we +* use d_drop to remove it from the dcache lookup on it's
^^^^ its
fs/sysfs/dir.c out_bad: · line 292
Quoted 2 lines
fs/sysfs/dir.c +2
-0+* old parent. If this dentry persists later when a lookup +* is performed at it's new name the dentry will be readded
^^^^ its
Other than the above comment changes,
Signature · 1 line
tejun
Re: [PATCH 15/20] sysfs: Kill sysfs_addrm_start and sysfs_addrm_finish
In reply to Eric W. BiedermanQuoted 7 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
With lazy inode updates and dentry operations bringing everything into sync on demand there is no longer any need to immediately update the vfs or grab
i_mutexto protect those updates as we make changes to sysfs.
Quoted 5 lines
So stop updating the vfs inodes and move what remains of
sysfs_addrm_startandsysfs_addrm_finsih(just barely more than taking thesysfs_mutex) intosysfs_add_oneandsysfs_remove_one.Signed-off-by Eric W. Biederman <[email protected]>
This looks so better than the original code. :-)
Signature · 1 line
tejun
Re: [PATCH 14/20] sysfs: In sysfs_chmod_file lazily propagate the mode change.
In reply to Eric W. BiedermanQuoted 8 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Now that
sysfs_getattrandsysfs_permissionrefresh the vfs inode there is no need to immediatly push the mode change into the vfs cache. Reducing the amount of work needed and simplifying the locking.Signed-off-by Eric W. Biederman <[email protected]>
Cool.
Signature · 1 line
tejun
Re: [PATCH 13/20] sysfs: Implement sysfs_getattr & sysfs_permission
In reply to Eric W. BiedermanQuoted 8 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
With the implementation of
sysfs_getattrandsysfs_permissionsysfs becomes able to lazily propogate inode attribute changes
from thesysfs_direntsto the vfs inodes. This paves the way
for deleting significant chunks of now unnecessary code.Signed-off-by Eric W. Biederman <[email protected]>
Signature · 1 line
tejun
Re: [PATCH 12/20] sysfs: Nicely indent sysfs_symlink_inode_operations
In reply to Eric W. BiedermanQuoted 7 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Lining up the functions in
sysfs_symlink_inode_operationsfollows the pattern in the rest of sysfs and makes things slightly more readable.Signed-off-by Eric W. Biederman <[email protected]>
Signature · 1 line
tejun
Re: [PATCH 11/20] sysfs: Update s_iattr on link and unlink.
In reply to Eric W. BiedermanQuoted 7 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Currently sysfs updates the timestamps on the vfs directory inode when we create or remove a directory entry but doesn't update the cached copy on the
sysfs_dirent, fix that oversight.Signed-off-by Eric W. Biederman <[email protected]>
Signature · 1 line
tejun
Re: [PATCH 10/20] sysfs: Fix locking and factor out sysfs_sd_setattr
In reply to Eric W. BiedermanQuoted 10 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Cleanly separate the work that is specific to setting the attributes of a
sysfs_direntfrom what is needed to update the attributes of a vfs inode.Additionally grab the
sysfs_mutexto keep any nasties from surprising us when updating thesysfs_dirent.Signed-off-by Eric W. Biederman <[email protected]>
Signature · 1 line
tejun
Re: [PATCH 09/20] sysfs: Simplify iattr assignments
In reply to Eric W. BiedermanQuoted 8 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
The granularity of sysfs time when we keep it is 1 ns. Which when passed to
timestamp_truncresults in a nop. So remove the unnecessary function call makingsysfs_setattrslightly easier to read.Signed-off-by Eric W. Biederman <[email protected]>
Signature · 1 line
tejun
Re: [PATCH 08/20] sysfs: Optimize just changing the sysfs file mode.
In reply to Eric W. BiedermanQuoted 34 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Don't allocate a struct iattr for the sysfs dentry if just the mode changes because we have a field for that on the
sysfs_dirent, and we can trigger that case withsysfs_chmod_file.Signed-off-by Eric W. Biederman <[email protected]>--- fs/sysfs/inode.c | 22 ++++++++++++++-------- 1 files changed, 14 insertions(+), 8 deletions(-)fs/sysfs/inode.c +5
-1@@ -60,12 +60,16 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)return error; iattr->ia_valid &= ~ATTR_SIZE ;/* ignore size changes */ +if (iattr->ia_valid &ATTR_MODE ) { +if (!in_group_p (inode->i_gid) && !capable (CAP_FSETID )) + iattr->ia_mode &= ~S_ISGID ; + } error =inode_setattr (inode, iattr);if (error)return error; -if (!sd_iattr) { +if (!sd_iattr && (ia_valid & ~ATTR_MODE )) {/* setting attributes for the first time, allocate now */ sd_iattr =kzalloc (sizeof (struct iattr ),GFP_KERNEL );if (!sd_iattr)
fs/sysfs/inode.c int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) · line 90
Quoted 9 lines
fs/sysfs/inode.c +6
-0@@ -78,6 +82,13 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) sd->s_iattr = sd_iattr; } +if (ia_valid &ATTR_MODE ) + sd->s_mode = iattr->ia_mode; + +/* If we don't need the extra attributes leave */ +if (!sd_iattr) +return 0 ;
One visible difference is lack of timestamp update. Is there any use case where sysfs file mode changing needs to be fast?
Thanks.
Signature · 1 line
tejun
Re: [PATCH 08/20] sysfs: Optimize just changing the sysfs file mode.
Quoted 38 lines · Tejun Heo
Quoted 37 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Don't allocate a struct iattr for the sysfs dentry if just the mode changes because we have a field for that on the
sysfs_dirent, and we can trigger that case withsysfs_chmod_file.Signed-off-by Eric W. Biederman <[email protected]>--- fs/sysfs/inode.c | 22 ++++++++++++++-------- 1 files changed, 14 insertions(+), 8 deletions(-)fs/sysfs/inode.c +5
-1@@ -60,12 +60,16 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)return error; iattr->ia_valid &= ~ATTR_SIZE ;/* ignore size changes */ +if (iattr->ia_valid &ATTR_MODE ) { +if (!in_group_p (inode->i_gid) && !capable (CAP_FSETID )) + iattr->ia_mode &= ~S_ISGID ; + } error =inode_setattr (inode, iattr);if (error)return error; -if (!sd_iattr) { +if (!sd_iattr && (ia_valid & ~ATTR_MODE )) {/* setting attributes for the first time, allocate now */ sd_iattr =kzalloc (sizeof (struct iattr ),GFP_KERNEL );if (!sd_iattr)@@ -78,6 +82,13 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) sd->s_iattr = sd_iattr; }
Quoted 9 lines
fs/sysfs/inode.c int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) · line 90
Quoted 6 lines
fs/sysfs/inode.c +6
-0+if (ia_valid &ATTR_MODE ) + sd->s_mode = iattr->ia_mode; + +/* If we don't need the extra attributes leave */ +if (!sd_iattr) +return 0 ;One visible difference is lack of timestamp update. Is there any use case where sysfs file mode changing needs to be fast?\
Not really. If the time changes we set something besides ATTR_MODE like ATTR_MTIME or ATTR_CTIME. If we come in through any of the user space entry points ATTR_CTIME appears to be set so this optimization will not trigger.
I think there are cases where we only opportunistically track time changes, when the structure is allocated that this changes but it is a very small percentage of the time.
The practical effect of my changes should be that we only track timestamps when user space actually performs an explicit change to the file.
If someone was depending on some weird indirect side effect like that on one of the 5-6 files that calls sysfs_chmod let's make it explicit.
For me this isn't about making this go faster. This is about keeping the sysfs data structures small when we can.
It doesn't really complicate the code and we wind up doing the obvious thing.
Eric
Re: [PATCH 08/20] sysfs: Optimize just changing the sysfs file mode.
Hello,
Quoted 15 lines · Eric W. Biederman
Quoted 2 lines
One visible difference is lack of timestamp update. Is there any use case where sysfs file mode changing needs to be fast?\
Not really. If the time changes we set something besides
ATTR_MODElikeATTR_MTIMEorATTR_CTIME. If we come in through any of the user space entry pointsATTR_CTIMEappears to be set so this optimization will not trigger.I think there are cases where we only opportunistically track time changes, when the structure is allocated that this changes but it is a very small percentage of the time.
The practical effect of my changes should be that we only track timestamps when user space actually performs an explicit change to the file.
Quoted 7 lines
If someone was depending on some weird indirect side effect like that on one of the 5-6 files that calls
sysfs_chmodlet's make it explicit.For me this isn't about making this go faster. This is about keeping the sysfs data structures small when we can.
It doesn't really complicate the code and we wind up doing the obvious thing.
Well, it doesn't add a lot of complexity but also seems pointless when there basically is no use case which would benefit from this change. I suppose it's upto the maintainer. Greg?
Thanks.
Signature · 1 line
tejun
Re: [PATCH 07/20] sysfs: Simplify sysfs_chmod_file semantics
In reply to Eric W. BiedermanQuoted 8 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Currently every caller of
sysfs_chmod_filehappens at either file creation time to set a non-default mode or in response to a specific user requested space change in policy. Making timestamps of when the chmod happens and notification of a file changing mode uninteresting.
Quoted 5 lines
Remove the unnecessary time stamp and filesystem change notification, and removes the last of the explicit inotify and donitfy support from sysfs.
Signed-off-by Eric W. Biederman <[email protected]>
If Greg is okay with this,
Signature · 1 line
tejun
Re: [PATCH 06/20] sysfs: Use dentry_ops instead of directly playing with the dcache
In reply to Eric W. BiedermanHello,
Quoted 6 lines · Eric W. Biederman
Calling
d_dropunconditionally when asysfs_direntis deleted has the potential to leak mounts, so instead implement dentry delete and revalidate operations that cause sysfs dentries to be removed at the appropriate time.Signed-off-by Eric W. Biederman <[email protected]>
Great, thanks for doing this. It's much better than the fragile vfs tinkering sysfs has been doing.
Quoted 23 lines
fs/sysfs/dir.c +23
-0+static int sysfs_dentry_revalidate (struct dentry *dentry,struct nameidata *nd) +{ +struct sysfs_dirent *sd = dentry->d_fsdata; +int is_dir; + +mutex_lock (&sysfs_mutex); + +/* The sysfs dirent has been deleted */ +if (sd->s_flags &SYSFS_FLAG_REMOVED ) + goto out_bad; + +mutex_unlock (&sysfs_mutex); +out_valid: +return 1 ; +out_bad: +/* Remove the dentry from the dcache hashes. +* If this is a deleted dentry we use d_drop instead of d_delete +* so sysfs doesn't need to cope with negative dentries. +*/ + is_dir = (sysfs_type (sd) ==SYSFS_DIR ); +mutex_unlock (&sysfs_mutex); +if (is_dir) { +/* If we have submounts we must allow the vfs caches
fs/sysfs/dir.c void release_sysfs_dirent(struct sysfs_dirent * sd) · line 335
Quoted 10 lines
fs/sysfs/dir.c +10
-0+* to lie about the state of the filesystem to prevent +* leaks and other nasty things. +*/ +if (have_submounts (dentry)) + goto out_valid; +shrink_dcache_parent (dentry); + } +d_drop (dentry); +return 0 ; +}
Ummm... what happens if sysfs recreates those identical nodes again while the old dentries are lingering? The dead ones will linger till the submounts are gone and then look ups after that will show the new ones, right?
Thanks.
Signature · 1 line
tejun
Re: [PATCH 06/20] sysfs: Use dentry_ops instead of directly playing with the dcache
Quoted 30 lines · Tejun Heo
Quoted 30 lines
fs/sysfs/dir.c +30
-0+static int sysfs_dentry_revalidate (struct dentry *dentry,struct nameidata *nd) +{ +struct sysfs_dirent *sd = dentry->d_fsdata; +int is_dir; + +mutex_lock (&sysfs_mutex); + +/* The sysfs dirent has been deleted */ +if (sd->s_flags &SYSFS_FLAG_REMOVED ) + goto out_bad; + +mutex_unlock (&sysfs_mutex); +out_valid: +return 1 ; +out_bad: +/* Remove the dentry from the dcache hashes. +* If this is a deleted dentry we use d_drop instead of d_delete +* so sysfs doesn't need to cope with negative dentries. +*/ + is_dir = (sysfs_type (sd) ==SYSFS_DIR ); +mutex_unlock (&sysfs_mutex); +if (is_dir) { +/* If we have submounts we must allow the vfs caches +* to lie about the state of the filesystem to prevent +* leaks and other nasty things. +*/ +if (have_submounts (dentry)) + goto out_valid; +shrink_dcache_parent (dentry); + }
Quoted 8 lines
fs/sysfs/dir.c void release_sysfs_dirent(struct sysfs_dirent * sd) · line 335
Quoted 3 lines
fs/sysfs/dir.c +3
-0+d_drop (dentry); +return 0 ; +}Ummm... what happens if sysfs recreates those identical nodes again while the old dentries are lingering? The dead ones will linger till the submounts are gone and then look ups after that will show the new ones, right?
Yep. On the vfs level. The sysfs dirent tree will reflect what is going on with the hardware.
This is a vfs misfeature, that I hope someday we will get fixed. But for now it is better not to leak mount points. Especially since no one actually mounts things on sysfs.
Eric
Tejun Heo
Acked-byRe: [PATCH 06/20] sysfs: Use dentry_ops instead of directly playing with the dcache
Quoted 11 lines · Eric W. Biederman
Quoted 4 lines
Ummm... what happens if sysfs recreates those identical nodes again while the old dentries are lingering? The dead ones will linger till the submounts are gone and then look ups after that will show the new ones, right?
Yep. On the vfs level. The sysfs dirent tree will reflect what is going on with the hardware.
This is a vfs misfeature, that I hope someday we will get fixed. But for now it is better not to leak mount points. Especially since no one actually mounts things on sysfs.
fuse and debugfs do. :-P
Signature · 1 line
tejun
Re: [PATCH 05/20] sysfs: Rename sysfs_d_iput to sysfs_dentry_iput
In reply to Eric W. BiedermanQuoted 7 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Using dentry instead of d in the function name is what several other filesystems are doing and it seems to be a more readable convention.
Signed-off-by Eric W. Biederman <[email protected]>
Signature · 1 line
tejun
Re: [PATCH 04/20] sysfs: Handle the general case of removing of directories with subdirectories
In reply to Eric W. BiedermanQuoted 15 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Modify sysfs to properly remove directories containing attributes and subdirectories. The code is relatively simple and means we don't have to worry about what might use this logic.
In a quick survey I have only found
/sys/dev/charand/sys/dev/blockthat are removing non-enmpty directories today (and they are exclusively filled with symlinks). So only removing empty directories does not appear to be an option.I don't hold
sysfs_mutexacross the entire operation as that is unneeded for coherence at the sysfs level and some level of coordination is expected at the upper layers.Signed-off-by Eric W. Biederman <[email protected]>
...
Quoted 4 lines
fs/sysfs/dir.c +1
-3-void sysfs_remove_subdir (struct sysfs_dirent *sd) -{ -remove_dir (sd); +struct sysfs_dirent *sd = dir_sd;
fs/sysfs/dir.c const struct inode_operations sysfs_dir_inode_operations = { · line 747
Quoted 10 lines
fs/sysfs/dir.c +9
-0+mutex_lock (&sysfs_mutex); +while ((sysfs_type (sd) ==SYSFS_DIR ) && sd->s_dir.children) + sd = sd->s_dir.children; +if (sd != dir_sd) +sysfs_get (sd); +else + sd =NULL ; +mutex_unlock (&sysfs_mutex); +return sd; }
Some blank lines wouldn't hurt, especially after local variable declaration.
Quoted 20 lines
fs/sysfs/dir.c +2
-13-static void __sysfs_remove_dir (struct sysfs_dirent *dir_sd) +static void remove_dir (struct sysfs_dirent *dir_sd) {struct sysfs_addrm_cxt acxt; -struct sysfs_dirent **pos; - -if (!dir_sd) -return ; +struct sysfs_dirent *sd;pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name); -sysfs_addrm_start (&acxt, dir_sd); - pos = &dir_sd->s_dir.children; -while (*pos) { -struct sysfs_dirent *sd = *pos; -if (sysfs_type (sd) !=SYSFS_DIR ) -sysfs_remove_one (&acxt, sd); -else - pos = &(*pos)->s_sibling;
fs/sysfs/dir.c const struct inode_operations sysfs_dir_inode_operations = { · line 765
Quoted 10 lines
fs/sysfs/dir.c +8
-0+while ((sd =sysfs_get_one (dir_sd))) { +sysfs_addrm_start (&acxt, sd->s_parent); +sysfs_remove_one (&acxt, sd); +sysfs_addrm_finish (&acxt); +sysfs_put (sd); } +sysfs_addrm_start (&acxt, dir_sd->s_parent); +sysfs_remove_one (&acxt, dir_sd);sysfs_addrm_finish (&acxt); +}
I agree we should be heading this way but what happens to attributes or directories living below the subdirectories? If it's gonna handle recursive case, I think it better do it properly. I had patches of similar effect.
http://article.gmane.org/gmane.linux.kernel/582151
http://article.gmane.org/gmane.linux.kernel/582155
The patchset didn't really go anywhere but the recursive atomic removal should be usable.
Thanks.
Signature · 1 line
tejun
Re: [PATCH 04/20] sysfs: Handle the general case of removing of directories with subdirectories
Quoted 62 lines · Tejun Heo
Quoted 15 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Modify sysfs to properly remove directories containing attributes and subdirectories. The code is relatively simple and means we don't have to worry about what might use this logic.
In a quick survey I have only found
/sys/dev/charand/sys/dev/blockthat are removing non-enmpty directories today (and they are exclusively filled with symlinks). So only removing empty directories does not appear to be an option.I don't hold
sysfs_mutexacross the entire operation as that is unneeded for coherence at the sysfs level and some level of coordination is expected at the upper layers.Signed-off-by Eric W. Biederman <[email protected]>...
Quoted 4 lines
fs/sysfs/dir.c +1
-3-void sysfs_remove_subdir (struct sysfs_dirent *sd) -{ -remove_dir (sd); +struct sysfs_dirent *sd = dir_sd;fs/sysfs/dir.c const struct inode_operations sysfs_dir_inode_operations = { · line 747
Quoted 10 lines
fs/sysfs/dir.c +9
-0+mutex_lock (&sysfs_mutex); +while ((sysfs_type (sd) ==SYSFS_DIR ) && sd->s_dir.children) + sd = sd->s_dir.children; +if (sd != dir_sd) +sysfs_get (sd); +else + sd =NULL ; +mutex_unlock (&sysfs_mutex); +return sd; }Some blank lines wouldn't hurt, especially after local variable declaration.
Quoted 27 lines
fs/sysfs/dir.c +8
-13-static void __sysfs_remove_dir (struct sysfs_dirent *dir_sd) +static void remove_dir (struct sysfs_dirent *dir_sd) {struct sysfs_addrm_cxt acxt; -struct sysfs_dirent **pos; - -if (!dir_sd) -return ; +struct sysfs_dirent *sd;pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name); -sysfs_addrm_start (&acxt, dir_sd); - pos = &dir_sd->s_dir.children; -while (*pos) { -struct sysfs_dirent *sd = *pos; -if (sysfs_type (sd) !=SYSFS_DIR ) -sysfs_remove_one (&acxt, sd); -else - pos = &(*pos)->s_sibling; +while ((sd =sysfs_get_one (dir_sd))) { +sysfs_addrm_start (&acxt, sd->s_parent); +sysfs_remove_one (&acxt, sd); +sysfs_addrm_finish (&acxt); +sysfs_put (sd); } +sysfs_addrm_start (&acxt, dir_sd->s_parent);
Quoted 8 lines
fs/sysfs/dir.c const struct inode_operations sysfs_dir_inode_operations = { · line 765
Quoted 3 lines
fs/sysfs/dir.c +2
-0+sysfs_remove_one (&acxt, dir_sd);sysfs_addrm_finish (&acxt); +}I agree we should be heading this way but what happens to attributes or directories living below the subdirectories? If it's gonna handle recursive case, I think it better do it properly. I had patches of similar effect.
I do handle it properly. sysfs_get_one finds the deepest child of the first directory entry. Then I remove it. And I repeat until done.
The locking is correct, something that is much more difficult to tell with your version.
By grabbing and dropping the sysfs_mutex things are simpler, and they get even simpler in future patches.
Now looking at that code in detail there is a question of what happens if we add a directory entry while we are recursively deleting a directory. Neither your patch, my patch, nor the existing code handle that case (assuming the sysfs_dirent) was looked up before it is removed from it's parent directory. I expect another patch is called for to plug that theoretical gap.
I expect the way to close that hole is to have an extra flag that says we are removing a directory entry and refuse to add if that flag is set.
I would prefer to only remove empty directories. But when I instrumented things up I found cases where that does indeed happen.
Eric
Re: [PATCH 04/20] sysfs: Handle the general case of removing of directories with subdirectories
Quoted 10 lines · Eric W. Biederman
Quoted 4 lines
I agree we should be heading this way but what happens to attributes or directories living below the subdirectories? If it's gonna handle recursive case, I think it better do it properly. I had patches of similar effect.
I do handle it properly.
sysfs_get_onefinds the deepest child of the first directory entry. Then I remove it. And I repeat until done.The locking is correct, something that is much more difficult to tell with your version.
Why? :-)
Quoted 10 lines
By grabbing and dropping the
sysfs_mutexthings are simpler, and they get even simpler in future patches.Now looking at that code in detail there is a question of what happens if we add a directory entry while we are recursively deleting a directory. Neither your patch, my patch, nor the existing code handle that case (assuming the
sysfs_dirent) was looked up before it is removed from it's parent directory. I expect another patch is called for to plug that theoretical gap.
Quoted 6 lines
I expect the way to close that hole is to have an extra flag that says we are removing a directory entry and refuse to add if that flag is set.
I would prefer to only remove empty directories. But when I instrumented things up I found cases where that does indeed happen.
IIRC, my version did the whole thing while holding sysfs_mutex, so it's safe against such races. I can't really see why ops like this can't be atomic in sysfs. I don't really care how things are done but please make it atomic.
Thanks.
Signature · 1 line
tejun
Re: [PATCH 04/20] sysfs: Handle the general case of removing of directories with subdirectories
Quoted 6 lines · Tejun Heo
Quoted 5 lines · Eric W. Biederman
Quoted 4 lines
I agree we should be heading this way but what happens to attributes or directories living below the subdirectories? If it's gonna handle recursive case, I think it better do it properly. I had patches of similar effect.
Quoted 7 lines
Quoted 5 lines
I do handle it properly.
sysfs_get_onefinds the deepest child of the first directory entry. Then I remove it. And I repeat until done.The locking is correct, something that is much more difficult to tell with your version.
Why? :-)
Because mine is all in a single place and there is no optimization to get locks I don't need.
Unless I have misread your patch you are failing to get the i_mutex for child directories, if it possible to get it.
Something that it is trivial to see that I always do correctly. Simply because the distance between the lock and where I depend on it is so small.
Quoted 14 lines
Quoted 14 lines
By grabbing and dropping the
sysfs_mutexthings are simpler, and they get even simpler in future patches.Now looking at that code in detail there is a question of what happens if we add a directory entry while we are recursively deleting a directory. Neither your patch, my patch, nor the existing code handle that case (assuming the
sysfs_dirent) was looked up before it is removed from it's parent directory. I expect another patch is called for to plug that theoretical gap.I expect the way to close that hole is to have an extra flag that says we are removing a directory entry and refuse to add if that flag is set.
Quoted 7 lines
Quoted 2 lines
I would prefer to only remove empty directories. But when I instrumented things up I found cases where that does indeed happen.
IIRC, my version did the whole thing while holding
sysfs_mutex, so it's safe against such races. I can't really see why ops like this can't be atomic in sysfs. I don't really care how things are done but please make it atomic.
Nope. Holding the sysfs_mutex does not make you safe from such races. It actually makes you more prone to someone adding a directory entry to a deleted directory and not having it deleted. I have a chance of deleting the added directory entry.
The problem is that sysfs_add_one takes to sysfs_dirents. The look up of the directory is done before we take the sysfs_mutex. So the sysfs_dirent could be grabbed at any time.
Eric
Re: [PATCH 04/20] sysfs: Handle the general case of removing of directories with subdirectories
Hi,
Quoted 7 lines · Eric W. Biederman
Quoted 3 lines
Quoted 2 lines
The locking is correct, something that is much more difficult to tell with your version.
Why? :-)
Because mine is all in a single place and there is no optimization to get locks I don't need.
Quoted 6 lines
Unless I have misread your patch you are failing to get the
i_mutexfor child directories, if it possible to get it.Something that it is trivial to see that I always do correctly. Simply because the distance between the lock and where I depend on it is so small.
If this patch series works out, we don't need to grab i_mutexes while manipulating sd's, right?
Quoted 7 lines
Quoted 6 lines
Quoted 2 lines
I would prefer to only remove empty directories. But when I instrumented things up I found cases where that does indeed happen.
IIRC, my version did the whole thing while holding
sysfs_mutex, so it's safe against such races. I can't really see why ops like this can't be atomic in sysfs. I don't really care how things are done but please make it atomic.
Quoted 8 lines
Nope. Holding the
sysfs_mutexdoes not make you safe from such races. It actually makes you more prone to someone adding a directory entry to a deleted directory and not having it deleted. I have a chance of deleting the added directory entry.The problem is that
sysfs_add_onetakes tosysfs_dirents. The look up of the directory is done before we take thesysfs_mutex. So thesysfs_direntcould be grabbed at any time.
Well, it can be trivially fixed by checking the removed flag. The add/rm thing is designed to help additions and removals of multiple nodes at one go and I'd really like to see it working that way. Any chance you can change code toward that direction?
Thanks.
Signature · 1 line
tejun
Re: [PATCH 04/20] sysfs: Handle the general case of removing of directories with subdirectories
Quoted 4 lines · Tejun Heo
Well, it can be trivially fixed by checking the removed flag. The add/rm thing is designed to help additions and removals of multiple nodes at one go and I'd really like to see it working that way. Any chance you can change code toward that direction?
Yes. We definitely need to check the removed flag in sysfs_add_one. Regardless of anything else.
I need to sleep on this but I am inclined to get rid of the rest of the complications simply by failing the removal of non-empty directories. Going through the upper layers and making them properly responsible for their actions.
I am afraid friendlier in this circumstance might equate to easier to misuse and let code bugs pile up.
Eric
Re: [PATCH 04/20] sysfs: Handle the general case of removing of directories with subdirectories
Hello, Eric.
Quoted 10 lines · Eric W. Biederman
Quoted 4 lines · Tejun Heo
Well, it can be trivially fixed by checking the removed flag. The add/rm thing is designed to help additions and removals of multiple nodes at one go and I'd really like to see it working that way. Any chance you can change code toward that direction?
Yes. We definitely need to check the removed flag in
sysfs_add_one. Regardless of anything else.
Quoted 7 lines
I need to sleep on this but I am inclined to get rid of the rest of the complications simply by failing the removal of non-empty directories. Going through the upper layers and making them properly responsible for their actions.
I am afraid friendlier in this circumstance might equate to easier to misuse and let code bugs pile up.
I'm going through the latter part of the patchset and the code around this area gets much simpler there. Would it be possible to make it atomic after the simplification? Requiring recursive deletion from all the callers is silly and error prone.
Thanks.
Signature · 1 line
tejun
Re: [PATCH 04/20] sysfs: Handle the general case of removing of directories with subdirectories
Quoted 18 lines · Tejun Heo
Hello, Eric.
Quoted 15 lines · Eric W. Biederman
Quoted 4 lines · Tejun Heo
Well, it can be trivially fixed by checking the removed flag. The add/rm thing is designed to help additions and removals of multiple nodes at one go and I'd really like to see it working that way. Any chance you can change code toward that direction?
Yes. We definitely need to check the removed flag in
sysfs_add_one. Regardless of anything else.I need to sleep on this but I am inclined to get rid of the rest of the complications simply by failing the removal of non-empty directories. Going through the upper layers and making them properly responsible for their actions.
Quoted 7 lines
Quoted 2 lines
I am afraid friendlier in this circumstance might equate to easier to misuse and let code bugs pile up.
I'm going through the latter part of the patchset and the code around this area gets much simpler there. Would it be possible to make it atomic after the simplification? Requiring recursive deletion from all the callers is silly and error prone.
I have slept and looked at this in some detail.
There may be some virtue in better support from sysfs for deleting objects. At this point my observation is that support comes from the kobject and device layers. Where you can define all of the attributes of a device up front.
My goal is to make the current sysfs as simple and as correct as I can before changes are made to either it's interface or otherwise make it better suited to work.
The case I have been worried about is someone removing a subsystem before unregistering it's devices, or otherwise removing a real parent before removing it's children.
After a little more investigation that is exactly what is happening today with /sys/dev/char and /sys/dev/block.
Those ordering issues we must handle because quite frequently there are real hardware complications and that is exactly the case that the kernel device tree was built to address. So I expect any amount of getting it wrong in sysfs is actually getting it wrong in the device tree.
There is another problem with relying on recursive delete. When we come to delete one of our objects that someone else recursively deleted we will hit the BUG_ON in sysfs_remove_one, and then attempt to run operations that we have already run. Not maintaining that the prerequisite things exist for the lifetime of something in sysfs sounds really icky.
My plan going forward is to fix the ordering problems with deleting /sys/dev/char and /sys/dev/block. Add a WARN_ON if we delete a non-empty directory. Ensure we don't add something to an already deleted directory.
Eric
Re: [PATCH 04/20] sysfs: Handle the general case of removing of directories with subdirectories
Quoted 4 lines · Eric W. Biederman
My plan going forward is to fix the ordering problems with deleting
/sys/dev/charand/sys/dev/block. Add aWARN_ONif we delete a non-empty directory. Ensure we don't add something to an already deleted directory.
What's the problem in /sys/dev/? There are just a bunch of symlinks, one for every device with a dev_t, and all in flat directories, and no directory to remove.
Thanks,
Kay
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 04/20] sysfs: Handle the general case of removing of directories with subdirectories
Quoted 10 lines · Kay Sievers
Quoted 4 lines · Eric W. Biederman
My plan going forward is to fix the ordering problems with deleting
/sys/dev/charand/sys/dev/block. Add aWARN_ONif we delete a non-empty directory. Ensure we don't add something to an already deleted directory.What's the problem in
/sys/dev/? There are just a bunch of symlinks, one for every device with adev_t, and all in flat directories, and no directory to remove.
device_shutdown called during reboot removes /sys/dev/block and /sys/dev/char. The current sysfs_remove_dir (because it empties directories) removes all of those symlinks.
The problem is that it is the device objects for each individual device that owns those symlinks, and normally removes those symlinks.
Which means that in theory we could have double deletion going on.
In practice today it doesn't matter because this is at reboot.
And as far as that goes it is wrong to remove anything from sysfs during device_shutdown so the fix is just to not call kobject_put there.
Eric
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 04/20] sysfs: Handle the general case of removing of directories with subdirectories
Quoted 12 lines · Eric W. Biederman
Quoted 3 lines · Kay Sievers
What's the problem in
/sys/dev/? There are just a bunch of symlinks, one for every device with adev_t, and all in flat directories, and no directory to remove.
device_shutdowncalled during reboot removes/sys/dev/blockand/sys/dev/char. The currentsysfs_remove_dir(because it empties directories) removes all of those symlinks.The problem is that it is the device objects for each individual device that owns those symlinks, and normally removes those symlinks.
Quoted 6 lines
Which means that in theory we could have double deletion going on.
In practice today it doesn't matter because this is at reboot.
And as far as that goes it is wrong to remove anything from sysfs during
device_shutdownso the fix is just to not callkobject_putthere.
Yes, that's just a bug. These directories should never be removed.
Thanks,
Kay
Re: [PATCH 03/20] sysfs: Remove now unnecessary error reporting suppression.
In reply to Eric W. BiedermanQuoted 5 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Now that we use
sysfs_rename_linkin the places we previously usedsysfs_create_link_nowarnwe can removesysfs_create_link_nowarnand all it's supporting infrastructure.
I'm not entirely sure why implementing a rename helper means that we don't need nowarn version anymore. Nothing really changed or is it that the nowarn version wasn't too necessary anyway?
Thanks.
Signature · 1 line
tejun
Re: [PATCH 03/20] sysfs: Remove now unnecessary error reporting suppression.
Quoted 10 lines · Tejun Heo
Quoted 5 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Now that we use
sysfs_rename_linkin the places we previously usedsysfs_create_link_nowarnwe can removesysfs_create_link_nowarnand all it's supporting infrastructure.I'm not entirely sure why implementing a rename helper means that we don't need nowarn version anymore. Nothing really changed or is it that the nowarn version wasn't too necessary anyway?
nowarn was used exclusively in the hand coded version of rename. By switching the order I was able perform the operations such that even if the operation is ultimately a noop and are attempt to recreate the same link we won't have problems.
The two callers of device_rename are required (and do) perform locking to ensure the rename operation is safe. So the exact implementation in the sysfs does not matter. Although making it atomic would be ideal.
The nowarn helpers existed because the order was backwards in device rename and when a noop rename happened sysfs would mistakenly think there was a problem and complain. I think the upper layers suppress that case now for a while at least it lead to a lot of spurious warnings.
Eric
Re: [PATCH 03/20] sysfs: Remove now unnecessary error reporting suppression.
Quoted 22 lines · Eric W. Biederman
Quoted 9 lines · Tejun Heo
Quoted 5 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Now that we use
sysfs_rename_linkin the places we previously usedsysfs_create_link_nowarnwe can removesysfs_create_link_nowarnand all it's supporting infrastructure.I'm not entirely sure why implementing a rename helper means that we don't need nowarn version anymore. Nothing really changed or is it that the nowarn version wasn't too necessary anyway?
nowarn was used exclusively in the hand coded version of rename. By switching the order I was able perform the operations such that even if the operation is ultimately a noop and are attempt to recreate the same link we won't have problems.
The two callers of
device_renameare required (and do) perform locking to ensure the rename operation is safe. So the exact implementation in the sysfs does not matter. Although making it atomic would be ideal.
Quoted 5 lines
The nowarn helpers existed because the order was backwards in device rename and when a noop rename happened sysfs would mistakenly think there was a problem and complain. I think the upper layers suppress that case now for a while at least it lead to a lot of spurious warnings.
But, still, removing the original link on failure doesn't sound too enticing. Wouldn't it be better to detect the noop special case and do nothing instead of swapping the order?
Thanks.
Signature · 1 line
tejun
Re: [PATCH 01/20] sysfs: Implement sysfs_rename_link
In reply to Eric W. BiedermanQuoted 6 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Because of rename ordering problems we occassionally give false warnings about invalid sysfs operations, so implement a helper function for this common sysfs idiom.
Quoted 7 lines
This is a stripped down version of an earlier patch that also added
sysfs_delete_link.Cc Benjamin Thery <[email protected]>Cc Daniel Lezcano <[email protected]>Cc Tejun Heo <[email protected]>Signed-off-by Eric W. Biederman <[email protected]>
I think this has been brought up before but can you please use --no-chain-reply-to? It's painful to follow the deep nesting.
Thanks.
Signature · 1 line
tejun
Re: [PATCH 01/20] sysfs: Implement sysfs_rename_link
In reply to Eric W. BiedermanHello,
fs/sysfs/symlink.c void sysfs_remove_link(struct kobject * kobj, const char * name) · line 140
Quoted 7 lines · Eric W. Biederman
fs/sysfs/symlink.c +7
-0+int sysfs_rename_link (struct kobject *kobj,struct kobject *targ, +const char *old,const char *new) +{ +sysfs_remove_link (kobj, old); +return sysfs_create_link (kobj, targ, new); +} +
Removal and creation are done in the reverse order compared to the one used in device rename. The important difference is that previously failed operation was noop whereas it now would remove the current link. I think the old order is correct.
Thanks.
Signature · 1 line
tejun
Re: [PATCH 01/20] sysfs: Implement sysfs_rename_link
Quoted 13 lines · Tejun Heo
fs/sysfs/symlink.c void sysfs_remove_link(struct kobject * kobj, const char * name) · line 140
Quoted 7 lines · Eric W. Biederman
fs/sysfs/symlink.c +7
-0+int sysfs_rename_link (struct kobject *kobj,struct kobject *targ, + const char *old, const char *new) +{ + sysfs_remove_link(kobj, old); + return sysfs_create_link(kobj, targ, new); +} +Removal and creation are done in the reverse order compared to the one used in device rename. The important difference is that previously failed operation was noop whereas it now would remove the current link. I think the old order is correct.
The target string is composed on-demand, and it always points to the same kobject and *targ is not needed, right?
Can't we just change the name of the link, instead of removing and re-creating the entire thing, and all these issues go away?
Thanks,
Kay
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 01/20] sysfs: Implement sysfs_rename_link
Quoted 15 lines · Kay Sievers
Quoted 13 lines · Tejun Heo
fs/sysfs/symlink.c void sysfs_remove_link(struct kobject * kobj, const char * name) · line 140
Quoted 7 lines · Eric W. Biederman
fs/sysfs/symlink.c +7
-0+int sysfs_rename_link (struct kobject *kobj,struct kobject *targ, + const char *old, const char *new) +{ + sysfs_remove_link(kobj, old); + return sysfs_create_link(kobj, targ, new); +} +Removal and creation are done in the reverse order compared to the one used in device rename. The important difference is that previously failed operation was noop whereas it now would remove the current link. I think the old order is correct.
Quoted 5 lines
The target string is composed on-demand, and it always points to the same kobject and *targ is not needed, right?
Can't we just change the name of the link, instead of removing and re-creating the entire thing, and all these issues go away?
Good point. It looks like I can generalize sysfs_mv_dir into simply being sysfs_rename. All of the existing logic looks like it can handle that. I will look at doing an incremental patch for that.
Eric
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 01/20] sysfs: Implement sysfs_rename_link
Quoted 11 lines · Eric W. Biederman
Quoted 5 lines · Kay Sievers
The target string is composed on-demand, and it always points to the same kobject and *targ is not needed, right?
Can't we just change the name of the link, instead of removing and re-creating the entire thing, and all these issues go away?
Good point. It looks like I can generalize
sysfs_mv_dirinto simply beingsysfs_rename. All of the existing logic looks like it can handle that. I will look at doing an incremental patch for that.
Nice, would be great, if that can be made working. It would be much better than the current logic, and there would be no ordering problem, like Tejun mentioned, to solve anymore.
As we don't need to change the target for link, maybe:
sysfs_rename_file(kobj_parent, old_name, new_name);
that can act on symlinks and regular files would be useful?
Thanks,
Kay
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 01/20] sysfs: Implement sysfs_rename_link
In reply to Eric W. BiedermanSo, there's been a lot of talk in this thread.
Eric, do you have an updated set of patches for me to try out?
Or are there still problems, like the "fry the ext3 boot partition" that Kay found?
thanks,
greg k-h
Re: [PATCH 01/20] sysfs: Implement sysfs_rename_link
Quoted 4 lines · Greg KH
So, there's been a lot of talk in this thread.
Eric, do you have an updated set of patches for me to try out?
I think we should get a version of the patch in that removes all files in a directory on cleanup, but warn if a subdirectory is still there. James has a patch to fix the one issue we've seen so far with existing child directories.
After that, we should work on fixing the users that leave files behind, and can possibly stop cleaning up files, if we want to.
Quoted 2 lines
Or are there still problems, like the "fry the ext3 boot partition" that Kay found?
That is unrelated to Eric's patches, They just added the dump, which I tried to trigger. It's not entirely clear what caused the filesytem damage, but I was definitely able to reproduce the unclean shutdown without any of Eric's sysfs patches.
Thanks,
Kay
Re: [PATCH 01/20] sysfs: Implement sysfs_rename_link
Quoted 6 lines · Kay Sievers
Quoted 4 lines · Greg KH
So, there's been a lot of talk in this thread.
Eric, do you have an updated set of patches for me to try out?
Quoted 7 lines
I think we should get a version of the patch in that removes all files in a directory on cleanup, but warn if a subdirectory is still there. James has a patch to fix the one issue we've seen so far with existing child directories.
After that, we should work on fixing the users that leave files behind, and can possibly stop cleaning up files, if we want to.
That would be good.
But note that we always "allowed" such things to happen, so odds are there are lots of places in the kernel that took advantage of this. If we make it a rule, people will complain.
Quoted 7 lines
Quoted 2 lines
Or are there still problems, like the "fry the ext3 boot partition" that Kay found?
That is unrelated to Eric's patches, They just added the dump, which I tried to trigger. It's not entirely clear what caused the filesytem damage, but I was definitely able to reproduce the unclean shutdown without any of Eric's sysfs patches.
Ok.
But I think Eric had some updates to some of the patches along the way, so a whole new respin would be good to ensure I get the correct ones.
Eric?
thanks,
greg k-h
cover sysfs cleanups.
Quoted 8 lines · Greg KH
Quoted 7 lines
Quoted 2 lines
Or are there still problems, like the "fry the ext3 boot partition" that Kay found?
That is unrelated to Eric's patches, They just added the dump, which I tried to trigger. It's not entirely clear what caused the filesytem damage, but I was definitely able to reproduce the unclean shutdown without any of Eric's sysfs patches.
Quoted 4 lines
Ok.
But I think Eric had some updates to some of the patches along the way, so a whole new respin would be good to ensure I get the correct ones.
Ok. Here is my respun patchset. I have not changed which files we remove in a directory when we remove a non-empty directory. Leaving that issue to be addressed another time.
To accommodate that I have respun two patches:
patch 4 sysfs: Normalize removing sysfs directories. patch 15 sysfs: Kill sysfs_addrm_start and sysfs_addrm_finish
Killing addrm is only changed to track the previous differences.
Eric
PATCH 1/24 sysfs: Implement sysfs_rename_link
From: Eric W. Biederman <[email protected]>
Because of rename ordering problems we occassionally give false warnings about invalid sysfs operations, so implement a helper function for this common sysfs idiom.
This is a stripped down version of an earlier patch that also added sysfs_delete_link.
--- fs/sysfs/symlink.c | 16 ++++++++++++++++ include/linux/sysfs.h | 9 +++++++++ 2 files changed, 25 insertions(+), 0 deletions(-)
fs/sysfs/symlink.c +16 -0
@@ -122,6 +122,22 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)sysfs_hash_and_remove (parent_sd, name); } +/** +* sysfs_rename_link - rename symlink in object's directory. +* @kobj: object we're acting for. +* @targ: object we're pointing to. +* @old: previous name of the symlink. +* @new: new name of the symlink. +* +* A helper function for the common rename symlink idiom. +*/ +int sysfs_rename_link (struct kobject *kobj,struct kobject *targ, +const char *old,const char *new) +{ +sysfs_remove_link (kobj, old); +return sysfs_create_link (kobj, targ, new); +} +static int sysfs_get_target_path (struct sysfs_dirent *parent_sd,struct sysfs_dirent *target_sd,char *path) {
include/linux/sysfs.h +9 -0
@@ -109,6 +109,9 @@ int __must_check sysfs_create_link_nowarn(struct kobject *kobj, const char *name);void sysfs_remove_link (struct kobject *kobj,const char *name); +int sysfs_rename_link (struct kobject *kobj,struct kobject *target, +const char *old_name,const char *new_name); +int __must_check sysfs_create_group (struct kobject *kobj,const struct attribute_group *grp); int sysfs_update_group(struct kobject *kobj,
@@ -202,6 +205,12 @@ static inline void sysfs_remove_link(struct kobject *kobj, const char *name) { } +static inline int sysfs_rename_link (struct kobject *k,struct kobject *t, +const char *old_name,const char *new_name) +{ +return 0 ; +} +static inline int sysfs_create_group (struct kobject *kobj,const struct attribute_group *grp) {
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 2/24 driver core: Use sysfs_rename_link in device_rename
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Don't open code the renaming of symlinks in sysfs instead use the new helper function sysfs_rename_link
--- drivers/base/core.c | 18 ++++++------------ 1 files changed, 6 insertions(+), 12 deletions(-)
drivers/base/core.c +6 -12
@@ -1490,22 +1490,16 @@ int device_rename(struct device *dev, char *new_name)if (old_class_name) { new_class_name =make_class_name (dev->class->name, &dev->kobj);if (new_class_name) { - error =sysfs_create_link_nowarn (&dev->parent->kobj, - &dev->kobj, - new_class_name); -if (error) - goto out; -sysfs_remove_link (&dev->parent->kobj, old_class_name); + error =sysfs_rename_link (&dev->parent->kobj, + &dev->kobj, + old_class_name, + new_class_name); } }#else if (dev->class) { - error =sysfs_create_link_nowarn (&dev->class->p->class_subsys.kobj, - &dev->kobj,dev_name (dev)); -if (error) - goto out; -sysfs_remove_link (&dev->class->p->class_subsys.kobj, - old_device_name); + error =sysfs_rename_link (&dev->class->p->class_subsys.kobj, + &dev->kobj, old_device_name, new_name); }#endif
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 3/24 sysfs: Remove now unnecessary error reporting suppression.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Now that we use sysfs_rename_link in the places we previously used sysfs_create_link_nowarn we can remove sysfs_create_link_nowarn and all it's supporting infrastructure as it has no callers.
--- fs/sysfs/dir.c | 54 +++++++++++---------------------------------------- fs/sysfs/symlink.c | 42 ++++++++------------------------------- fs/sysfs/sysfs.h | 1 - 3 files changed, 21 insertions(+), 76 deletions(-)
fs/sysfs/dir.c +12 -42
@@ -397,43 +397,6 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, }/** -* __sysfs_add_one - add sysfs_dirent to parent without warning -* @acxt: addrm context to use -* @sd: sysfs_dirent to be added -* -* Get @acxt->parent_sd and set sd->s_parent to it and increment -* nlink of parent inode if @sd is a directory and link into the -* children list of the parent. -* -* This function should be called between calls to -* sysfs_addrm_start() and sysfs_addrm_finish() and should be -* passed the same @acxt as passed to sysfs_addrm_start(). -* -* LOCKING: -* Determined by sysfs_addrm_start(). -* -* RETURNS: -* 0 on success, -EEXIST if entry with the given name already -* exists. -*/ -int __sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) -{ -if (sysfs_find_dirent (acxt->parent_sd, sd->s_name)) -return -EEXIST ; - - sd->s_parent =sysfs_get (acxt->parent_sd); - -if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) -inc_nlink (acxt->parent_inode); - - acxt->cnt++; - -sysfs_link_sibling (sd); - -return 0 ; -} - -/** * sysfs_pathname - return full path to sysfs dirent * @sd: sysfs_dirent whose path we want * @path: caller allocated buffer
@@ -475,10 +438,7 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)*/ int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) { -int ret; - - ret =__sysfs_add_one (acxt, sd); -if (ret == -EEXIST ) { +if (sysfs_find_dirent (acxt->parent_sd, sd->s_name)) {char *path =kzalloc (PATH_MAX ,GFP_KERNEL ); WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n",
@@ -486,9 +446,19 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)strcat (strcat (sysfs_pathname (acxt->parent_sd, path),"/" ), sd->s_name));kfree (path); +return -EEXIST ; } -return ret; + sd->s_parent =sysfs_get (acxt->parent_sd); + +if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) +inc_nlink (acxt->parent_inode); + + acxt->cnt++; + +sysfs_link_sibling (sd); + +return 0 ; }/**
fs/sysfs/symlink.c +9 -33
60 lines not on this page · raw message
fs/sysfs/sysfs.h +0 -1
@@ -108,7 +108,6 @@ struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);void sysfs_put_active_two (struct sysfs_dirent *sd);void sysfs_addrm_start (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *parent_sd); -int __sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd);int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd);void sysfs_remove_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd);void sysfs_addrm_finish (struct sysfs_addrm_cxt *acxt);
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 4/24 sysfs: Normalize removing sysfs directories.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Individually wrap each call to sysfs_remove_one with sysfs_addrm_start and sysfs_addrm_finish this prepares for these functions to be removed.
I don't change the logic of which dirents we remove. I do document what we are doing and why what we are doing it.
A warning is added if we attempt to remove an non-empty directories so that users that would prevsiosly have had leaks and other problems like the scsi layer get a clear warning that there is a problem.
I don't hold sysfs_mutex across the entire operation as that is unneeded for coherence at the sysfs level and some level of coordination is expected at the upper layers.
--- fs/sysfs/dir.c | 62 +++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 44 insertions(+), 18 deletions(-)
fs/sysfs/dir.c +44 -18
@@ -732,12 +732,28 @@ const struct inode_operations sysfs_dir_inode_operations = { .setattr = sysfs_setattr, }; -static void remove_dir (struct sysfs_dirent *sd) +static void remove_dir (struct sysfs_dirent *dir_sd) {struct sysfs_addrm_cxt acxt; -sysfs_addrm_start (&acxt, sd->s_parent); -sysfs_remove_one (&acxt, sd); +pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name); + +/* Removing non-empty directories is not valid complain! */ +if (unlikely (dir_sd->s_dir.children)) { +struct sysfs_dirent *sd; + +WARN (1 ,KERN_WARNING "sysfs: removing non-empty dir: %s\n" , + dir_sd->s_name); + +mutex_lock (&sysfs_mutex); +for (sd = dir_sd->s_dir.children; sd; sd = sd->s_sibling) +printk (KERN_WARNING "%s/%s\n" , + dir_sd->s_name, sd->s_name); +mutex_unlock (&sysfs_mutex); + } + +sysfs_addrm_start (&acxt, dir_sd->s_parent); +sysfs_remove_one (&acxt, dir_sd);sysfs_addrm_finish (&acxt); }
@@ -746,27 +762,37 @@ void sysfs_remove_subdir(struct sysfs_dirent *sd)remove_dir (sd); } +static struct sysfs_dirent *get_dirent_to_remove (struct sysfs_dirent *dir_sd) +{ +struct sysfs_dirent *sd; + +mutex_lock (&sysfs_mutex); +for (sd = dir_sd->s_dir.children; sd; sd = sd->s_sibling) { +/* Directories might be owned by someone else +* making recursive directory removal unsafe. +*/ +if (sysfs_type (sd) ==SYSFS_DIR ) +continue ; +break ; + } +sysfs_get (sd); +mutex_unlock (&sysfs_mutex); + +return sd; +}static void __sysfs_remove_dir (struct sysfs_dirent *dir_sd) {struct sysfs_addrm_cxt acxt; -struct sysfs_dirent **pos; - -if (!dir_sd) -return ; - -pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name); -sysfs_addrm_start (&acxt, dir_sd); - pos = &dir_sd->s_dir.children; -while (*pos) { -struct sysfs_dirent *sd = *pos; +struct sysfs_dirent *sd; -if (sysfs_type (sd) !=SYSFS_DIR ) -sysfs_remove_one (&acxt, sd); -else - pos = &(*pos)->s_sibling; +/* Remove children that we think are safe */ +while ((sd =get_dirent_to_remove (dir_sd))) { +sysfs_addrm_start (&acxt, sd->s_parent); +sysfs_remove_one (&acxt, sd); +sysfs_addrm_finish (&acxt); +sysfs_put (sd); } -sysfs_addrm_finish (&acxt);remove_dir (dir_sd); }
Signature · 1 line
1.6.3.1.54.g99dd.dirty
Re: [PATCH 04/24] sysfs: Normalize removing sysfs directories.
Hello,
Quoted 4 lines · Eric W. Biederman
fs/sysfs/dir.c +0
-0@@ -732,12 +732,28 @@ const struct inode_operations sysfs_dir_inode_operations = { .setattr = sysfs_setattr, };
fs/sysfs/dir.c const struct inode_operations sysfs_dir_inode_operations = { · line 741
Quoted 10 lines
fs/sysfs/dir.c +4
-3-static void remove_dir (struct sysfs_dirent *sd) +static void remove_dir (struct sysfs_dirent *dir_sd) {struct sysfs_addrm_cxt acxt; -sysfs_addrm_start (&acxt, sd->s_parent); -sysfs_remove_one (&acxt, sd); +pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name); + +/* Removing non-empty directories is not valid complain! */
^^^ missing . or ,
Quoted 36 lines
fs/sysfs/dir.c +19
-12+static struct sysfs_dirent *get_dirent_to_remove (struct sysfs_dirent *dir_sd) +{ +struct sysfs_dirent *sd; + +mutex_lock (&sysfs_mutex); +for (sd = dir_sd->s_dir.children; sd; sd = sd->s_sibling) { +/* Directories might be owned by someone else +* making recursive directory removal unsafe. +*/ +if (sysfs_type (sd) ==SYSFS_DIR ) +continue ; +break ; + } +sysfs_get (sd); +mutex_unlock (&sysfs_mutex); + +return sd; +}static void __sysfs_remove_dir (struct sysfs_dirent *dir_sd) {struct sysfs_addrm_cxt acxt; -struct sysfs_dirent **pos; - -if (!dir_sd) -return ; - -pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name); -sysfs_addrm_start (&acxt, dir_sd); - pos = &dir_sd->s_dir.children; -while (*pos) { -struct sysfs_dirent *sd = *pos; +struct sysfs_dirent *sd; -if (sysfs_type (sd) !=SYSFS_DIR ) -sysfs_remove_one (&acxt, sd);
fs/sysfs/dir.c void sysfs_remove_subdir(struct sysfs_dirent *sd) · line 769
Quoted 10 lines
fs/sysfs/dir.c +6
-3-else - pos = &(*pos)->s_sibling; +/* Remove children that we think are safe */ +while ((sd =get_dirent_to_remove (dir_sd))) { +sysfs_addrm_start (&acxt, sd->s_parent); +sysfs_remove_one (&acxt, sd); +sysfs_addrm_finish (&acxt); +sysfs_put (sd); } -sysfs_addrm_finish (&acxt);
Ummm... Null @dir_sd handling is being removed, which could be fine but please do it in a separate patch or at least mention it in the patch description. Also, I'm quite uncomfortable with these things being done in non-atomic manner. It can be made to work but things like this can lead to subtle race conditions and with the kind of layering we put on top of sysfs (kobject, driver model, driver midlayers and so on), it isn't all that easy to verify what's going on, so NACK for this one.
Thanks.
Signature · 1 line
tejun
Re: [PATCH 04/24] sysfs: Normalize removing sysfs directories.
Quoted 54 lines · Tejun Heo
Hello,
Quoted 4 lines · Eric W. Biederman
fs/sysfs/dir.c +0
-0@@ -732,12 +732,28 @@ const struct inode_operations sysfs_dir_inode_operations = { .setattr = sysfs_setattr, };fs/sysfs/dir.c const struct inode_operations sysfs_dir_inode_operations = { · line 741
Quoted 10 lines
fs/sysfs/dir.c +4
-3-static void remove_dir (struct sysfs_dirent *sd) +static void remove_dir (struct sysfs_dirent *dir_sd) {struct sysfs_addrm_cxt acxt; -sysfs_addrm_start (&acxt, sd->s_parent); -sysfs_remove_one (&acxt, sd); +pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name); + +/* Removing non-empty directories is not valid complain! */ ^^^ missing . or ,Quoted 34 lines
fs/sysfs/dir.c +19
-10+static struct sysfs_dirent *get_dirent_to_remove (struct sysfs_dirent *dir_sd) +{ +struct sysfs_dirent *sd; + +mutex_lock (&sysfs_mutex); +for (sd = dir_sd->s_dir.children; sd; sd = sd->s_sibling) { +/* Directories might be owned by someone else +* making recursive directory removal unsafe. +*/ +if (sysfs_type (sd) ==SYSFS_DIR ) +continue ; +break ; + } +sysfs_get (sd); +mutex_unlock (&sysfs_mutex); + +return sd; +}static void __sysfs_remove_dir (struct sysfs_dirent *dir_sd) {struct sysfs_addrm_cxt acxt; -struct sysfs_dirent **pos; - -if (!dir_sd) -return ; - -pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name); -sysfs_addrm_start (&acxt, dir_sd); - pos = &dir_sd->s_dir.children; -while (*pos) { -struct sysfs_dirent *sd = *pos; +struct sysfs_dirent *sd;
Quoted 16 lines
fs/sysfs/dir.c void sysfs_remove_subdir(struct sysfs_dirent *sd) · line 769
Quoted 12 lines
fs/sysfs/dir.c +6
-5-if (sysfs_type (sd) !=SYSFS_DIR ) -sysfs_remove_one (&acxt, sd); -else - pos = &(*pos)->s_sibling; +/* Remove children that we think are safe */ +while ((sd =get_dirent_to_remove (dir_sd))) { +sysfs_addrm_start (&acxt, sd->s_parent); +sysfs_remove_one (&acxt, sd); +sysfs_addrm_finish (&acxt); +sysfs_put (sd); } -sysfs_addrm_finish (&acxt);Ummm... Null @dir_sd handling is being removed, which could be fine but please do it in a separate patch or at least mention it in the patch description.
Agreed. That should be documented. I took a look and it appears we are completely protected by the kobj->state_in_sysfs flag.
Also, I'm quite uncomfortable with these things
Quoted 5 lines
being done in non-atomic manner. It can be made to work but things like this can lead to subtle race conditions and with the kind of layering we put on top of sysfs (kobject, driver model, driver midlayers and so on), it isn't all that easy to verify what's going on, so NACK for this one.
Total nonsense.
Mucking about with sysfs after we start deleting a directory is a bug. At worst my change makes a buggy race slightly less deterministic.
I am not ready to consider keeping the current unnecessary atomic removal step. That unnecessary atomicity makes the following patches more difficult, and requires a lot of unnecessary retesting.
What do you think the extra unnecessary atomicity helps protect?
Eric
Re: [PATCH 04/24] sysfs: Normalize removing sysfs directories.
Quoted 9 lines · Eric W. Biederman
Also, I'm quite uncomfortable with these things
Quoted 5 lines
being done in non-atomic manner. It can be made to work but things like this can lead to subtle race conditions and with the kind of layering we put on top of sysfs (kobject, driver model, driver midlayers and so on), it isn't all that easy to verify what's going on, so NACK for this one.
Total nonsense.
Quoted 8 lines
Mucking about with sysfs after we start deleting a directory is a bug. At worst my change makes a buggy race slightly less deterministic.
I am not ready to consider keeping the current unnecessary atomic removal step. That unnecessary atomicity makes the following patches more difficult, and requires a lot of unnecessary retesting.
What do you think the extra unnecessary atomicity helps protect?
It's just not a clean API. When people are trying to code things way up in the stack, they aren't likely to look up the code to see what assumptions are being made especially when the stack is deep and complex and sysfs is near the bottom of the tall stack. IMHO implementing the usually expected semantics at this depth is worth every effort. It's just good implementation style which might look like wasted effort but will harden the stack in the long run. Plus, it's not like making it atomic is difficult or anything.
So, still NACK.
Thanks.
Signature · 1 line
tejun
Re: [PATCH 04/24] sysfs: Normalize removing sysfs directories.
Quoted 19 lines · Tejun Heo
Quoted 9 lines · Eric W. Biederman
Also, I'm quite uncomfortable with these things
Quoted 5 lines
being done in non-atomic manner. It can be made to work but things like this can lead to subtle race conditions and with the kind of layering we put on top of sysfs (kobject, driver model, driver midlayers and so on), it isn't all that easy to verify what's going on, so NACK for this one.
Total nonsense.
Quoted 8 lines
Mucking about with sysfs after we start deleting a directory is a bug. At worst my change makes a buggy race slightly less deterministic.
I am not ready to consider keeping the current unnecessary atomic removal step. That unnecessary atomicity makes the following patches more difficult, and requires a lot of unnecessary retesting.
What do you think the extra unnecessary atomicity helps protect?
Quoted 8 lines
It's just not a clean API. When people are trying to code things way up in the stack, they aren't likely to look up the code to see what assumptions are being made especially when the stack is deep and complex and sysfs is near the bottom of the tall stack. IMHO implementing the usually expected semantics at this depth is worth every effort. It's just good implementation style which might look like wasted effort but will harden the stack in the long run. Plus, it's not like making it atomic is difficult or anything.
I guess we are going to have to disagree on this one.
My take is simply that a correct user has to wait until no one else can find the kobject before calling kobject_del. At which point races are impossible, and it doesn't matter if sysfs_mutex is held across the entire operation.
For the long term I still intend to kill __sysfs_remove_dir. Just not in this patch series.
Eric
Re: [PATCH 04/24] sysfs: Normalize removing sysfs directories.
Hello,
Quoted 1 line · Eric W. Biederman
I guess we are going to have to disagree on this one.
Yeap, seems like it.
Quoted 4 lines
My take is simply that a correct user has to wait until no one else can find the kobject before calling
kobject_del. At which point races are impossible, and it doesn't matter ifsysfs_mutexis held across the entire operation.
This one also is a matter of degree. Way back when users could crash sysfs reliably from userland, the sysfs code had a lot of assumptions about object lifetime and synchronizaion which even the sysfs code itself didn't really follow leading to fragility. My focus while restructuring the code was to make the code behave as expected by the usual conventions. It could be that I'm a bit paranoid about this, but in general I really don't like when low level code doesn't do its due diligence to save several hours of effort to implement clean semantics, but again there's nothing wrong with your due and my due being different.
I guess I'll have to pass the buck to Greg again with my rather strong NACK.
Quoted 2 lines
For the long term I still intend to kill
__sysfs_remove_dir. Just not in this patch series.
Yeah, sysfs code is in the middle of two sane ways. sysfs either has to deal with children creation/removal including atomicity of the operations or it should force its users to do so. I prefer the former but any would be better than the current situation.
Thanks.
Signature · 1 line
tejun
Re: [PATCH 04/24] sysfs: Normalize removing sysfs directories.
Quoted 12 lines · Tejun Heo
Hello,
Quoted 1 line · Eric W. Biederman
I guess we are going to have to disagree on this one.
Yeap, seems like it.
Quoted 4 lines
My take is simply that a correct user has to wait until no one else can find the kobject before calling
kobject_del. At which point races are impossible, and it doesn't matter ifsysfs_mutexis held across the entire operation.
Quoted 10 lines
This one also is a matter of degree. Way back when users could crash sysfs reliably from userland, the sysfs code had a lot of assumptions about object lifetime and synchronizaion which even the sysfs code itself didn't really follow leading to fragility. My focus while restructuring the code was to make the code behave as expected by the usual conventions. It could be that I'm a bit paranoid about this, but in general I really don't like when low level code doesn't do its due diligence to save several hours of effort to implement clean semantics, but again there's nothing wrong with your due and my due being different.
Given a history of user space was crashing sysfs I can see where you would be nervous.
I come from the perspective of sysfs still having bugs (although not easily triggered), but the code is so complicated that people can't see them because there is just so much code. So I value every little bit of extra simplicity I can.
Quoted 7 lines
Quoted 2 lines
For the long term I still intend to kill
__sysfs_remove_dir. Just not in this patch series.Yeah, sysfs code is in the middle of two sane ways. sysfs either has to deal with children creation/removal including atomicity of the operations or it should force its users to do so. I prefer the former but any would be better than the current situation.
What user space cares about is that we perform the additions in the following order:
kobject_add()sysfs_add_file()kobject_uevent()
So that when user space receives the event it can consult sysfs and be safe in assuming all of the attributes for the device are present.
Since device_add calls kobject_uevent we must have all of the attributes setup in a manner that device_add can add them to sysfs, before device_add calls kobject_uevent.
So for most of the kernel today, the right solution is to setup attribute groups and set them on the device before device_add is called. For most of the code that really isn't too hard.
Making that also to get all of the attributes removed in device_del before sysfs_remove_dir is called.
So for the common case all of the complexity is handled at the device layer today.
There are a few more cases but that just takes time.
When I add that to the fact that there are cases where sysfs simply gets it wrong by deleting things like /sys/dev/char and /sys/dev/block. I can't see keeping __sysfs_remove_dir indefinitely.
Just adding my warning has turned up an issue in the scsi target vs host lifetime rules that does the wrong thing in sysfs, and that isn't something I can see sysfs making any easier by trying to be helpful.
Eric
Re: [PATCH 04/24] sysfs: Normalize removing sysfs directories.
In reply to Eric W. BiedermanQuoted 4 lines · Eric W. Biederman
My take is simply that a correct user has to wait until no one else can find the kobject before calling
kobject_del. At which point races are impossible, and it doesn't matter ifsysfs_mutexis held across the entire operation.
We have circular references between kobjects in some "advanced" users. We can not break the circle without calling _del() on one of the objects involved, but at that time all of the objects are still referenced by another object. Only a _del() will break the circle, and result in a release of the objects involved. Not sure how that would behave with this change?
Thanks,
Kay
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
James Bottomley
maintainerRe: [PATCH 04/24] sysfs: Normalize removing sysfs directories.
In reply to Eric W. BiedermanQuoted 30 lines · Eric W. Biederman
Quoted 19 lines · Tejun Heo
Quoted 9 lines · Eric W. Biederman
Also, I'm quite uncomfortable with these things
Quoted 5 lines
being done in non-atomic manner. It can be made to work but things like this can lead to subtle race conditions and with the kind of layering we put on top of sysfs (kobject, driver model, driver midlayers and so on), it isn't all that easy to verify what's going on, so NACK for this one.
Total nonsense.
Quoted 8 lines
Mucking about with sysfs after we start deleting a directory is a bug. At worst my change makes a buggy race slightly less deterministic.
I am not ready to consider keeping the current unnecessary atomic removal step. That unnecessary atomicity makes the following patches more difficult, and requires a lot of unnecessary retesting.
What do you think the extra unnecessary atomicity helps protect?
Quoted 8 lines
It's just not a clean API. When people are trying to code things way up in the stack, they aren't likely to look up the code to see what assumptions are being made especially when the stack is deep and complex and sysfs is near the bottom of the tall stack. IMHO implementing the usually expected semantics at this depth is worth every effort. It's just good implementation style which might look like wasted effort but will harden the stack in the long run. Plus, it's not like making it atomic is difficult or anything.
Quoted 6 lines
I guess we are going to have to disagree on this one.
My take is simply that a correct user has to wait until no one else can find the kobject before calling
kobject_del. At which point races are impossible, and it doesn't matter ifsysfs_mutexis held across the entire operation.
I'm afraid this one isn't a valid assumption. If you look in SCSI, you'll see we do get objects after they've been removed from visibility. We use it as part of the state model for how our objects work (objects removed from visibility are dying, but we still need them to be findable (and gettable).
Now, this could be altered as part of an object lifetime rewrite of SCSI (and I suspect a few other subsystems) but it's certainly an open question of whether the pain is worth the gain.
James
Re: [PATCH 04/24] sysfs: Normalize removing sysfs directories.
Quoted 38 lines · James Bottomley
Quoted 30 lines · Eric W. Biederman
Quoted 19 lines · Tejun Heo
Quoted 9 lines · Eric W. Biederman
Also, I'm quite uncomfortable with these things
Quoted 5 lines
being done in non-atomic manner. It can be made to work but things like this can lead to subtle race conditions and with the kind of layering we put on top of sysfs (kobject, driver model, driver midlayers and so on), it isn't all that easy to verify what's going on, so NACK for this one.
Total nonsense.
Quoted 8 lines
Mucking about with sysfs after we start deleting a directory is a bug. At worst my change makes a buggy race slightly less deterministic.
I am not ready to consider keeping the current unnecessary atomic removal step. That unnecessary atomicity makes the following patches more difficult, and requires a lot of unnecessary retesting.
What do you think the extra unnecessary atomicity helps protect?
Quoted 8 lines
It's just not a clean API. When people are trying to code things way up in the stack, they aren't likely to look up the code to see what assumptions are being made especially when the stack is deep and complex and sysfs is near the bottom of the tall stack. IMHO implementing the usually expected semantics at this depth is worth every effort. It's just good implementation style which might look like wasted effort but will harden the stack in the long run. Plus, it's not like making it atomic is difficult or anything.
Quoted 6 lines
I guess we are going to have to disagree on this one.
My take is simply that a correct user has to wait until no one else can find the kobject before calling
kobject_del. At which point races are impossible, and it doesn't matter ifsysfs_mutexis held across the entire operation.
Quoted 5 lines
I'm afraid this one isn't a valid assumption. If you look in SCSI, you'll see we do get objects after they've been removed from visibility. We use it as part of the state model for how our objects work (objects removed from visibility are dying, but we still need them to be findable (and gettable).
I was not precise enough. It appears I overlooked the fact that kobject_del is not always called from kobject_put by way of kobject_release.
Strictly the requirement is that after kobject_del we don't add, remove or otherwise manipulate sysfs attributes. That is we don't call any of:
sysfs_add_filesysfs_create_filesysfs_create_bin_filesysfs_remove_filesysfs_remove_bin_filesysfs_create_linksysfs_remove_linksysfs_create_groupsysfs_remove_groupsysfs_create_subdirsysfs_remove_subdir
Those all either oops or BUG today if you try it. So I can't see how a subsystem could depend on those working.
Also there is sysfs_remove_dir (on a subdirectory) aka kobject_del on a child object after kobject_del on the parent object.
As best I can tell that only works by fluke today.
Quoted 3 lines
Now, this could be altered as part of an object lifetime rewrite of SCSI (and I suspect a few other subsystems) but it's certainly an open question of whether the pain is worth the gain.
I won't tell you that sysfs, the kobject layer, or the device layer are the best thing since sliced bread. I'm just trying to simplify the code and get the bugs out.
Eric
James Bottomley
maintainerRe: [PATCH 04/24] sysfs: Normalize removing sysfs directories.
Quoted 46 lines · Eric W. Biederman
Quoted 38 lines · James Bottomley
Quoted 30 lines · Eric W. Biederman
Quoted 19 lines · Tejun Heo
Quoted 9 lines · Eric W. Biederman
Also, I'm quite uncomfortable with these things
Quoted 5 lines
being done in non-atomic manner. It can be made to work but things like this can lead to subtle race conditions and with the kind of layering we put on top of sysfs (kobject, driver model, driver midlayers and so on), it isn't all that easy to verify what's going on, so NACK for this one.
Total nonsense.
Quoted 8 lines
Mucking about with sysfs after we start deleting a directory is a bug. At worst my change makes a buggy race slightly less deterministic.
I am not ready to consider keeping the current unnecessary atomic removal step. That unnecessary atomicity makes the following patches more difficult, and requires a lot of unnecessary retesting.
What do you think the extra unnecessary atomicity helps protect?
Quoted 8 lines
It's just not a clean API. When people are trying to code things way up in the stack, they aren't likely to look up the code to see what assumptions are being made especially when the stack is deep and complex and sysfs is near the bottom of the tall stack. IMHO implementing the usually expected semantics at this depth is worth every effort. It's just good implementation style which might look like wasted effort but will harden the stack in the long run. Plus, it's not like making it atomic is difficult or anything.
Quoted 6 lines
I guess we are going to have to disagree on this one.
My take is simply that a correct user has to wait until no one else can find the kobject before calling
kobject_del. At which point races are impossible, and it doesn't matter ifsysfs_mutexis held across the entire operation.Quoted 5 lines
I'm afraid this one isn't a valid assumption. If you look in SCSI, you'll see we do get objects after they've been removed from visibility. We use it as part of the state model for how our objects work (objects removed from visibility are dying, but we still need them to be findable (and gettable).
Quoted 3 lines
I was not precise enough. It appears I overlooked the fact that
kobject_delis not always called fromkobject_putby way ofkobject_release.
OK ... just so you understand, I'm thinking about the device model rather than kobjects. device_del() can't be called from release methods because they're often called from interrupt context and the mutex requirements in device_del() mean it needs user context.
Quoted 17 lines
Strictly the requirement is that after
kobject_delwe don't add, remove or otherwise manipulate sysfs attributes. That is we don't call any of:
sysfs_add_filesysfs_create_filesysfs_create_bin_filesysfs_remove_filesysfs_remove_bin_filesysfs_create_linksysfs_remove_linksysfs_create_groupsysfs_remove_groupsysfs_create_subdirsysfs_remove_subdir
Quoted 2 lines
Those all either oops or BUG today if you try it. So I can't see how a subsystem could depend on those working.
It doesn't; you've altered your requirement. We can fully buy into this new relaxed one.
Quoted 4 lines
Also there is
sysfs_remove_dir(on a subdirectory) akakobject_delon a child object afterkobject_delon the parent object.As best I can tell that only works by fluke today.
Yes, that's an artifact of the fact that the reference counted lifecycle is on release ... del just happens at a certain point in it. We don't hold any counters that tell us what the visibility of our children are, so it's possible to make a parent invisible by calling del simply because you don't know.
Quoted 7 lines
Quoted 3 lines
Now, this could be altered as part of an object lifetime rewrite of SCSI (and I suspect a few other subsystems) but it's certainly an open question of whether the pain is worth the gain.
I won't tell you that sysfs, the kobject layer, or the device layer are the best thing since sliced bread. I'm just trying to simplify the code and get the bugs out.
James
Re: [PATCH 04/24] sysfs: Normalize removing sysfs directories.
Quoted 11 lines · James Bottomley
Quoted 11 lines
Quoted 10 lines
Quoted 4 lines
My take is simply that a correct user has to wait until no one else can find the kobject before calling
kobject_del. At which point races are impossible, and it doesn't matter ifsysfs_mutexis held across the entire operation.I'm afraid this one isn't a valid assumption. If you look in SCSI, you'll see we do get objects after they've been removed from visibility. We use it as part of the state model for how our objects work (objects removed from visibility are dying, but we still need them to be findable (and gettable).
Quoted 8 lines
Quoted 3 lines
I was not precise enough. It appears I overlooked the fact that
kobject_delis not always called fromkobject_putby way ofkobject_release.OK ... just so you understand, I'm thinking about the device model rather than kobjects.
device_del()can't be called from release methods because they're often called from interrupt context and the mutex requirements indevice_del()mean it needs user context.
Makes sense.
Quoted 17 lines
Quoted 17 lines
Strictly the requirement is that after
kobject_delwe don't add, remove or otherwise manipulate sysfs attributes. That is we don't call any of:
sysfs_add_filesysfs_create_filesysfs_create_bin_filesysfs_remove_filesysfs_remove_bin_filesysfs_create_linksysfs_remove_linksysfs_create_groupsysfs_remove_groupsysfs_create_subdirsysfs_remove_subdir
Quoted 5 lines
Quoted 2 lines
Those all either oops or BUG today if you try it. So I can't see how a subsystem could depend on those working.
It doesn't; you've altered your requirement. We can fully buy into this new relaxed one.
My apologies for misstating it earlier. Sometimes translating what is happening in sysfs up to the device model can be a bit of a challenge.
At the sysfs layer the requirement is all the same. Don't mess with a directory as or after you have deleted it.
To recap, my change that Tejun has a problem with is simply that I have refactored sysfs_remove_dir so that if there are directory entries present. A very fast observer in the kernel or in user space can see each directory entry being deleted individually. Before I delete the directory itself.
This is because I now drop and reacquire the sysfs_mutex in between each delete.
As the upper layers must already avoid messing with the attributes of a sysfs directory from the time we call kobject_del I don't see that this makes any difference to them.
Quoted 10 lines
Quoted 4 lines
Also there is
sysfs_remove_dir(on a subdirectory) akakobject_delon a child object afterkobject_delon the parent object.As best I can tell that only works by fluke today.
Yes, that's an artifact of the fact that the reference counted lifecycle is on release ... del just happens at a certain point in it. We don't hold any counters that tell us what the visibility of our children are, so it's possible to make a parent invisible by calling del simply because you don't know.
Strictly speaking my changes don't affect this part either except to issue a warning that something unexpected is going on.
Eric
PATCH 5/24 sysfs: Rename sysfs_d_iput to sysfs_dentry_iput
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Using dentry instead of d in the function name is what several other filesystems are doing and it seems to be a more readable convention.
--- fs/sysfs/dir.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
fs/sysfs/dir.c +2 -2
@@ -294,7 +294,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) goto repeat; } -static void sysfs_d_iput (struct dentry * dentry,struct inode * inode) +static void sysfs_dentry_iput (struct dentry * dentry,struct inode * inode) {struct sysfs_dirent * sd = dentry->d_fsdata;
@@ -303,7 +303,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) }static const struct dentry_operations sysfs_dentry_ops = { - .d_iput = sysfs_d_iput, + .d_iput = sysfs_dentry_iput, };struct sysfs_dirent *sysfs_new_dirent (const char *name,umode_t mode,int type)
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 6/24 sysfs: Use dentry_ops instead of directly playing with the dcache
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Calling d_drop unconditionally when a sysfs_dirent is deleted has the potential to leak mounts, so instead implement dentry delete and revalidate operations that cause sysfs dentries to be removed at the appropriate time.
--- fs/sysfs/dir.c | 73 +++++++++++++++++++++++++++++++++++-------------------- 1 files changed, 46 insertions(+), 27 deletions(-)
fs/sysfs/dir.c +46 -27
@@ -294,6 +294,46 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) goto repeat; } +static int sysfs_dentry_delete (struct dentry *dentry) +{ +struct sysfs_dirent *sd = dentry->d_fsdata; +return !!(sd->s_flags &SYSFS_FLAG_REMOVED ); +} + +static int sysfs_dentry_revalidate (struct dentry *dentry,struct nameidata *nd) +{ +struct sysfs_dirent *sd = dentry->d_fsdata; +int is_dir; + +mutex_lock (&sysfs_mutex); + +/* The sysfs dirent has been deleted */ +if (sd->s_flags &SYSFS_FLAG_REMOVED ) + goto out_bad; + +mutex_unlock (&sysfs_mutex); +out_valid: +return 1 ; +out_bad: +/* Remove the dentry from the dcache hashes. +* If this is a deleted dentry we use d_drop instead of d_delete +* so sysfs doesn't need to cope with negative dentries. +*/ + is_dir = (sysfs_type (sd) ==SYSFS_DIR ); +mutex_unlock (&sysfs_mutex); +if (is_dir) { +/* If we have submounts we must allow the vfs caches +* to lie about the state of the filesystem to prevent +* leaks and other nasty things. +*/ +if (have_submounts (dentry)) + goto out_valid; +shrink_dcache_parent (dentry); + } +d_drop (dentry); +return 0 ; +} +static void sysfs_dentry_iput (struct dentry * dentry,struct inode * inode) {struct sysfs_dirent * sd = dentry->d_fsdata;
@@ -303,6 +343,8 @@ static void sysfs_dentry_iput(struct dentry * dentry, struct inode * inode) }static const struct dentry_operations sysfs_dentry_ops = { + .d_revalidate = sysfs_dentry_revalidate, + .d_delete = sysfs_dentry_delete, .d_iput = sysfs_dentry_iput, };
@@ -493,44 +535,21 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) }/** -* sysfs_drop_dentry - drop dentry for the specified sysfs_dirent +* sysfs_dec_nlink - Decrement link count for the specified sysfs_dirent * @sd: target sysfs_dirent * -* Drop dentry for @sd. @sd must have been unlinked from its +* Decrement nlink for @sd. @sd must have been unlinked from its * parent on entry to this function such that it can't be looked * up anymore. */ -static void sysfs_drop_dentry (struct sysfs_dirent *sd) +static void sysfs_dec_nlink (struct sysfs_dirent *sd) {struct inode *inode; -struct dentry *dentry; inode =ilookup (sysfs_sb, sd->s_ino);if (!inode)return ; -/* Drop any existing dentries associated with sd. -* -* For the dentry to be properly freed we need to grab a -* reference to the dentry under the dcache lock, unhash it, -* and then put it. The playing with the dentry count allows -* dput to immediately free the dentry if it is not in use. -*/ -repeat: -spin_lock (&dcache_lock); -list_for_each_entry (dentry, &inode->i_dentry, d_alias) { -if (d_unhashed (dentry)) -continue ; -dget_locked (dentry); -spin_lock (&dentry->d_lock); -__d_drop (dentry); -spin_unlock (&dentry->d_lock); -spin_unlock (&dcache_lock); -dput (dentry); - goto repeat; - } -spin_unlock (&dcache_lock); -/* adjust nlink and update timestamp */ mutex_lock (&inode->i_mutex);
@@ -577,7 +596,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) acxt->removed = sd->s_sibling; sd->s_sibling =NULL ; -sysfs_drop_dentry (sd); +sysfs_dec_nlink (sd);sysfs_deactivate (sd);unmap_bin_file (sd);sysfs_put (sd);
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 7/24 sysfs: Simplify sysfs_chmod_file semantics
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Currently every caller of sysfs_chmod_file happens at either file creation time to set a non-default mode or in response to a specific user requested space change in policy. Making timestamps of when the chmod happens and notification of a file changing mode uninteresting.
Remove the unnecessary time stamp and filesystem change notification, and removes the last of the explicit inotify and donitfy support from sysfs.
--- fs/sysfs/file.c | 10 +--------- 1 files changed, 1 insertions(+), 9 deletions(-)
fs/sysfs/file.c +1 -9
@@ -602,17 +602,9 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)mutex_lock (&inode->i_mutex); newattrs.ia_mode = (mode &S_IALLUGO ) | (inode->i_mode & ~S_IALLUGO ); - newattrs.ia_valid =ATTR_MODE |ATTR_CTIME ; - newattrs.ia_ctime =current_fs_time (inode->i_sb); + newattrs.ia_valid =ATTR_MODE ; rc =sysfs_setattr (victim, &newattrs); -if (rc ==0 ) { -fsnotify_change (victim, newattrs.ia_valid); -mutex_lock (&sysfs_mutex); - victim_sd->s_mode = newattrs.ia_mode; -mutex_unlock (&sysfs_mutex); - } -mutex_unlock (&inode->i_mutex); out:dput (victim);
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 8/24 sysfs: Optimize just changing the sysfs file mode.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Don't allocate a struct iattr for the sysfs dentry if just the mode changes because we have a field for that on the sysfs_dirent, and we can trigger that case with sysfs_chmod_file.
--- fs/sysfs/inode.c | 22 ++++++++++++++-------- 1 files changed, 14 insertions(+), 8 deletions(-)
fs/sysfs/inode.c +14 -8
@@ -60,12 +60,16 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)return error; iattr->ia_valid &= ~ATTR_SIZE ;/* ignore size changes */ +if (iattr->ia_valid &ATTR_MODE ) { +if (!in_group_p (inode->i_gid) && !capable (CAP_FSETID )) + iattr->ia_mode &= ~S_ISGID ; + } error =inode_setattr (inode, iattr);if (error)return error; -if (!sd_iattr) { +if (!sd_iattr && (ia_valid & ~ATTR_MODE )) {/* setting attributes for the first time, allocate now */ sd_iattr =kzalloc (sizeof (struct iattr ),GFP_KERNEL );if (!sd_iattr)
@@ -78,6 +82,13 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) sd->s_iattr = sd_iattr; } +if (ia_valid &ATTR_MODE ) + sd->s_mode = iattr->ia_mode; + +/* If we don't need the extra attributes leave */ +if (!sd_iattr) +return 0 ; +/* attributes were changed atleast once in past */ if (ia_valid &ATTR_UID )
@@ -93,13 +104,8 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)if (ia_valid &ATTR_CTIME ) sd_iattr->ia_ctime =timespec_trunc (iattr->ia_ctime, inode->i_sb->s_time_gran); -if (ia_valid &ATTR_MODE ) { -umode_t mode = iattr->ia_mode; - -if (!in_group_p (inode->i_gid) && !capable (CAP_FSETID )) - mode &= ~S_ISGID ; - sd_iattr->ia_mode = sd->s_mode = mode; - } +if (ia_valid &ATTR_MODE ) + sd_iattr->ia_mode = iattr->ia_mode;return error; }
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 9/24 sysfs: Simplify iattr assignments
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
The granularity of sysfs time when we keep it is 1 ns. Which when passed to timestamp_trunc results in a nop. So remove the unnecessary function call making sysfs_setattr slightly easier to read.
--- fs/sysfs/inode.c | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-)
fs/sysfs/inode.c +3 -6
@@ -96,14 +96,11 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)if (ia_valid &ATTR_GID ) sd_iattr->ia_gid = iattr->ia_gid;if (ia_valid &ATTR_ATIME ) - sd_iattr->ia_atime =timespec_trunc (iattr->ia_atime, - inode->i_sb->s_time_gran); + sd_iattr->ia_atime = iattr->ia_atime;if (ia_valid &ATTR_MTIME ) - sd_iattr->ia_mtime =timespec_trunc (iattr->ia_mtime, - inode->i_sb->s_time_gran); + sd_iattr->ia_mtime = iattr->ia_mtime;if (ia_valid &ATTR_CTIME ) - sd_iattr->ia_ctime =timespec_trunc (iattr->ia_ctime, - inode->i_sb->s_time_gran); + sd_iattr->ia_ctime = iattr->ia_ctime;if (ia_valid &ATTR_MODE ) sd_iattr->ia_mode = iattr->ia_mode;
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 10/24 sysfs: Fix locking and factor out sysfs_sd_setattr
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Cleanly separate the work that is specific to setting the attributes of a sysfs_dirent from what is needed to update the attributes of a vfs inode.
Additionally grab the sysfs_mutex to keep any nasties from surprising us when updating the sysfs_dirent.
--- fs/sysfs/inode.c | 52 ++++++++++++++++++++++++++++++---------------------- fs/sysfs/sysfs.h | 1 + 2 files changed, 31 insertions(+), 22 deletions(-)
fs/sysfs/inode.c +30 -22
@@ -42,33 +42,12 @@ int __init sysfs_inode_init(void)return bdi_init (&sysfs_backing_dev_info); } -int sysfs_setattr (struct dentry * dentry,struct iattr * iattr) +int sysfs_sd_setattr (struct sysfs_dirent *sd,struct iattr * iattr) { -struct inode * inode = dentry->d_inode; -struct sysfs_dirent * sd = dentry->d_fsdata;struct iattr * sd_iattr;unsigned int ia_valid = iattr->ia_valid; -int error; - -if (!sd) -return -EINVAL ; sd_iattr = sd->s_iattr; - - error =inode_change_ok (inode, iattr); -if (error) -return error; - - iattr->ia_valid &= ~ATTR_SIZE ;/* ignore size changes */ -if (iattr->ia_valid &ATTR_MODE ) { -if (!in_group_p (inode->i_gid) && !capable (CAP_FSETID )) - iattr->ia_mode &= ~S_ISGID ; - } - - error =inode_setattr (inode, iattr); -if (error) -return error; -if (!sd_iattr && (ia_valid & ~ATTR_MODE )) {/* setting attributes for the first time, allocate now */ sd_iattr =kzalloc (sizeof (struct iattr ),GFP_KERNEL );
@@ -103,6 +82,35 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) sd_iattr->ia_ctime = iattr->ia_ctime;if (ia_valid &ATTR_MODE ) sd_iattr->ia_mode = iattr->ia_mode; +return 0 ; +} + +int sysfs_setattr (struct dentry * dentry,struct iattr * iattr) +{ +struct inode * inode = dentry->d_inode; +struct sysfs_dirent * sd = dentry->d_fsdata; +int error; + +if (!sd) +return -EINVAL ; + + error =inode_change_ok (inode, iattr); +if (error) +return error; + + iattr->ia_valid &= ~ATTR_SIZE ;/* ignore size changes */ +if (iattr->ia_valid &ATTR_MODE ) { +if (!in_group_p (inode->i_gid) && !capable (CAP_FSETID )) + iattr->ia_mode &= ~S_ISGID ; + } + + error =inode_setattr (inode, iattr); +if (error) +return error; + +mutex_lock (&sysfs_mutex); + error =sysfs_sd_setattr (sd, iattr); +mutex_unlock (&sysfs_mutex);return error; }
fs/sysfs/sysfs.h +1 -0
@@ -146,6 +146,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd)*/ struct inode *sysfs_get_inode (struct sysfs_dirent *sd);void sysfs_delete_inode (struct inode *inode); +int sysfs_sd_setattr (struct sysfs_dirent *sd,struct iattr *iattr);int sysfs_setattr (struct dentry *dentry,struct iattr *iattr);int sysfs_hash_and_remove (struct sysfs_dirent *dir_sd,const char *name);int sysfs_inode_init (void );
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 11/24 sysfs: Update s_iattr on link and unlink.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Currently sysfs updates the timestamps on the vfs directory inode when we create or remove a directory entry but doesn't update the cached copy on the sysfs_dirent, fix that oversight.
--- fs/sysfs/dir.c | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-)
fs/sysfs/dir.c +14 -0
@@ -480,6 +480,8 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)*/ int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) { +struct iattr *ps_iattr; +if (sysfs_find_dirent (acxt->parent_sd, sd->s_name)) {char *path =kzalloc (PATH_MAX ,GFP_KERNEL ); WARN(1, KERN_WARNING
@@ -500,6 +502,11 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)sysfs_link_sibling (sd); +/* Update timestamps on the parent */ + ps_iattr = acxt->parent_sd->s_iattr; +if (ps_iattr) + ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; +return 0 ; }
@@ -520,10 +527,17 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)*/ void sysfs_remove_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) { +struct iattr *ps_iattr; +BUG_ON (sd->s_flags &SYSFS_FLAG_REMOVED );sysfs_unlink_sibling (sd); +/* Update timestamps on the parent */ + ps_iattr = acxt->parent_sd->s_iattr; +if (ps_iattr) + ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; + sd->s_flags |=SYSFS_FLAG_REMOVED ; sd->s_sibling = acxt->removed; acxt->removed = sd;
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 12/24 sysfs: Nicely indent sysfs_symlink_inode_operations
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Lining up the functions in sysfs_symlink_inode_operations follows the pattern in the rest of sysfs and makes things slightly more readable.
--- fs/sysfs/symlink.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-)
fs/sysfs/symlink.c +3 -3
@@ -198,9 +198,9 @@ static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *co }const struct inode_operations sysfs_symlink_inode_operations = { - .readlink = generic_readlink, - .follow_link = sysfs_follow_link, - .put_link = sysfs_put_link, + .readlink = generic_readlink, + .follow_link = sysfs_follow_link, + .put_link = sysfs_put_link, };
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 13/24 sysfs: Implement sysfs_getattr & sysfs_permission
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
With the implementation of sysfs_getattr and sysfs_permission sysfs becomes able to lazily propogate inode attribute changes
from the sysfs_dirents to the vfs inodes. This paves the way
for deleting significant chunks of now unnecessary code.
--- fs/sysfs/dir.c | 2 + fs/sysfs/inode.c | 54 ++++++++++++++++++++++++++++++++++++++++----------- fs/sysfs/symlink.c | 3 ++ fs/sysfs/sysfs.h | 2 + 4 files changed, 49 insertions(+), 12 deletions(-)
fs/sysfs/dir.c +2 -0
@@ -763,6 +763,8 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,const struct inode_operations sysfs_dir_inode_operations = { .lookup = sysfs_lookup, .setattr = sysfs_setattr, + .getattr = sysfs_getattr, + .permission = sysfs_permission, };static void remove_dir (struct sysfs_dirent *dir_sd)
fs/sysfs/inode.c +42 -12
89 lines not on this page · raw message
fs/sysfs/symlink.c +3 -0
@@ -201,6 +201,9 @@ const struct inode_operations sysfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = sysfs_follow_link, .put_link = sysfs_put_link, + .setattr = sysfs_setattr, + .getattr = sysfs_getattr, + .permission = sysfs_permission, };
fs/sysfs/sysfs.h +2 -0
@@ -148,6 +148,8 @@ struct inode *sysfs_get_inode(struct sysfs_dirent *sd);void sysfs_delete_inode (struct inode *inode);int sysfs_sd_setattr (struct sysfs_dirent *sd,struct iattr *iattr);int sysfs_setattr (struct dentry *dentry,struct iattr *iattr); +int sysfs_getattr (struct vfsmount *mnt,struct dentry *dentry,struct kstat *stat); +int sysfs_permission (struct inode *inode,int mask);int sysfs_hash_and_remove (struct sysfs_dirent *dir_sd,const char *name);int sysfs_inode_init (void );
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 14/24 sysfs: In sysfs_chmod_file lazily propagate the mode change.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Now that sysfs_getattr and sysfs_permission refresh the vfs inode there is no need to immediatly push the mode change into the vfs cache. Reducing the amount of work needed and simplifying the locking.
--- fs/sysfs/file.c | 31 ++++++++----------------------- 1 files changed, 8 insertions(+), 23 deletions(-)
fs/sysfs/file.c +8 -23
@@ -577,38 +577,23 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);*/ int sysfs_chmod_file (struct kobject *kobj,struct attribute *attr,mode_t mode) { -struct sysfs_dirent *victim_sd =NULL ; -struct dentry *victim =NULL ; -struct inode * inode; +struct sysfs_dirent *sd;struct iattr newattrs;int rc; - rc = -ENOENT ; - victim_sd =sysfs_get_dirent (kobj->sd, attr->name); -if (!victim_sd) - goto out; +mutex_lock (&sysfs_mutex); -mutex_lock (&sysfs_rename_mutex); - victim =sysfs_get_dentry (victim_sd); -mutex_unlock (&sysfs_rename_mutex); -if (IS_ERR (victim)) { - rc =PTR_ERR (victim); - victim =NULL ; + rc = -ENOENT ; + sd =sysfs_find_dirent (kobj->sd, attr->name); +if (!sd) goto out; - } - - inode = victim->d_inode; -mutex_lock (&inode->i_mutex); - - newattrs.ia_mode = (mode &S_IALLUGO ) | (inode->i_mode & ~S_IALLUGO ); + newattrs.ia_mode = (mode &S_IALLUGO ) | (sd->s_mode & ~S_IALLUGO ); newattrs.ia_valid =ATTR_MODE ; - rc =sysfs_setattr (victim, &newattrs); + rc =sysfs_sd_setattr (sd, &newattrs); -mutex_unlock (&inode->i_mutex); out: -dput (victim); -sysfs_put (victim_sd); +mutex_unlock (&sysfs_mutex);return rc; }EXPORT_SYMBOL_GPL (sysfs_chmod_file);
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 15/24 sysfs: Kill sysfs_addrm_start and sysfs_addrm_finish
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
With lazy inode updates and dentry operations bringing everything into sync on demand there is no longer any need to immediately update the vfs or grab i_mutex to protect those updates as we make changes to sysfs.
So stop updating the vfs inodes and move what remains of sysfs_addrm_start and sysfs_addrm_finsih (just barely more than taking the sysfs_mutex) into sysfs_add_one and sysfs_remove_one.
--- fs/sysfs/dir.c | 188 +++++++--------------------------------------------- fs/sysfs/file.c | 6 +-- fs/sysfs/inode.c | 16 ++--- fs/sysfs/symlink.c | 6 +-- fs/sysfs/sysfs.h | 17 +---- 5 files changed, 32 insertions(+), 201 deletions(-)
fs/sysfs/dir.c +23 -165
@@ -382,62 +382,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)return NULL ; } -static int sysfs_ilookup_test (struct inode *inode,void *arg) -{ -struct sysfs_dirent *sd = arg; -return inode->i_ino == sd->s_ino; -} - -/** -* sysfs_addrm_start - prepare for sysfs_dirent add/remove -* @acxt: pointer to sysfs_addrm_cxt to be used -* @parent_sd: parent sysfs_dirent -* -* This function is called when the caller is about to add or -* remove sysfs_dirent under @parent_sd. This function acquires -* sysfs_mutex, grabs inode for @parent_sd if available and lock -* i_mutex of it. @acxt is used to keep and pass context to -* other addrm functions. -* -* LOCKING: -* Kernel thread context (may sleep). sysfs_mutex is locked on -* return. i_mutex of parent inode is locked on return if -* available. -*/ -void sysfs_addrm_start (struct sysfs_addrm_cxt *acxt, -struct sysfs_dirent *parent_sd) -{ -struct inode *inode; - -memset (acxt,0 ,sizeof (*acxt)); - acxt->parent_sd = parent_sd; - -/* Lookup parent inode. inode initialization is protected by -* sysfs_mutex, so inode existence can be determined by -* looking up inode while holding sysfs_mutex. -*/ -mutex_lock (&sysfs_mutex); - - inode =ilookup5 (sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test, - parent_sd); -if (inode) { -WARN_ON (inode->i_state &I_NEW ); - -/* parent inode available */ - acxt->parent_inode = inode; - -/* sysfs_mutex is below i_mutex in lock hierarchy. -* First, trylock i_mutex. If fails, unlock -* sysfs_mutex and lock them in order. -*/ -if (!mutex_trylock (&inode->i_mutex)) { -mutex_unlock (&sysfs_mutex); -mutex_lock (&inode->i_mutex); -mutex_lock (&sysfs_mutex); - } - } -} -/** * sysfs_pathname - return full path to sysfs dirent * @sd: sysfs_dirent whose path we want
@@ -460,161 +404,83 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)/** * sysfs_add_one - add sysfs_dirent to parent -* @acxt: addrm context to use +* @parent_sd: directory to add @sd into * @sd: sysfs_dirent to be added * -* Get @acxt->parent_sd and set sd->s_parent to it and increment +* Get @parent_sd and set sd->s_parent to it and increment * nlink of parent inode if @sd is a directory and link into the * children list of the parent. * -* This function should be called between calls to -* sysfs_addrm_start() and sysfs_addrm_finish() and should be -* passed the same @acxt as passed to sysfs_addrm_start(). -* * LOCKING: -* Determined by sysfs_addrm_start(). +* Kernel thread context (may sleep). Grabs sysfs_mutex. * * RETURNS: * 0 on success, -EEXIST if entry with the given name already * exists. */ -int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) +int sysfs_add_one (struct sysfs_dirent *parent_sd,struct sysfs_dirent *sd) {struct iattr *ps_iattr; -if (sysfs_find_dirent (acxt->parent_sd, sd->s_name)) { -char *path =kzalloc (PATH_MAX ,GFP_KERNEL ); +mutex_lock (&sysfs_mutex); +if (sysfs_find_dirent (parent_sd, sd->s_name)) { +char *path; +mutex_unlock (&sysfs_mutex); + + path =kzalloc (PATH_MAX ,GFP_KERNEL );WARN (1 ,KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n" , (path ==NULL ) ? sd->s_name : -strcat (strcat (sysfs_pathname (acxt->parent_sd, path),"/" ), +strcat (strcat (sysfs_pathname (parent_sd, path),"/" ), sd->s_name));kfree (path);return -EEXIST ; } - sd->s_parent =sysfs_get (acxt->parent_sd); - -if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) -inc_nlink (acxt->parent_inode); - - acxt->cnt++; - + sd->s_parent =sysfs_get (parent_sd);sysfs_link_sibling (sd);/* Update timestamps on the parent */ - ps_iattr = acxt->parent_sd->s_iattr; + ps_iattr = parent_sd->s_iattr;if (ps_iattr) ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; +mutex_unlock (&sysfs_mutex);return 0 ; }/** * sysfs_remove_one - remove sysfs_dirent from parent -* @acxt: addrm context to use * @sd: sysfs_dirent to be removed * * Mark @sd removed and drop nlink of parent inode if @sd is a * directory. @sd is unlinked from the children list. * -* This function should be called between calls to -* sysfs_addrm_start() and sysfs_addrm_finish() and should be -* passed the same @acxt as passed to sysfs_addrm_start(). -* * LOCKING: -* Determined by sysfs_addrm_start(). +* Kernel thread context (may sleep). Grabs sysfs_mutex. */ -void sysfs_remove_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) +void sysfs_remove_one (struct sysfs_dirent *sd) {struct iattr *ps_iattr;BUG_ON (sd->s_flags &SYSFS_FLAG_REMOVED ); +mutex_lock (&sysfs_mutex); +sysfs_unlink_sibling (sd);/* Update timestamps on the parent */ - ps_iattr = acxt->parent_sd->s_iattr; + ps_iattr = sd->s_parent->s_iattr;if (ps_iattr) ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; sd->s_flags |=SYSFS_FLAG_REMOVED ; - sd->s_sibling = acxt->removed; - acxt->removed = sd; - -if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) -drop_nlink (acxt->parent_inode); - - acxt->cnt++; -} - -/** -* sysfs_dec_nlink - Decrement link count for the specified sysfs_dirent -* @sd: target sysfs_dirent -* -* Decrement nlink for @sd. @sd must have been unlinked from its -* parent on entry to this function such that it can't be looked -* up anymore. -*/ -static void sysfs_dec_nlink (struct sysfs_dirent *sd) -{ -struct inode *inode; - - inode =ilookup (sysfs_sb, sd->s_ino); -if (!inode) -return ; - -/* adjust nlink and update timestamp */ -mutex_lock (&inode->i_mutex); - - inode->i_ctime =CURRENT_TIME ; -drop_nlink (inode); -if (sysfs_type (sd) ==SYSFS_DIR ) -drop_nlink (inode); - -mutex_unlock (&inode->i_mutex); - -iput (inode); -} -/** -* sysfs_addrm_finish - finish up sysfs_dirent add/remove -* @acxt: addrm context to finish up -* -* Finish up sysfs_dirent add/remove. Resources acquired by -* sysfs_addrm_start() are released and removed sysfs_dirents are -* cleaned up. Timestamps on the parent inode are updated. -* -* LOCKING: -* All mutexes acquired by sysfs_addrm_start() are released. -*/ -void sysfs_addrm_finish (struct sysfs_addrm_cxt *acxt) -{ -/* release resources acquired by sysfs_addrm_start() */ mutex_unlock (&sysfs_mutex); -if (acxt->parent_inode) { -struct inode *inode = acxt->parent_inode; -/* if added/removed, update timestamps on the parent */ -if (acxt->cnt) - inode->i_ctime = inode->i_mtime =CURRENT_TIME ; - -mutex_unlock (&inode->i_mutex); -iput (inode); - } - -/* kill removed sysfs_dirents */ -while (acxt->removed) { -struct sysfs_dirent *sd = acxt->removed; - - acxt->removed = sd->s_sibling; - sd->s_sibling =NULL ; - -sysfs_dec_nlink (sd); -sysfs_deactivate (sd); -unmap_bin_file (sd); -sysfs_put (sd); - } +sysfs_deactivate (sd); +unmap_bin_file (sd); +sysfs_put (sd); }/**
@@ -673,7 +539,6 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, const char *name, struct sysfs_dirent **p_sd) { umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; -struct sysfs_addrm_cxt acxt;struct sysfs_dirent *sd;int rc;
@@ -684,10 +549,8 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, sd->s_dir.kobj = kobj;/* link in */ -sysfs_addrm_start (&acxt, parent_sd); - rc =sysfs_add_one (&acxt, sd); -sysfs_addrm_finish (&acxt); + rc =sysfs_add_one (parent_sd, sd);if (rc ==0 ) *p_sd = sd;else
@@ -787,9 +650,7 @@ static void remove_dir(struct sysfs_dirent *dir_sd)mutex_unlock (&sysfs_mutex); } -sysfs_addrm_start (&acxt, dir_sd->s_parent);sysfs_remove_one (&acxt, dir_sd); -sysfs_addrm_finish (&acxt); }void sysfs_remove_subdir (struct sysfs_dirent *sd)
@@ -818,14 +679,11 @@ static struct sysfs_dirent *get_dirent_to_remove(struct sysfs_dirent *dir_sd)static void __sysfs_remove_dir (struct sysfs_dirent *dir_sd) { -struct sysfs_addrm_cxt acxt;struct sysfs_dirent *sd;/* Remove children that we think are safe */ while ((sd =get_dirent_to_remove (dir_sd))) { -sysfs_addrm_start (&acxt, sd->s_parent);sysfs_remove_one (&acxt, sd); -sysfs_addrm_finish (&acxt);sysfs_put (sd); }
fs/sysfs/file.c +1 -5
@@ -499,7 +499,6 @@ int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, const struct attribute *attr, int type, mode_t amode) { umode_t mode = (amode & S_IALLUGO) | S_IFREG; -struct sysfs_addrm_cxt acxt;struct sysfs_dirent *sd;int rc;
@@ -508,10 +507,7 @@ int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,return -ENOMEM ; sd->s_attr.attr = (void *)attr; -sysfs_addrm_start (&acxt, dir_sd); - rc =sysfs_add_one (&acxt, sd); -sysfs_addrm_finish (&acxt); - + rc =sysfs_add_one (dir_sd, sd);if (rc)sysfs_put (sd);
fs/sysfs/inode.c +5 -11
@@ -263,23 +263,17 @@ void sysfs_delete_inode(struct inode *inode)int sysfs_hash_and_remove (struct sysfs_dirent *dir_sd,const char *name) { -struct sysfs_addrm_cxt acxt;struct sysfs_dirent *sd;if (!dir_sd)return -ENOENT ; -sysfs_addrm_start (&acxt, dir_sd); - - sd =sysfs_find_dirent (dir_sd, name); -if (sd) -sysfs_remove_one (&acxt, sd); - -sysfs_addrm_finish (&acxt); - -if (sd) + sd =sysfs_get_dirent (dir_sd, name); +if (sd) { +sysfs_remove_one (sd); +sysfs_put (sd);return 0 ; -else + }else return -ENOENT ; }
fs/sysfs/symlink.c +1 -5
@@ -31,7 +31,6 @@ int sysfs_create_link(struct kobject *kobj, struct kobject *target,struct sysfs_dirent *parent_sd =NULL ;struct sysfs_dirent *target_sd =NULL ;struct sysfs_dirent *sd =NULL ; -struct sysfs_addrm_cxt acxt;int error;BUG_ON (!name);
@@ -65,10 +64,7 @@ int sysfs_create_link(struct kobject *kobj, struct kobject *target, sd->s_symlink.target_sd = target_sd; target_sd =NULL ;/* reference is now owned by the symlink */ -sysfs_addrm_start (&acxt, parent_sd); - error =sysfs_add_one (&acxt, sd); -sysfs_addrm_finish (&acxt); - + error =sysfs_add_one (parent_sd, sd);if (error) goto out_put;
fs/sysfs/sysfs.h +2 -15
@@ -77,16 +77,6 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd) }/* -* Context structure to be used while adding/removing nodes. -*/ -struct sysfs_addrm_cxt { -struct sysfs_dirent *parent_sd; -struct inode *parent_inode; -struct sysfs_dirent *removed; -int cnt; -}; - -/* * mount.c */ extern struct sysfs_dirent sysfs_root;
@@ -106,11 +96,8 @@ extern const struct inode_operations sysfs_dir_inode_operations;struct dentry *sysfs_get_dentry (struct sysfs_dirent *sd);struct sysfs_dirent *sysfs_get_active_two (struct sysfs_dirent *sd);void sysfs_put_active_two (struct sysfs_dirent *sd); -void sysfs_addrm_start (struct sysfs_addrm_cxt *acxt, -struct sysfs_dirent *parent_sd); -int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd); -void sysfs_remove_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd); -void sysfs_addrm_finish (struct sysfs_addrm_cxt *acxt); +int sysfs_add_one (struct sysfs_dirent *parent_sd,struct sysfs_dirent *sd); +void sysfs_remove_one (struct sysfs_dirent *sd);struct sysfs_dirent *sysfs_find_dirent (struct sysfs_dirent *parent_sd,const unsigned char *name);
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 16/24 sysfs: Propagate renames to the vfs on demand
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
By teaching sysfs_revalidate to hide a dentry for a sysfs_dirent if the sysfs_dirent has been renamed, and by teaching sysfs_lookup to return the original dentry if the sysfs dirent has been renamed. I can show the results of renames correctly without having to update the dcache during the directory rename.
This massively simplifies the rename logic allowing a lot of weird sysfs special cases to be removed along with a lot of now unnecesary helper code.
--- fs/namei.c | 22 ------- fs/sysfs/dir.c | 156 ++++++++++--------------------------------------- fs/sysfs/inode.c | 12 ---- fs/sysfs/sysfs.h | 1 - include/linux/namei.h | 1 - 5 files changed, 32 insertions(+), 160 deletions(-)
fs/namei.c +0 -22
@@ -1260,28 +1260,6 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)return __lookup_hash (&this, base,NULL ); } -/** -* lookup_one_noperm - bad hack for sysfs -* @name: pathname component to lookup -* @base: base directory to lookup from -* -* This is a variant of lookup_one_len that doesn't perform any permission -* checks. It's a horrible hack to work around the braindead sysfs -* architecture and should not be used anywhere else. -* -* DON'T USE THIS FUNCTION EVER, thanks. -*/ -struct dentry *lookup_one_noperm (const char *name,struct dentry *base) -{ -int err; -struct qstr this; - - err =__lookup_one_len (name, &this, base,strlen (name)); -if (err) -return ERR_PTR (err); -return __lookup_hash (&this, base,NULL ); -} -int user_path_at (int dfd,const char __user *name,unsigned flags,struct path *path) {
fs/sysfs/dir.c +32 -124
238 lines not on this page · raw message
fs/sysfs/inode.c +0 -12
@@ -132,17 +132,6 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) inode->i_ctime = iattr->ia_ctime; } - -/* -* sysfs has a different i_mutex lock order behavior for i_mutex than other -* filesystems; sysfs i_mutex is called in many places with subsystem locks -* held. At the same time, many of the VFS locking rules do not apply to -* sysfs at all (cross directory rename for example). To untangle this mess -* (which gives false positives in lockdep), we're giving sysfs inodes their -* own class for i_mutex. -*/ -static struct lock_class_key sysfs_inode_imutex_key; -static int sysfs_count_nlink (struct sysfs_dirent *sd) {struct sysfs_dirent *child;
@@ -190,7 +179,6 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) inode->i_mapping->a_ops = &sysfs_aops; inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; inode->i_op = &sysfs_inode_operations; -lockdep_set_class (&inode->i_mutex, &sysfs_inode_imutex_key);set_default_inode_attr (inode, sd->s_mode);sysfs_refresh_inode (sd, inode);
fs/sysfs/sysfs.h +0 -1
@@ -87,7 +87,6 @@ extern struct kmem_cache *sysfs_dir_cachep;* dir.c */ extern struct mutex sysfs_mutex; -extern struct mutex sysfs_rename_mutex;extern spinlock_t sysfs_assoc_lock;extern const struct file_operations sysfs_dir_operations;
include/linux/namei.h +0 -1
@@ -76,7 +76,6 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);extern void release_open_intent (struct nameidata *);extern struct dentry *lookup_one_len (const char *,struct dentry *,int ); -extern struct dentry *lookup_one_noperm (const char *,struct dentry *);extern int follow_down (struct vfsmount **,struct dentry **);extern int follow_up (struct vfsmount **,struct dentry **);
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 17/24 sysfs: Merge sysfs_rename_dir and sysfs_move_dir
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
These two functions do 90% of the same work and it doesn't significantly obfuscate the function to allow both the parent dir and the name to change at the same time. So merge them together to simplify maintenance, and increase testing.
--- fs/sysfs/dir.c | 66 +++++++++++++++++++++++-------------------------------- 1 files changed, 28 insertions(+), 38 deletions(-)
fs/sysfs/dir.c +28 -38
@@ -688,30 +688,42 @@ void sysfs_remove_dir(struct kobject * kobj)__sysfs_remove_dir (sd); } -int sysfs_rename_dir (struct kobject * kobj,const char *new_name) +static int sysfs_mv_dir (struct sysfs_dirent *sd, +struct sysfs_dirent *new_parent_sd,const char *new_name) { -struct sysfs_dirent *sd = kobj->sd;const char *dup_name =NULL ;int error;mutex_lock (&sysfs_mutex); error =0 ; -if (strcmp (sd->s_name, new_name) ==0 ) +if ((sd->s_parent == new_parent_sd) && + (strcmp (sd->s_name, new_name) ==0 )) goto out;/* nothing to rename */ error = -EEXIST ; -if (sysfs_find_dirent (sd->s_parent, new_name)) +if (sysfs_find_dirent (new_parent_sd, new_name)) goto out;/* rename sysfs_dirent */ - error = -ENOMEM ; - new_name = dup_name =kstrdup (new_name,GFP_KERNEL ); -if (!new_name) - goto out; +if (strcmp (sd->s_name, new_name) !=0 ) { + error = -ENOMEM ; + new_name = dup_name =kstrdup (new_name,GFP_KERNEL ); +if (!new_name) + goto out; + + dup_name = sd->s_name; + sd->s_name = new_name; + } - dup_name = sd->s_name; - sd->s_name = new_name; +/* Remove from old parent's list and insert into new parent's list. */ +if (sd->s_parent != new_parent_sd) { +sysfs_unlink_sibling (sd); +sysfs_get (new_parent_sd); +sysfs_put (sd->s_parent); + sd->s_parent = new_parent_sd; +sysfs_link_sibling (sd); + } error =0 ; out:
@@ -720,36 +732,14 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)return error; } -int sysfs_move_dir (struct kobject *kobj,struct kobject *new_parent_kobj) +int sysfs_rename_dir (struct kobject * kobj,const char *new_name) { -struct sysfs_dirent *sd = kobj->sd; -struct sysfs_dirent *new_parent_sd; -int error; - -BUG_ON (!sd->s_parent); - -mutex_lock (&sysfs_mutex); - new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; - - error =0 ; -if (sd->s_parent == new_parent_sd) - goto out;/* nothing to move */ - - error = -EEXIST ; -if (sysfs_find_dirent (new_parent_sd, sd->s_name)) - goto out; - -/* Remove from old parent's list and insert into new parent's list. */ -sysfs_unlink_sibling (sd); -sysfs_get (new_parent_sd); -sysfs_put (sd->s_parent); - sd->s_parent = new_parent_sd; -sysfs_link_sibling (sd); +return sysfs_mv_dir (kobj->sd, kobj->sd->s_parent, new_name); +} - error =0 ; -out: -mutex_unlock (&sysfs_mutex); -return error; +int sysfs_move_dir (struct kobject *kobj,struct kobject *new_parent_kobj) +{ +return sysfs_mv_dir (kobj->sd, new_parent_kobj->sd, kobj->sd->s_name); }/* Relationship between s_mode and the DT_xxx types */
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 18/24 sysfs: Pass super_block to sysfs_get_inode
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Currently sysfs_get_inode magically returns an inode on sysfs_sb. Make the super_block parameter explicit and the code becomes clearer.
--- fs/sysfs/dir.c | 2 +- fs/sysfs/inode.c | 5 +++-- fs/sysfs/mount.c | 2 +- fs/sysfs/sysfs.h | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-)
fs/sysfs/dir.c +1 -1
@@ -579,7 +579,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, }/* attach dentry and inode */ - inode =sysfs_get_inode (sd); + inode =sysfs_get_inode (dir->i_sb, sd);if (!inode) { ret =ERR_PTR (-ENOMEM ); goto out_unlock;
fs/sysfs/inode.c +3 -2
@@ -210,6 +210,7 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)/** * sysfs_get_inode - get inode for sysfs_dirent +* @sb: super block * @sd: sysfs_dirent to allocate inode for * * Get inode for @sd. If such inode doesn't exist, a new inode
@@ -222,11 +223,11 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)* RETURNS: * Pointer to allocated inode on success, NULL on failure. */ -struct inode *sysfs_get_inode (struct sysfs_dirent *sd) +struct inode *sysfs_get_inode (struct super_block *sb,struct sysfs_dirent *sd) {struct inode *inode; - inode =iget_locked (sysfs_sb, sd->s_ino); + inode =iget_locked (sb, sd->s_ino);if (inode && (inode->i_state &I_NEW ))sysfs_init_inode (sd, inode);
fs/sysfs/mount.c +1 -1
@@ -54,7 +54,7 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)/* get root inode, initialize and unlock it */ mutex_lock (&sysfs_mutex); - inode =sysfs_get_inode (&sysfs_root); + inode =sysfs_get_inode (sb, &sysfs_root);mutex_unlock (&sysfs_mutex);if (!inode) {pr_debug ("sysfs: could not get root inode\n" );
fs/sysfs/sysfs.h +1 -1
@@ -130,7 +130,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd)/* * inode.c */ -struct inode *sysfs_get_inode (struct sysfs_dirent *sd); +struct inode *sysfs_get_inode (struct super_block *sb,struct sysfs_dirent *sd);void sysfs_delete_inode (struct inode *inode);int sysfs_sd_setattr (struct sysfs_dirent *sd,struct iattr *iattr);int sysfs_setattr (struct dentry *dentry,struct iattr *iattr);
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 19/24 sysfs: Kill unused sysfs_sb variable.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Now that there are no more users we can remove
the sysfs_sb variable.
--- fs/sysfs/mount.c | 2 -- fs/sysfs/sysfs.h | 1 - 2 files changed, 0 insertions(+), 3 deletions(-)
fs/sysfs/mount.c +0 -2
@@ -23,7 +23,6 @@static struct vfsmount *sysfs_mount; -struct super_block * sysfs_sb =NULL ;struct kmem_cache *sysfs_dir_cachep;static const struct super_operations sysfs_ops = {
@@ -50,7 +49,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_magic =SYSFS_MAGIC ; sb->s_op = &sysfs_ops; sb->s_time_gran =1 ; - sysfs_sb = sb;/* get root inode, initialize and unlock it */ mutex_lock (&sysfs_mutex);
fs/sysfs/sysfs.h +0 -1
@@ -80,7 +80,6 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd)* mount.c */ extern struct sysfs_dirent sysfs_root; -extern struct super_block *sysfs_sb;extern struct kmem_cache *sysfs_dir_cachep;/*
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 20/24 sysfs: Normalize error handling in sysfs_fill_inode
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Use a single error exit path instead of doing whatever is the required cleanup at each point we find the error. Ultimately this should make the code more maintainable.
--- fs/sysfs/mount.c | 16 +++++++++++----- 1 files changed, 11 insertions(+), 5 deletions(-)
fs/sysfs/mount.c +11 -5
@@ -41,8 +41,9 @@ struct sysfs_dirent sysfs_root = {static int sysfs_fill_super (struct super_block *sb,void *data,int silent) { -struct inode *inode; -struct dentry *root; +struct inode *inode =NULL ; +struct dentry *root =NULL ; +int error; sb->s_blocksize =PAGE_CACHE_SIZE ; sb->s_blocksize_bits =PAGE_CACHE_SHIFT ;
@@ -51,24 +52,29 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_time_gran =1 ;/* get root inode, initialize and unlock it */ + error = -ENOMEM ;mutex_lock (&sysfs_mutex); inode =sysfs_get_inode (sb, &sysfs_root);mutex_unlock (&sysfs_mutex);if (!inode) {pr_debug ("sysfs: could not get root inode\n" ); -return -ENOMEM ; + goto err_out; }/* instantiate and link root dentry */ + error = -ENOMEM ; root =d_alloc_root (inode);if (!root) {pr_debug ("%s: could not get root dentry!\n" ,__func__); -iput (inode); -return -ENOMEM ; + goto err_out; } root->d_fsdata = &sysfs_root; sb->s_root = root;return 0 ; +err_out: +dput (root); +iput (inode); +return error; } static int sysfs_get_sb(struct file_system_type *fs_type,
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 21/24 sysfs: Rename sysfs_mv_dir sysfs_rename
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
It turns out that sysfs_mv_dir actually makes no assumptions that what
is being renamed is a directory. So rename sysfs_mv_dir to sysfs_rename to
reflect the functions general utility. Later we will use it rename symlinks in sysfs.
--- fs/sysfs/dir.c | 6 +++--- fs/sysfs/sysfs.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-)
fs/sysfs/dir.c +3 -3
@@ -688,7 +688,7 @@ void sysfs_remove_dir(struct kobject * kobj)__sysfs_remove_dir (sd); } -static int sysfs_mv_dir (struct sysfs_dirent *sd, +int sysfs_rename (struct sysfs_dirent *sd,struct sysfs_dirent *new_parent_sd,const char *new_name) {const char *dup_name =NULL ;
@@ -734,12 +734,12 @@ static int sysfs_mv_dir(struct sysfs_dirent *sd,int sysfs_rename_dir (struct kobject * kobj,const char *new_name) { -return sysfs_mv_dir (kobj->sd, kobj->sd->s_parent, new_name); +return sysfs_rename (kobj->sd, kobj->sd->s_parent, new_name); }int sysfs_move_dir (struct kobject *kobj,struct kobject *new_parent_kobj) { -return sysfs_mv_dir (kobj->sd, new_parent_kobj->sd, kobj->sd->s_name); +return sysfs_rename (kobj->sd, new_parent_kobj->sd, kobj->sd->s_name); }/* Relationship between s_mode and the DT_xxx types */
fs/sysfs/sysfs.h +3 -0
@@ -109,6 +109,9 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, struct sysfs_dirent **p_sd);void sysfs_remove_subdir (struct sysfs_dirent *sd); +int sysfs_rename (struct sysfs_dirent *sd, +struct sysfs_dirent *new_parent_sd,const char *new_name); +static inline struct sysfs_dirent *__sysfs_get (struct sysfs_dirent *sd) {if (sd) {
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 22/24 sysfs: Make sysfs_rename_link atomic
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Use the existing sysfs_rename to make sysfs_rename_link an atomic operation that does less work. While I am at add additional sanity checking to ensure it is a symlink I am renaming.
--- fs/sysfs/symlink.c | 26 ++++++++++++++++++++++++-- 1 files changed, 24 insertions(+), 2 deletions(-)
fs/sysfs/symlink.c +24 -2
@@ -106,8 +106,30 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)int sysfs_rename_link (struct kobject *kobj,struct kobject *targ,const char *old,const char *new) { -sysfs_remove_link (kobj, old); -return sysfs_create_link (kobj, targ, new); +struct sysfs_dirent *parent_sd, *sd =NULL ; +int result; + +if (!kobj) + parent_sd = &sysfs_root; +else + parent_sd = kobj->sd; + + result = -ENOENT ; + sd =sysfs_get_dirent (parent_sd, old); +if (!sd) + goto out; + + result = -EINVAL ; +if (sysfs_type (sd) !=SYSFS_KOBJ_LINK ) + goto out; +if (sd->s_symlink.target_sd->s_dir.kobj != targ) + goto out; + + result =sysfs_rename (sd, parent_sd, new); + +out: +sysfs_put (sd); +return result; } static int sysfs_get_target_path(struct sysfs_dirent *parent_sd,
Signature · 1 line
1.6.3.1.54.g99dd.dirty
Re: [PATCH 22/24] sysfs: Make sysfs_rename_link atomic
Quoted 8 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Use the existing
sysfs_renameto makesysfs_rename_linkan atomic operation that does less work. While I am at add additional sanity checking to ensure it is a symlink I am renaming.Acked-by Kay Sievers <[email protected]>Signed-off-by Eric W. Biederman <[email protected]>
It would be really nice to merge or group this together with the first three patches. Other than that,
Signature · 1 line
tejun
Re: [PATCH 22/24] sysfs: Make sysfs_rename_link atomic
Quoted 7 lines · Tejun Heo
Quoted 6 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Use the existing
sysfs_renameto makesysfs_rename_linkan atomic operation that does less work. While I am at add additional sanity checking to ensure it is a symlink I am renaming.
Quoted 5 lines
Quoted 2 lines
Acked-by Kay Sievers <[email protected]>Signed-off-by Eric W. Biederman <[email protected]>It would be really nice to merge or group this together with the first three patches. Other than that,
Perfection is the enemy of the good on that one. That just convolutes things unnecessarily, makes the patches harder to review, and requires additional testing.
I much prefer to work in a tree without rewinding.
Quoted 4 lines
Acked-by Tejun Heo <[email protected]>Signature · 1 line
tejun
Re: [PATCH 22/24] sysfs: Make sysfs_rename_link atomic
Quoted 11 lines · Eric W. Biederman
Quoted 9 lines · Tejun Heo
Quoted 8 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Use the existing
sysfs_renameto makesysfs_rename_linkan atomic operation that does less work. While I am at add additional sanity checking to ensure it is a symlink I am renaming.Acked-by Kay Sievers <[email protected]>Signed-off-by Eric W. Biederman <[email protected]>
Quoted 8 lines
Quoted 2 lines
It would be really nice to merge or group this together with the first three patches. Other than that,
Perfection is the enemy of the good on that one. That just convolutes things unnecessarily, makes the patches harder to review, and requires additional testing.
I much prefer to work in a tree without rewinding.
Everything is a matter of degree and I don't think my bar here was too high. Unless patches are in some exported tree and when the content of the patchset changes (you're changing the behavior of the same code two times), reordering patches is what's usually done. When the end results stay the same, reshuffling isn't that much of work, is it?
Well, I'm not the maintainer and things like this are mostly upto the maintainer, so let's leave it to be decided by Greg.
Thanks.
Signature · 1 line
tejun
PATCH 23/24 driver core: Don't remove kobjects in device_shutdown.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
device_shutdown is defined to just shutdown the hardware and to not clean up any kernel data structures. Therefore don't put the kobjects for /sys/dev and /sys/dev/block and /sys/dev/char.
This ensures we don't remove /sys/dev/block and /sys/dev/char while we still have symlinks from there to the actual devices.
--- drivers/base/core.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-)
drivers/base/core.c +0 -3
@@ -1653,7 +1653,4 @@ void device_shutdown(void) dev->driver->shutdown (dev); } } -kobject_put (sysfs_dev_char_kobj); -kobject_put (sysfs_dev_block_kobj); -kobject_put (dev_kobj); }
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 24/24 sysfs: In sysfs_add_one fail if the targe directory has been removed.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
If a bug in the upper layers results in someone attempting to add to a sysfs directory that has already been removed, warn about it and fail.
I don't believe this has ever happened, and it certainly never should happen, but be strict to avoid errors creeping in.
--- fs/sysfs/dir.c | 37 +++++++++++++++++++++++-------------- 1 files changed, 23 insertions(+), 14 deletions(-)
fs/sysfs/dir.c +22 -13
@@ -394,21 +394,17 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)int sysfs_add_one (struct sysfs_dirent *parent_sd,struct sysfs_dirent *sd) {struct iattr *ps_iattr; +char *path; +int result;mutex_lock (&sysfs_mutex); -if (sysfs_find_dirent (parent_sd, sd->s_name)) { -char *path; -mutex_unlock (&sysfs_mutex); - path =kzalloc (PATH_MAX ,GFP_KERNEL ); -WARN (1 ,KERN_WARNING -"sysfs: cannot create duplicate filename '%s'\n" , - (path ==NULL ) ? sd->s_name : -strcat (strcat (sysfs_pathname (parent_sd, path),"/" ), - sd->s_name)); -kfree (path); -return -EEXIST ; - } + result = -ENOENT ; +if (parent_sd->s_flags &SYSFS_FLAG_REMOVED ) + goto out_err; + +if (sysfs_find_dirent (parent_sd, sd->s_name)) + goto out_err; sd->s_parent =sysfs_get (parent_sd);sysfs_link_sibling (sd);
@@ -417,9 +413,22 @@ int sysfs_add_one(struct sysfs_dirent *parent_sd, struct sysfs_dirent *sd) ps_iattr = parent_sd->s_iattr;if (ps_iattr) ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; -mutex_unlock (&sysfs_mutex);return 0 ; + +out_err: +mutex_unlock (&sysfs_mutex); + + path =kzalloc (PATH_MAX ,GFP_KERNEL ); +WARN (1 ,KERN_WARNING "sysfs: cannot create '%s' %s\n" , + (path ==NULL ) ? sd->s_name : +strcat (strcat (sysfs_pathname (parent_sd, path),"/" ), + sd->s_name), + (result == -EEXIST ?"duplicate filename" :"no such directory" ) + ); +kfree (path); + +return result; }/**
Signature · 1 line
1.6.3.1.54.g99dd.dirty
Re: [PATCH 24/24] sysfs: In sysfs_add_one fail if the targe directory has been removed.
Quoted 11 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
If a bug in the upper layers results in someone attempting to add to a sysfs directory that has already been removed, warn about it and fail.
I don't believe this has ever happened, and it certainly never should happen, but be strict to avoid errors creeping in.
Acked-by Kay Sievers <[email protected]>Signed-off-by Eric W. Biederman <[email protected]>
Signature · 1 line
tejun
cover sysfs cleanups v3.
In reply to Eric W. BiedermanHere is the third respin of my sysfs patches.
Tejun had a good point I was doing to much when I touched __sysfs_read_dir. So that work has been split into 3 patches.
This made a good excuse for me to review the if (!dir_sd) check and be certain it was not needed. I have not found any actual problems so the resulting code is the same as the last patchset.
Now the change to delete each dirent in sysfs_read_dir is it's own separate patch so Tejun can happily beat me up on just that one idea. I honestly can't see how holding sysfs_mutex over the entire directory deletion helps anything.
The net change is less buggy than the current sysfs and a fair bit simpler.
git-diff-tree --stat v2.6.30-rc5..HEAD
drivers/base/core.c | 21 +-- fs/namei.c | 22 -- fs/sysfs/dir.c | 596 ++++++++++++++++--------------------------------- fs/sysfs/file.c | 47 +--- fs/sysfs/inode.c | 154 ++++++++------ fs/sysfs/mount.c | 20 +- fs/sysfs/symlink.c | 93 +++++---- fs/sysfs/sysfs.h | 28 +-- include/linux/namei.h | 1 - include/linux/sysfs.h | 9 + 10 files changed, 383 insertions(+), 608 deletions(-)
Eric
PATCH 1/26 sysfs: Implement sysfs_rename_link
From: Eric W. Biederman <[email protected]>
Because of rename ordering problems we occassionally give false warnings about invalid sysfs operations, so implement a helper function for this common sysfs idiom.
This is a stripped down version of an earlier patch that also added sysfs_delete_link.
--- fs/sysfs/symlink.c | 16 ++++++++++++++++ include/linux/sysfs.h | 9 +++++++++ 2 files changed, 25 insertions(+), 0 deletions(-)
fs/sysfs/symlink.c +16 -0
@@ -122,6 +122,22 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)sysfs_hash_and_remove (parent_sd, name); } +/** +* sysfs_rename_link - rename symlink in object's directory. +* @kobj: object we're acting for. +* @targ: object we're pointing to. +* @old: previous name of the symlink. +* @new: new name of the symlink. +* +* A helper function for the common rename symlink idiom. +*/ +int sysfs_rename_link (struct kobject *kobj,struct kobject *targ, +const char *old,const char *new) +{ +sysfs_remove_link (kobj, old); +return sysfs_create_link (kobj, targ, new); +} +static int sysfs_get_target_path (struct sysfs_dirent *parent_sd,struct sysfs_dirent *target_sd,char *path) {
include/linux/sysfs.h +9 -0
@@ -109,6 +109,9 @@ int __must_check sysfs_create_link_nowarn(struct kobject *kobj, const char *name);void sysfs_remove_link (struct kobject *kobj,const char *name); +int sysfs_rename_link (struct kobject *kobj,struct kobject *target, +const char *old_name,const char *new_name); +int __must_check sysfs_create_group (struct kobject *kobj,const struct attribute_group *grp); int sysfs_update_group(struct kobject *kobj,
@@ -202,6 +205,12 @@ static inline void sysfs_remove_link(struct kobject *kobj, const char *name) { } +static inline int sysfs_rename_link (struct kobject *k,struct kobject *t, +const char *old_name,const char *new_name) +{ +return 0 ; +} +static inline int sysfs_create_group (struct kobject *kobj,const struct attribute_group *grp) {
Signature · 1 line
1.6.3.1.54.g99dd.dirty
[email protected]
Appliedpatch sysfs-implement-sysfs_rename_link.patch added to gregkh-2.6 tree
This is a note to let you know that I've just added the patch titled
Subject: sysfs: Implement sysfs_rename_link
to my gregkh-2.6 tree. Its filename is
sysfs-implement-sysfs_rename_link.patch
This tree can be found at
http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/
Quoted 1 line
From [email protected] Tue Jun 2 15:34:06 2009
From: "Eric W. Biederman" <[email protected]>
Date: Fri, 29 May 2009 13:19:11 -0700
Subject: sysfs: Implement sysfs_rename_link
To: Andrew Morton <[email protected]>, Greg Kroah-Hartman <[email protected]>
Cc: Tejun Heo <[email protected]>, Cornelia Huck <[email protected]>, <[email protected]>, Kay Sievers <[email protected]>, Greg KH <[email protected]>, "Eric W. Biederman" <[email protected]>, Benjamin Thery <[email protected]>, Daniel Lezcano <[email protected]>, "Eric W. Biederman" <[email protected]>
Message-ID: <[email protected]>
From: Eric W. Biederman <[email protected]>
Because of rename ordering problems we occassionally give false warnings about invalid sysfs operations, so implement a helper function for this common sysfs idiom.
This is a stripped down version of an earlier patch that also added sysfs_delete_link.
--- fs/sysfs/symlink.c | 16 ++++++++++++++++ include/linux/sysfs.h | 9 +++++++++ 2 files changed, 25 insertions(+)
fs/sysfs/symlink.c +16 -0
@@ -122,6 +122,22 @@ void sysfs_remove_link(struct kobject *sysfs_hash_and_remove (parent_sd, name); } +/** +* sysfs_rename_link - rename symlink in object's directory. +* @kobj: object we're acting for. +* @targ: object we're pointing to. +* @old: previous name of the symlink. +* @new: new name of the symlink. +* +* A helper function for the common rename symlink idiom. +*/ +int sysfs_rename_link (struct kobject *kobj,struct kobject *targ, +const char *old,const char *new) +{ +sysfs_remove_link (kobj, old); +return sysfs_create_link (kobj, targ, new); +} +static int sysfs_get_target_path (struct sysfs_dirent *parent_sd,struct sysfs_dirent *target_sd,char *path) {
include/linux/sysfs.h +9 -0
@@ -109,6 +109,9 @@ int __must_check sysfs_create_link_nowar const char *name);void sysfs_remove_link (struct kobject *kobj,const char *name); +int sysfs_rename_link (struct kobject *kobj,struct kobject *target, +const char *old_name,const char *new_name); +int __must_check sysfs_create_group (struct kobject *kobj,const struct attribute_group *grp); int sysfs_update_group(struct kobject *kobj,
@@ -202,6 +205,12 @@ static inline void sysfs_remove_link(str { } +static inline int sysfs_rename_link (struct kobject *k,struct kobject *t, +const char *old_name,const char *new_name) +{ +return 0 ; +} +static inline int sysfs_create_group (struct kobject *kobj,const struct attribute_group *grp) {
PATCH 2/26 driver core: Use sysfs_rename_link in device_rename
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Don't open code the renaming of symlinks in sysfs instead use the new helper function sysfs_rename_link
--- drivers/base/core.c | 18 ++++++------------ 1 files changed, 6 insertions(+), 12 deletions(-)
drivers/base/core.c +6 -12
@@ -1490,22 +1490,16 @@ int device_rename(struct device *dev, char *new_name)if (old_class_name) { new_class_name =make_class_name (dev->class->name, &dev->kobj);if (new_class_name) { - error =sysfs_create_link_nowarn (&dev->parent->kobj, - &dev->kobj, - new_class_name); -if (error) - goto out; -sysfs_remove_link (&dev->parent->kobj, old_class_name); + error =sysfs_rename_link (&dev->parent->kobj, + &dev->kobj, + old_class_name, + new_class_name); } }#else if (dev->class) { - error =sysfs_create_link_nowarn (&dev->class->p->class_subsys.kobj, - &dev->kobj,dev_name (dev)); -if (error) - goto out; -sysfs_remove_link (&dev->class->p->class_subsys.kobj, - old_device_name); + error =sysfs_rename_link (&dev->class->p->class_subsys.kobj, + &dev->kobj, old_device_name, new_name); }#endif
Signature · 1 line
1.6.3.1.54.g99dd.dirty
[email protected]
Appliedpatch driver-core-use-sysfs_rename_link-in-device_rename.patch added to gregkh-2.6 tree
This is a note to let you know that I've just added the patch titled
Subject: driver core: Use sysfs_rename_link in device_rename
to my gregkh-2.6 tree. Its filename is
driver-core-use-sysfs_rename_link-in-device_rename.patch
This tree can be found at
http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/
Quoted 1 line
From [email protected] Tue Jun 2 15:34:29 2009
From: "Eric W. Biederman" <[email protected]>
Date: Fri, 29 May 2009 13:19:12 -0700
Subject: driver core: Use sysfs_rename_link in device_rename
To: Andrew Morton <[email protected]>, Greg Kroah-Hartman <[email protected]>
Cc: Tejun Heo <[email protected]>, Cornelia Huck <[email protected]>, <[email protected]>, Kay Sievers <[email protected]>, Greg KH <[email protected]>, "Eric W. Biederman" <[email protected]>, "Eric W. Biederman" <[email protected]>
Message-ID: <[email protected]>
From: Eric W. Biederman <[email protected]>
Don't open code the renaming of symlinks in sysfs instead use the new helper function sysfs_rename_link
--- drivers/base/core.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-)
drivers/base/core.c +6 -12
@@ -1546,22 +1546,16 @@ int device_rename(struct device *dev, chif (old_class_name) { new_class_name =make_class_name (dev->class->name, &dev->kobj);if (new_class_name) { - error =sysfs_create_link_nowarn (&dev->parent->kobj, - &dev->kobj, - new_class_name); -if (error) - goto out; -sysfs_remove_link (&dev->parent->kobj, old_class_name); + error =sysfs_rename_link (&dev->parent->kobj, + &dev->kobj, + old_class_name, + new_class_name); } }#else if (dev->class) { - error =sysfs_create_link_nowarn (&dev->class->p->class_subsys.kobj, - &dev->kobj,dev_name (dev)); -if (error) - goto out; -sysfs_remove_link (&dev->class->p->class_subsys.kobj, - old_device_name); + error =sysfs_rename_link (&dev->class->p->class_subsys.kobj, + &dev->kobj, old_device_name, new_name); }#endif
PATCH 3/26 sysfs: Remove now unnecessary error reporting suppression.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Now that we use sysfs_rename_link in the places we previously used sysfs_create_link_nowarn we can remove sysfs_create_link_nowarn and all it's supporting infrastructure as it has no callers.
--- fs/sysfs/dir.c | 54 +++++++++++---------------------------------------- fs/sysfs/symlink.c | 42 ++++++++------------------------------- fs/sysfs/sysfs.h | 1 - 3 files changed, 21 insertions(+), 76 deletions(-)
fs/sysfs/dir.c +12 -42
@@ -397,43 +397,6 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, }/** -* __sysfs_add_one - add sysfs_dirent to parent without warning -* @acxt: addrm context to use -* @sd: sysfs_dirent to be added -* -* Get @acxt->parent_sd and set sd->s_parent to it and increment -* nlink of parent inode if @sd is a directory and link into the -* children list of the parent. -* -* This function should be called between calls to -* sysfs_addrm_start() and sysfs_addrm_finish() and should be -* passed the same @acxt as passed to sysfs_addrm_start(). -* -* LOCKING: -* Determined by sysfs_addrm_start(). -* -* RETURNS: -* 0 on success, -EEXIST if entry with the given name already -* exists. -*/ -int __sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) -{ -if (sysfs_find_dirent (acxt->parent_sd, sd->s_name)) -return -EEXIST ; - - sd->s_parent =sysfs_get (acxt->parent_sd); - -if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) -inc_nlink (acxt->parent_inode); - - acxt->cnt++; - -sysfs_link_sibling (sd); - -return 0 ; -} - -/** * sysfs_pathname - return full path to sysfs dirent * @sd: sysfs_dirent whose path we want * @path: caller allocated buffer
@@ -475,10 +438,7 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)*/ int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) { -int ret; - - ret =__sysfs_add_one (acxt, sd); -if (ret == -EEXIST ) { +if (sysfs_find_dirent (acxt->parent_sd, sd->s_name)) {char *path =kzalloc (PATH_MAX ,GFP_KERNEL ); WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n",
@@ -486,9 +446,19 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)strcat (strcat (sysfs_pathname (acxt->parent_sd, path),"/" ), sd->s_name));kfree (path); +return -EEXIST ; } -return ret; + sd->s_parent =sysfs_get (acxt->parent_sd); + +if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) +inc_nlink (acxt->parent_inode); + + acxt->cnt++; + +sysfs_link_sibling (sd); + +return 0 ; }/**
fs/sysfs/symlink.c +9 -33
60 lines not on this page · raw message
fs/sysfs/sysfs.h +0 -1
@@ -108,7 +108,6 @@ struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);void sysfs_put_active_two (struct sysfs_dirent *sd);void sysfs_addrm_start (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *parent_sd); -int __sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd);int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd);void sysfs_remove_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd);void sysfs_addrm_finish (struct sysfs_addrm_cxt *acxt);
Signature · 1 line
1.6.3.1.54.g99dd.dirty
[email protected]
Appliedpatch sysfs-remove-now-unnecessary-error-reporting-suppression.patch added to gregkh-2.6 tree
This is a note to let you know that I've just added the patch titled
Subject: sysfs: Remove now unnecessary error reporting suppression.
to my gregkh-2.6 tree. Its filename is
sysfs-remove-now-unnecessary-error-reporting-suppression.patch
This tree can be found at
http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/
Quoted 1 line
From [email protected] Tue Jun 2 15:35:03 2009
From: "Eric W. Biederman" <[email protected]>
Date: Fri, 29 May 2009 13:19:13 -0700
Subject: sysfs: Remove now unnecessary error reporting suppression.
To: Andrew Morton <[email protected]>, Greg Kroah-Hartman <[email protected]>
Cc: Tejun Heo <[email protected]>, Cornelia Huck <[email protected]>, <[email protected]>, Kay Sievers <[email protected]>, Greg KH <[email protected]>, "Eric W. Biederman" <[email protected]>, "Eric W. Biederman" <[email protected]>
Message-ID: <[email protected]>
From: Eric W. Biederman <[email protected]>
Now that we use sysfs_rename_link in the places we previously used sysfs_create_link_nowarn we can remove sysfs_create_link_nowarn and all it's supporting infrastructure as it has no callers.
--- fs/sysfs/dir.c | 54 +++++++++++------------------------------------------ fs/sysfs/symlink.c | 42 ++++++++--------------------------------- fs/sysfs/sysfs.h | 1 3 files changed, 21 insertions(+), 76 deletions(-)
fs/sysfs/dir.c +12 -42
@@ -397,43 +397,6 @@ void sysfs_addrm_start(struct sysfs_addr }/** -* __sysfs_add_one - add sysfs_dirent to parent without warning -* @acxt: addrm context to use -* @sd: sysfs_dirent to be added -* -* Get @acxt->parent_sd and set sd->s_parent to it and increment -* nlink of parent inode if @sd is a directory and link into the -* children list of the parent. -* -* This function should be called between calls to -* sysfs_addrm_start() and sysfs_addrm_finish() and should be -* passed the same @acxt as passed to sysfs_addrm_start(). -* -* LOCKING: -* Determined by sysfs_addrm_start(). -* -* RETURNS: -* 0 on success, -EEXIST if entry with the given name already -* exists. -*/ -int __sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) -{ -if (sysfs_find_dirent (acxt->parent_sd, sd->s_name)) -return -EEXIST ; - - sd->s_parent =sysfs_get (acxt->parent_sd); - -if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) -inc_nlink (acxt->parent_inode); - - acxt->cnt++; - -sysfs_link_sibling (sd); - -return 0 ; -} - -/** * sysfs_pathname - return full path to sysfs dirent * @sd: sysfs_dirent whose path we want * @path: caller allocated buffer
@@ -475,10 +438,7 @@ static char *sysfs_pathname(struct sysfs*/ int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) { -int ret; - - ret =__sysfs_add_one (acxt, sd); -if (ret == -EEXIST ) { +if (sysfs_find_dirent (acxt->parent_sd, sd->s_name)) {char *path =kzalloc (PATH_MAX ,GFP_KERNEL ); WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n",
@@ -486,9 +446,19 @@ int sysfs_add_one(struct sysfs_addrm_cxtstrcat (strcat (sysfs_pathname (acxt->parent_sd, path),"/" ), sd->s_name));kfree (path); +return -EEXIST ; } -return ret; + sd->s_parent =sysfs_get (acxt->parent_sd); + +if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) +inc_nlink (acxt->parent_inode); + + acxt->cnt++; + +sysfs_link_sibling (sd); + +return 0 ; }/**
fs/sysfs/symlink.c +9 -33
60 lines not on this page · raw message
fs/sysfs/sysfs.h +0 -1
@@ -108,7 +108,6 @@ struct sysfs_dirent *sysfs_get_active_twvoid sysfs_put_active_two (struct sysfs_dirent *sd);void sysfs_addrm_start (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *parent_sd); -int __sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd);int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd);void sysfs_remove_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd);void sysfs_addrm_finish (struct sysfs_addrm_cxt *acxt);
PATCH 4/26 sysfs: sysfs_remove_dir stop checking for bogus cases.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
kobj->sd can not be NULL in sysfs_remove_dir.
sysfs_remove_dir is only called from kobject_add (to clean up after failure) and from kobject_del at the end of a kobject's life. In both cases kobject_add has already called sysfs_create_dir successfully. The only writers of kobj->sd are sysfs_create_dir on sucess and sysfs_remove_dir when it clears the kobj just before deleting the directory.
Which means at the time sysfs_remove_dir is called kobj->sd will be valid.
--- fs/sysfs/dir.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-)
fs/sysfs/dir.c +0 -3
@@ -752,9 +752,6 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)struct sysfs_addrm_cxt acxt;struct sysfs_dirent **pos; -if (!dir_sd) -return ; -pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name);sysfs_addrm_start (&acxt, dir_sd); pos = &dir_sd->s_dir.children;
Signature · 1 line
1.6.3.1.54.g99dd.dirty
Re: [PATCH 04/26] sysfs: sysfs_remove_dir stop checking for bogus cases.
Quoted 4 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
kobj->sdcan not be NULL insysfs_remove_dir.
Quoted 8 lines
sysfs_remove_diris only called fromkobject_add(to clean up after failure) and fromkobject_delat the end of a kobject's life. In both caseskobject_addhas already calledsysfs_create_dirsuccessfully. The only writers ofkobj->sdaresysfs_create_diron sucess andsysfs_remove_dirwhen it clears the kobj just before deleting the directory.Which means at the time
sysfs_remove_diris calledkobj->sdwill be valid.
Yeah, we would hope so.
But as we have been forced to add many checks like this into the driver core to handle those "no one could ever call this" type problems that have been springing up over time, I am hesitant to remove this check.
Why do you want to remove it, what is the problem here you are trying to solve?
thanks,
greg k-h
Re: [PATCH 04/26] sysfs: sysfs_remove_dir stop checking for bogus cases.
Quoted 14 lines · Greg KH
Quoted 4 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
kobj->sdcan not be NULL insysfs_remove_dir.Quoted 8 lines
sysfs_remove_diris only called fromkobject_add(to clean up after failure) and fromkobject_delat the end of a kobject's life. In both caseskobject_addhas already calledsysfs_create_dirsuccessfully. The only writers ofkobj->sdaresysfs_create_diron sucess andsysfs_remove_dirwhen it clears the kobj just before deleting the directory.Which means at the time
sysfs_remove_diris calledkobj->sdwill be valid.
Quoted 8 lines
Yeah, we would hope so.
But as we have been forced to add many checks like this into the driver core to handle those "no one could ever call this" type problems that have been springing up over time, I am hesitant to remove this check.
Why do you want to remove it, what is the problem here you are trying to solve?
I'm cleaning up and simplifying the code.
In this particular instance the check is actually wrong. There is no
valid code path that depends on that behavior. Which means the test
is both useless and actively obscures the code.
Making it a BUG_ON would be valid.
The other side of it is I realized I had been running for months without that check. I had deleted it as an oversight. Then when the code churn was small enough and Tejun asked me about it. I split this hunk out into it's own separate patch. As I figured it deserved it's own patch so the change could stand out and be reviewed. Since my review of the code path showed no valid use case I kept it.
Eric
PATCH 5/26 sysfs: Improve sysfs directory deletion debugging.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
We have found several cases where directories are deleted without removing all of their subdirectories. That case isn't valid so warn anyone who makes that mistake, and continue to leak dirents to keep the system as operational as possible.
Move the debug message when a directory is deleted into remove_dir so we are told when subdirectories are deleted as well as full fledge kobject directories.
--- fs/sysfs/dir.c | 23 +++++++++++++++++++---- 1 files changed, 19 insertions(+), 4 deletions(-)
fs/sysfs/dir.c +19 -4
@@ -732,12 +732,28 @@ const struct inode_operations sysfs_dir_inode_operations = { .setattr = sysfs_setattr, }; -static void remove_dir (struct sysfs_dirent *sd) +static void remove_dir (struct sysfs_dirent *dir_sd) {struct sysfs_addrm_cxt acxt; -sysfs_addrm_start (&acxt, sd->s_parent); -sysfs_remove_one (&acxt, sd); +pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name); + +/* Removing non-empty directories is not valid complain! */ +if (unlikely (dir_sd->s_dir.children)) { +struct sysfs_dirent *sd; + +WARN (1 ,KERN_WARNING "sysfs: removing non-empty dir: %s\n" , + dir_sd->s_name); + +mutex_lock (&sysfs_mutex); +for (sd = dir_sd->s_dir.children; sd; sd = sd->s_sibling) +printk (KERN_WARNING "%s/%s\n" , + dir_sd->s_name, sd->s_name); +mutex_unlock (&sysfs_mutex); + } + +sysfs_addrm_start (&acxt, dir_sd->s_parent); +sysfs_remove_one (&acxt, dir_sd);sysfs_addrm_finish (&acxt); }
@@ -752,7 +768,6 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)struct sysfs_addrm_cxt acxt;struct sysfs_dirent **pos; -pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name);sysfs_addrm_start (&acxt, dir_sd); pos = &dir_sd->s_dir.children;while (*pos) {
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 6/26 sysfs: Don't hold addrm_start/addrm_finish over multiple removals.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
With respect to the basic integrity of the sysfs data structures holding the locks across the deletion of multiple sysfs_dirents is unnecessary.
Upper layers are required to coordinate their activity so that they do not add or delete entries in sysfs directories as they are being removed, and I have seen nothing to indicate the don't. The upper layers can not rely on sysfs doing anything for them as it is a compile option and may not be there. So the previous atomic delete of the directory entries and the directory serves no useful purpose.
By removing the only case where addrm_start/addrm_finish are held over multiple dirent removals I simplify the requirements and pave the way removing sysfs_addrm_start and sysfs_addrm_finish completely.
Additionally add some comments explaining some of the thinking behind sysfs_dirent removal in __sysfs_remove_dir.
--- fs/sysfs/dir.c | 36 +++++++++++++++++++++++++----------- 1 files changed, 25 insertions(+), 11 deletions(-)
fs/sysfs/dir.c +25 -11
@@ -762,23 +762,37 @@ void sysfs_remove_subdir(struct sysfs_dirent *sd)remove_dir (sd); } +static struct sysfs_dirent *get_dirent_to_remove (struct sysfs_dirent *dir_sd) +{ +struct sysfs_dirent *sd; + +mutex_lock (&sysfs_mutex); +for (sd = dir_sd->s_dir.children; sd; sd = sd->s_sibling) { +/* Directories might be owned by someone else +* making recursive directory removal unsafe. +*/ +if (sysfs_type (sd) ==SYSFS_DIR ) +continue ; +break ; + } +sysfs_get (sd); +mutex_unlock (&sysfs_mutex); + +return sd; +}static void __sysfs_remove_dir (struct sysfs_dirent *dir_sd) {struct sysfs_addrm_cxt acxt; -struct sysfs_dirent **pos; - -sysfs_addrm_start (&acxt, dir_sd); - pos = &dir_sd->s_dir.children; -while (*pos) { -struct sysfs_dirent *sd = *pos; +struct sysfs_dirent *sd; -if (sysfs_type (sd) !=SYSFS_DIR ) -sysfs_remove_one (&acxt, sd); -else - pos = &(*pos)->s_sibling; +/* Remove children that we think are safe */ +while ((sd =get_dirent_to_remove (dir_sd))) { +sysfs_addrm_start (&acxt, sd->s_parent); +sysfs_remove_one (&acxt, sd); +sysfs_addrm_finish (&acxt); +sysfs_put (sd); } -sysfs_addrm_finish (&acxt);remove_dir (dir_sd); }
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 7/26 sysfs: Rename sysfs_d_iput to sysfs_dentry_iput
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Using dentry instead of d in the function name is what several other filesystems are doing and it seems to be a more readable convention.
--- fs/sysfs/dir.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
fs/sysfs/dir.c +2 -2
@@ -294,7 +294,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) goto repeat; } -static void sysfs_d_iput (struct dentry * dentry,struct inode * inode) +static void sysfs_dentry_iput (struct dentry * dentry,struct inode * inode) {struct sysfs_dirent * sd = dentry->d_fsdata;
@@ -303,7 +303,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) }static const struct dentry_operations sysfs_dentry_ops = { - .d_iput = sysfs_d_iput, + .d_iput = sysfs_dentry_iput, };struct sysfs_dirent *sysfs_new_dirent (const char *name,umode_t mode,int type)
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 8/26 sysfs: Use dentry_ops instead of directly playing with the dcache
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Calling d_drop unconditionally when a sysfs_dirent is deleted has the potential to leak mounts, so instead implement dentry delete and revalidate operations that cause sysfs dentries to be removed at the appropriate time.
--- fs/sysfs/dir.c | 73 +++++++++++++++++++++++++++++++++++-------------------- 1 files changed, 46 insertions(+), 27 deletions(-)
fs/sysfs/dir.c +46 -27
@@ -294,6 +294,46 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) goto repeat; } +static int sysfs_dentry_delete (struct dentry *dentry) +{ +struct sysfs_dirent *sd = dentry->d_fsdata; +return !!(sd->s_flags &SYSFS_FLAG_REMOVED ); +} + +static int sysfs_dentry_revalidate (struct dentry *dentry,struct nameidata *nd) +{ +struct sysfs_dirent *sd = dentry->d_fsdata; +int is_dir; + +mutex_lock (&sysfs_mutex); + +/* The sysfs dirent has been deleted */ +if (sd->s_flags &SYSFS_FLAG_REMOVED ) + goto out_bad; + +mutex_unlock (&sysfs_mutex); +out_valid: +return 1 ; +out_bad: +/* Remove the dentry from the dcache hashes. +* If this is a deleted dentry we use d_drop instead of d_delete +* so sysfs doesn't need to cope with negative dentries. +*/ + is_dir = (sysfs_type (sd) ==SYSFS_DIR ); +mutex_unlock (&sysfs_mutex); +if (is_dir) { +/* If we have submounts we must allow the vfs caches +* to lie about the state of the filesystem to prevent +* leaks and other nasty things. +*/ +if (have_submounts (dentry)) + goto out_valid; +shrink_dcache_parent (dentry); + } +d_drop (dentry); +return 0 ; +} +static void sysfs_dentry_iput (struct dentry * dentry,struct inode * inode) {struct sysfs_dirent * sd = dentry->d_fsdata;
@@ -303,6 +343,8 @@ static void sysfs_dentry_iput(struct dentry * dentry, struct inode * inode) }static const struct dentry_operations sysfs_dentry_ops = { + .d_revalidate = sysfs_dentry_revalidate, + .d_delete = sysfs_dentry_delete, .d_iput = sysfs_dentry_iput, };
@@ -493,44 +535,21 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) }/** -* sysfs_drop_dentry - drop dentry for the specified sysfs_dirent +* sysfs_dec_nlink - Decrement link count for the specified sysfs_dirent * @sd: target sysfs_dirent * -* Drop dentry for @sd. @sd must have been unlinked from its +* Decrement nlink for @sd. @sd must have been unlinked from its * parent on entry to this function such that it can't be looked * up anymore. */ -static void sysfs_drop_dentry (struct sysfs_dirent *sd) +static void sysfs_dec_nlink (struct sysfs_dirent *sd) {struct inode *inode; -struct dentry *dentry; inode =ilookup (sysfs_sb, sd->s_ino);if (!inode)return ; -/* Drop any existing dentries associated with sd. -* -* For the dentry to be properly freed we need to grab a -* reference to the dentry under the dcache lock, unhash it, -* and then put it. The playing with the dentry count allows -* dput to immediately free the dentry if it is not in use. -*/ -repeat: -spin_lock (&dcache_lock); -list_for_each_entry (dentry, &inode->i_dentry, d_alias) { -if (d_unhashed (dentry)) -continue ; -dget_locked (dentry); -spin_lock (&dentry->d_lock); -__d_drop (dentry); -spin_unlock (&dentry->d_lock); -spin_unlock (&dcache_lock); -dput (dentry); - goto repeat; - } -spin_unlock (&dcache_lock); -/* adjust nlink and update timestamp */ mutex_lock (&inode->i_mutex);
@@ -577,7 +596,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) acxt->removed = sd->s_sibling; sd->s_sibling =NULL ; -sysfs_drop_dentry (sd); +sysfs_dec_nlink (sd);sysfs_deactivate (sd);unmap_bin_file (sd);sysfs_put (sd);
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 9/26 sysfs: Simplify sysfs_chmod_file semantics
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Currently every caller of sysfs_chmod_file happens at either file creation time to set a non-default mode or in response to a specific user requested space change in policy. Making timestamps of when the chmod happens and notification of a file changing mode uninteresting.
Remove the unnecessary time stamp and filesystem change notification, and removes the last of the explicit inotify and donitfy support from sysfs.
--- fs/sysfs/file.c | 10 +--------- 1 files changed, 1 insertions(+), 9 deletions(-)
fs/sysfs/file.c +1 -9
@@ -602,17 +602,9 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)mutex_lock (&inode->i_mutex); newattrs.ia_mode = (mode &S_IALLUGO ) | (inode->i_mode & ~S_IALLUGO ); - newattrs.ia_valid =ATTR_MODE |ATTR_CTIME ; - newattrs.ia_ctime =current_fs_time (inode->i_sb); + newattrs.ia_valid =ATTR_MODE ; rc =sysfs_setattr (victim, &newattrs); -if (rc ==0 ) { -fsnotify_change (victim, newattrs.ia_valid); -mutex_lock (&sysfs_mutex); - victim_sd->s_mode = newattrs.ia_mode; -mutex_unlock (&sysfs_mutex); - } -mutex_unlock (&inode->i_mutex); out:dput (victim);
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 10/26 sysfs: Optimize just changing the sysfs file mode.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Don't allocate a struct iattr for the sysfs dentry if just the mode changes because we have a field for that on the sysfs_dirent, and we can trigger that case with sysfs_chmod_file.
--- fs/sysfs/inode.c | 22 ++++++++++++++-------- 1 files changed, 14 insertions(+), 8 deletions(-)
fs/sysfs/inode.c +14 -8
@@ -60,12 +60,16 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)return error; iattr->ia_valid &= ~ATTR_SIZE ;/* ignore size changes */ +if (iattr->ia_valid &ATTR_MODE ) { +if (!in_group_p (inode->i_gid) && !capable (CAP_FSETID )) + iattr->ia_mode &= ~S_ISGID ; + } error =inode_setattr (inode, iattr);if (error)return error; -if (!sd_iattr) { +if (!sd_iattr && (ia_valid & ~ATTR_MODE )) {/* setting attributes for the first time, allocate now */ sd_iattr =kzalloc (sizeof (struct iattr ),GFP_KERNEL );if (!sd_iattr)
@@ -78,6 +82,13 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) sd->s_iattr = sd_iattr; } +if (ia_valid &ATTR_MODE ) + sd->s_mode = iattr->ia_mode; + +/* If we don't need the extra attributes leave */ +if (!sd_iattr) +return 0 ; +/* attributes were changed atleast once in past */ if (ia_valid &ATTR_UID )
@@ -93,13 +104,8 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)if (ia_valid &ATTR_CTIME ) sd_iattr->ia_ctime =timespec_trunc (iattr->ia_ctime, inode->i_sb->s_time_gran); -if (ia_valid &ATTR_MODE ) { -umode_t mode = iattr->ia_mode; - -if (!in_group_p (inode->i_gid) && !capable (CAP_FSETID )) - mode &= ~S_ISGID ; - sd_iattr->ia_mode = sd->s_mode = mode; - } +if (ia_valid &ATTR_MODE ) + sd_iattr->ia_mode = iattr->ia_mode;return error; }
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 11/26 sysfs: Simplify iattr assignments
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
The granularity of sysfs time when we keep it is 1 ns. Which when passed to timestamp_trunc results in a nop. So remove the unnecessary function call making sysfs_setattr slightly easier to read.
--- fs/sysfs/inode.c | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-)
fs/sysfs/inode.c +3 -6
@@ -96,14 +96,11 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)if (ia_valid &ATTR_GID ) sd_iattr->ia_gid = iattr->ia_gid;if (ia_valid &ATTR_ATIME ) - sd_iattr->ia_atime =timespec_trunc (iattr->ia_atime, - inode->i_sb->s_time_gran); + sd_iattr->ia_atime = iattr->ia_atime;if (ia_valid &ATTR_MTIME ) - sd_iattr->ia_mtime =timespec_trunc (iattr->ia_mtime, - inode->i_sb->s_time_gran); + sd_iattr->ia_mtime = iattr->ia_mtime;if (ia_valid &ATTR_CTIME ) - sd_iattr->ia_ctime =timespec_trunc (iattr->ia_ctime, - inode->i_sb->s_time_gran); + sd_iattr->ia_ctime = iattr->ia_ctime;if (ia_valid &ATTR_MODE ) sd_iattr->ia_mode = iattr->ia_mode;
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 12/26 sysfs: Fix locking and factor out sysfs_sd_setattr
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Cleanly separate the work that is specific to setting the attributes of a sysfs_dirent from what is needed to update the attributes of a vfs inode.
Additionally grab the sysfs_mutex to keep any nasties from surprising us when updating the sysfs_dirent.
--- fs/sysfs/inode.c | 52 ++++++++++++++++++++++++++++++---------------------- fs/sysfs/sysfs.h | 1 + 2 files changed, 31 insertions(+), 22 deletions(-)
fs/sysfs/inode.c +30 -22
@@ -42,33 +42,12 @@ int __init sysfs_inode_init(void)return bdi_init (&sysfs_backing_dev_info); } -int sysfs_setattr (struct dentry * dentry,struct iattr * iattr) +int sysfs_sd_setattr (struct sysfs_dirent *sd,struct iattr * iattr) { -struct inode * inode = dentry->d_inode; -struct sysfs_dirent * sd = dentry->d_fsdata;struct iattr * sd_iattr;unsigned int ia_valid = iattr->ia_valid; -int error; - -if (!sd) -return -EINVAL ; sd_iattr = sd->s_iattr; - - error =inode_change_ok (inode, iattr); -if (error) -return error; - - iattr->ia_valid &= ~ATTR_SIZE ;/* ignore size changes */ -if (iattr->ia_valid &ATTR_MODE ) { -if (!in_group_p (inode->i_gid) && !capable (CAP_FSETID )) - iattr->ia_mode &= ~S_ISGID ; - } - - error =inode_setattr (inode, iattr); -if (error) -return error; -if (!sd_iattr && (ia_valid & ~ATTR_MODE )) {/* setting attributes for the first time, allocate now */ sd_iattr =kzalloc (sizeof (struct iattr ),GFP_KERNEL );
@@ -103,6 +82,35 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) sd_iattr->ia_ctime = iattr->ia_ctime;if (ia_valid &ATTR_MODE ) sd_iattr->ia_mode = iattr->ia_mode; +return 0 ; +} + +int sysfs_setattr (struct dentry * dentry,struct iattr * iattr) +{ +struct inode * inode = dentry->d_inode; +struct sysfs_dirent * sd = dentry->d_fsdata; +int error; + +if (!sd) +return -EINVAL ; + + error =inode_change_ok (inode, iattr); +if (error) +return error; + + iattr->ia_valid &= ~ATTR_SIZE ;/* ignore size changes */ +if (iattr->ia_valid &ATTR_MODE ) { +if (!in_group_p (inode->i_gid) && !capable (CAP_FSETID )) + iattr->ia_mode &= ~S_ISGID ; + } + + error =inode_setattr (inode, iattr); +if (error) +return error; + +mutex_lock (&sysfs_mutex); + error =sysfs_sd_setattr (sd, iattr); +mutex_unlock (&sysfs_mutex);return error; }
fs/sysfs/sysfs.h +1 -0
@@ -146,6 +146,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd)*/ struct inode *sysfs_get_inode (struct sysfs_dirent *sd);void sysfs_delete_inode (struct inode *inode); +int sysfs_sd_setattr (struct sysfs_dirent *sd,struct iattr *iattr);int sysfs_setattr (struct dentry *dentry,struct iattr *iattr);int sysfs_hash_and_remove (struct sysfs_dirent *dir_sd,const char *name);int sysfs_inode_init (void );
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 13/26 sysfs: Update s_iattr on link and unlink.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Currently sysfs updates the timestamps on the vfs directory inode when we create or remove a directory entry but doesn't update the cached copy on the sysfs_dirent, fix that oversight.
--- fs/sysfs/dir.c | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-)
fs/sysfs/dir.c +14 -0
@@ -480,6 +480,8 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)*/ int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) { +struct iattr *ps_iattr; +if (sysfs_find_dirent (acxt->parent_sd, sd->s_name)) {char *path =kzalloc (PATH_MAX ,GFP_KERNEL ); WARN(1, KERN_WARNING
@@ -500,6 +502,11 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)sysfs_link_sibling (sd); +/* Update timestamps on the parent */ + ps_iattr = acxt->parent_sd->s_iattr; +if (ps_iattr) + ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; +return 0 ; }
@@ -520,10 +527,17 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)*/ void sysfs_remove_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) { +struct iattr *ps_iattr; +BUG_ON (sd->s_flags &SYSFS_FLAG_REMOVED );sysfs_unlink_sibling (sd); +/* Update timestamps on the parent */ + ps_iattr = acxt->parent_sd->s_iattr; +if (ps_iattr) + ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; + sd->s_flags |=SYSFS_FLAG_REMOVED ; sd->s_sibling = acxt->removed; acxt->removed = sd;
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 14/26 sysfs: Nicely indent sysfs_symlink_inode_operations
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Lining up the functions in sysfs_symlink_inode_operations follows the pattern in the rest of sysfs and makes things slightly more readable.
--- fs/sysfs/symlink.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-)
fs/sysfs/symlink.c +3 -3
@@ -198,9 +198,9 @@ static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *co }const struct inode_operations sysfs_symlink_inode_operations = { - .readlink = generic_readlink, - .follow_link = sysfs_follow_link, - .put_link = sysfs_put_link, + .readlink = generic_readlink, + .follow_link = sysfs_follow_link, + .put_link = sysfs_put_link, };
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 15/26 sysfs: Implement sysfs_getattr & sysfs_permission
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
With the implementation of sysfs_getattr and sysfs_permission sysfs becomes able to lazily propogate inode attribute changes
from the sysfs_dirents to the vfs inodes. This paves the way
for deleting significant chunks of now unnecessary code.
--- fs/sysfs/dir.c | 2 + fs/sysfs/inode.c | 54 ++++++++++++++++++++++++++++++++++++++++----------- fs/sysfs/symlink.c | 3 ++ fs/sysfs/sysfs.h | 2 + 4 files changed, 49 insertions(+), 12 deletions(-)
fs/sysfs/dir.c +2 -0
@@ -763,6 +763,8 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,const struct inode_operations sysfs_dir_inode_operations = { .lookup = sysfs_lookup, .setattr = sysfs_setattr, + .getattr = sysfs_getattr, + .permission = sysfs_permission, };static void remove_dir (struct sysfs_dirent *dir_sd)
fs/sysfs/inode.c +42 -12
89 lines not on this page · raw message
fs/sysfs/symlink.c +3 -0
@@ -201,6 +201,9 @@ const struct inode_operations sysfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = sysfs_follow_link, .put_link = sysfs_put_link, + .setattr = sysfs_setattr, + .getattr = sysfs_getattr, + .permission = sysfs_permission, };
fs/sysfs/sysfs.h +2 -0
@@ -148,6 +148,8 @@ struct inode *sysfs_get_inode(struct sysfs_dirent *sd);void sysfs_delete_inode (struct inode *inode);int sysfs_sd_setattr (struct sysfs_dirent *sd,struct iattr *iattr);int sysfs_setattr (struct dentry *dentry,struct iattr *iattr); +int sysfs_getattr (struct vfsmount *mnt,struct dentry *dentry,struct kstat *stat); +int sysfs_permission (struct inode *inode,int mask);int sysfs_hash_and_remove (struct sysfs_dirent *dir_sd,const char *name);int sysfs_inode_init (void );
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 16/26 sysfs: In sysfs_chmod_file lazily propagate the mode change.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Now that sysfs_getattr and sysfs_permission refresh the vfs inode there is no need to immediatly push the mode change into the vfs cache. Reducing the amount of work needed and simplifying the locking.
--- fs/sysfs/file.c | 31 ++++++++----------------------- 1 files changed, 8 insertions(+), 23 deletions(-)
fs/sysfs/file.c +8 -23
@@ -577,38 +577,23 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);*/ int sysfs_chmod_file (struct kobject *kobj,struct attribute *attr,mode_t mode) { -struct sysfs_dirent *victim_sd =NULL ; -struct dentry *victim =NULL ; -struct inode * inode; +struct sysfs_dirent *sd;struct iattr newattrs;int rc; - rc = -ENOENT ; - victim_sd =sysfs_get_dirent (kobj->sd, attr->name); -if (!victim_sd) - goto out; +mutex_lock (&sysfs_mutex); -mutex_lock (&sysfs_rename_mutex); - victim =sysfs_get_dentry (victim_sd); -mutex_unlock (&sysfs_rename_mutex); -if (IS_ERR (victim)) { - rc =PTR_ERR (victim); - victim =NULL ; + rc = -ENOENT ; + sd =sysfs_find_dirent (kobj->sd, attr->name); +if (!sd) goto out; - } - - inode = victim->d_inode; -mutex_lock (&inode->i_mutex); - - newattrs.ia_mode = (mode &S_IALLUGO ) | (inode->i_mode & ~S_IALLUGO ); + newattrs.ia_mode = (mode &S_IALLUGO ) | (sd->s_mode & ~S_IALLUGO ); newattrs.ia_valid =ATTR_MODE ; - rc =sysfs_setattr (victim, &newattrs); + rc =sysfs_sd_setattr (sd, &newattrs); -mutex_unlock (&inode->i_mutex); out: -dput (victim); -sysfs_put (victim_sd); +mutex_unlock (&sysfs_mutex);return rc; }EXPORT_SYMBOL_GPL (sysfs_chmod_file);
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 17/26 sysfs: Kill sysfs_addrm_start and sysfs_addrm_finish
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
With lazy inode updates and dentry operations bringing everything into sync on demand there is no longer any need to immediately update the vfs or grab i_mutex to protect those updates as we make changes to sysfs.
So stop updating the vfs inodes and move what remains of sysfs_addrm_start and sysfs_addrm_finsih (just barely more than taking the sysfs_mutex) into sysfs_add_one and sysfs_remove_one.
--- fs/sysfs/dir.c | 194 +++++++--------------------------------------------- fs/sysfs/file.c | 6 +-- fs/sysfs/inode.c | 16 ++--- fs/sysfs/symlink.c | 6 +-- fs/sysfs/sysfs.h | 17 +---- 5 files changed, 34 insertions(+), 205 deletions(-)
fs/sysfs/dir.c +25 -169
@@ -382,62 +382,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)return NULL ; } -static int sysfs_ilookup_test (struct inode *inode,void *arg) -{ -struct sysfs_dirent *sd = arg; -return inode->i_ino == sd->s_ino; -} - -/** -* sysfs_addrm_start - prepare for sysfs_dirent add/remove -* @acxt: pointer to sysfs_addrm_cxt to be used -* @parent_sd: parent sysfs_dirent -* -* This function is called when the caller is about to add or -* remove sysfs_dirent under @parent_sd. This function acquires -* sysfs_mutex, grabs inode for @parent_sd if available and lock -* i_mutex of it. @acxt is used to keep and pass context to -* other addrm functions. -* -* LOCKING: -* Kernel thread context (may sleep). sysfs_mutex is locked on -* return. i_mutex of parent inode is locked on return if -* available. -*/ -void sysfs_addrm_start (struct sysfs_addrm_cxt *acxt, -struct sysfs_dirent *parent_sd) -{ -struct inode *inode; - -memset (acxt,0 ,sizeof (*acxt)); - acxt->parent_sd = parent_sd; - -/* Lookup parent inode. inode initialization is protected by -* sysfs_mutex, so inode existence can be determined by -* looking up inode while holding sysfs_mutex. -*/ -mutex_lock (&sysfs_mutex); - - inode =ilookup5 (sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test, - parent_sd); -if (inode) { -WARN_ON (inode->i_state &I_NEW ); - -/* parent inode available */ - acxt->parent_inode = inode; - -/* sysfs_mutex is below i_mutex in lock hierarchy. -* First, trylock i_mutex. If fails, unlock -* sysfs_mutex and lock them in order. -*/ -if (!mutex_trylock (&inode->i_mutex)) { -mutex_unlock (&sysfs_mutex); -mutex_lock (&inode->i_mutex); -mutex_lock (&sysfs_mutex); - } - } -} -/** * sysfs_pathname - return full path to sysfs dirent * @sd: sysfs_dirent whose path we want
@@ -460,161 +404,83 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)/** * sysfs_add_one - add sysfs_dirent to parent -* @acxt: addrm context to use +* @parent_sd: directory to add @sd into * @sd: sysfs_dirent to be added * -* Get @acxt->parent_sd and set sd->s_parent to it and increment +* Get @parent_sd and set sd->s_parent to it and increment * nlink of parent inode if @sd is a directory and link into the * children list of the parent. * -* This function should be called between calls to -* sysfs_addrm_start() and sysfs_addrm_finish() and should be -* passed the same @acxt as passed to sysfs_addrm_start(). -* * LOCKING: -* Determined by sysfs_addrm_start(). +* Kernel thread context (may sleep). Grabs sysfs_mutex. * * RETURNS: * 0 on success, -EEXIST if entry with the given name already * exists. */ -int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) +int sysfs_add_one (struct sysfs_dirent *parent_sd,struct sysfs_dirent *sd) {struct iattr *ps_iattr; -if (sysfs_find_dirent (acxt->parent_sd, sd->s_name)) { -char *path =kzalloc (PATH_MAX ,GFP_KERNEL ); +mutex_lock (&sysfs_mutex); +if (sysfs_find_dirent (parent_sd, sd->s_name)) { +char *path; +mutex_unlock (&sysfs_mutex); + + path =kzalloc (PATH_MAX ,GFP_KERNEL );WARN (1 ,KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n" , (path ==NULL ) ? sd->s_name : -strcat (strcat (sysfs_pathname (acxt->parent_sd, path),"/" ), +strcat (strcat (sysfs_pathname (parent_sd, path),"/" ), sd->s_name));kfree (path);return -EEXIST ; } - sd->s_parent =sysfs_get (acxt->parent_sd); - -if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) -inc_nlink (acxt->parent_inode); - - acxt->cnt++; - + sd->s_parent =sysfs_get (parent_sd);sysfs_link_sibling (sd);/* Update timestamps on the parent */ - ps_iattr = acxt->parent_sd->s_iattr; + ps_iattr = parent_sd->s_iattr;if (ps_iattr) ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; +mutex_unlock (&sysfs_mutex);return 0 ; }/** * sysfs_remove_one - remove sysfs_dirent from parent -* @acxt: addrm context to use * @sd: sysfs_dirent to be removed * * Mark @sd removed and drop nlink of parent inode if @sd is a * directory. @sd is unlinked from the children list. * -* This function should be called between calls to -* sysfs_addrm_start() and sysfs_addrm_finish() and should be -* passed the same @acxt as passed to sysfs_addrm_start(). -* * LOCKING: -* Determined by sysfs_addrm_start(). +* Kernel thread context (may sleep). Grabs sysfs_mutex. */ -void sysfs_remove_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) +void sysfs_remove_one (struct sysfs_dirent *sd) {struct iattr *ps_iattr;BUG_ON (sd->s_flags &SYSFS_FLAG_REMOVED ); +mutex_lock (&sysfs_mutex); +sysfs_unlink_sibling (sd);/* Update timestamps on the parent */ - ps_iattr = acxt->parent_sd->s_iattr; + ps_iattr = sd->s_parent->s_iattr;if (ps_iattr) ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; sd->s_flags |=SYSFS_FLAG_REMOVED ; - sd->s_sibling = acxt->removed; - acxt->removed = sd; - -if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) -drop_nlink (acxt->parent_inode); - acxt->cnt++; -} - -/** -* sysfs_dec_nlink - Decrement link count for the specified sysfs_dirent -* @sd: target sysfs_dirent -* -* Decrement nlink for @sd. @sd must have been unlinked from its -* parent on entry to this function such that it can't be looked -* up anymore. -*/ -static void sysfs_dec_nlink (struct sysfs_dirent *sd) -{ -struct inode *inode; - - inode =ilookup (sysfs_sb, sd->s_ino); -if (!inode) -return ; - -/* adjust nlink and update timestamp */ -mutex_lock (&inode->i_mutex); - - inode->i_ctime =CURRENT_TIME ; -drop_nlink (inode); -if (sysfs_type (sd) ==SYSFS_DIR ) -drop_nlink (inode); - -mutex_unlock (&inode->i_mutex); - -iput (inode); -} - -/** -* sysfs_addrm_finish - finish up sysfs_dirent add/remove -* @acxt: addrm context to finish up -* -* Finish up sysfs_dirent add/remove. Resources acquired by -* sysfs_addrm_start() are released and removed sysfs_dirents are -* cleaned up. Timestamps on the parent inode are updated. -* -* LOCKING: -* All mutexes acquired by sysfs_addrm_start() are released. -*/ -void sysfs_addrm_finish (struct sysfs_addrm_cxt *acxt) -{ -/* release resources acquired by sysfs_addrm_start() */ mutex_unlock (&sysfs_mutex); -if (acxt->parent_inode) { -struct inode *inode = acxt->parent_inode; - -/* if added/removed, update timestamps on the parent */ -if (acxt->cnt) - inode->i_ctime = inode->i_mtime =CURRENT_TIME ; -mutex_unlock (&inode->i_mutex); -iput (inode); - } - -/* kill removed sysfs_dirents */ -while (acxt->removed) { -struct sysfs_dirent *sd = acxt->removed; - - acxt->removed = sd->s_sibling; - sd->s_sibling =NULL ; - -sysfs_dec_nlink (sd); -sysfs_deactivate (sd); -unmap_bin_file (sd); -sysfs_put (sd); - } +sysfs_deactivate (sd); +unmap_bin_file (sd); +sysfs_put (sd); }/**
@@ -673,7 +539,6 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, const char *name, struct sysfs_dirent **p_sd) { umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; -struct sysfs_addrm_cxt acxt;struct sysfs_dirent *sd;int rc;
@@ -684,10 +549,8 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, sd->s_dir.kobj = kobj;/* link in */ -sysfs_addrm_start (&acxt, parent_sd); - rc =sysfs_add_one (&acxt, sd); -sysfs_addrm_finish (&acxt); + rc =sysfs_add_one (parent_sd, sd);if (rc ==0 ) *p_sd = sd;else
@@ -769,8 +632,6 @@ const struct inode_operations sysfs_dir_inode_operations = {static void remove_dir (struct sysfs_dirent *dir_sd) { -struct sysfs_addrm_cxt acxt; -pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name);/* Removing non-empty directories is not valid complain! */
@@ -787,9 +648,7 @@ static void remove_dir(struct sysfs_dirent *dir_sd)mutex_unlock (&sysfs_mutex); } -sysfs_addrm_start (&acxt, dir_sd->s_parent); -sysfs_remove_one (&acxt, dir_sd); -sysfs_addrm_finish (&acxt); +sysfs_remove_one (dir_sd); }void sysfs_remove_subdir (struct sysfs_dirent *sd)
@@ -818,14 +677,11 @@ static struct sysfs_dirent *get_dirent_to_remove(struct sysfs_dirent *dir_sd)static void __sysfs_remove_dir (struct sysfs_dirent *dir_sd) { -struct sysfs_addrm_cxt acxt;struct sysfs_dirent *sd;/* Remove children that we think are safe */ while ((sd =get_dirent_to_remove (dir_sd))) { -sysfs_addrm_start (&acxt, sd->s_parent); -sysfs_remove_one (&acxt, sd); -sysfs_addrm_finish (&acxt); +sysfs_remove_one (sd);sysfs_put (sd); }
fs/sysfs/file.c +1 -5
@@ -499,7 +499,6 @@ int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, const struct attribute *attr, int type, mode_t amode) { umode_t mode = (amode & S_IALLUGO) | S_IFREG; -struct sysfs_addrm_cxt acxt;struct sysfs_dirent *sd;int rc;
@@ -508,10 +507,7 @@ int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,return -ENOMEM ; sd->s_attr.attr = (void *)attr; -sysfs_addrm_start (&acxt, dir_sd); - rc =sysfs_add_one (&acxt, sd); -sysfs_addrm_finish (&acxt); - + rc =sysfs_add_one (dir_sd, sd);if (rc)sysfs_put (sd);
fs/sysfs/inode.c +5 -11
@@ -263,23 +263,17 @@ void sysfs_delete_inode(struct inode *inode)int sysfs_hash_and_remove (struct sysfs_dirent *dir_sd,const char *name) { -struct sysfs_addrm_cxt acxt;struct sysfs_dirent *sd;if (!dir_sd)return -ENOENT ; -sysfs_addrm_start (&acxt, dir_sd); - - sd =sysfs_find_dirent (dir_sd, name); -if (sd) -sysfs_remove_one (&acxt, sd); - -sysfs_addrm_finish (&acxt); - -if (sd) + sd =sysfs_get_dirent (dir_sd, name); +if (sd) { +sysfs_remove_one (sd); +sysfs_put (sd);return 0 ; -else + }else return -ENOENT ; }
fs/sysfs/symlink.c +1 -5
@@ -31,7 +31,6 @@ int sysfs_create_link(struct kobject *kobj, struct kobject *target,struct sysfs_dirent *parent_sd =NULL ;struct sysfs_dirent *target_sd =NULL ;struct sysfs_dirent *sd =NULL ; -struct sysfs_addrm_cxt acxt;int error;BUG_ON (!name);
@@ -65,10 +64,7 @@ int sysfs_create_link(struct kobject *kobj, struct kobject *target, sd->s_symlink.target_sd = target_sd; target_sd =NULL ;/* reference is now owned by the symlink */ -sysfs_addrm_start (&acxt, parent_sd); - error =sysfs_add_one (&acxt, sd); -sysfs_addrm_finish (&acxt); - + error =sysfs_add_one (parent_sd, sd);if (error) goto out_put;
fs/sysfs/sysfs.h +2 -15
@@ -77,16 +77,6 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd) }/* -* Context structure to be used while adding/removing nodes. -*/ -struct sysfs_addrm_cxt { -struct sysfs_dirent *parent_sd; -struct inode *parent_inode; -struct sysfs_dirent *removed; -int cnt; -}; - -/* * mount.c */ extern struct sysfs_dirent sysfs_root;
@@ -106,11 +96,8 @@ extern const struct inode_operations sysfs_dir_inode_operations;struct dentry *sysfs_get_dentry (struct sysfs_dirent *sd);struct sysfs_dirent *sysfs_get_active_two (struct sysfs_dirent *sd);void sysfs_put_active_two (struct sysfs_dirent *sd); -void sysfs_addrm_start (struct sysfs_addrm_cxt *acxt, -struct sysfs_dirent *parent_sd); -int sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd); -void sysfs_remove_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd); -void sysfs_addrm_finish (struct sysfs_addrm_cxt *acxt); +int sysfs_add_one (struct sysfs_dirent *parent_sd,struct sysfs_dirent *sd); +void sysfs_remove_one (struct sysfs_dirent *sd);struct sysfs_dirent *sysfs_find_dirent (struct sysfs_dirent *parent_sd,const unsigned char *name);
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 18/26 sysfs: Propagate renames to the vfs on demand
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
By teaching sysfs_revalidate to hide a dentry for a sysfs_dirent if the sysfs_dirent has been renamed, and by teaching sysfs_lookup to return the original dentry if the sysfs dirent has been renamed. I can show the results of renames correctly without having to update the dcache during the directory rename.
This massively simplifies the rename logic allowing a lot of weird sysfs special cases to be removed along with a lot of now unnecesary helper code.
--- fs/namei.c | 22 ------- fs/sysfs/dir.c | 156 ++++++++++--------------------------------------- fs/sysfs/inode.c | 12 ---- fs/sysfs/sysfs.h | 1 - include/linux/namei.h | 1 - 5 files changed, 32 insertions(+), 160 deletions(-)
fs/namei.c +0 -22
@@ -1260,28 +1260,6 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)return __lookup_hash (&this, base,NULL ); } -/** -* lookup_one_noperm - bad hack for sysfs -* @name: pathname component to lookup -* @base: base directory to lookup from -* -* This is a variant of lookup_one_len that doesn't perform any permission -* checks. It's a horrible hack to work around the braindead sysfs -* architecture and should not be used anywhere else. -* -* DON'T USE THIS FUNCTION EVER, thanks. -*/ -struct dentry *lookup_one_noperm (const char *name,struct dentry *base) -{ -int err; -struct qstr this; - - err =__lookup_one_len (name, &this, base,strlen (name)); -if (err) -return ERR_PTR (err); -return __lookup_hash (&this, base,NULL ); -} -int user_path_at (int dfd,const char __user *name,unsigned flags,struct path *path) {
fs/sysfs/dir.c +32 -124
238 lines not on this page · raw message
fs/sysfs/inode.c +0 -12
@@ -132,17 +132,6 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) inode->i_ctime = iattr->ia_ctime; } - -/* -* sysfs has a different i_mutex lock order behavior for i_mutex than other -* filesystems; sysfs i_mutex is called in many places with subsystem locks -* held. At the same time, many of the VFS locking rules do not apply to -* sysfs at all (cross directory rename for example). To untangle this mess -* (which gives false positives in lockdep), we're giving sysfs inodes their -* own class for i_mutex. -*/ -static struct lock_class_key sysfs_inode_imutex_key; -static int sysfs_count_nlink (struct sysfs_dirent *sd) {struct sysfs_dirent *child;
@@ -190,7 +179,6 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) inode->i_mapping->a_ops = &sysfs_aops; inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; inode->i_op = &sysfs_inode_operations; -lockdep_set_class (&inode->i_mutex, &sysfs_inode_imutex_key);set_default_inode_attr (inode, sd->s_mode);sysfs_refresh_inode (sd, inode);
fs/sysfs/sysfs.h +0 -1
@@ -87,7 +87,6 @@ extern struct kmem_cache *sysfs_dir_cachep;* dir.c */ extern struct mutex sysfs_mutex; -extern struct mutex sysfs_rename_mutex;extern spinlock_t sysfs_assoc_lock;extern const struct file_operations sysfs_dir_operations;
include/linux/namei.h +0 -1
@@ -76,7 +76,6 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);extern void release_open_intent (struct nameidata *);extern struct dentry *lookup_one_len (const char *,struct dentry *,int ); -extern struct dentry *lookup_one_noperm (const char *,struct dentry *);extern int follow_down (struct vfsmount **,struct dentry **);extern int follow_up (struct vfsmount **,struct dentry **);
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 19/26 sysfs: Merge sysfs_rename_dir and sysfs_move_dir
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
These two functions do 90% of the same work and it doesn't significantly obfuscate the function to allow both the parent dir and the name to change at the same time. So merge them together to simplify maintenance, and increase testing.
--- fs/sysfs/dir.c | 66 +++++++++++++++++++++++-------------------------------- 1 files changed, 28 insertions(+), 38 deletions(-)
fs/sysfs/dir.c +28 -38
@@ -686,30 +686,42 @@ void sysfs_remove_dir(struct kobject * kobj)__sysfs_remove_dir (sd); } -int sysfs_rename_dir (struct kobject * kobj,const char *new_name) +static int sysfs_mv_dir (struct sysfs_dirent *sd, +struct sysfs_dirent *new_parent_sd,const char *new_name) { -struct sysfs_dirent *sd = kobj->sd;const char *dup_name =NULL ;int error;mutex_lock (&sysfs_mutex); error =0 ; -if (strcmp (sd->s_name, new_name) ==0 ) +if ((sd->s_parent == new_parent_sd) && + (strcmp (sd->s_name, new_name) ==0 )) goto out;/* nothing to rename */ error = -EEXIST ; -if (sysfs_find_dirent (sd->s_parent, new_name)) +if (sysfs_find_dirent (new_parent_sd, new_name)) goto out;/* rename sysfs_dirent */ - error = -ENOMEM ; - new_name = dup_name =kstrdup (new_name,GFP_KERNEL ); -if (!new_name) - goto out; +if (strcmp (sd->s_name, new_name) !=0 ) { + error = -ENOMEM ; + new_name = dup_name =kstrdup (new_name,GFP_KERNEL ); +if (!new_name) + goto out; + + dup_name = sd->s_name; + sd->s_name = new_name; + } - dup_name = sd->s_name; - sd->s_name = new_name; +/* Remove from old parent's list and insert into new parent's list. */ +if (sd->s_parent != new_parent_sd) { +sysfs_unlink_sibling (sd); +sysfs_get (new_parent_sd); +sysfs_put (sd->s_parent); + sd->s_parent = new_parent_sd; +sysfs_link_sibling (sd); + } error =0 ; out:
@@ -718,36 +730,14 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)return error; } -int sysfs_move_dir (struct kobject *kobj,struct kobject *new_parent_kobj) +int sysfs_rename_dir (struct kobject * kobj,const char *new_name) { -struct sysfs_dirent *sd = kobj->sd; -struct sysfs_dirent *new_parent_sd; -int error; - -BUG_ON (!sd->s_parent); - -mutex_lock (&sysfs_mutex); - new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; - - error =0 ; -if (sd->s_parent == new_parent_sd) - goto out;/* nothing to move */ - - error = -EEXIST ; -if (sysfs_find_dirent (new_parent_sd, sd->s_name)) - goto out; - -/* Remove from old parent's list and insert into new parent's list. */ -sysfs_unlink_sibling (sd); -sysfs_get (new_parent_sd); -sysfs_put (sd->s_parent); - sd->s_parent = new_parent_sd; -sysfs_link_sibling (sd); +return sysfs_mv_dir (kobj->sd, kobj->sd->s_parent, new_name); +} - error =0 ; -out: -mutex_unlock (&sysfs_mutex); -return error; +int sysfs_move_dir (struct kobject *kobj,struct kobject *new_parent_kobj) +{ +return sysfs_mv_dir (kobj->sd, new_parent_kobj->sd, kobj->sd->s_name); }/* Relationship between s_mode and the DT_xxx types */
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 20/26 sysfs: Pass super_block to sysfs_get_inode
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Currently sysfs_get_inode magically returns an inode on sysfs_sb. Make the super_block parameter explicit and the code becomes clearer.
--- fs/sysfs/dir.c | 2 +- fs/sysfs/inode.c | 5 +++-- fs/sysfs/mount.c | 2 +- fs/sysfs/sysfs.h | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-)
fs/sysfs/dir.c +1 -1
@@ -579,7 +579,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, }/* attach dentry and inode */ - inode =sysfs_get_inode (sd); + inode =sysfs_get_inode (dir->i_sb, sd);if (!inode) { ret =ERR_PTR (-ENOMEM ); goto out_unlock;
fs/sysfs/inode.c +3 -2
@@ -210,6 +210,7 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)/** * sysfs_get_inode - get inode for sysfs_dirent +* @sb: super block * @sd: sysfs_dirent to allocate inode for * * Get inode for @sd. If such inode doesn't exist, a new inode
@@ -222,11 +223,11 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)* RETURNS: * Pointer to allocated inode on success, NULL on failure. */ -struct inode *sysfs_get_inode (struct sysfs_dirent *sd) +struct inode *sysfs_get_inode (struct super_block *sb,struct sysfs_dirent *sd) {struct inode *inode; - inode =iget_locked (sysfs_sb, sd->s_ino); + inode =iget_locked (sb, sd->s_ino);if (inode && (inode->i_state &I_NEW ))sysfs_init_inode (sd, inode);
fs/sysfs/mount.c +1 -1
@@ -54,7 +54,7 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)/* get root inode, initialize and unlock it */ mutex_lock (&sysfs_mutex); - inode =sysfs_get_inode (&sysfs_root); + inode =sysfs_get_inode (sb, &sysfs_root);mutex_unlock (&sysfs_mutex);if (!inode) {pr_debug ("sysfs: could not get root inode\n" );
fs/sysfs/sysfs.h +1 -1
@@ -130,7 +130,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd)/* * inode.c */ -struct inode *sysfs_get_inode (struct sysfs_dirent *sd); +struct inode *sysfs_get_inode (struct super_block *sb,struct sysfs_dirent *sd);void sysfs_delete_inode (struct inode *inode);int sysfs_sd_setattr (struct sysfs_dirent *sd,struct iattr *iattr);int sysfs_setattr (struct dentry *dentry,struct iattr *iattr);
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 21/26 sysfs: Kill unused sysfs_sb variable.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Now that there are no more users we can remove
the sysfs_sb variable.
--- fs/sysfs/mount.c | 2 -- fs/sysfs/sysfs.h | 1 - 2 files changed, 0 insertions(+), 3 deletions(-)
fs/sysfs/mount.c +0 -2
@@ -23,7 +23,6 @@static struct vfsmount *sysfs_mount; -struct super_block * sysfs_sb =NULL ;struct kmem_cache *sysfs_dir_cachep;static const struct super_operations sysfs_ops = {
@@ -50,7 +49,6 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_magic =SYSFS_MAGIC ; sb->s_op = &sysfs_ops; sb->s_time_gran =1 ; - sysfs_sb = sb;/* get root inode, initialize and unlock it */ mutex_lock (&sysfs_mutex);
fs/sysfs/sysfs.h +0 -1
@@ -80,7 +80,6 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd)* mount.c */ extern struct sysfs_dirent sysfs_root; -extern struct super_block *sysfs_sb;extern struct kmem_cache *sysfs_dir_cachep;/*
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 22/26 sysfs: Normalize error handling in sysfs_fill_inode
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Use a single error exit path instead of doing whatever is the required cleanup at each point we find the error. Ultimately this should make the code more maintainable.
--- fs/sysfs/mount.c | 16 +++++++++++----- 1 files changed, 11 insertions(+), 5 deletions(-)
fs/sysfs/mount.c +11 -5
@@ -41,8 +41,9 @@ struct sysfs_dirent sysfs_root = {static int sysfs_fill_super (struct super_block *sb,void *data,int silent) { -struct inode *inode; -struct dentry *root; +struct inode *inode =NULL ; +struct dentry *root =NULL ; +int error; sb->s_blocksize =PAGE_CACHE_SIZE ; sb->s_blocksize_bits =PAGE_CACHE_SHIFT ;
@@ -51,24 +52,29 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_time_gran =1 ;/* get root inode, initialize and unlock it */ + error = -ENOMEM ;mutex_lock (&sysfs_mutex); inode =sysfs_get_inode (sb, &sysfs_root);mutex_unlock (&sysfs_mutex);if (!inode) {pr_debug ("sysfs: could not get root inode\n" ); -return -ENOMEM ; + goto err_out; }/* instantiate and link root dentry */ + error = -ENOMEM ; root =d_alloc_root (inode);if (!root) {pr_debug ("%s: could not get root dentry!\n" ,__func__); -iput (inode); -return -ENOMEM ; + goto err_out; } root->d_fsdata = &sysfs_root; sb->s_root = root;return 0 ; +err_out: +dput (root); +iput (inode); +return error; } static int sysfs_get_sb(struct file_system_type *fs_type,
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 23/26 sysfs: Rename sysfs_mv_dir sysfs_rename
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
It turns out that sysfs_mv_dir actually makes no assumptions that what
is being renamed is a directory. So rename sysfs_mv_dir to sysfs_rename to
reflect the functions general utility. Later we will use it rename symlinks in sysfs.
--- fs/sysfs/dir.c | 6 +++--- fs/sysfs/sysfs.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-)
fs/sysfs/dir.c +3 -3
@@ -686,7 +686,7 @@ void sysfs_remove_dir(struct kobject * kobj)__sysfs_remove_dir (sd); } -static int sysfs_mv_dir (struct sysfs_dirent *sd, +int sysfs_rename (struct sysfs_dirent *sd,struct sysfs_dirent *new_parent_sd,const char *new_name) {const char *dup_name =NULL ;
@@ -732,12 +732,12 @@ static int sysfs_mv_dir(struct sysfs_dirent *sd,int sysfs_rename_dir (struct kobject * kobj,const char *new_name) { -return sysfs_mv_dir (kobj->sd, kobj->sd->s_parent, new_name); +return sysfs_rename (kobj->sd, kobj->sd->s_parent, new_name); }int sysfs_move_dir (struct kobject *kobj,struct kobject *new_parent_kobj) { -return sysfs_mv_dir (kobj->sd, new_parent_kobj->sd, kobj->sd->s_name); +return sysfs_rename (kobj->sd, new_parent_kobj->sd, kobj->sd->s_name); }/* Relationship between s_mode and the DT_xxx types */
fs/sysfs/sysfs.h +3 -0
@@ -109,6 +109,9 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, struct sysfs_dirent **p_sd);void sysfs_remove_subdir (struct sysfs_dirent *sd); +int sysfs_rename (struct sysfs_dirent *sd, +struct sysfs_dirent *new_parent_sd,const char *new_name); +static inline struct sysfs_dirent *__sysfs_get (struct sysfs_dirent *sd) {if (sd) {
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 24/26 sysfs: Make sysfs_rename_link atomic
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Use the existing sysfs_rename to make sysfs_rename_link an atomic operation that does less work. While I am at add additional sanity checking to ensure it is a symlink I am renaming.
--- fs/sysfs/symlink.c | 26 ++++++++++++++++++++++++-- 1 files changed, 24 insertions(+), 2 deletions(-)
fs/sysfs/symlink.c +24 -2
@@ -106,8 +106,30 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)int sysfs_rename_link (struct kobject *kobj,struct kobject *targ,const char *old,const char *new) { -sysfs_remove_link (kobj, old); -return sysfs_create_link (kobj, targ, new); +struct sysfs_dirent *parent_sd, *sd =NULL ; +int result; + +if (!kobj) + parent_sd = &sysfs_root; +else + parent_sd = kobj->sd; + + result = -ENOENT ; + sd =sysfs_get_dirent (parent_sd, old); +if (!sd) + goto out; + + result = -EINVAL ; +if (sysfs_type (sd) !=SYSFS_KOBJ_LINK ) + goto out; +if (sd->s_symlink.target_sd->s_dir.kobj != targ) + goto out; + + result =sysfs_rename (sd, parent_sd, new); + +out: +sysfs_put (sd); +return result; } static int sysfs_get_target_path(struct sysfs_dirent *parent_sd,
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 25/26 driver core: Don't remove kobjects in device_shutdown.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
device_shutdown is defined to just shutdown the hardware and to not clean up any kernel data structures. Therefore don't put the kobjects for /sys/dev and /sys/dev/block and /sys/dev/char.
This ensures we don't remove /sys/dev/block and /sys/dev/char while we still have symlinks from there to the actual devices.
--- drivers/base/core.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-)
drivers/base/core.c +0 -3
@@ -1653,7 +1653,4 @@ void device_shutdown(void) dev->driver->shutdown (dev); } } -kobject_put (sysfs_dev_char_kobj); -kobject_put (sysfs_dev_block_kobj); -kobject_put (dev_kobj); }
Signature · 1 line
1.6.3.1.54.g99dd.dirty
PATCH 26/26 sysfs: In sysfs_add_one fail if the targe directory has been removed.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
If a bug in the upper layers results in someone attempting to add to a sysfs directory that has already been removed, warn about it and fail.
I don't believe this has ever happened, and it certainly never should happen, but be strict to avoid errors creeping in.
--- fs/sysfs/dir.c | 37 +++++++++++++++++++++++-------------- 1 files changed, 23 insertions(+), 14 deletions(-)
fs/sysfs/dir.c +22 -13
@@ -394,21 +394,17 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)int sysfs_add_one (struct sysfs_dirent *parent_sd,struct sysfs_dirent *sd) {struct iattr *ps_iattr; +char *path; +int result;mutex_lock (&sysfs_mutex); -if (sysfs_find_dirent (parent_sd, sd->s_name)) { -char *path; -mutex_unlock (&sysfs_mutex); - path =kzalloc (PATH_MAX ,GFP_KERNEL ); -WARN (1 ,KERN_WARNING -"sysfs: cannot create duplicate filename '%s'\n" , - (path ==NULL ) ? sd->s_name : -strcat (strcat (sysfs_pathname (parent_sd, path),"/" ), - sd->s_name)); -kfree (path); -return -EEXIST ; - } + result = -ENOENT ; +if (parent_sd->s_flags &SYSFS_FLAG_REMOVED ) + goto out_err; + +if (sysfs_find_dirent (parent_sd, sd->s_name)) + goto out_err; sd->s_parent =sysfs_get (parent_sd);sysfs_link_sibling (sd);
@@ -417,9 +413,22 @@ int sysfs_add_one(struct sysfs_dirent *parent_sd, struct sysfs_dirent *sd) ps_iattr = parent_sd->s_iattr;if (ps_iattr) ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; -mutex_unlock (&sysfs_mutex);return 0 ; + +out_err: +mutex_unlock (&sysfs_mutex); + + path =kzalloc (PATH_MAX ,GFP_KERNEL ); +WARN (1 ,KERN_WARNING "sysfs: cannot create '%s' %s\n" , + (path ==NULL ) ? sd->s_name : +strcat (strcat (sysfs_pathname (parent_sd, path),"/" ), + sd->s_name), + (result == -EEXIST ?"duplicate filename" :"no such directory" ) + ); +kfree (path); + +return result; }/**
Signature · 1 line
1.6.3.1.54.g99dd.dirty
Re: [PATCH 01/20] sysfs: Implement sysfs_rename_link
In reply to Kay SieversQuoted 6 lines · Kay Sievers
Quoted 4 lines · Greg KH
So, there's been a lot of talk in this thread.
Eric, do you have an updated set of patches for me to try out?
Quoted 7 lines
I think we should get a version of the patch in that removes all files in a directory on cleanup, but warn if a subdirectory is still there. James has a patch to fix the one issue we've seen so far with existing child directories.
After that, we should work on fixing the users that leave files behind, and can possibly stop cleaning up files, if we want to.
Agreed. We are not yet ready to only remove empty directories from sysfs. So fixing that problem with the current sysfs should be done in a separate patchset after the other fixes.
I will look at putting that together.
Eric
[PATCH 21/20] sysfs: Rename sysfs_mv_dir sysfs_rename
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
It turns out that sysfs_mv_dir actually makes no assumptions that what
is being renamed is a directory. So rename sysfs_mv_dir to sysfs_rename to
reflect the functions general utility. Later we will use it rename symlinks in sysfs.
--- fs/sysfs/dir.c | 6 +++--- fs/sysfs/sysfs.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-)
fs/sysfs/dir.c +3 -3
@@ -660,7 +660,7 @@ void sysfs_remove_dir(struct kobject * kobj)remove_dir (sd); } -static int sysfs_mv_dir (struct sysfs_dirent *sd, +int sysfs_rename (struct sysfs_dirent *sd,struct sysfs_dirent *new_parent_sd,const char *new_name) {const char *dup_name =NULL ;
@@ -706,12 +706,12 @@ static int sysfs_mv_dir(struct sysfs_dirent *sd,int sysfs_rename_dir (struct kobject * kobj,const char *new_name) { -return sysfs_mv_dir (kobj->sd, kobj->sd->s_parent, new_name); +return sysfs_rename (kobj->sd, kobj->sd->s_parent, new_name); }int sysfs_move_dir (struct kobject *kobj,struct kobject *new_parent_kobj) { -return sysfs_mv_dir (kobj->sd, new_parent_kobj->sd, kobj->sd->s_name); +return sysfs_rename (kobj->sd, new_parent_kobj->sd, kobj->sd->s_name); }/* Relationship between s_mode and the DT_xxx types */
fs/sysfs/sysfs.h +3 -0
@@ -109,6 +109,9 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, struct sysfs_dirent **p_sd);void sysfs_remove_subdir (struct sysfs_dirent *sd); +int sysfs_rename (struct sysfs_dirent *sd, +struct sysfs_dirent *new_parent_sd,const char *new_name); +static inline struct sysfs_dirent *__sysfs_get (struct sysfs_dirent *sd) {if (sd) {
Signature · 1 line
1.6.3.1.54.g99dd.dirty
[PATCH 22/20] sysfs: Make sysfs_rename_link atomic
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
Use the existing sysfs_rename to make sysfs_rename_link an atomic operation that does less work. While I am at add additional sanity checking to ensure it is a symlink I am renaming.
--- fs/sysfs/symlink.c | 26 ++++++++++++++++++++++++-- 1 files changed, 24 insertions(+), 2 deletions(-)
fs/sysfs/symlink.c +24 -2
@@ -106,8 +106,30 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)int sysfs_rename_link (struct kobject *kobj,struct kobject *targ,const char *old,const char *new) { -sysfs_remove_link (kobj, old); -return sysfs_create_link (kobj, targ, new); +struct sysfs_dirent *parent_sd, *sd =NULL ; +int result; + +if (!kobj) + parent_sd = &sysfs_root; +else + parent_sd = kobj->sd; + + result = -ENOENT ; + sd =sysfs_get_dirent (parent_sd, old); +if (!sd) + goto out; + + result = -EINVAL ; +if (sysfs_type (sd) !=SYSFS_KOBJ_LINK ) + goto out; +if (sd->s_symlink.target_sd->s_dir.kobj != targ) + goto out; + + result =sysfs_rename (sd, parent_sd, new); + +out: +sysfs_put (sd); +return result; } static int sysfs_get_target_path(struct sysfs_dirent *parent_sd,
Signature · 1 line
1.6.3.1.54.g99dd.dirty
Kay Sievers
Acked-byRe: [PATCH 22/20] sysfs: Make sysfs_rename_link atomic
Quoted 7 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Use the existing
sysfs_renameto makesysfs_rename_linkan atomic operation that does less work. While I am at add additional sanity checking to ensure it is a symlink I am renaming.Signed-off-by Eric W. Biederman <[email protected]>
Looks great, and so much better than the remove and re-create thing.
Thanks,
Kay
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 22/20] sysfs: Make sysfs_rename_link atomic
Quoted 10 lines · Kay Sievers
Quoted 7 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Use the existing
sysfs_renameto makesysfs_rename_linkan atomic operation that does less work. While I am at add additional sanity checking to ensure it is a symlink I am renaming.Signed-off-by Eric W. Biederman <[email protected]>Looks great, and so much better than the remove and re-create thing.
Do you have your git tree public somewhere, or do you mind sending me an all-in-one patch? I like to give it a try here.
Thanks,
Kay
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 22/20] sysfs: Make sysfs_rename_link atomic
Quoted 8 lines · Kay Sievers
Quoted 7 lines · Kay Sievers
Quoted 6 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
Use the existing
sysfs_renameto makesysfs_rename_linkan atomic operation that does less work. While I am at add additional sanity checking to ensure it is a symlink I am renaming.
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
Signed-off-by Eric W. Biederman <[email protected]>Looks great, and so much better than the remove and re-create thing.
Do you have your git tree public somewhere, or do you mind sending me an all-in-one patch? I like to give it a try here.
Looks good. It survives a heavy hotplug setup just fine, renaming works fine here, and sysfs looks right. There are a bunch of warnings for some non-empty directories, which I replied with in the patch that added the warning.
Thanks,
Kay
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 23/20] driver core: Don't remove kobjects in device_shutdown.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
device_shutdown is defined to just shutdown the hardware and to not clean up any kernel data structures. Therefore don't put the kobjects for /sys/dev and /sys/dev/block and /sys/dev/char.
This ensures we don't remove /sys/dev/block and /sys/dev/char while we still have symlinks from there to the actual devices.
--- drivers/base/core.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-)
drivers/base/core.c +0 -3
@@ -1653,7 +1653,4 @@ void device_shutdown(void) dev->driver->shutdown (dev); } } -kobject_put (sysfs_dev_char_kobj); -kobject_put (sysfs_dev_block_kobj); -kobject_put (dev_kobj); }
Signature · 1 line
1.6.3.1.54.g99dd.dirty
Kay Sievers
Acked-byRe: [PATCH 23/20] driver core: Don't remove kobjects in device_shutdown.
Quoted 10 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
device_shutdownis defined to just shutdown the hardware and to not clean up any kernel data structures. Therefore don't put the kobjects for/sys/devand/sys/dev/blockand/sys/dev/char.This ensures we don't remove
/sys/dev/blockand/sys/dev/charwhile we still have symlinks from there to the actual devices.Signed-off-by Eric W. Biederman <[email protected]>
Looks good.
Thanks,
Kay
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 24/20] sysfs: In sysfs_add_one fail if the targe directory has been removed.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
If a bug in the upper layers results in someone attempting to add to a sysfs directory that has already been removed, warn about it and fail.
I don't believe this has ever happened, and it certainly never should happen, but be strict to avoid errors creeping in.
--- fs/sysfs/dir.c | 37 +++++++++++++++++++++++-------------- 1 files changed, 23 insertions(+), 14 deletions(-)
fs/sysfs/dir.c +22 -13
@@ -394,21 +394,17 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path)int sysfs_add_one (struct sysfs_dirent *parent_sd,struct sysfs_dirent *sd) {struct iattr *ps_iattr; +char *path; +int result;mutex_lock (&sysfs_mutex); -if (sysfs_find_dirent (parent_sd, sd->s_name)) { -char *path; -mutex_unlock (&sysfs_mutex); - path =kzalloc (PATH_MAX ,GFP_KERNEL ); -WARN (1 ,KERN_WARNING -"sysfs: cannot create duplicate filename '%s'\n" , - (path ==NULL ) ? sd->s_name : -strcat (strcat (sysfs_pathname (parent_sd, path),"/" ), - sd->s_name)); -kfree (path); -return -EEXIST ; - } + result = -ENOENT ; +if (parent_sd->s_flags &SYSFS_FLAG_REMOVED ) + goto out_err; + +if (sysfs_find_dirent (parent_sd, sd->s_name)) + goto out_err; sd->s_parent =sysfs_get (parent_sd);sysfs_link_sibling (sd);
@@ -417,9 +413,22 @@ int sysfs_add_one(struct sysfs_dirent *parent_sd, struct sysfs_dirent *sd) ps_iattr = parent_sd->s_iattr;if (ps_iattr) ps_iattr->ia_ctime = ps_iattr->ia_mtime =CURRENT_TIME ; -mutex_unlock (&sysfs_mutex);return 0 ; + +out_err: +mutex_unlock (&sysfs_mutex); + + path =kzalloc (PATH_MAX ,GFP_KERNEL ); +WARN (1 ,KERN_WARNING "sysfs: cannot create '%s' %s\n" , + (path ==NULL ) ? sd->s_name : +strcat (strcat (sysfs_pathname (parent_sd, path),"/" ), + sd->s_name), + (result == -EEXIST ?"duplicate filename" :"no such directory" ) + ); +kfree (path); + +return result; }/**
Signature · 1 line
1.6.3.1.54.g99dd.dirty
Kay Sievers
Acked-byRe: [PATCH 24/20] sysfs: In sysfs_add_one fail if the targe directory has been removed.
Quoted 10 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
If a bug in the upper layers results in someone attempting to add to a sysfs directory that has already been removed, warn about it and fail.
I don't believe this has ever happened, and it certainly never should happen, but be strict to avoid errors creeping in.
Signed-off-by Eric W. Biederman <[email protected]>
Sounds like a good idea.
Thanks,
Kay
[PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
In reply to Eric W. BiedermanFrom: Eric W. Biederman <[email protected]>
I have looked and I have not found a single legitimate case today where we remove sysfs directories with anything in them. The only case I have found to date was a bug. It was a problem of ownership. The files in
the directory where not owned by the directory itself. Leaving open
the potential for double deletion of the directory contents.
--- fs/sysfs/dir.c | 24 ++++-------------------- 1 files changed, 4 insertions(+), 20 deletions(-)
fs/sysfs/dir.c +4 -20
@@ -617,30 +617,14 @@ const struct inode_operations sysfs_dir_inode_operations = { .permission = sysfs_permission, }; -static struct sysfs_dirent *sysfs_get_one (struct sysfs_dirent *dir_sd) -{ -struct sysfs_dirent *sd = dir_sd; -mutex_lock (&sysfs_mutex); -while ((sysfs_type (sd) ==SYSFS_DIR ) && sd->s_dir.children) - sd = sd->s_dir.children; -if (sd != dir_sd) -sysfs_get (sd); -else - sd =NULL ; -mutex_unlock (&sysfs_mutex); -return sd; -} -static void remove_dir (struct sysfs_dirent *dir_sd) { -struct sysfs_dirent *sd; -pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name); -while ((sd =sysfs_get_one (dir_sd))) { -sysfs_remove_one (sd); -sysfs_put (sd); - } +WARN (dir_sd->s_dir.children, +KERN_WARNING "sysfs: removing non-empty dir: %s\n" , + dir_sd->s_name); +sysfs_remove_one (dir_sd); }
Signature · 1 line
1.6.3.1.54.g99dd.dirty
Kay Sievers
Acked-byRe: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 9 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
I have looked and I have not found a single legitimate case today where we remove sysfs directories with anything in them. The only case I have found to date was a bug. It was a problem of ownership. The files in the directory where not owned by the directory itself. Leaving open the potential for double deletion of the directory contents.
Signed-off-by Eric W. Biederman <[email protected]>
Sounds good to me. We should try that, and see if there was any valid use case we didn't think of, and if not, it's good to do what this patch does.
Thanks,
Kay
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 9 lines · Kay Sievers
Quoted 8 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
I have looked and I have not found a single legitimate case today where we remove sysfs directories with anything in them. The only case I have found to date was a bug. It was a problem of ownership. The files in
the directory where not owned by the directory itself. Leaving open
the potential for double deletion of the directory contents.
Quoted 5 lines
Quoted 1 line
Signed-off-by Eric W. Biederman <[email protected]>Sounds good to me. We should try that, and see if there was any valid use case we didn't think of, and if not, it's good to do what this patch does.
I get a bunch of warnings here. The question is if the users should be fixed, the warning removed, and/or the auto-deletion added back?
I've added:
- WARN(dir_sd->s_dir.children,
- KERN_WARNING "sysfs: removing non-empty dir: %s\n",
- dir_sd->s_name);
+ if (dir_sd->s_dir.children) {
+ struct sysfs_dirent *sd;
+
+ WARN(dir_sd->s_dir.children,
+ KERN_WARNING "sysfs: removing non-empty dir: %s\n",
+ dir_sd->s_name);
+ sd = dir_sd->s_dir.children;
+ while (sd) {
+ printk(KERN_WARNING "%s/%s\n", dir_sd->s_name, sd->s_name);
+ sd = sd->s_sibling;
+ }
+ }
And get non-empty directories from CPU, SCSI, firmware_class, sound, block:
sysfs: removing non-empty dir: state0
state0/name
state0/desc
state0/latency
state0/power
state0/usage
state0/time
sysfs: removing non-empty dir: 0000:03:00.0
0000:03:00.0/data
0000:03:00.0/loading
sysfs: removing non-empty dir: iosched
iosched/quantum
iosched/fifo_expire_sync
iosched/fifo_expire_async
iosched/back_seek_max
iosched/back_seek_penalty
iosched/slice_sync
iosched/slice_async
iosched/slice_async_rq
iosched/slice_idle
sysfs: removing non-empty dir: queue
queue/nr_requests
queue/read_ahead_kb
queue/max_hw_sectors_kb
queue/max_sectors_kb
queue/scheduler
queue/hw_sector_size
queue/rotational
queue/nomerges
queue/rq_affinity
queue/iostats
sysfs: removing non-empty dir: 4:0:0:0
4:0:0:0/queue_depth
4:0:0:0/queue_type
4:0:0:0/max_sectors
sysfs: removing non-empty dir: host4
host4/target4:0:0
sysfs: removing non-empty dir: pcmC1D0c
pcmC1D0c/pcm_class
sysfs: removing non-empty dir: card1
card1/id
card1/number
Thanks,
Kay
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 10 lines · Kay Sievers
Quoted 9 lines · Kay Sievers
Quoted 8 lines · Eric W. Biederman
From: Eric W. Biederman <[email protected]>
I have looked and I have not found a single legitimate case today where we remove sysfs directories with anything in them. The only case I have found to date was a bug. It was a problem of ownership. The files in
the directory where not owned by the directory itself. Leaving open
the potential for double deletion of the directory contents.
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Signed-off-by Eric W. Biederman <[email protected]>Sounds good to me. We should try that, and see if there was any valid use case we didn't think of, and if not, it's good to do what this patch does.
I get a bunch of warnings here. The question is if the users should be fixed, the warning removed, and/or the auto-deletion added back?
Thanks for finding these. I was afraid I hadn't look far enough. To see if non-empty directories were a problem.
Most of these look like attributes, for which the non-empty directory removal was correct. Although I am puzzled by why we missed them.
host4/target4:0:0 worries me. I don't have my head wrapped around what that is yet. But is looks like is a directory (which we currently do not handle correctly), and even more it looks like that is quite possibly two kobjects in a parent/child situation where the child was not removed when the child was.
It definitely warrants more investigation.
....
Let's make the plan to investigate these, and see how hard it would be to actually remove these with the current device/sysfs infrastructure.
Fixing the users and adding back auto-deletion are the only two real options.
I expect we have uncovered at least one more real bug. So I am inclined to make the policy that we fix the users.
Quoted 61 lines
I've added:
- WARN(dir_sd->s_dir.children,
-KERN_WARNING"sysfs: removing non-empty dir: %s\n",
-dir_sd->s_name);
+ if (dir_sd->s_dir.children) {
+ structsysfs_dirent*sd;
+
+ WARN(dir_sd->s_dir.children,
+KERN_WARNING"sysfs: removing non-empty dir: %s\n",
+dir_sd->s_name);
+ sd =dir_sd->s_dir.children;
+ while (sd) {
+printk(KERN_WARNING "%s/%s\n", dir_sd->s_name, sd->s_name);
+ sd =sd->s_sibling;
+ }
+ }And get non-empty directories from CPU, SCSI,
firmware_class, sound, block:
sysfs: removing non-empty dir: state0
state0/name
state0/desc
state0/latency
state0/power
state0/usage
state0/timesysfs: removing non-empty dir: 0000:03:00.0
0000:03:00.0/data
0000:03:00.0/loadingsysfs: removing non-empty dir: iosched
iosched/quantum
iosched/fifo_expire_sync
iosched/fifo_expire_async
iosched/back_seek_max
iosched/back_seek_penalty
iosched/slice_sync
iosched/slice_async
iosched/slice_async_rq
iosched/slice_idlesysfs: removing non-empty dir: queue
queue/nr_requests
queue/read_ahead_kb
queue/max_hw_sectors_kb
queue/max_sectors_kb
queue/scheduler
queue/hw_sector_size
queue/rotational
queue/nomerges
queue/rq_affinity
queue/iostatssysfs: removing non-empty dir: 4:0:0:0
4:0:0:0/queue_depth
4:0:0:0/queue_type
4:0:0:0/max_sectorssysfs: removing non-empty dir: host4
host4/target4:0:0
Quoted 6 lines
sysfs: removing non-empty dir: pcmC1D0c
pcmC1D0c/pcm_classsysfs: removing non-empty dir: card1
card1/id
card1/number
Eric
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 2 lines · Eric W. Biederman
Most of these look like attributes, for which the non-empty directory removal was correct. Although I am puzzled by why we missed them.
Yes, most of them are attributes. I have USB hubs here with lots of devices connected, setups I use for udev testing, so this might trigger things that usually don't happen.
Quoted 7 lines
host4/target4:0:0 worries me. I don't have my head wrapped around what that is yet. But is looks like is a directory (which we currently do not handle correctly), and even more it looks like that is quite possibly two kobjects in a parent/child situation where the child was not removed when the child was.
It definitely warrants more investigation.
It seems like a real bug. We get:
dir: host5/target5:0:0
and we removed a parent from an active child, and the device path misses all its parents:
'target7:0:0' (ffff880124eb1158): fill_kobj_path: path = '/host7/target7:0:0'
it gets cleaned up:
'target7:0:0': free name
but it should still be fixed in the user. Adding Alan Stern, maybe he has an idea what's going on here.
Note, that it is hard to reproduce, It only happens with a frequent connect/disconnects on a hub full of devices. But it still seems like a real bug in the USB device cleanup logic. At the end of this mail is the log of all files which did exist at cleanup.
Quoted 4 lines
Let's make the plan to investigate these, and see how hard it would be to actually remove these with the current device/sysfs infrastructure.
Fixing the users and adding back auto-deletion are the only two real options.
Seems, we should remove non-directory files, which in most cases belong to the kobject itself, but the user's cleanup logic does not cover the removal of the created files.
But I think, we should still warn, if we find a sub-directory inside a directory we are going to remove.
Thanks,
Kay
attr: state0/name attr: state0/desc attr: state0/latency attr: state0/power attr: state0/usage attr: state0/time attr: state1/name attr: state1/desc attr: state1/latency attr: state1/power attr: state1/usage attr: state1/time attr: state2/name attr: state2/desc attr: state2/latency attr: state2/power attr: state2/usage attr: state2/time attr: state3/name attr: state3/desc attr: state3/latency attr: state3/power attr: state3/usage attr: state3/time attr: state0/name attr: state0/desc attr: state0/latency attr: state0/power attr: state0/usage attr: state0/time attr: state1/name attr: state1/desc attr: state1/latency attr: state1/power attr: state1/usage attr: state1/time attr: state2/name attr: state2/desc attr: state2/latency attr: state2/power attr: state2/usage attr: state2/time attr: state3/name attr: state3/desc attr: state3/latency attr: state3/power attr: state3/usage attr: state3/time battr: 0000:03:00.0/data attr: 0000:03:00.0/loading attr: pcmC1D0c/pcm_class attr: card1/id attr: card1/number attr: iosched/quantum attr: iosched/fifo_expire_sync attr: iosched/fifo_expire_async attr: iosched/back_seek_max attr: iosched/back_seek_penalty attr: iosched/slice_sync attr: iosched/slice_async attr: iosched/slice_async_rq attr: iosched/slice_idle attr: queue/nr_requests attr: queue/read_ahead_kb attr: queue/max_hw_sectors_kb attr: queue/max_sectors_kb attr: queue/scheduler attr: queue/hw_sector_size attr: queue/rotational attr: queue/nomerges attr: queue/rq_affinity attr: queue/iostats attr: 5:0:0:0/queue_depth attr: 5:0:0:0/queue_type attr: 5:0:0:0/max_sectors attr: iosched/quantum attr: iosched/fifo_expire_sync attr: iosched/fifo_expire_async attr: iosched/back_seek_max attr: iosched/back_seek_penalty attr: iosched/slice_sync attr: iosched/slice_async attr: iosched/slice_async_rq attr: iosched/slice_idle attr: queue/nr_requests attr: queue/read_ahead_kb attr: queue/max_hw_sectors_kb attr: queue/max_sectors_kb attr: queue/scheduler attr: queue/hw_sector_size attr: queue/rotational attr: queue/nomerges attr: queue/rq_affinity attr: queue/iostats attr: 5:0:0:1/queue_depth attr: 5:0:0:1/queue_type attr: 5:0:0:1/max_sectors dir: host5/target5:0:0 attr: pcmC1D0c/pcm_class attr: card1/id attr: card1/number attr: pcmC1D0c/pcm_class attr: card1/id attr: card1/number attr: iosched/quantum attr: iosched/fifo_expire_sync attr: iosched/fifo_expire_async attr: iosched/back_seek_max attr: iosched/back_seek_penalty attr: iosched/slice_sync attr: iosched/slice_async attr: iosched/slice_async_rq attr: iosched/slice_idle attr: queue/nr_requests attr: queue/read_ahead_kb attr: queue/max_hw_sectors_kb attr: queue/max_sectors_kb attr: queue/scheduler attr: queue/hw_sector_size attr: queue/rotational attr: queue/nomerges attr: queue/rq_affinity attr: queue/iostats attr: 6:0:0:0/queue_depth attr: 6:0:0:0/queue_type attr: 6:0:0:0/max_sectors attr: iosched/quantum attr: iosched/fifo_expire_sync attr: iosched/fifo_expire_async attr: iosched/back_seek_max attr: iosched/back_seek_penalty attr: iosched/slice_sync attr: iosched/slice_async attr: iosched/slice_async_rq attr: iosched/slice_idle attr: queue/nr_requests attr: queue/read_ahead_kb attr: queue/max_hw_sectors_kb attr: queue/max_sectors_kb attr: queue/scheduler attr: queue/hw_sector_size attr: queue/rotational attr: queue/nomerges attr: queue/rq_affinity attr: queue/iostats attr: 6:0:0:1/queue_depth attr: 6:0:0:1/queue_type attr: 6:0:0:1/max_sectors attr: pcmC1D0c/pcm_class attr: card1/id attr: card1/number attr: pcmC1D0c/pcm_class attr: card1/id attr: card1/number
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 27 lines · Kay Sievers
Quoted 2 lines · Eric W. Biederman
Most of these look like attributes, for which the non-empty directory removal was correct. Although I am puzzled by why we missed them.
Yes, most of them are attributes. I have USB hubs here with lots of devices connected, setups I use for udev testing, so this might trigger things that usually don't happen.
Quoted 7 lines
host4/target4:0:0 worries me. I don't have my head wrapped around what that is yet. But is looks like is a directory (which we currently do not handle correctly), and even more it looks like that is quite possibly two kobjects in a parent/child situation where the child was not removed when the child was.
It definitely warrants more investigation.
It seems like a real bug. We get:
dir: host5/target5:0:0and we removed a parent from an active child, and the device path misses all its parents:
'target7:0:0' (ffff880124eb1158):fill_kobj_path: path = '/host7/target7:0:0'it gets cleaned up:
'target7:0:0': free name
Quoted 7 lines
but it should still be fixed in the user. Adding Alan Stern, maybe he has an idea what's going on here.
Note, that it is hard to reproduce, It only happens with a frequent connect/disconnects on a hub full of devices. But it still seems like a real bug in the USB device cleanup logic. At the end of this mail is the log of all files which did exist at cleanup.
This looks like a bug I found almost two weeks ago. The bug was introduced by Arjan as part of his async conversion (the async routine runs without acquiring one of the mutexes held by its caller). The result is a race in the sd driver -- no connection with USB, by the way -- so it's a little difficult to trigger. I posted a patch, but the reporter never said whether or not the patch fixed the problem. Hence the patch hasn't been submitted.
Here it is for you to try out.
Alan Stern
drivers/scsi/sd.c +12 -8
@@ -1892,12 +1892,16 @@ static int sd_format_disk_name(char *prestatic void sd_probe_async (void *data,async_cookie_t cookie) {struct scsi_disk *sdkp = data; -struct scsi_device *sdp; +struct scsi_device *sdp = sdkp->device; +struct Scsi_Host *shost = sdp->host;struct gendisk *gd;u32 index;struct device *dev; - sdp = sdkp->device; +mutex_lock (&shost->scan_mutex); +if (!scsi_host_scan_allowed (shost)) + goto out_unlock_host; + gd = sdkp->disk; index = sdkp->index; dev = &sdp->sdev_gendev;
@@ -1915,8 +1919,10 @@ static void sd_probe_async(void *data, a sdkp->dev.class = &sd_disk_class;dev_set_name (&sdkp->dev,dev_name (&sdp->sdev_gendev)); -if (device_add (&sdkp->dev)) - goto out_free_index; +if (device_add (&sdkp->dev)) { +ida_remove (&sd_index_ida, index); + goto out_unlock_host; + }get_device (&sdp->sdev_gendev);
@@ -1955,10 +1961,8 @@ static void sd_probe_async(void *data, asd_printk (KERN_NOTICE , sdkp,"Attached SCSI %sdisk\n" , sdp->removable ?"removable " :"" ); -return ; - - out_free_index: -ida_remove (&sd_index_ida, index); + out_unlock_host: +mutex_unlock (&shost->scan_mutex); }/**
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 4 lines · Alan Stern
This looks like a bug I found almost two weeks ago. The bug was introduced by Arjan as part of his async conversion (the async routine runs without acquiring one of the mutexes held by its caller). The result is a race in the sd driver -- no connection with USB,
Ah, I see.
Quoted 1 line
by the way -- so it's a little difficult to trigger.
I can trigger it pretty reliable now on plain -rc7 , but only with more hubs in-between the storage device. It usually take less than 10-15 connect/disconnect cycles.
It looks like a serious bug though, after the bug triggered, random, likely unrelated, applications crash, and I can not cleanly shot down anymore.
Quoted 5 lines
I posted a patch, but the
reporter never said whether or not the patch fixed the problem. Hence the patch hasn't been submitted.Here it is for you to try out.
I'll give it try now.
Kay
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 12 lines · Kay Sievers
Quoted 1 line · Alan Stern
by the way -- so it's a little difficult to trigger.
I can trigger it pretty reliable now on plain -rc7 , but only with more hubs in-between the storage device. It usually take less than 10-15 connect/disconnect cycles.
It looks like a serious bug though, after the bug triggered, random, likely unrelated, applications crash, and I can not cleanly shot down anymore.
Quoted 7 lines
Quoted 5 lines
I posted a patch, but the
reporter never said whether or not the patch fixed the problem. Hence the patch hasn't been submitted.Here it is for you to try out.
I'll give it try now.
It still shows the same issue. Here is the trace with the target directory left-over, when the host directory goes away: "host5/target5:0:0", and the devpath with the parents lost "path = '/host5/target5:0:0'":
Thanks,
Kay
[ 58.399021] kobject: 'host5' (ffff88012c52b558): kobject_uevent_env [ 58.399041] kobject: 'host5' (ffff88012c52b558): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host5/scsi_host/host5' [ 58.399213] kobject: 'scsi_host' (ffff88012548cdd0): kobject_cleanup [ 58.399217] kobject: 'scsi_host' (ffff88012548cdd0): auto cleanup kobject_del [ 58.399236] kobject: 'scsi_host' (ffff88012548cdd0): calling ktype release [ 58.399239] kobject: (ffff88012548cdd0): dynamic_kobj_release [ 58.399243] kobject: 'scsi_host': free name [ 58.399247] kobject: 'host5' (ffff88012c52b558): kobject_cleanup [ 58.399250] kobject: 'host5' (ffff88012c52b558): calling ktype release [ 58.399255] kobject: 'host5': free name [ 58.399315] kobject: 'host5' (ffff88012c52b388): kobject_uevent_env [ 58.399335] kobject: 'host5' (ffff88012c52b388): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host5' [ 58.399484] ------------[ cut here ]------------ [ 58.399493] WARNING: at fs/sysfs/dir.c:794 sysfs_remove_dir+0xb2/0xd0() [ 58.399497] Hardware name: 2776LEG [ 58.399499] XXX dir: host5/target5:0:0 ... [ 58.399594] Pid: 226, comm: khubd Not tainted 2.6.30-rc7-dirty #40 [ 58.399598] Call Trace: [ 58.399605] [<ffffffff8023c6a8>] warn_slowpath_common+0x78/0xb0 [ 58.399610] [<ffffffff8023c73c>] warn_slowpath_fmt+0x3c/0x40 [ 58.399614] [<ffffffff803229f6>] ? sysfs_addrm_start+0x76/0xd0 [ 58.399619] [<ffffffff80323012>] sysfs_remove_dir+0xb2/0xd0 [ 58.399626] [<ffffffff803e5036>] kobject_del+0x16/0x40 [ 58.399632] [<ffffffff80477645>] device_del+0x165/0x1a0 [ 58.399638] [<ffffffff8048256f>] scsi_remove_host+0xcf/0x120 [ 58.399652] [<ffffffffa02fd3cb>] quiesce_and_remove_host+0x6b/0xb0 [usb_storage] [ 58.399662] [<ffffffffa02fd4f8>] usb_stor_disconnect+0x18/0x30 [usb_storage] [ 58.399686] [<ffffffffa0062fae>] usb_unbind_interface+0x6e/0x140 [usbcore] [ 58.399694] [<ffffffff80479e29>] __device_release_driver+0x59/0xa0 [ 58.399699] [<ffffffff80479f68>] device_release_driver+0x28/0x40 [ 58.399704] [<ffffffff8047927c>] bus_remove_device+0xac/0xe0 [ 58.399709] [<ffffffff80477607>] device_del+0x127/0x1a0 [ 58.399726] [<ffffffffa005fb77>] usb_disable_device+0xa7/0x130 [usbcore] [ 58.399744] [<ffffffffa005a818>] usb_disconnect+0xc8/0x140 [usbcore] [ 58.399761] [<ffffffffa005a804>] usb_disconnect+0xb4/0x140 [usbcore] [ 58.399778] [<ffffffffa005b8db>] hub_thread+0x50b/0x1230 [usbcore] [ 58.399784] [<ffffffff80565a56>] ? _spin_unlock_irq+0x26/0x30 [ 58.399790] [<ffffffff80237d1e>] ? finish_task_switch+0x7e/0x140 [ 58.399795] [<ffffffff80237cdb>] ? finish_task_switch+0x3b/0x140 [ 58.399802] [<ffffffff802549e0>] ? autoremove_wake_function+0x0/0x40 [ 58.399818] [<ffffffffa005b3d0>] ? hub_thread+0x0/0x1230 [usbcore] [ 58.399823] [<ffffffff802545b5>] kthread+0x55/0xa0 [ 58.399829] [<ffffffff8020cf3a>] child_rip+0xa/0x20 [ 58.399833] [<ffffffff80254560>] ? kthread+0x0/0xa0 [ 58.399838] [<ffffffff8020cf30>] ? child_rip+0x0/0x20 [ 58.399842] ---[ end trace a5fdfdfd6227b73e ]--- ... [ 58.853385] kobject: 'target5:0:0' (ffff880129980480): kobject_uevent_env [ 58.853405] kobject: 'target5:0:0' (ffff880129980480): fill_kobj_path: path = '/host5/target5:0:0' [ 58.853643] kobject: 'target5:0:0' (ffff880129980480): kobject_cleanup [ 58.853647] kobject: 'target5:0:0' (ffff880129980480): calling ktype release [ 58.853653] kobject: 'host5' (ffff88012c52b388): kobject_cleanup [ 58.853657] kobject: 'host5' (ffff88012c52b388): calling ktype release [ 58.853701] kobject: '2-2.4:1.0' (ffff8801255319f0): kobject_cleanup [ 58.853705] kobject: '2-2.4:1.0' (ffff8801255319f0): calling ktype release [ 58.853721] kobject: '2-2.4:1.0': free name [ 58.853736] kobject: 'host5': free name [ 58.853742] kobject: 'target5:0:0': free name [ 58.853748] kobject: '5:0:0:0': free name
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Since this appears to be a bug in the SCSI layer, let's add some SCSI people to the CC: list.
To summarize the problem: The SCSI core tries to unregister a host while its sysfs directory is still non-empty because the target hasn't been unregistered yet.
Quoted 81 lines · Kay Sievers
Quoted 12 lines · Kay Sievers
Quoted 1 line · Alan Stern
by the way -- so it's a little difficult to trigger.
I can trigger it pretty reliable now on plain -rc7 , but only with more hubs in-between the storage device. It usually take less than 10-15 connect/disconnect cycles.
It looks like a serious bug though, after the bug triggered, random, likely unrelated, applications crash, and I can not cleanly shot down anymore.
Quoted 7 lines
Quoted 5 lines
I posted a patch, but the
reporter never said whether or not the patch fixed the problem. Hence the patch hasn't been submitted.Here it is for you to try out.
I'll give it try now.
It still shows the same issue. Here is the trace with the target directory left-over, when the host directory goes away: "host5/target5:0:0", and the devpath with the parents lost "path = '/host5/target5:0:0'":
Thanks,
Kay[ 58.399021] kobject: 'host5' (ffff88012c52b558): kobject_uevent_env [ 58.399041] kobject: 'host5' (ffff88012c52b558): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host5/scsi_host/host5' [ 58.399213] kobject: 'scsi_host' (ffff88012548cdd0): kobject_cleanup [ 58.399217] kobject: 'scsi_host' (ffff88012548cdd0): auto cleanup kobject_del [ 58.399236] kobject: 'scsi_host' (ffff88012548cdd0): calling ktype release [ 58.399239] kobject: (ffff88012548cdd0): dynamic_kobj_release [ 58.399243] kobject: 'scsi_host': free name [ 58.399247] kobject: 'host5' (ffff88012c52b558): kobject_cleanup [ 58.399250] kobject: 'host5' (ffff88012c52b558): calling ktype release [ 58.399255] kobject: 'host5': free name [ 58.399315] kobject: 'host5' (ffff88012c52b388): kobject_uevent_env [ 58.399335] kobject: 'host5' (ffff88012c52b388): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host5' [ 58.399484] ------------[ cut here ]------------ [ 58.399493] WARNING: at fs/sysfs/dir.c:794 sysfs_remove_dir+0xb2/0xd0() [ 58.399497] Hardware name: 2776LEG [ 58.399499] XXX dir: host5/target5:0:0 ... [ 58.399594] Pid: 226, comm: khubd Not tainted 2.6.30-rc7-dirty #40 [ 58.399598] Call Trace: [ 58.399605] [<ffffffff8023c6a8>] warn_slowpath_common+0x78/0xb0 [ 58.399610] [<ffffffff8023c73c>] warn_slowpath_fmt+0x3c/0x40 [ 58.399614] [<ffffffff803229f6>] ? sysfs_addrm_start+0x76/0xd0 [ 58.399619] [<ffffffff80323012>] sysfs_remove_dir+0xb2/0xd0 [ 58.399626] [<ffffffff803e5036>] kobject_del+0x16/0x40 [ 58.399632] [<ffffffff80477645>] device_del+0x165/0x1a0 [ 58.399638] [<ffffffff8048256f>] scsi_remove_host+0xcf/0x120 [ 58.399652] [<ffffffffa02fd3cb>] quiesce_and_remove_host+0x6b/0xb0 [usb_storage] [ 58.399662] [<ffffffffa02fd4f8>] usb_stor_disconnect+0x18/0x30 [usb_storage] [ 58.399686] [<ffffffffa0062fae>] usb_unbind_interface+0x6e/0x140 [usbcore] [ 58.399694] [<ffffffff80479e29>] __device_release_driver+0x59/0xa0 [ 58.399699] [<ffffffff80479f68>] device_release_driver+0x28/0x40 [ 58.399704] [<ffffffff8047927c>] bus_remove_device+0xac/0xe0 [ 58.399709] [<ffffffff80477607>] device_del+0x127/0x1a0 [ 58.399726] [<ffffffffa005fb77>] usb_disable_device+0xa7/0x130 [usbcore] [ 58.399744] [<ffffffffa005a818>] usb_disconnect+0xc8/0x140 [usbcore] [ 58.399761] [<ffffffffa005a804>] usb_disconnect+0xb4/0x140 [usbcore] [ 58.399778] [<ffffffffa005b8db>] hub_thread+0x50b/0x1230 [usbcore] [ 58.399784] [<ffffffff80565a56>] ? _spin_unlock_irq+0x26/0x30 [ 58.399790] [<ffffffff80237d1e>] ? finish_task_switch+0x7e/0x140 [ 58.399795] [<ffffffff80237cdb>] ? finish_task_switch+0x3b/0x140 [ 58.399802] [<ffffffff802549e0>] ? autoremove_wake_function+0x0/0x40 [ 58.399818] [<ffffffffa005b3d0>] ? hub_thread+0x0/0x1230 [usbcore] [ 58.399823] [<ffffffff802545b5>] kthread+0x55/0xa0 [ 58.399829] [<ffffffff8020cf3a>] child_rip+0xa/0x20 [ 58.399833] [<ffffffff80254560>] ? kthread+0x0/0xa0 [ 58.399838] [<ffffffff8020cf30>] ? child_rip+0x0/0x20 [ 58.399842] ---[ end trace a5fdfdfd6227b73e ]--- ... [ 58.853385] kobject: 'target5:0:0' (ffff880129980480): kobject_uevent_env [ 58.853405] kobject: 'target5:0:0' (ffff880129980480): fill_kobj_path: path = '/host5/target5:0:0' [ 58.853643] kobject: 'target5:0:0' (ffff880129980480): kobject_cleanup [ 58.853647] kobject: 'target5:0:0' (ffff880129980480): calling ktype release
Quoted 8 lines
[ 58.853653] kobject: 'host5' (ffff88012c52b388): kobject_cleanup [ 58.853657] kobject: 'host5' (ffff88012c52b388): calling ktype release [ 58.853701] kobject: '2-2.4:1.0' (ffff8801255319f0): kobject_cleanup [ 58.853705] kobject: '2-2.4:1.0' (ffff8801255319f0): calling ktype release [ 58.853721] kobject: '2-2.4:1.0': free name [ 58.853736] kobject: 'host5': free name [ 58.853742] kobject: 'target5:0:0': free name [ 58.853748] kobject: '5:0:0:0': free name
Can you provide more of the context? I'd like to see the log starting from when these devices were first registered.
Alan Stern
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 9 lines · Alan Stern
Since this appears to be a bug in the SCSI layer, let's add some SCSI people to the CC: list.
To summarize the problem: The SCSI core tries to unregister a host while its sysfs directory is still non-empty because the target hasn't been unregistered yet.
Can you provide more of the context? I'd like to see the log starting from when these devices were first registered.
I was able to trigger it with a USB storage device only, connected to a hub, and I removed the hub from the host.
Kay
[21415.579166] usb 2-2: new high speed USB device using ehci_hcd and address 26 [21415.693822] kobject: '2-2' (ffff8801390c9128): kobject_add_internal: parent: 'usb2', set: 'devices' [21415.694151] kobject: '2-2' (ffff8801390c9128): kobject_uevent_env [21415.694186] kobject: '2-2' (ffff8801390c9128): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2' [21415.694299] usb 2-2: configuration #1 chosen from 1 choice [21415.695512] kobject: '2-2:1.0' (ffff8800b9716b48): kobject_add_internal: parent: '2-2', set: 'devices' [21415.695612] kobject: '2-2:1.0' (ffff8800b9716b48): kobject_uevent_env [21415.695645] kobject: '2-2:1.0' (ffff8800b9716b48): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2:1.0' [21415.695750] hub 2-2:1.0: USB hub found [21415.696415] hub 2-2:1.0: 4 ports detected [21415.701428] kobject: 'usb_endpoint' (ffff8800b9648198): kobject_add_internal: parent: '2-2:1.0', set: '<NULL>' [21415.701457] kobject: 'usbdev2.26_ep81' (ffff8800b96f56f0): kobject_add_internal: parent: 'usb_endpoint', set: 'devices' [21415.701656] kobject: 'usbdev2.26_ep81' (ffff8800b96f56f0): kobject_uevent_env [21415.701694] kobject: 'usbdev2.26_ep81' (ffff8800b96f56f0): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2:1.0/usb_endpoint/usbdev2.26_ep81' [21415.701826] kobject: 'usb_endpoint' (ffff8800b96486e8): kobject_add_internal: parent: '2-2', set: '<NULL>' [21415.701847] kobject: 'usbdev2.26_ep00' (ffff8800b96f5dc8): kobject_add_internal: parent: 'usb_endpoint', set: 'devices' [21415.701972] kobject: 'usbdev2.26_ep00' (ffff8800b96f5dc8): kobject_uevent_env [21415.702030] kobject: 'usbdev2.26_ep00' (ffff8800b96f5dc8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/usb_endpoint/usbdev2.26_ep00' [21415.974325] usb 2-2.4: new high speed USB device using ehci_hcd and address 27 [21416.060815] kobject: '2-2.4' (ffff88013422cb20): kobject_add_internal: parent: '2-2', set: 'devices' [21416.061184] kobject: '2-2.4' (ffff88013422cb20): kobject_uevent_env [21416.061218] kobject: '2-2.4' (ffff88013422cb20): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4' [21416.061330] usb 2-2.4: configuration #1 chosen from 1 choice [21416.063752] kobject: '2-2.4:1.0' (ffff88013a9cc908): kobject_add_internal: parent: '2-2.4', set: 'devices' [21416.063862] kobject: '2-2.4:1.0' (ffff88013a9cc908): kobject_uevent_env [21416.063897] kobject: '2-2.4:1.0' (ffff88013a9cc908): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0' [21416.097456] scsi10 : SCSI emulation for USB Mass Storage devices [21416.097474] kobject: 'host10' (ffff8801001592f8): kobject_add_internal: parent: '2-2.4:1.0', set: 'devices' [21416.097520] kobject: 'host10' (ffff8801001592f8): kobject_uevent_env [21416.097541] kobject: 'host10' (ffff8801001592f8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10' [21416.097797] kobject: 'scsi_host' (ffff8801340d3880): kobject_add_internal: parent: 'host10', set: '<NULL>' [21416.097808] kobject: 'host10' (ffff8801001594c8): kobject_add_internal: parent: 'scsi_host', set: 'devices' [21416.097888] kobject: 'host10' (ffff8801001594c8): kobject_uevent_env [21416.097908] kobject: 'host10' (ffff8801001594c8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/scsi_host/host10' [21416.109077] kobject: 'usb_endpoint' (ffff8801340d3f68): kobject_add_internal: parent: '2-2.4:1.0', set: '<NULL>' [21416.109096] kobject: 'usbdev2.27_ep81' (ffff8800b9668b88): kobject_add_internal: parent: 'usb_endpoint', set: 'devices' [21416.109238] kobject: 'usbdev2.27_ep81' (ffff8800b9668b88): kobject_uevent_env [21416.109259] kobject: 'usbdev2.27_ep81' (ffff8800b9668b88): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/usb_endpoint/usbdev2.27_ep81' [21416.110897] kobject: 'usbdev2.27_ep02' (ffff8800b9668268): kobject_add_internal: parent: 'usb_endpoint', set: 'devices' [21416.111007] kobject: 'usbdev2.27_ep02' (ffff8800b9668268): kobject_uevent_env [21416.111027] kobject: 'usbdev2.27_ep02' (ffff8800b9668268): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/usb_endpoint/usbdev2.27_ep02' [21416.112326] kobject: 'usb_endpoint' (ffff880115b54990): kobject_add_internal: parent: '2-2.4', set: '<NULL>' [21416.112340] kobject: 'usbdev2.27_ep00' (ffff8800b9668dd0): kobject_add_internal: parent: 'usb_endpoint', set: 'devices' [21416.112439] kobject: 'usbdev2.27_ep00' (ffff8800b9668dd0): kobject_uevent_env [21416.112459] kobject: 'usbdev2.27_ep00' (ffff8800b9668dd0): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/usb_endpoint/usbdev2.27_ep00' [21416.112675] usb-storage: device found at 27 [21416.112678] usb-storage: waiting for device to settle before scanning [21421.113280] scsi 10:0:0:0: Direct-Access SanDisk U3 Cruzer Micro 8.02 PQ: 0 ANSI: 0 CCS [21421.113304] kobject: 'target10:0:0' (ffff88013a9c9158): kobject_add_internal: parent: 'host10', set: 'devices' [21421.113378] kobject: 'target10:0:0' (ffff88013a9c9158): kobject_uevent_env [21421.113414] kobject: 'target10:0:0' (ffff88013a9c9158): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0' [21421.113836] kobject: '10:0:0:0' (ffff88012bb87588): kobject_add_internal: parent: 'target10:0:0', set: 'devices' [21421.118125] kobject: '10:0:0:0' (ffff88012bb87588): kobject_uevent_env [21421.118200] kobject: '10:0:0:0' (ffff88012bb87588): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0' [21421.120456] kobject: 'scsi_device' (ffff8801078d8220): kobject_add_internal: parent: '10:0:0:0', set: '<NULL>' [21421.120476] kobject: '10:0:0:0' (ffff88012bb87758): kobject_add_internal: parent: 'scsi_device', set: 'devices' [21421.120538] kobject: '10:0:0:0' (ffff88012bb87758): kobject_uevent_env [21421.120575] kobject: '10:0:0:0' (ffff88012bb87758): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0/scsi_device/10:0:0:0' [21421.121003] kobject: 'scsi_generic' (ffff8801388d55d8): kobject_add_internal: parent: '10:0:0:0', set: '<NULL>' [21421.121022] kobject: 'sg3' (ffff8800b966a000): kobject_add_internal: parent: 'scsi_generic', set: 'devices' [21421.121197] kobject: 'sg3' (ffff8800b966a000): kobject_uevent_env [21421.121233] kobject: 'sg3' (ffff8800b966a000): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0/scsi_generic/sg3' [21421.127335] sd 10:0:0:0: Attached scsi generic sg3 type 0 [21421.127393] kobject: 'bsg' (ffff8801388d56e8): kobject_add_internal: parent: '10:0:0:0', set: '<NULL>' [21421.127412] kobject: '10:0:0:0' (ffff8800b966a248): kobject_add_internal: parent: 'bsg', set: 'devices' [21421.127541] kobject: '10:0:0:0' (ffff8800b966a248): kobject_uevent_env [21421.127581] kobject: '10:0:0:0' (ffff8800b966a248): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0/bsg/10:0:0:0' [21421.128699] scsi 10:0:0:1: CD-ROM SanDisk U3 Cruzer Micro 8.02 PQ: 0 ANSI: 0 [21421.128720] kobject: '10:0:0:1' (ffff880139003b90): kobject_add_internal: parent: 'target10:0:0', set: 'devices' [21421.128870] kobject: '10:0:0:1' (ffff880139003b90): kobject_uevent_env [21421.128904] kobject: '10:0:0:1' (ffff880139003b90): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:1' [21421.132180] sr0: scsi3-mmc drive: 48x/48x tray [21421.132220] kobject: 'block' (ffff880139009d48): kobject_add_internal: parent: '10:0:0:1', set: '<NULL>' [21421.132241] kobject: 'sr0' (ffff880138836fa8): kobject_add_internal: parent: 'block', set: 'devices' [21421.132378] kobject: 'sr0' (ffff880138836fa8): kobject_uevent_env [21421.132385] kobject: 'sr0' (ffff880138836fa8): kobject_uevent_env: uevent_suppress caused the event to drop! [21421.132417] kobject: 'holders' (ffff880129f63440): kobject_add_internal: parent: 'sr0', set: '<NULL>' [21421.132437] kobject: 'slaves' (ffff88013886c6e8): kobject_add_internal: parent: 'sr0', set: '<NULL>' [21421.132450] kobject: 'sr0' (ffff880138836fa8): kobject_uevent_env [21421.132485] kobject: 'sr0' (ffff880138836fa8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:1/block/sr0' [21421.132837] kobject: 'queue' (ffff88013aea0ff0): kobject_add_internal: parent: 'sr0', set: '<NULL>' [21421.132903] kobject: 'queue' (ffff88013aea0ff0): kobject_uevent_env [21421.132910] kobject: 'queue' (ffff88013aea0ff0): kobject_uevent_env: filter function caused the event to drop! [21421.132921] kobject: 'iosched' (ffff8801350a5c40): kobject_add_internal: parent: 'queue', set: '<NULL>' [21421.136715] kobject: 'iosched' (ffff8801350a5c40): kobject_uevent_env [21421.136721] kobject: 'iosched' (ffff8801350a5c40): kobject_uevent_env: filter function caused the event to drop! [21421.136738] kobject: '11:0' (ffff8800b96696e0): kobject_add_internal: parent: 'bdi', set: 'devices' [21421.136785] kobject: '11:0' (ffff8800b96696e0): kobject_uevent_env [21421.136804] kobject: '11:0' (ffff8800b96696e0): fill_kobj_path: path = '/devices/virtual/bdi/11:0' [21421.137067] sr 10:0:0:1: Attached scsi CD-ROM sr0 [21421.137086] kobject: 'scsi_device' (ffff880129c6a550): kobject_add_internal: parent: '10:0:0:1', set: '<NULL>' [21421.137098] kobject: '10:0:0:1' (ffff880139003d60): kobject_add_internal: parent: 'scsi_device', set: 'devices' [21421.137148] kobject: '10:0:0:1' (ffff880139003d60): kobject_uevent_env [21421.137170] kobject: '10:0:0:1' (ffff880139003d60): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:1/scsi_device/10:0:0:1' [21421.137369] kobject: 'scsi_generic' (ffff880129c6a6e8): kobject_add_internal: parent: '10:0:0:1', set: '<NULL>' [21421.137380] kobject: 'sg4' (ffff8800b9669928): kobject_add_internal: parent: 'scsi_generic', set: 'devices' [21421.137463] kobject: 'sg4' (ffff8800b9669928): kobject_uevent_env [21421.137483] kobject: 'sg4' (ffff8800b9669928): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:1/scsi_generic/sg4' [21421.137660] sr 10:0:0:1: Attached scsi generic sg4 type 5 [21421.137683] kobject: 'bsg' (ffff880129c6add0): kobject_add_internal: parent: '10:0:0:1', set: '<NULL>' [21421.137692] kobject: '10:0:0:1' (ffff8800b96686e8): kobject_add_internal: parent: 'bsg', set: 'devices' [21421.137746] kobject: '10:0:0:1' (ffff8800b96686e8): kobject_uevent_env [21421.137766] kobject: '10:0:0:1' (ffff8800b96686e8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:1/bsg/10:0:0:1' [21421.139671] kobject: '10:0:0:2' (ffff8801158df588): kobject_cleanup [21421.139676] kobject: '10:0:0:2' (ffff8801158df588): calling ktype release [21421.139696] kobject: '<NULL>' (ffff88013a9bbc40): kobject_cleanup [21421.139700] kobject: '<NULL>' (ffff88013a9bbc40): calling ktype release [21421.139708] kobject: '<NULL>' (ffff88013aea2730): kobject_cleanup [21421.139712] kobject: '<NULL>' (ffff88013aea2730): calling ktype release [21421.139737] kobject: '10:0:0:2': free name [21421.139858] kobject: '10:0:1:0' (ffff8801158df588): kobject_cleanup [21421.139862] kobject: '10:0:1:0' (ffff8801158df588): calling ktype release [21421.139876] kobject: '<NULL>' (ffff880139385af8): kobject_cleanup [21421.139880] kobject: '<NULL>' (ffff880139385af8): calling ktype release [21421.139887] kobject: '<NULL>' (ffff88013aea2730): kobject_cleanup [21421.139890] kobject: '<NULL>' (ffff88013aea2730): calling ktype release [21421.139912] kobject: '10:0:1:0': free name [21421.139918] kobject: 'target10:0:1' (ffff88013a9c99e8): kobject_cleanup [21421.139922] kobject: 'target10:0:1' (ffff88013a9c99e8): calling ktype release [21421.139928] kobject: 'target10:0:1': free name [21421.140064] kobject: '10:0:2:0' (ffff8801158df588): kobject_cleanup [21421.140068] kobject: '10:0:2:0' (ffff8801158df588): calling ktype release [21421.140082] kobject: '<NULL>' (ffff880139385af8): kobject_cleanup [21421.140086] kobject: '<NULL>' (ffff880139385af8): calling ktype release [21421.140092] kobject: '<NULL>' (ffff88013aea2730): kobject_cleanup [21421.140096] kobject: '<NULL>' (ffff88013aea2730): calling ktype release [21421.140118] kobject: '10:0:2:0': free name [21421.140124] kobject: 'target10:0:2' (ffff880124839158): kobject_cleanup [21421.140142] kobject: 'target10:0:2' (ffff880124839158): calling ktype release [21421.140149] kobject: 'target10:0:2': free name [21421.140267] kobject: '10:0:3:0' (ffff8801158df588): kobject_cleanup [21421.140271] kobject: '10:0:3:0' (ffff8801158df588): calling ktype release [21421.140285] kobject: '<NULL>' (ffff880139385af8): kobject_cleanup [21421.140289] kobject: '<NULL>' (ffff880139385af8): calling ktype release [21421.140296] kobject: '<NULL>' (ffff88013aea2730): kobject_cleanup [21421.140299] kobject: '<NULL>' (ffff88013aea2730): calling ktype release [21421.140321] kobject: '10:0:3:0': free name [21421.140329] kobject: 'target10:0:3' (ffff880121091158): kobject_cleanup [21421.140332] kobject: 'target10:0:3' (ffff880121091158): calling ktype release [21421.140338] kobject: 'target10:0:3': free name [21421.140459] kobject: '10:0:4:0' (ffff8801158df588): kobject_cleanup [21421.140463] kobject: '10:0:4:0' (ffff8801158df588): calling ktype release [21421.140477] kobject: '<NULL>' (ffff880139385af8): kobject_cleanup [21421.140481] kobject: '<NULL>' (ffff880139385af8): calling ktype release [21421.140488] kobject: '<NULL>' (ffff88013aea2730): kobject_cleanup [21421.140491] kobject: '<NULL>' (ffff88013aea2730): calling ktype release [21421.140513] kobject: '10:0:4:0': free name [21421.140520] kobject: 'target10:0:4' (ffff880121091158): kobject_cleanup [21421.140524] kobject: 'target10:0:4' (ffff880121091158): calling ktype release [21421.140529] kobject: 'target10:0:4': free name [21421.140652] kobject: '10:0:5:0' (ffff8801158df588): kobject_cleanup [21421.140655] kobject: '10:0:5:0' (ffff8801158df588): calling ktype release [21421.140669] kobject: '<NULL>' (ffff880139385af8): kobject_cleanup [21421.140673] kobject: '<NULL>' (ffff880139385af8): calling ktype release [21421.140680] kobject: '<NULL>' (ffff88013aea2730): kobject_cleanup [21421.140684] kobject: '<NULL>' (ffff88013aea2730): calling ktype release [21421.140706] kobject: '10:0:5:0': free name [21421.140713] kobject: 'target10:0:5' (ffff880121091158): kobject_cleanup [21421.140716] kobject: 'target10:0:5' (ffff880121091158): calling ktype release [21421.140722] kobject: 'target10:0:5': free name [21421.140839] kobject: '10:0:6:0' (ffff8801158df588): kobject_cleanup [21421.140843] kobject: '10:0:6:0' (ffff8801158df588): calling ktype release [21421.140857] kobject: '<NULL>' (ffff880139385af8): kobject_cleanup [21421.140861] kobject: '<NULL>' (ffff880139385af8): calling ktype release [21421.140868] kobject: '<NULL>' (ffff88013aea2730): kobject_cleanup [21421.140871] kobject: '<NULL>' (ffff88013aea2730): calling ktype release [21421.140893] kobject: '10:0:6:0': free name [21421.140900] kobject: 'target10:0:6' (ffff880121091158): kobject_cleanup [21421.140904] kobject: 'target10:0:6' (ffff880121091158): calling ktype release [21421.140909] kobject: 'target10:0:6': free name [21421.141026] kobject: '10:0:7:0' (ffff8801158df588): kobject_cleanup [21421.141030] kobject: '10:0:7:0' (ffff8801158df588): calling ktype release [21421.141044] kobject: '<NULL>' (ffff880139385af8): kobject_cleanup [21421.141048] kobject: '<NULL>' (ffff880139385af8): calling ktype release [21421.141054] kobject: '<NULL>' (ffff88013aea2730): kobject_cleanup [21421.141058] kobject: '<NULL>' (ffff88013aea2730): calling ktype release [21421.141080] kobject: '10:0:7:0': free name [21421.141086] kobject: 'target10:0:7' (ffff880121091158): kobject_cleanup [21421.141090] kobject: 'target10:0:7' (ffff880121091158): calling ktype release [21421.141095] kobject: 'target10:0:7': free name [21421.141101] usb-storage: device scan complete [21421.170592] kobject: 'scsi_disk' (ffff880134173770): kobject_add_internal: parent: '10:0:0:0', set: '<NULL>' [21421.170611] kobject: '10:0:0:0' (ffff8800b9669dc8): kobject_add_internal: parent: 'scsi_disk', set: 'devices' [21421.170684] kobject: '10:0:0:0' (ffff8800b9669dc8): kobject_uevent_env [21421.170708] kobject: '10:0:0:0' (ffff8800b9669dc8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0/scsi_disk/10:0:0:0' [21421.171628] sd 10:0:0:0: [sdd] 31777279 512-byte hardware sectors: (16.2 GB/15.1 GiB) [21421.172223] sd 10:0:0:0: [sdd] Write Protect is off [21421.172228] sd 10:0:0:0: [sdd] Mode Sense: 45 00 00 08 [21421.172231] sd 10:0:0:0: [sdd] Assuming drive cache: write through [21421.172265] kobject: 'block' (ffff8800b14ae000): kobject_add_internal: parent: '10:0:0:0', set: '<NULL>' [21421.172285] kobject: 'sdd' (ffff88013af24920): kobject_add_internal: parent: 'block', set: 'devices' [21421.188631] kobject: 'sdd' (ffff88013af24920): kobject_uevent_env [21421.188637] kobject: 'sdd' (ffff88013af24920): kobject_uevent_env: uevent_suppress caused the event to drop! [21421.188658] kobject: 'holders' (ffff8800b9648880): kobject_add_internal: parent: 'sdd', set: '<NULL>' [21421.188669] kobject: 'slaves' (ffff8800b9648908): kobject_add_internal: parent: 'sdd', set: '<NULL>' [21421.189054] kobject: '10:0:0:0' (ffff88012bb87588): kobject_uevent_env [21421.189077] kobject: '10:0:0:0' (ffff88012bb87588): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0' [21421.190637] sd 10:0:0:0: [sdd] Assuming drive cache: write through [21421.190671] sdd: sdd1 [21421.191270] kobject: 'sdd' (ffff88013af24920): kobject_uevent_env [21421.191275] kobject: 'sdd' (ffff88013af24920): kobject_uevent_env: uevent_suppress caused the event to drop! [21421.191282] sdd: p1 size 31793076 limited to end of disk [21421.191305] kobject: 'sdd1' (ffff8800b9711588): kobject_add_internal: parent: 'sdd', set: 'devices' [21421.191397] kobject: 'sdd1' (ffff8800b9711588): kobject_uevent_env [21421.191401] kobject: 'sdd1' (ffff8800b9711588): kobject_uevent_env: uevent_suppress caused the event to drop! [21421.191412] kobject: 'holders' (ffff8800b9648a18): kobject_add_internal: parent: 'sdd1', set: '<NULL>' [21421.191420] kobject: 'sdd1' (ffff8800b9711588): kobject_uevent_env [21421.191441] kobject: 'sdd1' (ffff8800b9711588): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0/block/sdd/sdd1' [21421.192001] kobject: 'sdd' (ffff88013af24920): kobject_uevent_env [21421.192034] kobject: 'sdd' (ffff88013af24920): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0/block/sdd' [21421.192209] kobject: 'sdd1' (ffff8800b9711588): kobject_uevent_env [21421.192230] kobject: 'sdd1' (ffff8800b9711588): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0/block/sdd/sdd1' [21421.192399] kobject: 'queue' (ffff88013aea1b90): kobject_add_internal: parent: 'sdd', set: '<NULL>' [21421.192445] kobject: 'queue' (ffff88013aea1b90): kobject_uevent_env [21421.192450] kobject: 'queue' (ffff88013aea1b90): kobject_uevent_env: filter function caused the event to drop! [21421.192456] kobject: 'iosched' (ffff8801392a6158): kobject_add_internal: parent: 'queue', set: '<NULL>' [21421.192488] kobject: 'iosched' (ffff8801392a6158): kobject_uevent_env [21421.192492] kobject: 'iosched' (ffff8801392a6158): kobject_uevent_env: filter function caused the event to drop! [21421.192505] kobject: '259:917504' (ffff8800b96f5498): kobject_add_internal: parent: 'bdi', set: 'devices' [21421.192557] kobject: '259:917504' (ffff8800b96f5498): kobject_uevent_env [21421.192575] kobject: '259:917504' (ffff8800b96f5498): fill_kobj_path: path = '/devices/virtual/bdi/259:917504' [21421.192762] sd 10:0:0:0: [sdd] Attached SCSI removable disk [21421.258331] kobject: 'sdd' (ffff88013af24920): kobject_uevent_env [21421.258358] kobject: 'sdd' (ffff88013af24920): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0/block/sdd' [21421.276118] kobject: '65534' (ffff88013ab522e8): kobject_add_internal: parent: 'uids', set: 'uids' [21421.281107] kobject: '65534' (ffff88013ab522e8): kobject_uevent_env [21421.281162] kobject: '65534' (ffff88013ab522e8): fill_kobj_path: path = '/kernel/uids/65534' [21421.333642] kobject: '10:0:0:1' (ffff880139003b90): kobject_uevent_env [21421.333667] kobject: '10:0:0:1' (ffff880139003b90): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:1' [21421.335399] kobject: '65534' (ffff88013ab522e8): kobject_uevent_env [21421.335420] kobject: '65534' (ffff88013ab522e8): fill_kobj_path: path = '/kernel/uids/65534' [21421.335554] kobject: '65534' (ffff88013ab522e8): kobject_cleanup [21421.335558] kobject: '65534' (ffff88013ab522e8): calling ktype release [21421.335562] kobject: '65534': free name [21421.340587] kobject: '65534' (ffff88013ab522e8): kobject_add_internal: parent: 'uids', set: 'uids' [21421.340610] kobject: '65534' (ffff88013ab522e8): kobject_uevent_env [21421.340631] kobject: '65534' (ffff88013ab522e8): fill_kobj_path: path = '/kernel/uids/65534' [21421.361164] kobject: '65534' (ffff88013ab522e8): kobject_uevent_env [21421.361185] kobject: '65534' (ffff88013ab522e8): fill_kobj_path: path = '/kernel/uids/65534' [21421.361344] kobject: '65534' (ffff88013ab522e8): kobject_cleanup [21421.361348] kobject: '65534' (ffff88013ab522e8): calling ktype release [21421.361351] kobject: '65534': free name [21421.425012] kobject: '65534' (ffff88013ab522e8): kobject_add_internal: parent: 'uids', set: 'uids' [21421.425033] kobject: '65534' (ffff88013ab522e8): kobject_uevent_env [21421.425051] kobject: '65534' (ffff88013ab522e8): fill_kobj_path: path = '/kernel/uids/65534' [21421.447972] kobject: 'sr0' (ffff880138836fa8): kobject_uevent_env [21421.448000] kobject: 'sr0' (ffff880138836fa8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:1/block/sr0' [21421.462036] kobject: '65534' (ffff88013ab522e8): kobject_uevent_env [21421.462058] kobject: '65534' (ffff88013ab522e8): fill_kobj_path: path = '/kernel/uids/65534' [21421.462129] kobject: '65534' (ffff88013ab522e8): kobject_cleanup [21421.462133] kobject: '65534' (ffff88013ab522e8): calling ktype release [21421.462136] kobject: '65534': free name [21421.508994] kobject: '65534' (ffff88013ab522e8): kobject_add_internal: parent: 'uids', set: 'uids' [21421.509015] kobject: '65534' (ffff88013ab522e8): kobject_uevent_env [21421.509034] kobject: '65534' (ffff88013ab522e8): fill_kobj_path: path = '/kernel/uids/65534' [21421.538933] kobject: '65534' (ffff88013ab522e8): kobject_uevent_env [21421.538955] kobject: '65534' (ffff88013ab522e8): fill_kobj_path: path = '/kernel/uids/65534' [21421.539110] kobject: '65534' (ffff88013ab522e8): kobject_cleanup [21421.539114] kobject: '65534' (ffff88013ab522e8): calling ktype release [21421.539118] kobject: '65534': free name [21421.548145] kobject: '65534' (ffff88013ab522e8): kobject_add_internal: parent: 'uids', set: 'uids' [21421.548165] kobject: '65534' (ffff88013ab522e8): kobject_uevent_env [21421.548184] kobject: '65534' (ffff88013ab522e8): fill_kobj_path: path = '/kernel/uids/65534' [21421.588200] kobject: '65534' (ffff88013ab522e8): kobject_uevent_env [21421.588221] kobject: '65534' (ffff88013ab522e8): fill_kobj_path: path = '/kernel/uids/65534' [21421.588365] kobject: '65534' (ffff88013ab522e8): kobject_cleanup [21421.588370] kobject: '65534' (ffff88013ab522e8): calling ktype release [21421.588373] kobject: '65534': free name [21421.722647] kobject: '65534' (ffff8801390f02e8): kobject_add_internal: parent: 'uids', set: 'uids' [21421.722668] kobject: '65534' (ffff8801390f02e8): kobject_uevent_env [21421.722687] kobject: '65534' (ffff8801390f02e8): fill_kobj_path: path = '/kernel/uids/65534' [21421.756036] kobject: '65534' (ffff8801390f02e8): kobject_uevent_env [21421.756057] kobject: '65534' (ffff8801390f02e8): fill_kobj_path: path = '/kernel/uids/65534' [21421.756195] kobject: '65534' (ffff8801390f02e8): kobject_cleanup [21421.756199] kobject: '65534' (ffff8801390f02e8): calling ktype release [21421.756202] kobject: '65534': free name [21423.065910] usb 2-2: USB disconnect, address 26 [21423.065915] usb 2-2.4: USB disconnect, address 27 [21423.066144] kobject: 'usbdev2.27_ep81' (ffff8800b9668b88): kobject_uevent_env [21423.066168] kobject: 'usbdev2.27_ep81' (ffff8800b9668b88): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/usb_endpoint/usbdev2.27_ep81' [21423.066227] kobject: 'usbdev2.27_ep81' (ffff8800b9668b88): kobject_cleanup [21423.066231] kobject: 'usbdev2.27_ep81' (ffff8800b9668b88): calling ktype release [21423.066245] kobject: 'usbdev2.27_ep81': free name [21423.066363] kobject: 'usbdev2.27_ep02' (ffff8800b9668268): kobject_uevent_env [21423.066383] kobject: 'usbdev2.27_ep02' (ffff8800b9668268): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/usb_endpoint/usbdev2.27_ep02' [21423.066430] kobject: 'usb_endpoint' (ffff8801340d3f68): kobject_cleanup [21423.066434] kobject: 'usb_endpoint' (ffff8801340d3f68): auto cleanup kobject_del [21423.066453] kobject: 'usb_endpoint' (ffff8801340d3f68): calling ktype release [21423.066457] kobject: (ffff8801340d3f68): dynamic_kobj_release [21423.066462] kobject: 'usb_endpoint': free name [21423.066466] kobject: 'usbdev2.27_ep02' (ffff8800b9668268): kobject_cleanup [21423.066470] kobject: 'usbdev2.27_ep02' (ffff8800b9668268): calling ktype release [21423.066476] kobject: 'usbdev2.27_ep02': free name [21423.066708] kobject: '10:0:0:0' (ffff8800b966a248): kobject_uevent_env [21423.066727] kobject: '10:0:0:0' (ffff8800b966a248): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0/bsg/10:0:0:0' [21423.066773] kobject: 'bsg' (ffff8801388d56e8): kobject_cleanup [21423.066776] kobject: 'bsg' (ffff8801388d56e8): auto cleanup kobject_del [21423.066795] kobject: 'bsg' (ffff8801388d56e8): calling ktype release [21423.066798] kobject: (ffff8801388d56e8): dynamic_kobj_release [21423.066802] kobject: 'bsg': free name [21423.066806] kobject: '10:0:0:0' (ffff8800b966a248): kobject_cleanup [21423.066808] kobject: '10:0:0:0' (ffff8800b966a248): calling ktype release [21423.066815] kobject: '10:0:0:0': free name [21423.066928] kobject: 'sg3' (ffff8800b966a000): kobject_uevent_env [21423.066945] kobject: 'sg3' (ffff8800b966a000): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0/scsi_generic/sg3' [21423.066988] kobject: 'scsi_generic' (ffff8801388d55d8): kobject_cleanup [21423.066991] kobject: 'scsi_generic' (ffff8801388d55d8): auto cleanup kobject_del [21423.067020] kobject: 'scsi_generic' (ffff8801388d55d8): calling ktype release [21423.067023] kobject: (ffff8801388d55d8): dynamic_kobj_release [21423.067026] kobject: 'scsi_generic': free name [21423.067030] kobject: 'sg3' (ffff8800b966a000): kobject_cleanup [21423.067033] kobject: 'sg3' (ffff8800b966a000): calling ktype release [21423.067038] kobject: 'sg3': free name [21423.067045] kobject: '<NULL>' (ffff8800b154c578): kobject_cleanup [21423.067048] kobject: '<NULL>' (ffff8800b154c578): calling ktype release [21423.067056] kobject: '<NULL>' (ffff88013af21178): kobject_cleanup [21423.067059] kobject: '<NULL>' (ffff88013af21178): calling ktype release [21423.067077] kobject: '10:0:0:0' (ffff88012bb87758): kobject_uevent_env [21423.067094] kobject: '10:0:0:0' (ffff88012bb87758): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0/scsi_device/10:0:0:0' [21423.067144] kobject: 'scsi_device' (ffff8801078d8220): kobject_cleanup [21423.067148] kobject: 'scsi_device' (ffff8801078d8220): auto cleanup kobject_del [21423.067165] kobject: 'scsi_device' (ffff8801078d8220): calling ktype release [21423.067169] kobject: (ffff8801078d8220): dynamic_kobj_release [21423.067174] kobject: 'scsi_device': free name [21423.067178] kobject: '10:0:0:0' (ffff88012bb87758): kobject_cleanup [21423.067181] kobject: '10:0:0:0' (ffff88012bb87758): calling ktype release [21423.067186] kobject: '10:0:0:0': free name [21423.067469] kobject: '10:0:0:0' (ffff8800b9669dc8): kobject_uevent_env [21423.067490] kobject: '10:0:0:0' (ffff8800b9669dc8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0/scsi_disk/10:0:0:0' [21423.067543] kobject: 'scsi_disk' (ffff880134173770): kobject_cleanup [21423.067546] kobject: 'scsi_disk' (ffff880134173770): auto cleanup kobject_del [21423.067564] kobject: 'scsi_disk' (ffff880134173770): calling ktype release [21423.067568] kobject: (ffff880134173770): dynamic_kobj_release [21423.067573] kobject: 'scsi_disk': free name [21423.106153] kobject: 'holders' (ffff8800b9648a18): kobject_cleanup [21423.106159] kobject: 'holders' (ffff8800b9648a18): auto cleanup kobject_del [21423.106178] kobject: 'holders' (ffff8800b9648a18): calling ktype release [21423.106182] kobject: (ffff8800b9648a18): dynamic_kobj_release [21423.106187] kobject: 'holders': free name [21423.106327] kobject: 'sdd1' (ffff8800b9711588): kobject_uevent_env [21423.106352] kobject: 'sdd1' (ffff8800b9711588): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0/block/sdd/sdd1' [21423.106507] kobject: '259:917504' (ffff8800b96f5498): kobject_uevent_env [21423.106526] kobject: '259:917504' (ffff8800b96f5498): fill_kobj_path: path = '/devices/virtual/bdi/259:917504' [21423.106572] kobject: '259:917504' (ffff8800b96f5498): kobject_cleanup [21423.106575] kobject: '259:917504' (ffff8800b96f5498): calling ktype release [21423.106584] kobject: '259:917504': free name [21423.106590] kobject: 'iosched' (ffff8801392a6158): kobject_uevent_env [21423.106595] kobject: 'iosched' (ffff8801392a6158): kobject_uevent_env: filter function caused the event to drop! [21423.106628] kobject: 'queue' (ffff88013aea1b90): kobject_uevent_env [21423.106632] kobject: 'queue' (ffff88013aea1b90): kobject_uevent_env: filter function caused the event to drop! [21423.106680] kobject: 'holders' (ffff8800b9648880): kobject_cleanup [21423.106684] kobject: 'holders' (ffff8800b9648880): auto cleanup kobject_del [21423.106694] kobject: 'holders' (ffff8800b9648880): calling ktype release [21423.106698] kobject: (ffff8800b9648880): dynamic_kobj_release [21423.106702] kobject: 'holders': free name [21423.106706] kobject: 'slaves' (ffff8800b9648908): kobject_cleanup [21423.106709] kobject: 'slaves' (ffff8800b9648908): auto cleanup kobject_del [21423.106720] kobject: 'slaves' (ffff8800b9648908): calling ktype release [21423.106724] kobject: (ffff8800b9648908): dynamic_kobj_release [21423.106728] kobject: 'slaves': free name [21423.106897] kobject: 'sdd' (ffff88013af24920): kobject_uevent_env [21423.106918] kobject: 'sdd' (ffff88013af24920): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0/block/sdd' [21423.106970] kobject: 'block' (ffff8800b14ae000): kobject_cleanup [21423.106974] kobject: 'block' (ffff8800b14ae000): auto cleanup kobject_del [21423.106995] kobject: 'block' (ffff8800b14ae000): calling ktype release [21423.106999] kobject: (ffff8800b14ae000): dynamic_kobj_release [21423.107023] kobject: 'block': free name [21423.111501] kobject: '10:0:0:0' (ffff88012bb87588): kobject_uevent_env [21423.111527] kobject: '10:0:0:0' (ffff88012bb87588): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:0' [21423.111721] kobject: '10:0:0:1' (ffff8800b96686e8): kobject_uevent_env [21423.111743] kobject: '10:0:0:1' (ffff8800b96686e8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:1/bsg/10:0:0:1' [21423.111796] kobject: 'bsg' (ffff880129c6add0): kobject_cleanup [21423.111800] kobject: 'bsg' (ffff880129c6add0): auto cleanup kobject_del [21423.111821] kobject: 'bsg' (ffff880129c6add0): calling ktype release [21423.111825] kobject: (ffff880129c6add0): dynamic_kobj_release [21423.111831] kobject: 'bsg': free name [21423.111835] kobject: '10:0:0:1' (ffff8800b96686e8): kobject_cleanup [21423.111838] kobject: '10:0:0:1' (ffff8800b96686e8): calling ktype release [21423.111847] kobject: '10:0:0:1': free name [21423.112456] kobject: 'sg4' (ffff8800b9669928): kobject_uevent_env [21423.112477] kobject: 'sg4' (ffff8800b9669928): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:1/scsi_generic/sg4' [21423.112530] kobject: 'scsi_generic' (ffff880129c6a6e8): kobject_cleanup [21423.112534] kobject: 'scsi_generic' (ffff880129c6a6e8): auto cleanup kobject_del [21423.112553] kobject: 'scsi_generic' (ffff880129c6a6e8): calling ktype release [21423.112556] kobject: (ffff880129c6a6e8): dynamic_kobj_release [21423.112560] kobject: 'scsi_generic': free name [21423.112565] kobject: 'sg4' (ffff8800b9669928): kobject_cleanup [21423.112568] kobject: 'sg4' (ffff8800b9669928): calling ktype release [21423.112574] kobject: 'sg4': free name [21423.112581] kobject: '<NULL>' (ffff8800b154ced8): kobject_cleanup [21423.112585] kobject: '<NULL>' (ffff8800b154ced8): calling ktype release [21423.112594] kobject: '<NULL>' (ffff88013a9f2298): kobject_cleanup [21423.112597] kobject: '<NULL>' (ffff88013a9f2298): calling ktype release [21423.112618] kobject: '10:0:0:1' (ffff880139003d60): kobject_uevent_env [21423.112638] kobject: '10:0:0:1' (ffff880139003d60): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:1/scsi_device/10:0:0:1' [21423.112687] kobject: 'scsi_device' (ffff880129c6a550): kobject_cleanup [21423.112690] kobject: 'scsi_device' (ffff880129c6a550): auto cleanup kobject_del [21423.112709] kobject: 'scsi_device' (ffff880129c6a550): calling ktype release [21423.112713] kobject: (ffff880129c6a550): dynamic_kobj_release [21423.112717] kobject: 'scsi_device': free name [21423.112722] kobject: '10:0:0:1' (ffff880139003d60): kobject_cleanup [21423.112725] kobject: '10:0:0:1' (ffff880139003d60): calling ktype release [21423.112730] kobject: '10:0:0:1': free name [21423.113117] kobject: '11:0' (ffff8800b96696e0): kobject_uevent_env [21423.113137] kobject: '11:0' (ffff8800b96696e0): fill_kobj_path: path = '/devices/virtual/bdi/11:0' [21423.113187] kobject: '11:0' (ffff8800b96696e0): kobject_cleanup [21423.113191] kobject: '11:0' (ffff8800b96696e0): calling ktype release [21423.113197] kobject: '11:0': free name [21423.113202] kobject: 'iosched' (ffff8801350a5c40): kobject_uevent_env [21423.113206] kobject: 'iosched' (ffff8801350a5c40): kobject_uevent_env: filter function caused the event to drop! [21423.113248] kobject: 'queue' (ffff88013aea0ff0): kobject_uevent_env [21423.113252] kobject: 'queue' (ffff88013aea0ff0): kobject_uevent_env: filter function caused the event to drop! [21423.113289] kobject: 'holders' (ffff880129f63440): kobject_cleanup [21423.113292] kobject: 'holders' (ffff880129f63440): auto cleanup kobject_del [21423.113303] kobject: 'holders' (ffff880129f63440): calling ktype release [21423.113306] kobject: (ffff880129f63440): dynamic_kobj_release [21423.113311] kobject: 'holders': free name [21423.113315] kobject: 'slaves' (ffff88013886c6e8): kobject_cleanup [21423.113319] kobject: 'slaves' (ffff88013886c6e8): auto cleanup kobject_del [21423.113329] kobject: 'slaves' (ffff88013886c6e8): calling ktype release [21423.113332] kobject: (ffff88013886c6e8): dynamic_kobj_release [21423.113337] kobject: 'slaves': free name [21423.113500] kobject: 'sr0' (ffff880138836fa8): kobject_uevent_env [21423.113520] kobject: 'sr0' (ffff880138836fa8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:1/block/sr0' [21423.113568] kobject: 'block' (ffff880139009d48): kobject_cleanup [21423.113571] kobject: 'block' (ffff880139009d48): auto cleanup kobject_del [21423.113606] kobject: 'block' (ffff880139009d48): calling ktype release [21423.113610] kobject: (ffff880139009d48): dynamic_kobj_release [21423.113615] kobject: 'block': free name [21423.113755] kobject: 'sr0' (ffff880138836fa8): kobject_cleanup [21423.113759] kobject: 'sr0' (ffff880138836fa8): calling ktype release [21423.113770] kobject: 'sr0': free name [21423.113780] kobject: '10:0:0:1' (ffff880139003b90): kobject_uevent_env [21423.113800] kobject: '10:0:0:1' (ffff880139003b90): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/target10:0:0/10:0:0:1' [21423.113878] kobject: '10:0:0:1' (ffff880139003b90): kobject_cleanup [21423.113882] kobject: '10:0:0:1' (ffff880139003b90): calling ktype release [21423.113905] kobject: 'iosched' (ffff8801350a5c40): kobject_cleanup [21423.113908] kobject: 'iosched' (ffff8801350a5c40): calling ktype release [21423.113916] kobject: 'iosched': free name [21423.113921] kobject: 'queue' (ffff88013aea0ff0): kobject_cleanup [21423.113925] kobject: 'queue' (ffff88013aea0ff0): calling ktype release [21423.113949] kobject: 'queue': free name [21423.113961] kobject: '10:0:0:1': free name [21423.114098] kobject: 'host10' (ffff8801001594c8): kobject_uevent_env [21423.114118] kobject: 'host10' (ffff8801001594c8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10/scsi_host/host10' [21423.114164] kobject: 'scsi_host' (ffff8801340d3880): kobject_cleanup [21423.114168] kobject: 'scsi_host' (ffff8801340d3880): auto cleanup kobject_del [21423.114186] kobject: 'scsi_host' (ffff8801340d3880): calling ktype release [21423.114190] kobject: (ffff8801340d3880): dynamic_kobj_release [21423.114194] kobject: 'scsi_host': free name [21423.114198] kobject: 'host10' (ffff8801001594c8): kobject_cleanup [21423.114201] kobject: 'host10' (ffff8801001594c8): calling ktype release [21423.114207] kobject: 'host10': free name [21423.114258] kobject: 'host10' (ffff8801001592f8): kobject_uevent_env [21423.114277] kobject: 'host10' (ffff8801001592f8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0/host10' [21423.114310] ------------[ cut here ]------------ [21423.114319] WARNING: at fs/sysfs/dir.c:794 sysfs_remove_dir+0xb2/0xd0() [21423.114322] Hardware name: 2776LEG [21423.114325] XXX dir: host10/target10:0:0 [21423.114327] Modules linked in: sr_mod cdrom sit tunnel4 ipv6 tun aes_x86_64 aes_generic i915 drm i2c_algo_bit i2c_core acpi_cpufreq snd_pcm_oss snd_mixer_oss snd_seq snd_seq_device edd pl2303 usbserial usblp fuse loop dm_mod usb_storage usbhid hid cdc_ether usbnet cdc_wdm cdc_acm uvcvideo videodev v4l1_compat v4l2_compat_ioctl32 arc4 ecb snd_hda_codec_conexant snd_hda_intel kvm_intel snd_hda_codec snd_pcm iwlagn thinkpad_acpi kvm snd_timer iwlcore hwmon rfkill mac80211 backlight uhci_hcd joydev pcspkr evdev led_class snd sg cfg80211 battery nvram ehci_hcd ac soundcore e1000e usbcore snd_page_alloc thermal button processor intel_agp [21423.114421] Pid: 213, comm: khubd Tainted: G W 2.6.30-rc7-dirty #41 [21423.114425] Call Trace: [21423.114433] [<ffffffff8023c6a8>] warn_slowpath_common+0x78/0xb0 [21423.114438] [<ffffffff8023c73c>] warn_slowpath_fmt+0x3c/0x40 [21423.114442] [<ffffffff80322a16>] ? sysfs_addrm_start+0x76/0xd0 [21423.114447] [<ffffffff80323032>] sysfs_remove_dir+0xb2/0xd0 [21423.114455] [<ffffffff803e5056>] kobject_del+0x16/0x40 [21423.114461] [<ffffffff80477665>] device_del+0x165/0x1a0 [21423.114467] [<ffffffff8048258f>] scsi_remove_host+0xcf/0x120 [21423.114481] [<ffffffffa02c93cb>] quiesce_and_remove_host+0x6b/0xb0 [usb_storage] [21423.114492] [<ffffffffa02c94f8>] usb_stor_disconnect+0x18/0x30 [usb_storage] [21423.114514] [<ffffffffa003ffae>] usb_unbind_interface+0x6e/0x140 [usbcore] [21423.114523] [<ffffffff80479e49>] __device_release_driver+0x59/0xa0 [21423.114528] [<ffffffff80479f88>] device_release_driver+0x28/0x40 [21423.114533] [<ffffffff8047929c>] bus_remove_device+0xac/0xe0 [21423.114538] [<ffffffff80477627>] device_del+0x127/0x1a0 [21423.114557] [<ffffffffa003cb77>] usb_disable_device+0xa7/0x130 [usbcore] [21423.114575] [<ffffffffa0037818>] usb_disconnect+0xc8/0x140 [usbcore] [21423.114593] [<ffffffffa0037804>] usb_disconnect+0xb4/0x140 [usbcore] [21423.114611] [<ffffffffa00388db>] hub_thread+0x50b/0x1230 [usbcore] [21423.114617] [<ffffffff80565a76>] ? _spin_unlock_irq+0x26/0x30 [21423.114623] [<ffffffff80237d1e>] ? finish_task_switch+0x7e/0x140 [21423.114629] [<ffffffff80237cdb>] ? finish_task_switch+0x3b/0x140 [21423.114635] [<ffffffff802549e0>] ? autoremove_wake_function+0x0/0x40 [21423.114653] [<ffffffffa00383d0>] ? hub_thread+0x0/0x1230 [usbcore] [21423.114658] [<ffffffff802545b5>] kthread+0x55/0xa0 [21423.114664] [<ffffffff8020cf3a>] child_rip+0xa/0x20 [21423.114669] [<ffffffff80254560>] ? kthread+0x0/0xa0 [21423.114674] [<ffffffff8020cf30>] ? child_rip+0x0/0x20 [21423.114678] ---[ end trace 89cad9e6bbbcf701 ]--- [21423.114755] kobject: '2-2.4:1.0' (ffff88013a9cc908): kobject_uevent_env [21423.114774] kobject: '2-2.4:1.0' (ffff88013a9cc908): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/2-2.4:1.0' [21423.114976] kobject: 'usbdev2.27_ep00' (ffff8800b9668dd0): kobject_uevent_env [21423.114995] kobject: 'usbdev2.27_ep00' (ffff8800b9668dd0): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4/usb_endpoint/usbdev2.27_ep00' [21423.115059] kobject: 'usb_endpoint' (ffff880115b54990): kobject_cleanup [21423.115063] kobject: 'usb_endpoint' (ffff880115b54990): auto cleanup kobject_del [21423.115092] kobject: 'usb_endpoint' (ffff880115b54990): calling ktype release [21423.115096] kobject: (ffff880115b54990): dynamic_kobj_release [21423.115101] kobject: 'usb_endpoint': free name [21423.115106] kobject: 'usbdev2.27_ep00' (ffff8800b9668dd0): kobject_cleanup [21423.115109] kobject: 'usbdev2.27_ep00' (ffff8800b9668dd0): calling ktype release [21423.115117] kobject: 'usbdev2.27_ep00': free name [21423.115513] kobject: '2-2.4' (ffff88013422cb20): kobject_uevent_env [21423.115532] kobject: '2-2.4' (ffff88013422cb20): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2.4' [21423.115583] kobject: '2-2.4' (ffff88013422cb20): kobject_cleanup [21423.115586] kobject: '2-2.4' (ffff88013422cb20): calling ktype release [21423.115607] kobject: '2-2.4': free name [21423.115808] kobject: 'usbdev2.26_ep81' (ffff8800b96f56f0): kobject_uevent_env [21423.115828] kobject: 'usbdev2.26_ep81' (ffff8800b96f56f0): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2:1.0/usb_endpoint/usbdev2.26_ep81' [21423.115875] kobject: 'usb_endpoint' (ffff8800b9648198): kobject_cleanup [21423.115879] kobject: 'usb_endpoint' (ffff8800b9648198): auto cleanup kobject_del [21423.115898] kobject: 'usb_endpoint' (ffff8800b9648198): calling ktype release [21423.115902] kobject: (ffff8800b9648198): dynamic_kobj_release [21423.115907] kobject: 'usb_endpoint': free name [21423.115912] kobject: 'usbdev2.26_ep81' (ffff8800b96f56f0): kobject_cleanup [21423.115915] kobject: 'usbdev2.26_ep81' (ffff8800b96f56f0): calling ktype release [21423.115924] kobject: 'usbdev2.26_ep81': free name [21423.116154] kobject: '2-2:1.0' (ffff8800b9716b48): kobject_uevent_env [21423.116173] kobject: '2-2:1.0' (ffff8800b9716b48): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/2-2:1.0' [21423.116224] kobject: '2-2:1.0' (ffff8800b9716b48): kobject_cleanup [21423.116228] kobject: '2-2:1.0' (ffff8800b9716b48): calling ktype release [21423.116235] kobject: '2-2:1.0': free name [21423.116364] kobject: 'usbdev2.26_ep00' (ffff8800b96f5dc8): kobject_uevent_env [21423.116383] kobject: 'usbdev2.26_ep00' (ffff8800b96f5dc8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2/usb_endpoint/usbdev2.26_ep00' [21423.116432] kobject: 'usb_endpoint' (ffff8800b96486e8): kobject_cleanup [21423.116435] kobject: 'usb_endpoint' (ffff8800b96486e8): auto cleanup kobject_del [21423.116455] kobject: 'usb_endpoint' (ffff8800b96486e8): calling ktype release [21423.116459] kobject: (ffff8800b96486e8): dynamic_kobj_release [21423.116463] kobject: 'usb_endpoint': free name [21423.116468] kobject: 'usbdev2.26_ep00' (ffff8800b96f5dc8): kobject_cleanup [21423.116472] kobject: 'usbdev2.26_ep00' (ffff8800b96f5dc8): calling ktype release [21423.116478] kobject: 'usbdev2.26_ep00': free name [21423.116830] kobject: '2-2' (ffff8801390c9128): kobject_uevent_env [21423.116849] kobject: '2-2' (ffff8801390c9128): fill_kobj_path: path = '/devices/pci0000:00/0000:00:1d.7/usb2/2-2' [21423.116897] kobject: '2-2' (ffff8801390c9128): kobject_cleanup [21423.116901] kobject: '2-2' (ffff8801390c9128): calling ktype release [21423.116917] kobject: '2-2': free name [21423.269004] kobject: 'sdd1' (ffff8800b9711588): kobject_cleanup [21423.269009] kobject: 'sdd1' (ffff8800b9711588): calling ktype release [21423.269021] kobject: 'sdd1': free name [21423.269040] kobject: '10:0:0:0' (ffff8800b9669dc8): kobject_cleanup [21423.269044] kobject: '10:0:0:0' (ffff8800b9669dc8): calling ktype release [21423.269055] kobject: '10:0:0:0': free name [21423.269062] kobject: '10:0:0:0' (ffff88012bb87588): kobject_cleanup [21423.269066] kobject: '10:0:0:0' (ffff88012bb87588): calling ktype release [21423.269103] kobject: 'iosched' (ffff8801392a6158): kobject_cleanup [21423.269106] kobject: 'iosched' (ffff8801392a6158): calling ktype release [21423.269114] kobject: 'iosched': free name [21423.269119] kobject: 'queue' (ffff88013aea1b90): kobject_cleanup [21423.269123] kobject: 'queue' (ffff88013aea1b90): calling ktype release [21423.272572] kobject: 'queue': free name [21423.272654] kobject: 'target10:0:0' (ffff88013a9c9158): kobject_uevent_env [21423.272674] kobject: 'target10:0:0' (ffff88013a9c9158): fill_kobj_path: path = '/host10/target10:0:0' [21423.272864] kobject: 'target10:0:0' (ffff88013a9c9158): kobject_cleanup [21423.272869] kobject: 'target10:0:0' (ffff88013a9c9158): calling ktype release [21423.272876] kobject: 'host10' (ffff8801001592f8): kobject_cleanup [21423.272879] kobject: 'host10' (ffff8801001592f8): calling ktype release [21423.272936] kobject: '2-2.4:1.0' (ffff88013a9cc908): kobject_cleanup [21423.272939] kobject: '2-2.4:1.0' (ffff88013a9cc908): calling ktype release [21423.272954] kobject: '2-2.4:1.0': free name [21423.272969] kobject: 'host10': free name [21423.272984] kobject: 'target10:0:0': free name [21423.272990] kobject: '10:0:0:0': free name [21423.272995] kobject: 'sdd' (ffff88013af24920): kobject_cleanup [21423.272998] kobject: 'sdd' (ffff88013af24920): calling ktype release [21423.273011] kobject: 'sdd': free name
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 8 lines · Kay Sievers
Quoted 6 lines · Alan Stern
Since this appears to be a bug in the SCSI layer, let's add some SCSI people to the CC: list.
To summarize the problem: The SCSI core tries to unregister a host while its sysfs directory is still non-empty because the target hasn't been unregistered yet.
Quoted 5 lines
Quoted 2 lines
Can you provide more of the context? I'd like to see the log starting from when these devices were first registered.
I was able to trigger it with a USB storage device only, connected to a hub, and I removed the hub from the host.
Okay, it's a long log dump, but useful. Evidently the problem is caused by the fact that scsi_target_reap() is called by scsi_device_dev_release_usercontext() instead of by __scsi_remove_device() (both functions in drivers/scsi/scsi_sysfs.c).
There's probably a reason for this, but I don't know what it is. Maybe James can explain.
Alan Stern
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
In reply to Kay SieversQuoted 11 lines · Kay Sievers
Quoted 1 line · Alan Stern
by the way -- so it's a little difficult to trigger.
I can trigger it pretty reliable now on plain -rc7 , but only with more hubs in-between the storage device. It usually take less than 10-15 connect/disconnect cycles.
It looks like a serious bug though, after the bug triggered, random, likely unrelated, applications crash, and I can not cleanly shot down anymore.
Just a heads up if anybody is trying to reproduce this, it trashed my ext3 rootfs, which is not recoverable.
Not sure what exactly caused this, but I didn't have anything like this for a very long time.
I tried to reproduce the issue a few times more, and it crashed random processes after the bug triggered, like mentioned above, and the box never shut down cleanly.
It's entirely possible, that bug causes serious issues.
Thanks,
Kay
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 16 lines · Kay Sievers
Quoted 11 lines · Kay Sievers
Quoted 1 line · Alan Stern
by the way -- so it's a little difficult to trigger.
I can trigger it pretty reliable now on plain -rc7 , but only with more hubs in-between the storage device. It usually take less than 10-15 connect/disconnect cycles.
It looks like a serious bug though, after the bug triggered, random, likely unrelated, applications crash, and I can not cleanly shot down anymore.
Just a heads up if anybody is trying to reproduce this, it trashed my ext3 rootfs, which is not recoverable.
Quoted 8 lines
Not sure what exactly caused this, but I didn't have anything like this for a very long time.
I tried to reproduce the issue a few times more, and it crashed random processes after the bug triggered, like mentioned above, and the box never shut down cleanly.
It's entirely possible, that bug causes serious issues.
If you don't mind trashing some more ext3 root filesystems :-) you can try this patch. It's almost certainly not quite the right thing to do and I have probably messed up the target's reference counting, but maybe it's a step in the right direction.
This strange business of deferring unregistration into a workqueue means that the calls might not be executed in the same order that they're made.
Alan Stern
drivers/scsi/scsi_scan.c +1 -0
@@ -956,6 +956,7 @@ static inline void scsi_destroy_sdev(strif (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy (sdev);transport_destroy_device (&sdev->sdev_gendev); +put_device (sdev->sdev_gendev.parent);put_device (&sdev->sdev_gendev); }
drivers/scsi/scsi_sysfs.c +1 -2
@@ -327,8 +327,6 @@ static void scsi_device_dev_release_user sdev->request_queue =NULL ; } -scsi_target_reap (scsi_target (sdev)); -kfree (sdev->inquiry);kfree (sdev);
@@ -954,6 +952,7 @@ void __scsi_remove_device(struct scsi_deif (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy (sdev);transport_destroy_device (dev); +scsi_target_reap (scsi_target (sdev));put_device (dev); }
James Bottomley
maintainerRe: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 65 lines · Alan Stern
Quoted 16 lines · Kay Sievers
Quoted 11 lines · Kay Sievers
Quoted 1 line · Alan Stern
by the way -- so it's a little difficult to trigger.
I can trigger it pretty reliable now on plain -rc7 , but only with more hubs in-between the storage device. It usually take less than 10-15 connect/disconnect cycles.
It looks like a serious bug though, after the bug triggered, random, likely unrelated, applications crash, and I can not cleanly shot down anymore.
Just a heads up if anybody is trying to reproduce this, it trashed my ext3 rootfs, which is not recoverable.
Quoted 8 lines
Not sure what exactly caused this, but I didn't have anything like this for a very long time.
I tried to reproduce the issue a few times more, and it crashed random processes after the bug triggered, like mentioned above, and the box never shut down cleanly.
It's entirely possible, that bug causes serious issues.
If you don't mind trashing some more ext3 root filesystems :-) you can try this patch. It's almost certainly not quite the right thing to do and I have probably messed up the target's reference counting, but maybe it's a step in the right direction.
This strange business of deferring unregistration into a workqueue means that the calls might not be executed in the same order that they're made.
Alan Stern
Index:
usb-2.6/drivers/scsi/scsi_scan.c
===================================================================drivers/scsi/scsi_scan.c +1
-0@@ -956,6 +956,7 @@ static inline void scsi_destroy_sdev(strif (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy (sdev);transport_destroy_device (&sdev->sdev_gendev); +put_device (sdev->sdev_gendev.parent);put_device (&sdev->sdev_gendev); }Index:
usb-2.6/drivers/scsi/scsi_sysfs.c
===================================================================drivers/scsi/scsi_sysfs.c +0
-2@@ -327,8 +327,6 @@ static void scsi_device_dev_release_user sdev->request_queue =NULL ; } -scsi_target_reap (scsi_target (sdev)); -kfree (sdev->inquiry);kfree (sdev);
drivers/scsi/scsi_sysfs.c void __scsi_remove_device(struct scsi_de · line 957
Quoted 6 lines
drivers/scsi/scsi_sysfs.c +1
-0@@ -954,6 +952,7 @@ void __scsi_remove_device(struct scsi_deif (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy (sdev);transport_destroy_device (dev); +scsi_target_reap (scsi_target (sdev));put_device (dev); }
Um, well, you're right, it's wrong. The reap needs to be matched with the reap_ref++
It's hard to follow the problem without full context, but if I understand correctly the problem is you want all the target directories removed before you call device_del() on the host and the thing that gets in the way is the necessary user context removal of the host. So a simple solution, rather than mucking with the way it works, is to wait for the workqueues to complete. Does this fix it?
James
---
drivers/scsi/scsi_scan.c +6 -0
@@ -1877,6 +1877,12 @@ void scsi_forget_host(struct Scsi_Host *shost) goto restart; }spin_unlock_irqrestore (shost->host_lock, flags); + +/* +* the sdev removal goes through a workqueue for user context, so +* make sure it's all complete before we return +*/ +flush_scheduled_work (); }/*
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 7 lines · James Bottomley
Quoted 4 lines · Alan Stern
If you don't mind trashing some more ext3 root filesystems :-) you can try this patch. It's almost certainly not quite the right thing to do and I have probably messed up the target's reference counting, but maybe it's a step in the right direction.
Quoted 6 lines
It's hard to follow the problem without full context, but if I understand correctly the problem is you want all the target directories removed before you call
device_del()on the host and the thing that gets in the way is the necessary user context removal of the host. So a simple solution, rather than mucking with the way it works, is to wait for the workqueues to complete. Does this fix it?
Ok, I copied my newly installed system to another disks, to have a root filesytem to trash again by this bug. :)
Which of your patches should I try?
Thanks,
Kay
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 4 lines · Kay Sievers
Ok, I copied my newly installed system to another disks, to have a root filesytem to trash again by this bug. :)
Which of your patches should I try?
James's patch, not mine.
Alan Stern
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 8 lines · Alan Stern
Quoted 4 lines · Kay Sievers
Ok, I copied my newly installed system to another disks, to have a root filesytem to trash again by this bug. :)
Which of your patches should I try?
James's patch, not mine.
I tried both, both don't fix the issue. With Alan's patch it *seems* the target device never gets removed, at least I didn't see anything in the kobject debug logs.
Kay
James Bottomley
maintainerRe: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 6 lines · Kay Sievers
Quoted 5 lines · Alan Stern
Quoted 3 lines · Kay Sievers
Ok, I copied my newly installed system to another disks, to have a root filesytem to trash again by this bug. :)
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
Which of your patches should I try?
James's patch, not mine.
I tried both, both don't fix the issue. With Alan's patch it *seems* the target device never gets removed, at least I didn't see anything in the kobject debug logs.
OK ... perhaps we have to wait a little harder: try this; it waits until all the targets have disappeared from visibility via an event.
James
---
drivers/scsi/hosts.c +2 -0
@@ -173,6 +173,8 @@ void scsi_remove_host(struct Scsi_Host *shost)BUG_ON (scsi_host_set_state (shost,SHOST_DEL_RECOVERY ));spin_unlock_irqrestore (shost->host_lock, flags); +scsi_wait_for_targets_gone (shost); +transport_unregister_device (&shost->shost_gendev);device_unregister (&shost->shost_dev);device_del (&shost->shost_gendev);
drivers/scsi/scsi_scan.c +8 -0
@@ -32,6 +32,7 @@#include <linux/delay.h> #include <linux/kthread.h> #include <linux/spinlock.h> +#include <linux/wait.h> #include <linux/async.h> #include <scsi/scsi.h>
@@ -324,6 +325,12 @@ out:return NULL ; } +static DECLARE_WAIT_QUEUE_HEAD (scsi_target_removed); +void scsi_wait_for_targets_gone (struct Scsi_Host *shost) +{ +wait_event (scsi_target_removed,list_empty (&shost->__targets)); +} +static void scsi_target_destroy (struct scsi_target *starget) {struct device *dev = &starget->dev;
@@ -336,6 +343,7 @@ static void scsi_target_destroy(struct scsi_target *starget) shost->hostt->target_destroy (starget);list_del_init (&starget->siblings);spin_unlock_irqrestore (shost->host_lock, flags); +wake_up (&scsi_target_removed);put_device (dev); }
include/scsi/scsi_host.h +1 -0
@@ -747,6 +747,7 @@ static inline int scsi_host_scan_allowed(struct Scsi_Host *shost)extern void scsi_unblock_requests (struct Scsi_Host *);extern void scsi_block_requests (struct Scsi_Host *); +extern void scsi_wait_for_targets_gone (struct Scsi_Host *);struct class_container ;
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 2 lines · James Bottomley
OK ... perhaps we have to wait a little harder: try this; it waits until all the targets have disappeared from visibility via an event.
That seems to work fine here.
Thanks,
Kay
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 7 lines · Kay Sievers
Quoted 2 lines · James Bottomley
OK ... perhaps we have to wait a little harder: try this; it waits until all the targets have disappeared from visibility via an event.
That seems to work fine here.
It's good for a short-term fix. For the longer term, I still think it's a mistake to wait for the sdevs to be released before deleting the target. It gives user programs the ability to block the host-removal thread indefinitely.
Alan Stern
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Hi all,
Quoted 5 lines · Alan Stern
Quoted 3 lines · Kay Sievers
On Wed, May 27, 2009 at 01:49, James Bottomley
<[email protected]> wrote:
Quoted 9 lines
Quoted 3 lines
Quoted 2 lines
OK ... perhaps we have to wait a little harder: try this; it waits until all the targets have disappeared from visibility via an event.
That seems to work fine here.
It's good for a short-term fix. For the longer term, I still think it's a mistake to wait for the sdevs to be released before deleting the target. It gives user programs the ability to block the host-removal thread indefinitely.
Quite so. We should rather see to have the reference counting fixed properly, than this would go away automatically.
So I just have to look for someone to fix my iSCSI bugs, than I could revamp my patchset ...
Sigh.
Cheers,
Hannes
Signature · 8 lines
Dr. Hannes Reinecke zSeries & Storage [email protected] +49 911 74053 688 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: Markus Rex, HRB 16746 (AG Nürnberg) -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
James Bottomley
maintainerRe: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 12 lines · Hannes Reinecke
Hi all,
Quoted 9 lines · Alan Stern
Quoted 6 lines · Kay Sievers
Quoted 2 lines · James Bottomley
OK ... perhaps we have to wait a little harder: try this; it waits until all the targets have disappeared from visibility via an event.
That seems to work fine here.
Quoted 7 lines
Quoted 5 lines
It's good for a short-term fix. For the longer term, I still think it's a mistake to wait for the sdevs to be released before deleting the target. It gives user programs the ability to block the host-removal thread indefinitely.
Quite so. We should rather see to have the reference counting fixed properly, than this would go away automatically.
Hardly ... our current refcounting is on destruction (releases). This problem is an instance of visibility (the del calls) we need the visibility teardown to work nicely. We currently have no refcounting on the visibility. Even if we did (and we could add a ref on when the underlying device del calls are done), what happens if the target needs to become visible again. Apparently the generic device infrastructure can't accept doing an add on a previously del'd device.
The most obvious way of fixing this is to have a special case for targets of dying hosts ... they could call del early on the understanding that they're never getting new underlying devices. That would allow the wait to trigger on the last target del, which is what is optimal.
James
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 7 lines · James Bottomley
Hardly ... our current refcounting is on destruction (releases). This problem is an instance of visibility (the del calls) we need the visibility teardown to work nicely. We currently have no refcounting on the visibility. Even if we did (and we could add a ref on when the underlying device del calls are done), what happens if the target needs to become visible again. Apparently the generic device infrastructure can't accept doing an add on a previously del'd device.
Definitely not.
Quoted 5 lines
The most obvious way of fixing this is to have a special case for targets of dying hosts ... they could call del early on the understanding that they're never getting new underlying devices. That would allow the wait to trigger on the last target del, which is what is optimal.
I don't understand all the subtle issues here. In other contexts, the solution would be to initialize a refcount to 1 when the target is allocated, increment it when a device is added, and decrement it when a device is removed or the host is removed. When the refcount goes to 0, the target is deleted. Why wouldn't this kind of approach work?
Alan Stern
James Bottomley
maintainerRe: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 18 lines · Alan Stern
Quoted 7 lines · James Bottomley
Hardly ... our current refcounting is on destruction (releases). This problem is an instance of visibility (the del calls) we need the visibility teardown to work nicely. We currently have no refcounting on the visibility. Even if we did (and we could add a ref on when the underlying device del calls are done), what happens if the target needs to become visible again. Apparently the generic device infrastructure can't accept doing an add on a previously del'd device.
Definitely not.
Quoted 5 lines
The most obvious way of fixing this is to have a special case for targets of dying hosts ... they could call del early on the understanding that they're never getting new underlying devices. That would allow the wait to trigger on the last target del, which is what is optimal.
Quoted 5 lines
I don't understand all the subtle issues here. In other contexts, the solution would be to initialize a refcount to 1 when the target is allocated, increment it when a device is added, and decrement it when a device is removed or the host is removed. When the refcount goes to 0, the target is deleted. Why wouldn't this kind of approach work?
Um, well that's exactly how it works (modulo the fact that there are parts of the lifecycle where the ref count is zero, like scanning). The problem you're complaining about is that the device ref on the target may take a long time to release, so we can't key the del event on the refcount going to zero, which is what we do today.
James
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 8 lines · James Bottomley
Quoted 5 lines
I don't understand all the subtle issues here. In other contexts, the solution would be to initialize a refcount to 1 when the target is allocated, increment it when a device is added, and decrement it when a device is removed or the host is removed. When the refcount goes to 0, the target is deleted. Why wouldn't this kind of approach work?
Um, well that's exactly how it works (modulo the fact that there are parts of the lifecycle where the ref count is zero, like scanning).
Why does that happen? It's reasonable that there should be times during scanning when the target doesn't have any children, but the refcount should still be positive.
Quoted 4 lines
The
problem you're complaining about is that the device ref on the target may take a long time to release, so we can't key the del event on the refcount going to zero, which is what we do today.
Maybe we should be talking about two separate refcounts: a normal get_device/put_device kref counter for the target's lifetime, and a visibility counter (one for each child device and one overall) which keys the del event and must go to 0 before the host removal finishes.
Alan Stern
James Bottomley
maintainerRe: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 8 lines · Alan Stern
Quoted 6 lines · James Bottomley
Quoted 5 lines
I don't understand all the subtle issues here. In other contexts, the solution would be to initialize a refcount to 1 when the target is allocated, increment it when a device is added, and decrement it when a device is removed or the host is removed. When the refcount goes to 0, the target is deleted. Why wouldn't this kind of approach work?
Quoted 6 lines
Quoted 2 lines
Um, well that's exactly how it works (modulo the fact that there are parts of the lifecycle where the ref count is zero, like scanning).
Why does that happen? It's reasonable that there should be times during scanning when the target doesn't have any children, but the refcount should still be positive.
By refcount, I mean count of underlying devices.
Quoted 9 lines
Quoted 4 lines
The
problem you're complaining about is that the device ref on the target may take a long time to release, so we can't key the del event on the refcount going to zero, which is what we do today.Maybe we should be talking about two separate refcounts: a normal get_device/put_device kref counter for the target's lifetime, and a visibility counter (one for each child device and one overall) which keys the del event and must go to 0 before the host removal finishes.
Um, well, that's roughly how I said we'd have to fix all of this in the email to hannes ... it would be much easier if we could make a del'd device visible, but now we have to have different behaviours depending on whether the host is going away or not.
James
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 1 line · James Bottomley
By refcount, I mean count of underlying devices.
Does that mean only registered devices, or does it include devices which are unregistered but not yet released?
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
The
problem you're complaining about is that the device ref on the target may take a long time to release, so we can't key the del event on the refcount going to zero, which is what we do today.
Quoted 8 lines
Quoted 4 lines
Maybe we should be talking about two separate refcounts: a normal get_device/put_device kref counter for the target's lifetime, and a visibility counter (one for each child device and one overall) which keys the del event and must go to 0 before the host removal finishes.
Um, well, that's roughly how I said we'd have to fix all of this in the email to hannes ... it would be much easier if we could make a del'd device visible,
I don't follow. Why would you want to delete a target before the host is removed and then make it visible again later? Because it doesn't have any underlying devices at the moment but may gain some later on?
If that's the case, why not delete the target when there are no more registered devices beneath it and then create a new target structure when a new device appears?
Quoted 2 lines
but now we have to have different behaviours depending on whether the host is going away or not.
Yes, one does get the feeling that we're going around in circles...
Okay. So now I have made two proposals. One is to delete targets and create new ones as needed. The other is to keep a target hanging around, even if there are no underlying devices, until the host is removed. This can be implemented easily by making the counter represent the number of registered devices plus one for the host.
Alan Stern
P.S.: If the counter is made to refer to registered devices, as opposed to un-released devices, would there ever be a situation where you want to delete a target in a non-process context?
James Bottomley
maintainerRe: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 6 lines · Alan Stern
Quoted 1 line · James Bottomley
By refcount, I mean count of underlying devices.
Does that mean only registered devices, or does it include devices which are unregistered but not yet released?
All devices ... scsi_device has to has a target parent before its usable.
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
Quoted 4 lines
The
problem you're complaining about is that the device ref on the target may take a long time to release, so we can't key the del event on the refcount going to zero, which is what we do today.Maybe we should be talking about two separate refcounts: a normal get_device/put_device kref counter for the target's lifetime, and a visibility counter (one for each child device and one overall) which keys the del event and must go to 0 before the host removal finishes.
Quoted 7 lines
Quoted 3 lines
Um, well, that's roughly how I said we'd have to fix all of this in the email to hannes ... it would be much easier if we could make a del'd device visible,
I don't follow. Why would you want to delete a target before the host is removed and then make it visible again later? Because it doesn't have any underlying devices at the moment but may gain some later on?
Perhaps I haven't made the problem clear enough. You only want early del if the host is going away, otherwise the target might be reused and it can't be if you've called del on it. So there needs to be an integration into the host lifecycle in some form.
James
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 10 lines · James Bottomley
Quoted 6 lines · Alan Stern
Quoted 1 line · James Bottomley
By refcount, I mean count of underlying devices.
Does that mean only registered devices, or does it include devices which are unregistered but not yet released?
All devices ...
scsi_devicehas to has a target parent before its usable.
I can't tell whether you understood my point. After a scsi_device is unregistered but before it is released -- i.e., when its state is SDEV_DEL -- it _is_ essentially unusable. So why wait until it is released to decrement the target's device counter? Why not do the decrement in __scsi_remove_device()?
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
Um, well, that's roughly how I said we'd have to fix all of this in the email to hannes ... it would be much easier if we could make a del'd device visible,
Quoted 8 lines
Quoted 3 lines
I don't follow. Why would you want to delete a target before the host is removed and then make it visible again later? Because it doesn't have any underlying devices at the moment but may gain some later on?
Perhaps I haven't made the problem clear enough. You only want early del if the host is going away, otherwise the target might be reused and it can't be if you've called del on it. So there needs to be an integration into the host lifecycle in some form.
Yes, granted. That integration doesn't have to be complicated. Basically, you just decrement the counters in all the targets when setting a host's state to SHOST_DEL or SHOST_DEL_RECOVERY. At that point there's no reason to keep an unpopulated target around, right?
Up until that point, the counter's value should be one more than the number of underlying sdevs. So if the counter decrements to 0 then there were no underlying sdevs and the target is deleted immediately; otherwise it is deleted when the last remaining sdev is deleted.
Alan Stern
James Bottomley
maintainerRe: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 10 lines · Alan Stern
Quoted 8 lines · James Bottomley
Quoted 6 lines · Alan Stern
Quoted 1 line · James Bottomley
By refcount, I mean count of underlying devices.
Does that mean only registered devices, or does it include devices which are unregistered but not yet released?
Quoted 8 lines
Quoted 2 lines
All devices ...
scsi_devicehas to has a target parent before its usable.I can't tell whether you understood my point. After a
scsi_deviceis unregistered but before it is released -- i.e., when its state isSDEV_DEL-- it _is_ essentially unusable. So why wait until it is released to decrement the target's device counter? Why not do the decrement in__scsi_remove_device()?
because the use model of the device still requires a valid target. Even though it gets gated in several places in SDEV_DEL, we still have use of the target parent. This is fixable, but only by a long audit of all the sdev uses plus the enforcement of no use of target in DEL state rule, which adds complexity.
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
Quoted 3 lines
Um, well, that's roughly how I said we'd have to fix all of this in the email to hannes ... it would be much easier if we could make a del'd device visible,
I don't follow. Why would you want to delete a target before the host is removed and then make it visible again later? Because it doesn't have any underlying devices at the moment but may gain some later on?
Quoted 8 lines
Quoted 4 lines
Perhaps I haven't made the problem clear enough. You only want early del if the host is going away, otherwise the target might be reused and it can't be if you've called del on it. So there needs to be an integration into the host lifecycle in some form.
Yes, granted. That integration doesn't have to be complicated. Basically, you just decrement the counters in all the targets when setting a host's state to
SHOST_DELorSHOST_DEL_RECOVERY. At that
And SHOST_CANCEL and SHOST_CANCEL_RECOVERY.
Quoted 1 line
point there's no reason to keep an unpopulated target around, right?
If the child list were empty, sure. However, it's likely not going to be at this point.
Quoted 4 lines
Up until that point, the counter's value should be one more than the number of underlying sdevs. So if the counter decrements to 0 then there were no underlying sdevs and the target is deleted immediately; otherwise it is deleted when the last remaining sdev is deleted.
No, that's the problem. It can be removed from visibility if it has no visible sdevs, but it can't be deleted until the last sdev is released.
James
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 11 lines · James Bottomley
Quoted 5 lines
I can't tell whether you understood my point. After a
scsi_deviceis unregistered but before it is released -- i.e., when its state isSDEV_DEL-- it _is_ essentially unusable. So why wait until it is released to decrement the target's device counter? Why not do the decrement in__scsi_remove_device()?because the use model of the device still requires a valid target. Even though it gets gated in several places in
SDEV_DEL, we still have use of the target parent. This is fixable, but only by a long audit of all the sdev uses plus the enforcement of no use of target in DEL state rule, which adds complexity.
You're failing to distinguish properly between "delete" and "release". A target (or device in general) is deleted when it is removed from visibility -- i.e., when device_del() is called. It is released when the final put_device() call occurs and the data structure is deallocated.
So, all I'm saying is there's nothing wrong with deleting a target when all its children are deleted, provided the target isn't released until all the children are released. Below you say the same thing.
Quoted 10 lines
Quoted 8 lines
Quoted 4 lines
Perhaps I haven't made the problem clear enough. You only want early del if the host is going away, otherwise the target might be reused and it can't be if you've called del on it. So there needs to be an integration into the host lifecycle in some form.
Yes, granted. That integration doesn't have to be complicated. Basically, you just decrement the counters in all the targets when setting a host's state to
SHOST_DELorSHOST_DEL_RECOVERY. At thatAnd
SHOST_CANCELandSHOST_CANCEL_RECOVERY.
If you prefer. I thought SHOST_DEL would be more appropriate because it occurs after scsi_forget_host() is called. All those transitions occur in scsi_remove_host(), anyway.
Quoted 4 lines
Quoted 1 line
point there's no reason to keep an unpopulated target around, right?
If the child list were empty, sure. However, it's likely not going to be at this point.
Regardless, it will work either way.
Quoted 7 lines
Quoted 4 lines
Up until that point, the counter's value should be one more than the number of underlying sdevs. So if the counter decrements to 0 then there were no underlying sdevs and the target is deleted immediately; otherwise it is deleted when the last remaining sdev is deleted.
No, that's the problem. It can be removed from visibility if it has no visible sdevs, but it can't be deleted until the last sdev is released.
Allow me to rephrase this: A target can be removed from visibility if it has no visible sdevs, but it can't be _released_ until the last sdev is released.
That's fine. You remove a target from visibility when target->reap_ref becomes 0. The target isn't released until the target's embedded struct device's refcount becomes 0. To make this work, simply have scsi_alloc_sdev() call
get_device(&starget->dev);
and have scsi_device_dev_release_usercontext() call
put_device(&starget->dev);
Doesn't that do exactly what you're asking for?
Alan Stern
James Bottomley
maintainerRe: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 14 lines · Alan Stern
Quoted 11 lines · James Bottomley
Quoted 5 lines
I can't tell whether you understood my point. After a
scsi_deviceis unregistered but before it is released -- i.e., when its state isSDEV_DEL-- it _is_ essentially unusable. So why wait until it is released to decrement the target's device counter? Why not do the decrement in__scsi_remove_device()?because the use model of the device still requires a valid target. Even though it gets gated in several places in
SDEV_DEL, we still have use of the target parent. This is fixable, but only by a long audit of all the sdev uses plus the enforcement of no use of target in DEL state rule, which adds complexity.
Quoted 5 lines
You're failing to distinguish properly between "delete" and "release". A target (or device in general) is deleted when it is removed from visibility -- i.e., when
device_del()is called. It is released when the finalput_device()call occurs and the data structure is deallocated.
I find the terms delete and release too close for comfort, which is why I've always been careful to say remove from visibility.
Quoted 14 lines
So, all I'm saying is there's nothing wrong with deleting a target when all its children are deleted, provided the target isn't released until all the children are released. Below you say the same thing.
Quoted 9 lines
Quoted 8 lines
Quoted 4 lines
Perhaps I haven't made the problem clear enough. You only want early del if the host is going away, otherwise the target might be reused and it can't be if you've called del on it. So there needs to be an integration into the host lifecycle in some form.
Yes, granted. That integration doesn't have to be complicated. Basically, you just decrement the counters in all the targets when setting a host's state to
SHOST_DELorSHOST_DEL_RECOVERY. At that
Quoted 5 lines
Quoted 1 line
And
SHOST_CANCELandSHOST_CANCEL_RECOVERY.If you prefer. I thought
SHOST_DELwould be more appropriate because it occurs afterscsi_forget_host()is called. All those transitions occur inscsi_remove_host(), anyway.
I mean in all four states.
Quoted 24 lines
Quoted 4 lines
Quoted 1 line
point there's no reason to keep an unpopulated target around, right?
If the child list were empty, sure. However, it's likely not going to be at this point.
Regardless, it will work either way.
Quoted 7 lines
Quoted 4 lines
Up until that point, the counter's value should be one more than the number of underlying sdevs. So if the counter decrements to 0 then there were no underlying sdevs and the target is deleted immediately; otherwise it is deleted when the last remaining sdev is deleted.
No, that's the problem. It can be removed from visibility if it has no visible sdevs, but it can't be deleted until the last sdev is released.
Allow me to rephrase this: A target can be removed from visibility if it has no visible sdevs, but it can't be _released_ until the last sdev is released.
That's fine. You remove a target from visibility when
target->reap_refbecomes 0. The target isn't released until the target's embedded struct device's refcount becomes 0. To make this work, simply havescsi_alloc_sdev()call
Quoted 7 lines
get_device(&starget->dev);and have
scsi_device_dev_release_usercontext()callput_device(&starget->dev);Doesn't that do exactly what you're asking for?
That's um what we do to day ... the addition has to be to the visibility management.
James
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 2 lines · James Bottomley
I find the terms delete and release too close for comfort, which is why I've always been careful to say remove from visibility.
Okay; I'll use your terms when conversing with you. :-)
Quoted 7 lines
Quoted 7 lines
That's fine. You remove a target from visibility when
target->reap_refbecomes 0. The target isn't released until the target's embedded struct device's refcount becomes 0. To make this work, simply havescsi_alloc_sdev()callget_device(&starget->dev);
Quoted 8 lines
Quoted 5 lines
and have
scsi_device_dev_release_usercontext()callput_device(&starget->dev);Doesn't that do exactly what you're asking for?
That's um what we do to day ... the addition has to be to the visibility management.
That's what I was trying to accomplish in the patch you said was wrong. It moved the call to scsi_target_reap() from scsi_device_dev_release_usercontext() into __scsi_remove_device(). That is, the target's count of underlying sdevs was to be decremented whenever an sdev was removed from visibility, not when the sdev was released.
That's how the problem should be solved. But the details need to be correct, and I don't understand how they all work (as you noticed when reading the patch).
Alan Stern
James Bottomley
maintainerRe: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 30 lines · Alan Stern
Quoted 2 lines · James Bottomley
I find the terms delete and release too close for comfort, which is why I've always been careful to say remove from visibility.
Okay; I'll use your terms when conversing with you. :-)
Quoted 7 lines
Quoted 7 lines
That's fine. You remove a target from visibility when
target->reap_refbecomes 0. The target isn't released until the target's embedded struct device's refcount becomes 0. To make this work, simply havescsi_alloc_sdev()callget_device(&starget->dev);Quoted 8 lines
Quoted 5 lines
and have
scsi_device_dev_release_usercontext()callput_device(&starget->dev);Doesn't that do exactly what you're asking for?
That's um what we do to day ... the addition has to be to the visibility management.
That's what I was trying to accomplish in the patch you said was wrong. It moved the call to
scsi_target_reap()fromscsi_device_dev_release_usercontext()into__scsi_remove_device(). That is, the target's count of underlying sdevs was to be decremented whenever an sdev was removed from visibility, not when the sdev was released.
Quoted 3 lines
That's how the problem should be solved. But the details need to be correct, and I don't understand how they all work (as you noticed when reading the patch).
Right, and I think reap_ref can be seconded to count underlying device visibility. However, the piece that's missing, is the fact that all of this has to be tied into the host state. If the host is running, you can't remove the target from visibility even if all its children are invisible because it might get another visible child added. once it goes into the cancel or del states, it can't acquire new children, so then it's safe to make a target with no visible children invisible.
James
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 2 lines · James Bottomley
Right, and I think
reap_refcan be seconded to count underlying device visibility.
Exactly. It should count the number of underlying devices that have not yet been removed from visibility (this may include some which still have to become visible), plus one if we want to keep the target hanging around for a while with no visible children (while scanning it, for example).
Quoted 4 lines
However, the piece that's missing, is the fact that all of
this has to be tied into the host state. If the host is running, you can't remove the target from visibility even if all its children are invisible because it might get another visible child added.
Are you sure about that? It's not obvious at all to me.
For example, suppose during scanning it turns out there are no LUNs at a particular target address. Why should the empty target be retained? You'd end up with unusable targets at all possible bus addresses.
Besides, if a target is removed from visibility and then another child is added, the answer is simply to create a new target structure. There's already code in scsi_alloc_target() to do this.
Quoted 3 lines
once it goes
into the cancel or del states, it can't acquire new children, so then it's safe to make a target with no visible children invisible.
If you grant my point above, targets don't need to be tied into the host state. They can be removed from visibility whenever the reap_ref counter goes to 0. This will happen naturally while the host is in the CANCEL state, thanks to scsi_forget_host().
There's another point to consider. If you do accept my argument that empty targets can be removed from visibility regardless of the host's state, then this removal races with addition of a new child. Since removal involves calling device_del(), it can't be protected by the host lock. Instead we'd have to use a mutex to protect both target addition and target removal.
Since the host's scan_mutex already protects target addition, extending its scope to encompass target removal (and perhaps sdev removal too) seems natural. Do you agree?
Alan Stern
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 6 lines · Alan Stern
There's another point to consider. If you do accept my argument that empty targets can be removed from visibility regardless of the host's state, then this removal races with addition of a new child. Since removal involves calling
device_del(), it can't be protected by the host lock. Instead we'd have to use a mutex to protect both target addition and target removal.
Careful. Holding a lock over device_del is an easy and hidden way to trigger a rare deadlocks.
Eric
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 11 lines · Eric W. Biederman
Quoted 6 lines · Alan Stern
There's another point to consider. If you do accept my argument that empty targets can be removed from visibility regardless of the host's state, then this removal races with addition of a new child. Since removal involves calling
device_del(), it can't be protected by the host lock. Instead we'd have to use a mutex to protect both target addition and target removal.Careful. Holding a lock over
device_delis an easy and hidden way to trigger a rare deadlocks.
Your point is well taken. In addition, I don't really like the idea of forcing device removal to wait for some other device to be added.
I'll work around the problem somehow... A short polling loop shoud do the job.
Alan Stern
James Bottomley
maintainerRe: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
In reply to Alan SternQuoted 11 lines · Alan Stern
Quoted 2 lines · James Bottomley
Right, and I think
reap_refcan be seconded to count underlying device visibility.Exactly. It should count the number of underlying devices that have not yet been removed from visibility (this may include some which still have to become visible), plus one if we want to keep the target hanging around for a while with no visible children (while scanning it, for example).
Quoted 6 lines
Quoted 4 lines
However, the piece that's missing, is the fact that all of
this has to be tied into the host state. If the host is running, you can't remove the target from visibility even if all its children are invisible because it might get another visible child added.Are you sure about that? It's not obvious at all to me.
Yes ... otherwise you have to elongate the DEL interval from a few ms to potentially anything. That would allow locking a target in a dying state and prevent any new LUNs being added.
Quoted 7 lines
For example, suppose during scanning it turns out there are no LUNs at a particular target address. Why should the empty target be retained? You'd end up with unusable targets at all possible bus addresses.
Besides, if a target is removed from visibility and then another child is added, the answer is simply to create a new target structure. There's already code in
scsi_alloc_target()to do this.
As I've said several times, this could be done, but we'd have to audit the code paths to make sure we allow for multiple same targets in the list.
Quoted 9 lines
Quoted 3 lines
once it goes
into the cancel or del states, it can't acquire new children, so then it's safe to make a target with no visible children invisible.If you grant my point above, targets don't need to be tied into the host state. They can be removed from visibility whenever the
reap_refcounter goes to 0. This will happen naturally while the host is in the CANCEL state, thanks toscsi_forget_host().
Quoted 6 lines
There's another point to consider. If you do accept my argument that empty targets can be removed from visibility regardless of the host's state, then this removal races with addition of a new child. Since removal involves calling
device_del(), it can't be protected by the host lock. Instead we'd have to use a mutex to protect both target addition and target removal.
No, this is state model 101 ... you alter the state inside the lock and call del outside of it. Technically you're lying about the state for the few us it takes to run out of the lock and del the target, but there's a papal indulgence for that.
Quoted 3 lines
Since the host's
scan_mutexalready protects target addition, extending its scope to encompass target removal (and perhaps sdev removal too) seems natural. Do you agree?
James
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 10 lines · James Bottomley
Quoted 6 lines
Quoted 4 lines
However, the piece that's missing, is the fact that all of
this has to be tied into the host state. If the host is running, you can't remove the target from visibility even if all its children are invisible because it might get another visible child added.Are you sure about that? It's not obvious at all to me.
Yes ... otherwise you have to elongate the DEL interval from a few ms to potentially anything. That would allow locking a target in a dying state and prevent any new LUNs being added.
How so? Why not unlink the target from the host's list when the device_del() call returns? A new target can be created any time after that, since the old one is now completely invisible.
Quoted 11 lines
Quoted 7 lines
For example, suppose during scanning it turns out there are no LUNs at a particular target address. Why should the empty target be retained? You'd end up with unusable targets at all possible bus addresses.
Besides, if a target is removed from visibility and then another child is added, the answer is simply to create a new target structure. There's already code in
scsi_alloc_target()to do this.As I've said several times, this could be done, but we'd have to audit the code paths to make sure we allow for multiple same targets in the list.
No, not if the old target is removed from the host's list before the new target is added.
Is there any reason the old target has to remain on the list? If there is, we can introduce a new state: STARGET_CLEANUP. The old target gets put into this state when device_del() returns. List entries in that state are ignored by __scsi_find_target() or whatever else looks through the list.
Alan Stern
P.S.: Does scsi_target_reap() really ever get called in non-process context? I couldn't find any place where that might happen.
James Bottomley
maintainerRe: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 9 lines · Alan Stern
Quoted 7 lines · James Bottomley
Quoted 6 lines
Quoted 4 lines
However, the piece that's missing, is the fact that all of
this has to be tied into the host state. If the host is running, you can't remove the target from visibility even if all its children are invisible because it might get another visible child added.Are you sure about that? It's not obvious at all to me.
Quoted 7 lines
Quoted 3 lines
Yes ... otherwise you have to elongate the DEL interval from a few ms to potentially anything. That would allow locking a target in a dying state and prevent any new LUNs being added.
How so? Why not unlink the target from the host's list when the
device_del()call returns? A new target can be created any time after that, since the old one is now completely invisible.
The answer to that one is several emails back: we need the target in the host list for the lifetime of the devices ... it's alterable, but even more auditing.
Quoted 21 lines
Quoted 11 lines
Quoted 7 lines
For example, suppose during scanning it turns out there are no LUNs at a particular target address. Why should the empty target be retained? You'd end up with unusable targets at all possible bus addresses.
Besides, if a target is removed from visibility and then another child is added, the answer is simply to create a new target structure. There's already code in
scsi_alloc_target()to do this.As I've said several times, this could be done, but we'd have to audit the code paths to make sure we allow for multiple same targets in the list.
No, not if the old target is removed from the host's list before the new target is added.
Is there any reason the old target has to remain on the list? If there is, we can introduce a new state:
STARGET_CLEANUP. The old target gets put into this state whendevice_del()returns. List entries in that state are ignored by__scsi_find_target()or whatever else looks through the list.
Quoted 6 lines
Alan Stern
P.S.: Doesscsi_target_reap()really ever get called in non-process context? I couldn't find any place where that might happen.From the device release, which is done by last put, which could be I/O
context.
James
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Quoted 7 lines · James Bottomley
Quoted 3 lines
How so? Why not unlink the target from the host's list when the
device_del()call returns? A new target can be created any time after that, since the old one is now completely invisible.The answer to that one is several emails back: we need the target in the host list for the lifetime of the devices ... it's alterable, but even more auditing.
I don't recall you mentioning that the target had to be linked into the host's list for the lifetime of the devices; I thought you said merely that the target had to _exist_ for the lifetime of the devices.
Does it really need to be linked, or is existence of the structure sufficient?
Likewise, after a device is removed from visibility, does it need to remain linked into the host's and target's lists?
Quoted 5 lines
Quoted 2 lines
P.S.: Doesscsi_target_reap()really ever get called in non-process context? I couldn't find any place where that might happen.From the device release, which is done by last put, which could be I/O context.
But scsi_target_reap() isn't called directly from the device release. It's called from scsi_device_dev_release_usercontext().
And besides, in the patch I'm working on it isn't called from either of those places -- it's called from __scsi_remove_device(). So I'll go ahead and get rid of scsi_target_reap_usercontext().
Alan Stern
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
Hi Alan,
Quoted 4 lines
And besides, in the patch I'm working on it isn't called from either of those places -- it's called from
__scsi_remove_device(). So I'll go ahead and get rid ofscsi_target_reap_usercontext().
And just for reference, here is my patchset I've created sometime ago which streamlines the sdev and starget lifetime. I think I've tried to send it upstream at one point but never got far with it. Be aware that it's relative to a rather git tree (2.6.22?) so it might not apply properly. But it's mainly to get you an idea of what I've done so far.
And would have continued pushing it if real life hadn't interfered ...
HTH.
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke zSeries & Storage [email protected] +49 911 74053 688 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: Markus Rex, HRB 16746 (AG Nürnberg)
Quoted 1 line
From
404fc549f858cd0cf3a84865442fe85fedb920deMon Sep 17 00:00:00 2001
From: Hannes Reinecke <[email protected]>
Date: Sat, 8 Mar 2008 10:30:58 +0100
Subject: [PATCH] Fix refcounting for attribute_container
attribute_container_add_device() took an explicit reference on the parent device, making it impossible to remove the parent by doing a simple put. So we'd rather _not_ take a reference here as attribute_container will be handled explicitly by calls to attribute_container_remove_device()/_destroy_device() anyway.
--- drivers/base/attribute_container.c | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-)
drivers/base/attribute_container.c +5 -3
@@ -114,10 +114,8 @@ static void attribute_container_release(struct device *classdev) {struct internal_container *ic = container_of(classdev, struct internal_container, classdev); -struct device *dev = classdev->parent;kfree (ic); -put_device (dev); }/**
@@ -164,7 +162,11 @@ attribute_container_add_device(struct device *dev, ic->cont = cont;device_initialize (&ic->classdev); - ic->classdev.parent =get_device (dev); +/* +* Don't increase refcount here, device will be +* removed explicitly by a call to _destroy(). +*/ + ic->classdev.parent = dev; ic->classdev.class = cont->class; cont->class->dev_release = attribute_container_release;strcpy (ic->classdev.bus_id, dev->bus_id);
Signature · 1 line
1.5.3.2
Quoted 1 line
From
9e96c5dd094d3822093656e87b71cd433e818cd2Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <[email protected]>
Date: Sat, 8 Mar 2008 12:28:17 +0100
Subject: [PATCH] Remove reap_ref
struct scsi_target contains a 'reap_ref' counter, which is basically a reference counter for the target.
As we now have proper reference counting we can remove this and clear out the calling sequence for scsi_target_reap().
--- drivers/scsi/scsi_scan.c | 22 ++++++++++++++-------- drivers/scsi/scsi_sysfs.c | 3 --- include/scsi/scsi_device.h | 1 - 3 files changed, 14 insertions(+), 12 deletions(-)
drivers/scsi/scsi_scan.c +14 -8
@@ -448,7 +448,6 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,return starget; found: - found_target->reap_ref++;spin_unlock_irqrestore (shost->host_lock, flags);if (found_target->state !=STARGET_DEL ) {put_device (parent);
@@ -505,7 +504,7 @@ void scsi_target_reap(struct scsi_target *starget)spin_lock_irqsave (shost->host_lock, flags); -if (--starget->reap_ref ==0 &&list_empty (&starget->devices)) { +if (list_empty (&starget->devices)) {if (starget->state ==STARGET_CREATED ) {spin_unlock_irqrestore (shost->host_lock, flags); starget->state =STARGET_DEL ;
@@ -1516,8 +1515,13 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,if (scsi_host_scan_allowed (shost))scsi_probe_and_add_lun (starget, lun,NULL , &sdev,1 , hostdata);mutex_unlock (&shost->scan_mutex); -transport_configure_device (&starget->dev); -scsi_target_reap (starget); +/* +* scsi_target_reap is called from the release function +* of each sdev. +*/ +if (starget->state !=STARGET_DEL ) +transport_configure_device (&starget->dev); +put_device (&starget->dev);return sdev;
@@ -1595,10 +1599,12 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel, } out_reap: -/* now determine if the target has any children at all -* and if not, nuke it */ -transport_configure_device (&starget->dev); -scsi_target_reap (starget); +/* +* scsi_target_reap is called from the release function +* of each sdev. +*/ +if (starget->state !=STARGET_DEL ) +transport_configure_device (&starget->dev);put_device (&starget->dev); }
drivers/scsi/scsi_sysfs.c +0 -3
@@ -297,7 +297,6 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) starget =to_scsi_target (parent);spin_lock_irqsave (sdev->host->host_lock, flags); - starget->reap_ref++;list_del (&sdev->siblings);list_del (&sdev->same_target_siblings);list_del (&sdev->starved_entry);
@@ -937,7 +936,6 @@ static void __scsi_remove_target(struct scsi_target *starget)struct scsi_device *sdev;spin_lock_irqsave (shost->host_lock, flags); - starget->reap_ref++; restart:list_for_each_entry (sdev, &shost->__devices, siblings) { if (sdev->channel != starget->channel ||
@@ -950,7 +948,6 @@ static void __scsi_remove_target(struct scsi_target *starget) goto restart; }spin_unlock_irqrestore (shost->host_lock, flags); -scsi_target_reap (starget); }static int __remove_child (struct device * dev,void * data)
include/scsi/scsi_device.h +0 -1
@@ -196,7 +196,6 @@ struct scsi_target {struct list_head siblings;struct list_head devices;struct device dev; -unsigned int reap_ref;/* protected by the host lock */ unsigned int channel;unsigned int id;/* target id ... replace * scsi_device.id eventually */
Signature · 1 line
1.5.3.2
Quoted 1 line
From
b15634110e53a8418378c952bd1b6488f2746f86Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <[email protected]>
Date: Mon, 25 Feb 2008 03:39:28 +0100
Subject: [PATCH] Improve error messages in scsi_sysfs_add_sdev()
When we fail to add a device to the driver core, only the very helpful message 'error X' is displayed.
Print out some more meaningful messages.
--- drivers/scsi/scsi_sysfs.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-)
drivers/scsi/scsi_sysfs.c +4 -2
@@ -830,12 +830,14 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) error =device_add (&sdev->sdev_gendev);if (error) {put_device (sdev->sdev_gendev.parent); -printk (KERN_INFO "error 1\n" ); +sdev_printk (KERN_INFO , sdev, +"failed to add device: %d\n" , error);return error; } error =device_add (&sdev->sdev_dev);if (error) { -printk (KERN_INFO "error 2\n" ); +sdev_printk (KERN_INFO , sdev, +"failed to add class device: %d\n" , error); goto clean_device; }
Signature · 1 line
1.5.3.2
Quoted 1 line
From
f1717cf66290b81f9b376ddeba65426c91fb7fe4Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <[email protected]>
Date: Sat, 8 Mar 2008 18:01:40 +0100
Subject: [PATCH] Remove stale put_device() from scsi_sysfs_add_sdev()
In one obscure error path someone decided to do a put_device() on the sdev parent.
This doesn't make much sense as we didn't take the reference previously. So remove it.
--- drivers/scsi/scsi_sysfs.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-)
drivers/scsi/scsi_sysfs.c +0 -1
@@ -829,7 +829,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) error =device_add (&sdev->sdev_gendev);if (error) { -put_device (sdev->sdev_gendev.parent);sdev_printk (KERN_INFO , sdev,"failed to add device: %d\n" , error);return error;
Signature · 1 line
1.5.3.2
Quoted 1 line
From
57109790e4cb53561f36d73a8efc7b9abd2736a9Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <[email protected]>
Date: Sat, 8 Mar 2008 18:04:13 +0100
Subject: [PATCH] Implement SDEV_NEW state
When a scsi_device is allocated it's state is set to SDEV_CREATED. However, we don't have any chance to detect if slave_alloc() has run successfully or not.
This patch introduces a state SDEV_NEW which is used instead of SDEV_CREATED upon initial sdev creation. After slave_alloc() has run successfully the state is changed to SDEV_CREATED. This allows us to detect later on if we might call slave_destroy() or not.
--- drivers/scsi/scsi_lib.c | 17 +++++++++++++---- drivers/scsi/scsi_scan.c | 9 ++++++++- drivers/scsi/scsi_sysfs.c | 1 + include/scsi/scsi_device.h | 3 ++- 4 files changed, 24 insertions(+), 6 deletions(-)
drivers/scsi/scsi_lib.c +13 -4
@@ -1999,12 +1999,21 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)return 0 ;switch (state) { -case SDEV_CREATED : +case SDEV_NEW :/* There are no legal states that come back to -* created. This is the manually initialised start +* new. This is the manually initialised start * state */ goto illegal; - + +case SDEV_CREATED : +switch (oldstate) { +case SDEV_NEW : +break ; +default : + goto illegal; + } +break ; +case SDEV_RUNNING :switch (oldstate) {case SDEV_CREATED :
@@ -2064,7 +2073,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)case SDEV_DEL :switch (oldstate) { -case SDEV_CREATED : +case SDEV_NEW :case SDEV_RUNNING :case SDEV_OFFLINE :case SDEV_CANCEL :
drivers/scsi/scsi_scan.c +8 -1
@@ -253,7 +253,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, sdev->id = starget->id; sdev->lun = lun; sdev->channel = starget->channel; - sdev->sdev_state =SDEV_CREATED ; + sdev->sdev_state =SDEV_NEW ;INIT_LIST_HEAD (&sdev->siblings);INIT_LIST_HEAD (&sdev->same_target_siblings);INIT_LIST_HEAD (&sdev->cmd_list);
@@ -307,9 +307,16 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,*/ if (ret == -ENXIO ) display_failure_msg =0 ; +/* +* sdev remains in SDEV_NEW as the release +* function has to know whether slave_alloc() +* failed or not. +*/ goto out_device_destroy; } } +/* Device is created properly */ +scsi_device_set_state (sdev,SDEV_CREATED );return sdev;
drivers/scsi/scsi_sysfs.c +1 -0
@@ -27,6 +27,7 @@ static const struct {enum scsi_device_state value;char *name; } sdev_states[] = { + { SDEV_NEW, "new" }, { SDEV_CREATED, "created" }, { SDEV_RUNNING, "running" }, { SDEV_CANCEL, "cancel" },
include/scsi/scsi_device.h +2 -1
@@ -28,7 +28,8 @@ struct scsi_mode_data {* scsi_lib:scsi_device_set_state(). */ enum scsi_device_state { -SDEV_CREATED =1 ,/* device created but not added to sysfs +SDEV_NEW =1 ,/* device created, slave_alloc has not run */ +SDEV_CREATED ,/* device created but not added to sysfs * Only internal commands allowed (for inq) */ SDEV_RUNNING ,/* device properly configured * All commands allowed */
Signature · 1 line
1.5.3.2
Quoted 1 line
From
a2d6ea3b183edc7a71f33e66fce63088c0f3e8a1Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <[email protected]>
Date: Mon, 25 Feb 2008 04:17:51 +0100
Subject: [PATCH] Rename __scsi_remove_device() into scsi_sysfs_remove_sdev()
__scsi_remove_device() is actually the counterpart to scsi_sysfs_add_sdev(). So we'd better rename it to avoid confusion.
--- drivers/scsi/scsi_priv.h | 2 +- drivers/scsi/scsi_scan.c | 4 ++-- drivers/scsi/scsi_sysfs.c | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-)
drivers/scsi/scsi_priv.h +1 -1
@@ -112,13 +112,13 @@ extern void scsi_exit_sysctl(void);/* scsi_sysfs.c */ extern int scsi_sysfs_add_sdev (struct scsi_device *); +extern void scsi_sysfs_remove_sdev (struct scsi_device *);extern int scsi_sysfs_add_host (struct Scsi_Host *);extern int scsi_sysfs_register (void );extern void scsi_sysfs_unregister (void );extern void scsi_sysfs_device_initialize (struct scsi_device *);extern int scsi_sysfs_target_initialize (struct scsi_device *);extern struct scsi_transport_template blank_transport_template; -extern void __scsi_remove_device (struct scsi_device *);extern struct bus_type scsi_bus_type;extern struct attribute_group *scsi_sysfs_shost_attr_groups[];
drivers/scsi/scsi_scan.c +2 -2
@@ -1131,7 +1131,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,if (scsi_device_get (sdev) ==0 ) { *sdevp = sdev; }else { -__scsi_remove_device (sdev); +scsi_sysfs_remove_sdev (sdev); res =SCSI_SCAN_NO_RESPONSE ; } }
@@ -1881,7 +1881,7 @@ void scsi_forget_host(struct Scsi_Host *shost)if (sdev->sdev_state ==SDEV_DEL )continue ;spin_unlock_irqrestore (shost->host_lock, flags); -__scsi_remove_device (sdev); +scsi_sysfs_remove_sdev (sdev); goto restart; }spin_unlock_irqrestore (shost->host_lock, flags);
drivers/scsi/scsi_sysfs.c +5 -5
@@ -851,7 +851,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)else error =device_create_file (&sdev->sdev_gendev, &dev_attr_queue_depth);if (error) { -__scsi_remove_device (sdev); +scsi_sysfs_remove_sdev (sdev); goto out; }if (sdev->host->hostt->change_queue_type)
@@ -859,7 +859,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)else error =device_create_file (&sdev->sdev_gendev, &dev_attr_queue_type);if (error) { -__scsi_remove_device (sdev); +scsi_sysfs_remove_sdev (sdev); goto out; }
@@ -879,7 +879,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) error =device_create_file (&sdev->sdev_gendev, sdev->host->hostt->sdev_attrs[i]);if (error) { -__scsi_remove_device (sdev); +scsi_sysfs_remove_sdev (sdev); goto out; } }
@@ -899,7 +899,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)return error; } -void __scsi_remove_device (struct scsi_device *sdev) +void scsi_sysfs_remove_sdev (struct scsi_device *sdev) {struct device *dev = &sdev->sdev_gendev;
@@ -926,7 +926,7 @@ void scsi_remove_device(struct scsi_device *sdev)struct Scsi_Host *shost = sdev->host;mutex_lock (&shost->scan_mutex); -__scsi_remove_device (sdev); +scsi_sysfs_remove_sdev (sdev);mutex_unlock (&shost->scan_mutex); }EXPORT_SYMBOL (scsi_remove_device);
Signature · 1 line
1.5.3.2
Quoted 1 line
From
96841a56d0127229a74d5555830759838ff06454Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <[email protected]>
Date: Sat, 8 Mar 2008 18:37:22 +0100
Subject: [PATCH] Remove stale reap_ref reference
--- drivers/scsi/scsi_scan.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-)
drivers/scsi/scsi_scan.c +0 -1
@@ -409,7 +409,6 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, } dev = &starget->dev;device_initialize (dev); - starget->reap_ref =1 ; dev->parent =get_device (parent);sprintf (dev->bus_id,"target%d:%d:%d" , shost->host_no, channel, id);
Signature · 1 line
1.5.3.2
Re: [PATCH 25/20] sysfs: Only support removing emtpy sysfs directories.
In reply to James BottomleyTo all interested parties:
I have just sent out a series of six patches addressing this problem. They are CC'ed to the linux-scsi list.
Alan Stern