Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6f2915eb authored by Chao Yu's avatar Chao Yu Committed by Jaegeuk Kim
Browse files

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: bb06664a534b ("f2fs: avoid race in between GC and block exchange")
Signed-off-by: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 8c3b1444
Loading
Loading
Loading
Loading
+9 −11
Original line number Diff line number Diff line
@@ -1168,14 +1168,14 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
	pg_start = offset >> 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);
	/* write out all dirty pages from offset */
	ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
	if (ret)
		goto out;

	/* avoid gc operation during block exchange */
	down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
		goto out_unlock;

	truncate_pagecache(inode, offset);

@@ -1194,9 +1194,8 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
	if (!ret)
		f2fs_i_size_write(inode, new_size);
out_unlock:
	up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
out:
	up_write(&F2FS_I(inode)->i_mmap_sem);
	up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
	return ret;
}

@@ -1367,6 +1366,9 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)

	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);
	ret = truncate_blocks(inode, i_size_read(inode), true);
	if (ret)
@@ -1377,9 +1379,6 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
	if (ret)
		goto out;

	/* avoid gc operation during block exchange */
	down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);

	truncate_pagecache(inode, offset);

	pg_start = offset >> PAGE_SHIFT;
@@ -1407,10 +1406,9 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)

	if (!ret)
		f2fs_i_size_write(inode, new_size);

	up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
out:
	up_write(&F2FS_I(inode)->i_mmap_sem);
	up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
	return ret;
}