diff options
author | Tejun Heo <htejun@gmail.com> | 2007-06-13 14:45:17 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-11 19:09:07 -0400 |
commit | 8312a8d7c1d19d31027bd4ca127ce671962c23d4 (patch) | |
tree | ee28a44611ac2192b265f5f85a74f7da98d2fdef /fs/sysfs/dir.c | |
parent | fc9f54b9982e14e6dbe023425c87ffbfd6992c45 (diff) |
sysfs: use iget_locked() instead of new_inode()
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>
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r-- | fs/sysfs/dir.c | 37 |
1 files changed, 21 insertions, 16 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index bbf3525fd222..06dff2c30c9b 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -219,14 +219,16 @@ static int create_dir(struct kobject *kobj, struct dentry *parent, | |||
219 | goto out_drop; | 219 | goto out_drop; |
220 | sd->s_elem.dir.kobj = kobj; | 220 | sd->s_elem.dir.kobj = kobj; |
221 | 221 | ||
222 | inode = sysfs_new_inode(sd); | 222 | inode = sysfs_get_inode(sd); |
223 | if (!inode) | 223 | if (!inode) |
224 | goto out_sput; | 224 | goto out_sput; |
225 | 225 | ||
226 | inode->i_op = &sysfs_dir_inode_operations; | 226 | if (inode->i_state & I_NEW) { |
227 | inode->i_fop = &sysfs_dir_operations; | 227 | inode->i_op = &sysfs_dir_inode_operations; |
228 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | 228 | inode->i_fop = &sysfs_dir_operations; |
229 | inc_nlink(inode); | 229 | /* directory inodes start off with i_nlink == 2 (for ".") */ |
230 | inc_nlink(inode); | ||
231 | } | ||
230 | 232 | ||
231 | /* link in */ | 233 | /* link in */ |
232 | error = -EEXIST; | 234 | error = -EEXIST; |
@@ -310,20 +312,23 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
310 | return NULL; | 312 | return NULL; |
311 | 313 | ||
312 | /* attach dentry and inode */ | 314 | /* attach dentry and inode */ |
313 | inode = sysfs_new_inode(sd); | 315 | inode = sysfs_get_inode(sd); |
314 | if (!inode) | 316 | if (!inode) |
315 | return ERR_PTR(-ENOMEM); | 317 | return ERR_PTR(-ENOMEM); |
316 | 318 | ||
317 | /* initialize inode according to type */ | 319 | if (inode->i_state & I_NEW) { |
318 | if (sd->s_type & SYSFS_KOBJ_ATTR) { | 320 | /* initialize inode according to type */ |
319 | inode->i_size = PAGE_SIZE; | 321 | if (sd->s_type & SYSFS_KOBJ_ATTR) { |
320 | inode->i_fop = &sysfs_file_operations; | 322 | inode->i_size = PAGE_SIZE; |
321 | } else if (sd->s_type & SYSFS_KOBJ_BIN_ATTR) { | 323 | inode->i_fop = &sysfs_file_operations; |
322 | struct bin_attribute *bin_attr = sd->s_elem.bin_attr.bin_attr; | 324 | } else if (sd->s_type & SYSFS_KOBJ_BIN_ATTR) { |
323 | inode->i_size = bin_attr->size; | 325 | struct bin_attribute *bin_attr = |
324 | inode->i_fop = &bin_fops; | 326 | sd->s_elem.bin_attr.bin_attr; |
325 | } else if (sd->s_type & SYSFS_KOBJ_LINK) | 327 | inode->i_size = bin_attr->size; |
326 | inode->i_op = &sysfs_symlink_inode_operations; | 328 | inode->i_fop = &bin_fops; |
329 | } else if (sd->s_type & SYSFS_KOBJ_LINK) | ||
330 | inode->i_op = &sysfs_symlink_inode_operations; | ||
331 | } | ||
327 | 332 | ||
328 | sysfs_instantiate(dentry, inode); | 333 | sysfs_instantiate(dentry, inode); |
329 | sysfs_attach_dentry(sd, dentry); | 334 | sysfs_attach_dentry(sd, dentry); |