nilfs2: fix the nilfs_iget() vs. nilfs_new_inode() races
Same story as in commit 41080b5a24
("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>
このコミットが含まれているのは:
@@ -51,9 +51,11 @@ static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode)
|
||||
int err = nilfs_add_link(dentry, inode);
|
||||
if (!err) {
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
return 0;
|
||||
}
|
||||
inode_dec_link_count(inode);
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
return err;
|
||||
}
|
||||
@@ -182,6 +184,7 @@ out:
|
||||
out_fail:
|
||||
drop_nlink(inode);
|
||||
nilfs_mark_inode_dirty(inode);
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
goto out;
|
||||
}
|
||||
@@ -201,11 +204,15 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir,
|
||||
inode_inc_link_count(inode);
|
||||
ihold(inode);
|
||||
|
||||
err = nilfs_add_nondir(dentry, inode);
|
||||
if (!err)
|
||||
err = nilfs_add_link(dentry, inode);
|
||||
if (!err) {
|
||||
d_instantiate(dentry, inode);
|
||||
err = nilfs_transaction_commit(dir->i_sb);
|
||||
else
|
||||
} else {
|
||||
inode_dec_link_count(inode);
|
||||
iput(inode);
|
||||
nilfs_transaction_abort(dir->i_sb);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -243,6 +250,7 @@ static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
|
||||
nilfs_mark_inode_dirty(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
out:
|
||||
if (!err)
|
||||
err = nilfs_transaction_commit(dir->i_sb);
|
||||
@@ -255,6 +263,7 @@ out_fail:
|
||||
drop_nlink(inode);
|
||||
drop_nlink(inode);
|
||||
nilfs_mark_inode_dirty(inode);
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
out_dir:
|
||||
drop_nlink(dir);
|
||||
|
新しいイシューから参照
ユーザーをブロックする