diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2014-12-10 18:54:34 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-10 20:41:16 -0500 |
commit | 705304a863cc41585508c0f476f6d3ec28cf7e00 (patch) | |
tree | 4520ccc069e5966baaae43866e925aa0a2c401fb /fs | |
parent | 72b9918ea4d7f2d8362a2defdb93e5fd25a86308 (diff) |
nilfs2: fix the nilfs_iget() vs. nilfs_new_inode() races
Same story as in commit 41080b5a2401 ("nfsd race fixes: ext2") (similar
ext2 fix) except that nilfs2 needs to use insert_inode_locked4() instead
of insert_inode_locked() and a bug of a check for dead inodes needs to
be fixed.
If nilfs_iget() is called from nfsd after nilfs_new_inode() calls
insert_inode_locked4(), nilfs_iget() will wait for unlock_new_inode() at
the end of nilfs_mkdir()/nilfs_create()/etc to unlock the inode.
If nilfs_iget() is called before nilfs_new_inode() calls
insert_inode_locked4(), it will create an in-core inode and read its
data from the on-disk inode. But, nilfs_iget() will find i_nlink equals
zero and fail at nilfs_read_inode_common(), which will lead it to call
iget_failed() and cleanly fail.
However, this sanity check doesn't work as expected for reused on-disk
inodes because they leave a non-zero value in i_mode field and it
hinders the test of i_nlink. This patch also fixes the issue by
removing the test on i_mode that nilfs2 doesn't need.
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nilfs2/inode.c | 32 | ||||
-rw-r--r-- | fs/nilfs2/namei.c | 15 |
2 files changed, 36 insertions, 11 deletions
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index e1fa69b341b9..8b5969538f39 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c | |||
@@ -49,6 +49,8 @@ struct nilfs_iget_args { | |||
49 | int for_gc; | 49 | int for_gc; |
50 | }; | 50 | }; |
51 | 51 | ||
52 | static int nilfs_iget_test(struct inode *inode, void *opaque); | ||
53 | |||
52 | void nilfs_inode_add_blocks(struct inode *inode, int n) | 54 | void nilfs_inode_add_blocks(struct inode *inode, int n) |
53 | { | 55 | { |
54 | struct nilfs_root *root = NILFS_I(inode)->i_root; | 56 | struct nilfs_root *root = NILFS_I(inode)->i_root; |
@@ -348,6 +350,17 @@ const struct address_space_operations nilfs_aops = { | |||
348 | .is_partially_uptodate = block_is_partially_uptodate, | 350 | .is_partially_uptodate = block_is_partially_uptodate, |
349 | }; | 351 | }; |
350 | 352 | ||
353 | static int nilfs_insert_inode_locked(struct inode *inode, | ||
354 | struct nilfs_root *root, | ||
355 | unsigned long ino) | ||
356 | { | ||
357 | struct nilfs_iget_args args = { | ||
358 | .ino = ino, .root = root, .cno = 0, .for_gc = 0 | ||
359 | }; | ||
360 | |||
361 | return insert_inode_locked4(inode, ino, nilfs_iget_test, &args); | ||
362 | } | ||
363 | |||
351 | struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) | 364 | struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) |
352 | { | 365 | { |
353 | struct super_block *sb = dir->i_sb; | 366 | struct super_block *sb = dir->i_sb; |
@@ -383,7 +396,7 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) | |||
383 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { | 396 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { |
384 | err = nilfs_bmap_read(ii->i_bmap, NULL); | 397 | err = nilfs_bmap_read(ii->i_bmap, NULL); |
385 | if (err < 0) | 398 | if (err < 0) |
386 | goto failed_bmap; | 399 | goto failed_after_creation; |
387 | 400 | ||
388 | set_bit(NILFS_I_BMAP, &ii->i_state); | 401 | set_bit(NILFS_I_BMAP, &ii->i_state); |
389 | /* No lock is needed; iget() ensures it. */ | 402 | /* No lock is needed; iget() ensures it. */ |
@@ -399,21 +412,24 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) | |||
399 | spin_lock(&nilfs->ns_next_gen_lock); | 412 | spin_lock(&nilfs->ns_next_gen_lock); |
400 | inode->i_generation = nilfs->ns_next_generation++; | 413 | inode->i_generation = nilfs->ns_next_generation++; |
401 | spin_unlock(&nilfs->ns_next_gen_lock); | 414 | spin_unlock(&nilfs->ns_next_gen_lock); |
402 | insert_inode_hash(inode); | 415 | if (nilfs_insert_inode_locked(inode, root, ino) < 0) { |
416 | err = -EIO; | ||
417 | goto failed_after_creation; | ||
418 | } | ||
403 | 419 | ||
404 | err = nilfs_init_acl(inode, dir); | 420 | err = nilfs_init_acl(inode, dir); |
405 | if (unlikely(err)) | 421 | if (unlikely(err)) |
406 | goto failed_acl; /* never occur. When supporting | 422 | goto failed_after_creation; /* never occur. When supporting |
407 | nilfs_init_acl(), proper cancellation of | 423 | nilfs_init_acl(), proper cancellation of |
408 | above jobs should be considered */ | 424 | above jobs should be considered */ |
409 | 425 | ||
410 | return inode; | 426 | return inode; |
411 | 427 | ||
412 | failed_acl: | 428 | failed_after_creation: |
413 | failed_bmap: | ||
414 | clear_nlink(inode); | 429 | clear_nlink(inode); |
430 | unlock_new_inode(inode); | ||
415 | iput(inode); /* raw_inode will be deleted through | 431 | iput(inode); /* raw_inode will be deleted through |
416 | generic_delete_inode() */ | 432 | nilfs_evict_inode() */ |
417 | goto failed; | 433 | goto failed; |
418 | 434 | ||
419 | failed_ifile_create_inode: | 435 | failed_ifile_create_inode: |
@@ -461,8 +477,8 @@ int nilfs_read_inode_common(struct inode *inode, | |||
461 | inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); | 477 | inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); |
462 | inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_ctime_nsec); | 478 | inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_ctime_nsec); |
463 | inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); | 479 | inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); |
464 | if (inode->i_nlink == 0 && inode->i_mode == 0) | 480 | if (inode->i_nlink == 0) |
465 | return -EINVAL; /* this inode is deleted */ | 481 | return -ESTALE; /* this inode is deleted */ |
466 | 482 | ||
467 | inode->i_blocks = le64_to_cpu(raw_inode->i_blocks); | 483 | inode->i_blocks = le64_to_cpu(raw_inode->i_blocks); |
468 | ii->i_flags = le32_to_cpu(raw_inode->i_flags); | 484 | ii->i_flags = le32_to_cpu(raw_inode->i_flags); |
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 9de78f08989e..0f84b257932c 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c | |||
@@ -51,9 +51,11 @@ static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode) | |||
51 | int err = nilfs_add_link(dentry, inode); | 51 | int err = nilfs_add_link(dentry, inode); |
52 | if (!err) { | 52 | if (!err) { |
53 | d_instantiate(dentry, inode); | 53 | d_instantiate(dentry, inode); |
54 | unlock_new_inode(inode); | ||
54 | return 0; | 55 | return 0; |
55 | } | 56 | } |
56 | inode_dec_link_count(inode); | 57 | inode_dec_link_count(inode); |
58 | unlock_new_inode(inode); | ||
57 | iput(inode); | 59 | iput(inode); |
58 | return err; | 60 | return err; |
59 | } | 61 | } |
@@ -182,6 +184,7 @@ out: | |||
182 | out_fail: | 184 | out_fail: |
183 | drop_nlink(inode); | 185 | drop_nlink(inode); |
184 | nilfs_mark_inode_dirty(inode); | 186 | nilfs_mark_inode_dirty(inode); |
187 | unlock_new_inode(inode); | ||
185 | iput(inode); | 188 | iput(inode); |
186 | goto out; | 189 | goto out; |
187 | } | 190 | } |
@@ -201,11 +204,15 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir, | |||
201 | inode_inc_link_count(inode); | 204 | inode_inc_link_count(inode); |
202 | ihold(inode); | 205 | ihold(inode); |
203 | 206 | ||
204 | err = nilfs_add_nondir(dentry, inode); | 207 | err = nilfs_add_link(dentry, inode); |
205 | if (!err) | 208 | if (!err) { |
209 | d_instantiate(dentry, inode); | ||
206 | err = nilfs_transaction_commit(dir->i_sb); | 210 | err = nilfs_transaction_commit(dir->i_sb); |
207 | else | 211 | } else { |
212 | inode_dec_link_count(inode); | ||
213 | iput(inode); | ||
208 | nilfs_transaction_abort(dir->i_sb); | 214 | nilfs_transaction_abort(dir->i_sb); |
215 | } | ||
209 | 216 | ||
210 | return err; | 217 | return err; |
211 | } | 218 | } |
@@ -243,6 +250,7 @@ static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
243 | 250 | ||
244 | nilfs_mark_inode_dirty(inode); | 251 | nilfs_mark_inode_dirty(inode); |
245 | d_instantiate(dentry, inode); | 252 | d_instantiate(dentry, inode); |
253 | unlock_new_inode(inode); | ||
246 | out: | 254 | out: |
247 | if (!err) | 255 | if (!err) |
248 | err = nilfs_transaction_commit(dir->i_sb); | 256 | err = nilfs_transaction_commit(dir->i_sb); |
@@ -255,6 +263,7 @@ out_fail: | |||
255 | drop_nlink(inode); | 263 | drop_nlink(inode); |
256 | drop_nlink(inode); | 264 | drop_nlink(inode); |
257 | nilfs_mark_inode_dirty(inode); | 265 | nilfs_mark_inode_dirty(inode); |
266 | unlock_new_inode(inode); | ||
258 | iput(inode); | 267 | iput(inode); |
259 | out_dir: | 268 | out_dir: |
260 | drop_nlink(dir); | 269 | drop_nlink(dir); |