mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 22:52:35 +02:00
f2fs: fix lock dependency in between dio_rwsem & i_mmap_sem
test/generic/208 reports a potential deadlock as below:
Chain exists of:
&mm->mmap_sem --> &fi->i_mmap_sem --> &fi->dio_rwsem[WRITE]
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(&fi->dio_rwsem[WRITE]);
lock(&fi->i_mmap_sem);
lock(&fi->dio_rwsem[WRITE]);
lock(&mm->mmap_sem);
This patch changes the lock dependency as below in fallocate() to
fix this issue:
- dio_rwsem
- i_mmap_sem
Fixes: bb06664a53 ("f2fs: avoid race in between GC and block exchange")
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
e5c7c86010
commit
e1f9be2f7c
|
|
@ -1170,14 +1170,14 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
|
||||||
pg_start = offset >> PAGE_SHIFT;
|
pg_start = offset >> PAGE_SHIFT;
|
||||||
pg_end = (offset + len) >> PAGE_SHIFT;
|
pg_end = (offset + len) >> PAGE_SHIFT;
|
||||||
|
|
||||||
|
/* avoid gc operation during block exchange */
|
||||||
|
down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
||||||
|
|
||||||
down_write(&F2FS_I(inode)->i_mmap_sem);
|
down_write(&F2FS_I(inode)->i_mmap_sem);
|
||||||
/* write out all dirty pages from offset */
|
/* write out all dirty pages from offset */
|
||||||
ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
|
ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out_unlock;
|
||||||
|
|
||||||
/* avoid gc operation during block exchange */
|
|
||||||
down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
|
||||||
|
|
||||||
truncate_pagecache(inode, offset);
|
truncate_pagecache(inode, offset);
|
||||||
|
|
||||||
|
|
@ -1196,9 +1196,8 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
|
||||||
if (!ret)
|
if (!ret)
|
||||||
f2fs_i_size_write(inode, new_size);
|
f2fs_i_size_write(inode, new_size);
|
||||||
out_unlock:
|
out_unlock:
|
||||||
up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
|
||||||
out:
|
|
||||||
up_write(&F2FS_I(inode)->i_mmap_sem);
|
up_write(&F2FS_I(inode)->i_mmap_sem);
|
||||||
|
up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1369,6 +1368,9 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
|
||||||
|
|
||||||
f2fs_balance_fs(sbi, true);
|
f2fs_balance_fs(sbi, true);
|
||||||
|
|
||||||
|
/* avoid gc operation during block exchange */
|
||||||
|
down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
||||||
|
|
||||||
down_write(&F2FS_I(inode)->i_mmap_sem);
|
down_write(&F2FS_I(inode)->i_mmap_sem);
|
||||||
ret = truncate_blocks(inode, i_size_read(inode), true);
|
ret = truncate_blocks(inode, i_size_read(inode), true);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
@ -1379,9 +1381,6 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* avoid gc operation during block exchange */
|
|
||||||
down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
|
||||||
|
|
||||||
truncate_pagecache(inode, offset);
|
truncate_pagecache(inode, offset);
|
||||||
|
|
||||||
pg_start = offset >> PAGE_SHIFT;
|
pg_start = offset >> PAGE_SHIFT;
|
||||||
|
|
@ -1409,10 +1408,9 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
f2fs_i_size_write(inode, new_size);
|
f2fs_i_size_write(inode, new_size);
|
||||||
|
|
||||||
up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
|
||||||
out:
|
out:
|
||||||
up_write(&F2FS_I(inode)->i_mmap_sem);
|
up_write(&F2FS_I(inode)->i_mmap_sem);
|
||||||
|
up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user