]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.4.172/f2fs-cover-more-area-with-nat_tree_lock.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.4.172 / f2fs-cover-more-area-with-nat_tree_lock.patch
CommitLineData
c2a518a0
GKH
1From foo@baz Fri Jan 18 09:16:11 CET 2019
2From: Jaegeuk Kim <jaegeuk@kernel.org>
3Date: Sat, 2 Jan 2016 09:19:41 -0800
4Subject: f2fs: cover more area with nat_tree_lock
5
6From: Jaegeuk Kim <jaegeuk@kernel.org>
7
8commit a51311938e14c17f5a94d30baac9d7bec71f5858 upstream.
9
10There was a subtle bug on nat cache management which incurs wrong nid allocation
11or wrong block addresses when try_to_free_nats is triggered heavily.
12This patch enlarges the previous coverage of nat_tree_lock to avoid data race.
13
14Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
15Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
16Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
17---
18 fs/f2fs/node.c | 29 ++++++++++++-----------------
19 1 file changed, 12 insertions(+), 17 deletions(-)
20
21--- a/fs/f2fs/node.c
22+++ b/fs/f2fs/node.c
23@@ -261,13 +261,11 @@ static void cache_nat_entry(struct f2fs_
24 {
25 struct nat_entry *e;
26
27- down_write(&nm_i->nat_tree_lock);
28 e = __lookup_nat_cache(nm_i, nid);
29 if (!e) {
30 e = grab_nat_entry(nm_i, nid);
31 node_info_from_raw_nat(&e->ni, ne);
32 }
33- up_write(&nm_i->nat_tree_lock);
34 }
35
36 static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
37@@ -379,6 +377,8 @@ void get_node_info(struct f2fs_sb_info *
38
39 memset(&ne, 0, sizeof(struct f2fs_nat_entry));
40
41+ down_write(&nm_i->nat_tree_lock);
42+
43 /* Check current segment summary */
44 mutex_lock(&curseg->curseg_mutex);
45 i = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 0);
46@@ -399,6 +399,7 @@ void get_node_info(struct f2fs_sb_info *
47 cache:
48 /* cache nat entry */
49 cache_nat_entry(NM_I(sbi), nid, &ne);
50+ up_write(&nm_i->nat_tree_lock);
51 }
52
53 /*
54@@ -1440,13 +1441,10 @@ static int add_free_nid(struct f2fs_sb_i
55
56 if (build) {
57 /* do not add allocated nids */
58- down_read(&nm_i->nat_tree_lock);
59 ne = __lookup_nat_cache(nm_i, nid);
60- if (ne &&
61- (!get_nat_flag(ne, IS_CHECKPOINTED) ||
62+ if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) ||
63 nat_get_blkaddr(ne) != NULL_ADDR))
64 allocated = true;
65- up_read(&nm_i->nat_tree_lock);
66 if (allocated)
67 return 0;
68 }
69@@ -1532,6 +1530,8 @@ static void build_free_nids(struct f2fs_
70 ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), FREE_NID_PAGES,
71 META_NAT, true);
72
73+ down_read(&nm_i->nat_tree_lock);
74+
75 while (1) {
76 struct page *page = get_current_nat_page(sbi, nid);
77
78@@ -1560,6 +1560,7 @@ static void build_free_nids(struct f2fs_
79 remove_free_nid(nm_i, nid);
80 }
81 mutex_unlock(&curseg->curseg_mutex);
82+ up_read(&nm_i->nat_tree_lock);
83
84 ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nm_i->next_scan_nid),
85 nm_i->ra_nid_pages, META_NAT, false);
86@@ -1842,14 +1843,12 @@ static void remove_nats_in_journal(struc
87
88 raw_ne = nat_in_journal(sum, i);
89
90- down_write(&nm_i->nat_tree_lock);
91 ne = __lookup_nat_cache(nm_i, nid);
92 if (!ne) {
93 ne = grab_nat_entry(nm_i, nid);
94 node_info_from_raw_nat(&ne->ni, &raw_ne);
95 }
96 __set_nat_cache_dirty(nm_i, ne);
97- up_write(&nm_i->nat_tree_lock);
98 }
99 update_nats_in_cursum(sum, -i);
100 mutex_unlock(&curseg->curseg_mutex);
101@@ -1883,7 +1882,6 @@ static void __flush_nat_entry_set(struct
102 struct f2fs_nat_block *nat_blk;
103 struct nat_entry *ne, *cur;
104 struct page *page = NULL;
105- struct f2fs_nm_info *nm_i = NM_I(sbi);
106
107 /*
108 * there are two steps to flush nat entries:
109@@ -1920,12 +1918,8 @@ static void __flush_nat_entry_set(struct
110 raw_ne = &nat_blk->entries[nid - start_nid];
111 }
112 raw_nat_from_node_info(raw_ne, &ne->ni);
113-
114- down_write(&NM_I(sbi)->nat_tree_lock);
115 nat_reset_flag(ne);
116 __clear_nat_cache_dirty(NM_I(sbi), ne);
117- up_write(&NM_I(sbi)->nat_tree_lock);
118-
119 if (nat_get_blkaddr(ne) == NULL_ADDR)
120 add_free_nid(sbi, nid, false);
121 }
122@@ -1937,9 +1931,7 @@ static void __flush_nat_entry_set(struct
123
124 f2fs_bug_on(sbi, set->entry_cnt);
125
126- down_write(&nm_i->nat_tree_lock);
127 radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set);
128- up_write(&nm_i->nat_tree_lock);
129 kmem_cache_free(nat_entry_set_slab, set);
130 }
131
132@@ -1959,6 +1951,9 @@ void flush_nat_entries(struct f2fs_sb_in
133
134 if (!nm_i->dirty_nat_cnt)
135 return;
136+
137+ down_write(&nm_i->nat_tree_lock);
138+
139 /*
140 * if there are no enough space in journal to store dirty nat
141 * entries, remove all entries from journal and merge them
142@@ -1967,7 +1962,6 @@ void flush_nat_entries(struct f2fs_sb_in
143 if (!__has_cursum_space(sum, nm_i->dirty_nat_cnt, NAT_JOURNAL))
144 remove_nats_in_journal(sbi);
145
146- down_write(&nm_i->nat_tree_lock);
147 while ((found = __gang_lookup_nat_set(nm_i,
148 set_idx, SETVEC_SIZE, setvec))) {
149 unsigned idx;
150@@ -1976,12 +1970,13 @@ void flush_nat_entries(struct f2fs_sb_in
151 __adjust_nat_entry_set(setvec[idx], &sets,
152 MAX_NAT_JENTRIES(sum));
153 }
154- up_write(&nm_i->nat_tree_lock);
155
156 /* flush dirty nats in nat entry set */
157 list_for_each_entry_safe(set, tmp, &sets, set_list)
158 __flush_nat_entry_set(sbi, set);
159
160+ up_write(&nm_i->nat_tree_lock);
161+
162 f2fs_bug_on(sbi, nm_i->dirty_nat_cnt);
163 }
164