Commit 83d17827a7a61fdd10f1ad628cc7b2004aa796a9
Committed by
Greg Kroah-Hartman
1 parent
53575aa5ba
nilfs2: fix the nilfs_iget() vs. nilfs_new_inode() races
commit 705304a863cc41585508c0f476f6d3ec28cf7e00 upstream. 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 2 changed files with 36 additions and 11 deletions Side-by-side Diff
fs/nilfs2/inode.c
... | ... | @@ -49,6 +49,8 @@ |
49 | 49 | int for_gc; |
50 | 50 | }; |
51 | 51 | |
52 | +static int nilfs_iget_test(struct inode *inode, void *opaque); | |
53 | + | |
52 | 54 | void nilfs_inode_add_blocks(struct inode *inode, int n) |
53 | 55 | { |
54 | 56 | struct nilfs_root *root = NILFS_I(inode)->i_root; |
... | ... | @@ -348,6 +350,17 @@ |
348 | 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 | 364 | struct inode *nilfs_new_inode(struct inode *dir, umode_t mode) |
352 | 365 | { |
353 | 366 | struct super_block *sb = dir->i_sb; |
... | ... | @@ -383,7 +396,7 @@ |
383 | 396 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { |
384 | 397 | err = nilfs_bmap_read(ii->i_bmap, NULL); |
385 | 398 | if (err < 0) |
386 | - goto failed_bmap; | |
399 | + goto failed_after_creation; | |
387 | 400 | |
388 | 401 | set_bit(NILFS_I_BMAP, &ii->i_state); |
389 | 402 | /* No lock is needed; iget() ensures it. */ |
390 | 403 | |
391 | 404 | |
392 | 405 | |
393 | 406 | |
... | ... | @@ -399,21 +412,24 @@ |
399 | 412 | spin_lock(&nilfs->ns_next_gen_lock); |
400 | 413 | inode->i_generation = nilfs->ns_next_generation++; |
401 | 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 | 420 | err = nilfs_init_acl(inode, dir); |
405 | 421 | if (unlikely(err)) |
406 | - goto failed_acl; /* never occur. When supporting | |
422 | + goto failed_after_creation; /* never occur. When supporting | |
407 | 423 | nilfs_init_acl(), proper cancellation of |
408 | 424 | above jobs should be considered */ |
409 | 425 | |
410 | 426 | return inode; |
411 | 427 | |
412 | - failed_acl: | |
413 | - failed_bmap: | |
428 | + failed_after_creation: | |
414 | 429 | clear_nlink(inode); |
430 | + unlock_new_inode(inode); | |
415 | 431 | iput(inode); /* raw_inode will be deleted through |
416 | - generic_delete_inode() */ | |
432 | + nilfs_evict_inode() */ | |
417 | 433 | goto failed; |
418 | 434 | |
419 | 435 | failed_ifile_create_inode: |
... | ... | @@ -461,8 +477,8 @@ |
461 | 477 | inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); |
462 | 478 | inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_ctime_nsec); |
463 | 479 | inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); |
464 | - if (inode->i_nlink == 0 && inode->i_mode == 0) | |
465 | - return -EINVAL; /* this inode is deleted */ | |
480 | + if (inode->i_nlink == 0) | |
481 | + return -ESTALE; /* this inode is deleted */ | |
466 | 482 | |
467 | 483 | inode->i_blocks = le64_to_cpu(raw_inode->i_blocks); |
468 | 484 | ii->i_flags = le32_to_cpu(raw_inode->i_flags); |
fs/nilfs2/namei.c
... | ... | @@ -51,9 +51,11 @@ |
51 | 51 | int err = nilfs_add_link(dentry, inode); |
52 | 52 | if (!err) { |
53 | 53 | d_instantiate(dentry, inode); |
54 | + unlock_new_inode(inode); | |
54 | 55 | return 0; |
55 | 56 | } |
56 | 57 | inode_dec_link_count(inode); |
58 | + unlock_new_inode(inode); | |
57 | 59 | iput(inode); |
58 | 60 | return err; |
59 | 61 | } |
... | ... | @@ -182,6 +184,7 @@ |
182 | 184 | out_fail: |
183 | 185 | drop_nlink(inode); |
184 | 186 | nilfs_mark_inode_dirty(inode); |
187 | + unlock_new_inode(inode); | |
185 | 188 | iput(inode); |
186 | 189 | goto out; |
187 | 190 | } |
188 | 191 | |
189 | 192 | |
... | ... | @@ -201,11 +204,15 @@ |
201 | 204 | inode_inc_link_count(inode); |
202 | 205 | ihold(inode); |
203 | 206 | |
204 | - err = nilfs_add_nondir(dentry, inode); | |
205 | - if (!err) | |
207 | + err = nilfs_add_link(dentry, inode); | |
208 | + if (!err) { | |
209 | + d_instantiate(dentry, inode); | |
206 | 210 | err = nilfs_transaction_commit(dir->i_sb); |
207 | - else | |
211 | + } else { | |
212 | + inode_dec_link_count(inode); | |
213 | + iput(inode); | |
208 | 214 | nilfs_transaction_abort(dir->i_sb); |
215 | + } | |
209 | 216 | |
210 | 217 | return err; |
211 | 218 | } |
... | ... | @@ -243,6 +250,7 @@ |
243 | 250 | |
244 | 251 | nilfs_mark_inode_dirty(inode); |
245 | 252 | d_instantiate(dentry, inode); |
253 | + unlock_new_inode(inode); | |
246 | 254 | out: |
247 | 255 | if (!err) |
248 | 256 | err = nilfs_transaction_commit(dir->i_sb); |
... | ... | @@ -255,6 +263,7 @@ |
255 | 263 | drop_nlink(inode); |
256 | 264 | drop_nlink(inode); |
257 | 265 | nilfs_mark_inode_dirty(inode); |
266 | + unlock_new_inode(inode); | |
258 | 267 | iput(inode); |
259 | 268 | out_dir: |
260 | 269 | drop_nlink(dir); |