4.15-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Chao Yu <[email protected]>


[ Upstream commit 21020812c9e1ab593367fad9ce579f842a0b406d ]

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: Chao Yu <[email protected]>
Signed-off-by: Jaegeuk Kim <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
 fs/f2fs/file.c |   20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -1186,14 +1186,14 @@ static int f2fs_collapse_range(struct in
        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);
 
@@ -1212,9 +1212,8 @@ static int f2fs_collapse_range(struct in
        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;
 }
 
@@ -1385,6 +1384,9 @@ static int f2fs_insert_range(struct inod
 
        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)
@@ -1395,9 +1397,6 @@ static int f2fs_insert_range(struct inod
        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;
@@ -1425,10 +1424,9 @@ static int f2fs_insert_range(struct inod
 
        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;
 }
 


Reply via email to