Skip to content

Commit

Permalink
sysfs: use iget_locked() instead of new_inode()
Browse files Browse the repository at this point in the history
After 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.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Tejun Heo authored and Greg Kroah-Hartman committed Jul 11, 2007
1 parent fc9f54b commit 8312a8d
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 26 deletions.
37 changes: 21 additions & 16 deletions fs/sysfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,16 @@ static int create_dir(struct kobject *kobj, struct dentry *parent,
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;
Expand Down Expand Up @@ -310,20 +312,23 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
return 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);
Expand Down
24 changes: 15 additions & 9 deletions fs/sysfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,23 +153,25 @@ void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
}

/**
* 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).
*
* 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;
Expand All @@ -180,7 +182,7 @@ struct inode * sysfs_new_inode(struct sysfs_dirent *sd)
* @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.
Expand All @@ -189,9 +191,13 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode)
{
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);
Expand Down
2 changes: 1 addition & 1 deletion fs/sysfs/sysfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ extern struct kmem_cache *sysfs_dir_cachep;

extern 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);
Expand Down

0 comments on commit 8312a8d

Please sign in to comment.