mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 20:32:04 +09:00
f2fs: call unlock_new_inode() before d_instantiate()
xfstest generic/429 sometimes hangs on f2fs, caused by a thread being
unable to take a directory's i_rwsem for write in vfs_rmdir(). In the
test, one thread repeatedly creates and removes a directory, and other
threads repeatedly look up a file in the directory. The bug is that
f2fs_mkdir() calls d_instantiate() before unlock_new_inode(), resulting
in the directory inode being exposed to lookups before it has been fully
initialized. And with CONFIG_DEBUG_LOCK_ALLOC, unlock_new_inode()
reinitializes ->i_rwsem, corrupting its state when it is already held.
Fix it by calling unlock_new_inode() before d_instantiate(). This
matches what other filesystems do.
Fixes: 57397d86c6 ("f2fs: add inode operations for special inodes")
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
committed by
Jaegeuk Kim
parent
c18b4f60c8
commit
dafecc032e
@@ -294,8 +294,8 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|||||||
|
|
||||||
alloc_nid_done(sbi, ino);
|
alloc_nid_done(sbi, ino);
|
||||||
|
|
||||||
d_instantiate(dentry, inode);
|
|
||||||
unlock_new_inode(inode);
|
unlock_new_inode(inode);
|
||||||
|
d_instantiate(dentry, inode);
|
||||||
|
|
||||||
if (IS_DIRSYNC(dir))
|
if (IS_DIRSYNC(dir))
|
||||||
f2fs_sync_fs(sbi->sb, 1);
|
f2fs_sync_fs(sbi->sb, 1);
|
||||||
@@ -594,8 +594,8 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
|
|||||||
err = page_symlink(inode, disk_link.name, disk_link.len);
|
err = page_symlink(inode, disk_link.name, disk_link.len);
|
||||||
|
|
||||||
err_out:
|
err_out:
|
||||||
d_instantiate(dentry, inode);
|
|
||||||
unlock_new_inode(inode);
|
unlock_new_inode(inode);
|
||||||
|
d_instantiate(dentry, inode);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Let's flush symlink data in order to avoid broken symlink as much as
|
* Let's flush symlink data in order to avoid broken symlink as much as
|
||||||
@@ -658,8 +658,8 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|||||||
|
|
||||||
alloc_nid_done(sbi, inode->i_ino);
|
alloc_nid_done(sbi, inode->i_ino);
|
||||||
|
|
||||||
d_instantiate(dentry, inode);
|
|
||||||
unlock_new_inode(inode);
|
unlock_new_inode(inode);
|
||||||
|
d_instantiate(dentry, inode);
|
||||||
|
|
||||||
if (IS_DIRSYNC(dir))
|
if (IS_DIRSYNC(dir))
|
||||||
f2fs_sync_fs(sbi->sb, 1);
|
f2fs_sync_fs(sbi->sb, 1);
|
||||||
@@ -710,8 +710,8 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
|
|||||||
|
|
||||||
alloc_nid_done(sbi, inode->i_ino);
|
alloc_nid_done(sbi, inode->i_ino);
|
||||||
|
|
||||||
d_instantiate(dentry, inode);
|
|
||||||
unlock_new_inode(inode);
|
unlock_new_inode(inode);
|
||||||
|
d_instantiate(dentry, inode);
|
||||||
|
|
||||||
if (IS_DIRSYNC(dir))
|
if (IS_DIRSYNC(dir))
|
||||||
f2fs_sync_fs(sbi->sb, 1);
|
f2fs_sync_fs(sbi->sb, 1);
|
||||||
|
|||||||
Reference in New Issue
Block a user