sysfs: assorted fixes
PATCH 1/1 sysfs: assorted fixes
Hello, all.
This patchset contains two cleanups and three fixes.
#01: make-sysfs_alloc_ino-static, cleanup
#02: fix-parent-refcounting, fix
#03: reorganize-sysfs_new_inode-and-sysfs_create, cleanup and prep for #04 #04: use-iget_locked-instead-of-new_inode, fix
#05: fix-root-sysfs_dirent-root-dentry-association, fix
fs/sysfs/dir.c | 143 +++++++++++++++++++++++-------------------------------- fs/sysfs/inode.c | 114 ++++++++++++++++++++++++------------------- fs/sysfs/mount.c | 19 ++++--- fs/sysfs/sysfs.h | 6 +- 4 files changed, 137 insertions(+), 145 deletions(-)
Please apply. Thanks.
--
tejun
PATCH 2/5 sysfs: fix parent refcounting during rename and move
Parent reference wasn't properly transferred during rename and move. Fix it.
--- fs/sysfs/dir.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-)
fs/sysfs/dir.c +6 -0
@@ -497,6 +497,9 @@ int sysfs_rename_dir(struct kobject * kod_move (kobj->dentry, new_dentry);list_del_init (&sd->s_sibling); +sysfs_get (parent_sd); +sysfs_put (sd->s_parent); + sd->s_parent = parent_sd;list_add (&sd->s_sibling, &parent_sd->s_children); error =0 ;
@@ -550,6 +553,9 @@ again:/* Remove from old parent's list and insert into new parent's list. */ list_del_init (&sd->s_sibling); +sysfs_get (new_parent_sd); +sysfs_put (sd->s_parent); + sd->s_parent = new_parent_sd;list_add (&sd->s_sibling, &new_parent_sd->s_children); out:
Signature · 1 line
1.4.3.4
PATCH 4/5 sysfs: use iget_locked() instead of new_inode()
In reply to Tejun HeoAfter dentry is reclaimed, sysfs always used to allocate new dentry and inode if the file is accessed again. This causes problem with operations which only pin the inode. For example, if inotify watch is added to a sysfs file and the dentry for the file is reclaimed, the next update event creates new dentry and new inode making the inotify watch miss all the events from there on.
This patch fixes it by using iget_locked() instead of new_inode(). sysfs_new_inode() is renamed to sysfs_get_inode() and inode is initialized iff the inode is newly allocated. sysfs_instantiate() is responsible for unlocking new inodes.
--- fs/sysfs/dir.c | 37 +++++++++++++++++++++---------------- fs/sysfs/inode.c | 24 +++++++++++++++--------- fs/sysfs/sysfs.h | 2 +- 3 files changed, 37 insertions(+), 26 deletions(-)
fs/sysfs/dir.c +21 -16
@@ -219,14 +219,16 @@ static int create_dir(struct kobject *ko goto out_drop; sd->s_elem.dir.kobj = kobj; - inode =sysfs_new_inode (sd); + inode =sysfs_get_inode (sd);if (!inode) goto out_sput; - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; -/* directory inodes start off with i_nlink == 2 (for "." entry) */ -inc_nlink (inode); +if (inode->i_state &I_NEW ) { + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; +/* directory inodes start off with i_nlink == 2 (for ".") */ +inc_nlink (inode); + }/* link in */ error = -EEXIST ;
@@ -310,20 +312,23 @@ static struct dentry * sysfs_lookup(strureturn NULL ;/* attach dentry and inode */ - inode =sysfs_new_inode (sd); + inode =sysfs_get_inode (sd);if (!inode)return ERR_PTR (-ENOMEM ); -/* initialize inode according to type */ -if (sd->s_type &SYSFS_KOBJ_ATTR ) { - inode->i_size =PAGE_SIZE ; - inode->i_fop = &sysfs_file_operations; - }else if (sd->s_type &SYSFS_KOBJ_BIN_ATTR ) { -struct bin_attribute *bin_attr = sd->s_elem.bin_attr.bin_attr; - inode->i_size = bin_attr->size; - inode->i_fop = &bin_fops; - }else if (sd->s_type &SYSFS_KOBJ_LINK ) - inode->i_op = &sysfs_symlink_inode_operations; +if (inode->i_state &I_NEW ) { +/* initialize inode according to type */ +if (sd->s_type &SYSFS_KOBJ_ATTR ) { + inode->i_size =PAGE_SIZE ; + inode->i_fop = &sysfs_file_operations; + }else if (sd->s_type &SYSFS_KOBJ_BIN_ATTR ) { +struct bin_attribute *bin_attr = + sd->s_elem.bin_attr.bin_attr; + inode->i_size = bin_attr->size; + inode->i_fop = &bin_fops; + }else if (sd->s_type &SYSFS_KOBJ_LINK ) + inode->i_op = &sysfs_symlink_inode_operations; + }sysfs_instantiate (dentry, inode);sysfs_attach_dentry (sd, dentry);
fs/sysfs/inode.c +15 -9
@@ -152,10 +152,12 @@ void sysfs_init_inode(struct sysfs_diren }/** -* sysfs_new_inode - allocate new inode for sysfs_dirent +* sysfs_get_inode - get inode for sysfs_dirent * @sd: sysfs_dirent to allocate inode for * -* Allocate inode for @sd and initialize basics. +* Get inode for @sd. If such inode doesn't exist, a new inode +* is allocated and basics are initialized. New inode is +* returned locked. * * LOCKING: * Kernel thread context (may sleep).
@@ -163,12 +165,12 @@ void sysfs_init_inode(struct sysfs_diren* RETURNS: * Pointer to allocated inode on success, NULL on failure. */ -struct inode *sysfs_new_inode (struct sysfs_dirent *sd) +struct inode *sysfs_get_inode (struct sysfs_dirent *sd) {struct inode *inode; - inode =new_inode (sysfs_sb); -if (inode) + inode =iget_locked (sysfs_sb, sd->s_ino); +if (inode && (inode->i_state &I_NEW ))sysfs_init_inode (sd, inode);return inode;
@@ -179,7 +181,7 @@ struct inode * sysfs_new_inode(struct sy* @dentry: dentry to be instantiated * @inode: inode associated with @sd * -* Instantiate @dentry with @inode. +* Unlock @inode if locked and instantiate @dentry with @inode. * * LOCKING: * None.
@@ -188,9 +190,13 @@ void sysfs_instantiate(struct dentry *de {BUG_ON (!dentry || dentry->d_inode); -if (dentry->d_parent && dentry->d_parent->d_inode) { -struct inode *p_inode = dentry->d_parent->d_inode; - p_inode->i_mtime = p_inode->i_ctime =CURRENT_TIME ; +if (inode->i_state &I_NEW ) { +unlock_new_inode (inode); + +if (dentry->d_parent && dentry->d_parent->d_inode) { +struct inode *p_inode = dentry->d_parent->d_inode; + p_inode->i_mtime = p_inode->i_ctime =CURRENT_TIME ; + } }d_instantiate (dentry, inode);
fs/sysfs/sysfs.h +1 -1
@@ -58,7 +58,7 @@ extern struct kmem_cache *sysfs_dir_cachextern void sysfs_delete_inode (struct inode *inode);extern void sysfs_init_inode (struct sysfs_dirent *sd,struct inode *inode); -extern struct inode *sysfs_new_inode (struct sysfs_dirent *sd); +extern struct inode *sysfs_get_inode (struct sysfs_dirent *sd);extern void sysfs_instantiate (struct dentry *dentry,struct inode *inode);extern void release_sysfs_dirent (struct sysfs_dirent * sd);
Signature · 1 line
1.4.3.4
PATCH 1/5 sysfs: make sysfs_alloc_ino() static
In reply to Tejun Heosysfs_alloc_ino() isn't used out side of fs/sysfs/dir.c. Make it static.
--- fs/sysfs/dir.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
fs/sysfs/dir.c +1 -1
@@ -20,7 +20,7 @@ spinlock_t kobj_sysfs_assoc_lock = SPIN_static spinlock_t sysfs_ino_lock =SPIN_LOCK_UNLOCKED ;static DEFINE_IDA (sysfs_ino_ida); -int sysfs_alloc_ino (ino_t *pino) +static int sysfs_alloc_ino (ino_t *pino) {int ino, rc;
Signature · 1 line
1.4.3.4
PATCH 3/5 sysfs: reorganize sysfs_new_indoe() and sysfs_create()
In reply to Tejun HeoReorganize/clean up sysfs_new_inode() and sysfs_create().
* sysfs_init_inode() is separated out from sysfs_new_inode() and is responsible for basic initialization.
* sysfs_instantiate() replaces the last step of sysfs_create() and is responsible for dentry instantitaion.
* type-specific initialization is moved out to the callers.
* mode is specified only once when creating a sysfs_dirent.
* spurious list_del_init(&sd->s_sibling) dropped from create_dir()
This change is to
* prepare for inode allocation fix.
* separate alloc and init code for synchronization update.
* make dentry/inode initialization more flexible for later changes.
This patch doesn't introduce visible behavior change.
--- fs/sysfs/dir.c | 130 ++++++++++++++++++++---------------------------------- fs/sysfs/inode.c | 108 ++++++++++++++++++++++++--------------------- fs/sysfs/mount.c | 18 ++++--- fs/sysfs/sysfs.h | 6 +- 4 files changed, 118 insertions(+), 144 deletions(-)
fs/sysfs/dir.c +48 -82
@@ -191,39 +191,18 @@ int sysfs_dirent_exist(struct sysfs_direreturn 0 ; } -static int init_dir (struct inode * inode) -{ - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; - -/* directory inodes start off with i_nlink == 2 (for "." entry) */ -inc_nlink (inode); -return 0 ; -} - -static int init_file (struct inode * inode) -{ - inode->i_size =PAGE_SIZE ; - inode->i_fop = &sysfs_file_operations; -return 0 ; -} - -static int init_symlink (struct inode * inode) -{ - inode->i_op = &sysfs_symlink_inode_operations; -return 0 ; -} -static int create_dir (struct kobject *kobj,struct dentry *parent,const char *name,struct dentry **p_dentry) {int error;umode_t mode =S_IFDIR |S_IRWXU |S_IRUGO |S_IXUGO ;struct dentry *dentry; +struct inode *inode;struct sysfs_dirent *sd;mutex_lock (&parent->d_inode->i_mutex); +/* allocate */ dentry =lookup_one_len (name, parent,strlen (name));if (IS_ERR (dentry)) { error =PTR_ERR (dentry);
@@ -231,7 +210,7 @@ static int create_dir(struct kobject *ko } error = -EEXIST ; -if (sysfs_dirent_exist (parent->d_fsdata, name)) +if (dentry->d_inode) goto out_dput; error = -ENOMEM ;
@@ -240,19 +219,31 @@ static int create_dir(struct kobject *ko goto out_drop; sd->s_elem.dir.kobj = kobj; - error =sysfs_create (sd, dentry, mode, init_dir); -if (error) + inode =sysfs_new_inode (sd); +if (!inode) goto out_sput; + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; +/* directory inodes start off with i_nlink == 2 (for "." entry) */ +inc_nlink (inode); + +/* link in */ + error = -EEXIST ; +if (sysfs_dirent_exist (parent->d_fsdata, name)) + goto out_iput; + +sysfs_instantiate (dentry, inode);inc_nlink (parent->d_inode);sysfs_attach_dirent (sd, parent->d_fsdata, dentry); *p_dentry = dentry; error =0 ; - goto out_dput; + goto out_unlock;/* pin directory dentry in core */ + out_iput: +iput (inode); out_sput: -list_del_init (&sd->s_sibling);sysfs_put (sd); out_drop:d_drop (dentry);
@@ -298,71 +289,46 @@ int sysfs_create_dir(struct kobject * koreturn error; } -/* attaches attribute's sysfs_dirent to the dentry corresponding to the -* attribute file -*/ -static int sysfs_attach_attr (struct sysfs_dirent * sd,struct dentry * dentry) -{ -struct attribute * attr =NULL ; -struct bin_attribute * bin_attr =NULL ; -int (* init) (struct inode *) =NULL ; -int error =0 ; - -if (sd->s_type &SYSFS_KOBJ_BIN_ATTR ) { - bin_attr = sd->s_elem.bin_attr.bin_attr; - attr = &bin_attr->attr; - }else { - attr = sd->s_elem.attr.attr; - init = init_file; - } - - error =sysfs_create (sd, dentry, - (attr->mode &S_IALLUGO ) |S_IFREG , init); -if (error) -return error; - -if (bin_attr) { - dentry->d_inode->i_size = bin_attr->size; - dentry->d_inode->i_fop = &bin_fops; - } - -sysfs_attach_dentry (sd, dentry); - -return 0 ; -} - -static int sysfs_attach_link (struct sysfs_dirent * sd,struct dentry * dentry) -{ -int err; - - err =sysfs_create (sd, dentry,S_IFLNK |S_IRWXUGO , init_symlink); -if (!err) -sysfs_attach_dentry (sd, dentry); - -return err; -} -static struct dentry *sysfs_lookup (struct inode *dir,struct dentry *dentry,struct nameidata *nd) {struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;struct sysfs_dirent * sd; -int err =0 ; +struct inode *inode; +int found =0 ;list_for_each_entry (sd, &parent_sd->s_children, s_sibling) { -if (sd->s_type &SYSFS_NOT_PINNED ) { -if (strcmp (sd->s_name, dentry->d_name.name)) -continue ; - -if (sd->s_type &SYSFS_KOBJ_LINK ) - err =sysfs_attach_link (sd, dentry); -else - err =sysfs_attach_attr (sd, dentry); +if ((sd->s_type &SYSFS_NOT_PINNED ) && + !strcmp (sd->s_name, dentry->d_name.name)) { + found =1 ;break ; } } -return ERR_PTR (err); +/* no such entry */ +if (!found) +return NULL ; + +/* attach dentry and inode */ + inode =sysfs_new_inode (sd); +if (!inode) +return ERR_PTR (-ENOMEM ); + +/* initialize inode according to type */ +if (sd->s_type &SYSFS_KOBJ_ATTR ) { + inode->i_size =PAGE_SIZE ; + inode->i_fop = &sysfs_file_operations; + }else if (sd->s_type &SYSFS_KOBJ_BIN_ATTR ) { +struct bin_attribute *bin_attr = sd->s_elem.bin_attr.bin_attr; + inode->i_size = bin_attr->size; + inode->i_fop = &bin_fops; + }else if (sd->s_type &SYSFS_KOBJ_LINK ) + inode->i_op = &sysfs_symlink_inode_operations; + +sysfs_instantiate (dentry, inode); +sysfs_attach_dentry (sd, dentry); + +return NULL ; }const struct inode_operations sysfs_dir_inode_operations = {
fs/sysfs/inode.c +57 -51
119 lines not on this page · raw message
fs/sysfs/mount.c +10 -8
@@ -27,6 +27,7 @@ static struct sysfs_dirent sysfs_root = .s_sibling = LIST_HEAD_INIT(sysfs_root.s_sibling), .s_children = LIST_HEAD_INIT(sysfs_root.s_children), .s_type = SYSFS_ROOT, + .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, .s_ino = 1, .s_iattr = NULL, };
@@ -43,18 +44,19 @@ static int sysfs_fill_super(struct super sb->s_time_gran =1 ; sysfs_sb = sb; - inode =sysfs_new_inode (S_IFDIR |S_IRWXU |S_IRUGO |S_IXUGO , - &sysfs_root); -if (inode) { - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; -/* directory inodes start off with i_nlink == 2 (for "." entry) */ -inc_nlink (inode); - }else { + inode =new_inode (sysfs_sb); +if (!inode) {pr_debug ("sysfs: could not get root inode\n" );return -ENOMEM ; } +sysfs_init_inode (&sysfs_root, inode); + + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; +/* directory inodes start off with i_nlink == 2 (for "." entry) */ +inc_nlink (inode); + root =d_alloc_root (inode);if (!root) {pr_debug ("%s: could not get root dentry!\n" ,__FUNCTION__);
fs/sysfs/sysfs.h +3 -3
@@ -57,9 +57,9 @@ extern struct vfsmount * sysfs_mount;extern struct kmem_cache *sysfs_dir_cachep;extern void sysfs_delete_inode (struct inode *inode); -extern struct inode *sysfs_new_inode (mode_t mode,struct sysfs_dirent *); -extern int sysfs_create (struct sysfs_dirent *sd,struct dentry *dentry, -int mode,int (*init)(struct inode *)); +extern void sysfs_init_inode (struct sysfs_dirent *sd,struct inode *inode); +extern struct inode *sysfs_new_inode (struct sysfs_dirent *sd); +extern void sysfs_instantiate (struct dentry *dentry,struct inode *inode);extern void release_sysfs_dirent (struct sysfs_dirent * sd);extern int sysfs_dirent_exist (struct sysfs_dirent *,const unsigned char *);
Signature · 1 line
1.4.3.4
PATCH 5/5 sysfs: fix root sysfs_dirent -> root dentry association
In reply to Tejun HeoThe root sysfs_dirent didn't point to the root dentry fix it.
--- fs/sysfs/mount.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
fs/sysfs/mount.c +1 -0
@@ -63,6 +63,7 @@ static int sysfs_fill_super(struct superiput (inode);return -ENOMEM ; } + sysfs_root.s_dentry = root; root->d_fsdata = &sysfs_root; sb->s_root = root;return 0 ;
Signature · 1 line
1.4.3.4
Quoted 10 lines · Tejun Heo
Hello, all.
This patchset contains two cleanups and three fixes.
#01: make-sysfs_alloc_ino-static, cleanup
#02: fix-parent-refcounting, fix
#03: reorganize-sysfs_new_inode-and-sysfs_create, cleanup and prep for #04 #04: use-iget_locked-instead-of-new_inode, fix
#05: fix-root-sysfs_dirent-root-dentry-association, fix
Quoted 7 lines
fs/sysfs/dir.c | 143 +++++++++++++++++++++++-------------------------------- fs/sysfs/inode.c | 114 ++++++++++++++++++++++++------------------- fs/sysfs/mount.c | 19 ++++--- fs/sysfs/sysfs.h | 6 +- 4 files changed, 137 insertions(+), 145 deletions(-)Please apply. Thanks.
I've tested this patchset a bit on s390 (device attach/detach and moving devices around) and didn't encounter problems. As far as I can see, this looks sane.
Quoted 19 lines · Cornelia Huck
Quoted 16 lines · Tejun Heo
Hello, all.
This patchset contains two cleanups and three fixes.
#01: make-sysfs_alloc_ino-static, cleanup
#02: fix-parent-refcounting, fix
#03: reorganize-sysfs_new_inode-and-sysfs_create, cleanup and prep for #04 #04: use-iget_locked-instead-of-new_inode, fix
#05: fix-root-sysfs_dirent-root-dentry-association, fixfs/sysfs/dir.c | 143 +++++++++++++++++++++++-------------------------------- fs/sysfs/inode.c | 114 ++++++++++++++++++++++++------------------- fs/sysfs/mount.c | 19 ++++--- fs/sysfs/sysfs.h | 6 +- 4 files changed, 137 insertions(+), 145 deletions(-)
Quoted 5 lines
Quoted 1 line
Please apply. Thanks.
I've tested this patchset a bit on s390 (device attach/detach and moving devices around) and didn't encounter problems. As far as I can see, this looks sane.
It boots on this laptop just fine too :)
Thanks for testing,
greg k-h