]>
Commit | Line | Data |
---|---|---|
72fc6108 GKH |
1 | From foo@baz Mon Apr 9 10:16:32 CEST 2018 |
2 | From: Chao Yu <yuchao0@huawei.com> | |
3 | Date: Thu, 23 Nov 2017 23:26:52 +0800 | |
4 | Subject: f2fs: fix lock dependency in between dio_rwsem & i_mmap_sem | |
5 | ||
6 | From: Chao Yu <yuchao0@huawei.com> | |
7 | ||
8 | ||
9 | [ Upstream commit 21020812c9e1ab593367fad9ce579f842a0b406d ] | |
10 | ||
11 | test/generic/208 reports a potential deadlock as below: | |
12 | ||
13 | Chain exists of: | |
14 | &mm->mmap_sem --> &fi->i_mmap_sem --> &fi->dio_rwsem[WRITE] | |
15 | ||
16 | Possible unsafe locking scenario: | |
17 | ||
18 | CPU0 CPU1 | |
19 | ---- ---- | |
20 | lock(&fi->dio_rwsem[WRITE]); | |
21 | lock(&fi->i_mmap_sem); | |
22 | lock(&fi->dio_rwsem[WRITE]); | |
23 | lock(&mm->mmap_sem); | |
24 | ||
25 | This patch changes the lock dependency as below in fallocate() to | |
26 | fix this issue: | |
27 | - dio_rwsem | |
28 | - i_mmap_sem | |
29 | ||
30 | Fixes: bb06664a534b ("f2fs: avoid race in between GC and block exchange") | |
31 | Signed-off-by: Chao Yu <yuchao0@huawei.com> | |
32 | Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> | |
33 | Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> | |
34 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
35 | --- | |
36 | fs/f2fs/file.c | 20 +++++++++----------- | |
37 | 1 file changed, 9 insertions(+), 11 deletions(-) | |
38 | ||
39 | --- a/fs/f2fs/file.c | |
40 | +++ b/fs/f2fs/file.c | |
41 | @@ -1186,14 +1186,14 @@ static int f2fs_collapse_range(struct in | |
42 | pg_start = offset >> PAGE_SHIFT; | |
43 | pg_end = (offset + len) >> PAGE_SHIFT; | |
44 | ||
45 | + /* avoid gc operation during block exchange */ | |
46 | + down_write(&F2FS_I(inode)->dio_rwsem[WRITE]); | |
47 | + | |
48 | down_write(&F2FS_I(inode)->i_mmap_sem); | |
49 | /* write out all dirty pages from offset */ | |
50 | ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX); | |
51 | if (ret) | |
52 | - goto out; | |
53 | - | |
54 | - /* avoid gc operation during block exchange */ | |
55 | - down_write(&F2FS_I(inode)->dio_rwsem[WRITE]); | |
56 | + goto out_unlock; | |
57 | ||
58 | truncate_pagecache(inode, offset); | |
59 | ||
60 | @@ -1212,9 +1212,8 @@ static int f2fs_collapse_range(struct in | |
61 | if (!ret) | |
62 | f2fs_i_size_write(inode, new_size); | |
63 | out_unlock: | |
64 | - up_write(&F2FS_I(inode)->dio_rwsem[WRITE]); | |
65 | -out: | |
66 | up_write(&F2FS_I(inode)->i_mmap_sem); | |
67 | + up_write(&F2FS_I(inode)->dio_rwsem[WRITE]); | |
68 | return ret; | |
69 | } | |
70 | ||
71 | @@ -1385,6 +1384,9 @@ static int f2fs_insert_range(struct inod | |
72 | ||
73 | f2fs_balance_fs(sbi, true); | |
74 | ||
75 | + /* avoid gc operation during block exchange */ | |
76 | + down_write(&F2FS_I(inode)->dio_rwsem[WRITE]); | |
77 | + | |
78 | down_write(&F2FS_I(inode)->i_mmap_sem); | |
79 | ret = truncate_blocks(inode, i_size_read(inode), true); | |
80 | if (ret) | |
81 | @@ -1395,9 +1397,6 @@ static int f2fs_insert_range(struct inod | |
82 | if (ret) | |
83 | goto out; | |
84 | ||
85 | - /* avoid gc operation during block exchange */ | |
86 | - down_write(&F2FS_I(inode)->dio_rwsem[WRITE]); | |
87 | - | |
88 | truncate_pagecache(inode, offset); | |
89 | ||
90 | pg_start = offset >> PAGE_SHIFT; | |
91 | @@ -1425,10 +1424,9 @@ static int f2fs_insert_range(struct inod | |
92 | ||
93 | if (!ret) | |
94 | f2fs_i_size_write(inode, new_size); | |
95 | - | |
96 | - up_write(&F2FS_I(inode)->dio_rwsem[WRITE]); | |
97 | out: | |
98 | up_write(&F2FS_I(inode)->i_mmap_sem); | |
99 | + up_write(&F2FS_I(inode)->dio_rwsem[WRITE]); | |
100 | return ret; | |
101 | } | |
102 |