]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.4.172/f2fs-fix-to-convert-inline-directory-correctly.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.4.172 / f2fs-fix-to-convert-inline-directory-correctly.patch
CommitLineData
c2a518a0
GKH
1From foo@baz Fri Jan 18 09:16:11 CET 2019
2From: Chao Yu <chao2.yu@samsung.com>
3Date: Mon, 22 Feb 2016 18:29:18 +0800
4Subject: f2fs: fix to convert inline directory correctly
5
6From: Chao Yu <chao2.yu@samsung.com>
7
8With below serials, we will lose parts of dirents:
9
101) mount f2fs with inline_dentry option
112) echo 1 > /sys/fs/f2fs/sdX/dir_level
123) mkdir dir
134) touch 180 files named [1-180] in dir
145) touch 181 in dir
156) echo 3 > /proc/sys/vm/drop_caches
167) ll dir
17
18ls: cannot access 2: No such file or directory
19ls: cannot access 4: No such file or directory
20ls: cannot access 5: No such file or directory
21ls: cannot access 6: No such file or directory
22ls: cannot access 8: No such file or directory
23ls: cannot access 9: No such file or directory
24...
25total 360
26drwxr-xr-x 2 root root 4096 Feb 19 15:12 ./
27drwxr-xr-x 3 root root 4096 Feb 19 15:11 ../
28-rw-r--r-- 1 root root 0 Feb 19 15:12 1
29-rw-r--r-- 1 root root 0 Feb 19 15:12 10
30-rw-r--r-- 1 root root 0 Feb 19 15:12 100
31-????????? ? ? ? ? ? 101
32-????????? ? ? ? ? ? 102
33-????????? ? ? ? ? ? 103
34...
35
36The reason is: when doing the inline dir conversion, we didn't consider
37that directory has hierarchical hash structure which can be configured
38through sysfs interface 'dir_level'.
39
40By default, dir_level of directory inode is 0, it means we have one bucket
41in hash table located in first level, all dirents will be hashed in this
42bucket, so it has no problem for us to do the duplication simply between
43inline dentry page and converted normal dentry page.
44
45However, if we configured dir_level with the value N (greater than 0), it
46will expand the bucket number of first level hash table by 2^N - 1, it
47hashs dirents into different buckets according their hash value, if we
48still move all dirents to first bucket, it makes incorrent locating for
49inline dirents, the result is, although we can iterate all dirents through
50->readdir, we can't stat some of them in ->lookup which based on hash
51table searching.
52
53This patch fixes this issue by rehashing dirents into correct position
54when converting inline directory.
55
56Signed-off-by: Chao Yu <chao2.yu@samsung.com>
57Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
58[bwh: Backported to 4.4:
59 - Keep using f2fs_crypto functions instead of generic fscrypt API
60 - Use remove_dirty_dir_inode() instead of remove_dirty_inode()
61 - Adjust context]
62Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
63Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
64---
65 fs/f2fs/dir.c | 87 +++++++++++++++++++++++---------------------
66 fs/f2fs/f2fs.h | 4 +-
67 fs/f2fs/inline.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++-
68 include/linux/f2fs_fs.h | 2 +
69 4 files changed, 144 insertions(+), 43 deletions(-)
70
71--- a/fs/f2fs/dir.c
72+++ b/fs/f2fs/dir.c
73@@ -48,7 +48,6 @@ unsigned char f2fs_filetype_table[F2FS_F
74 [F2FS_FT_SYMLINK] = DT_LNK,
75 };
76
77-#define S_SHIFT 12
78 static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = {
79 [S_IFREG >> S_SHIFT] = F2FS_FT_REG_FILE,
80 [S_IFDIR >> S_SHIFT] = F2FS_FT_DIR,
81@@ -64,6 +63,13 @@ void set_de_type(struct f2fs_dir_entry *
82 de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT];
83 }
84
85+unsigned char get_de_type(struct f2fs_dir_entry *de)
86+{
87+ if (de->file_type < F2FS_FT_MAX)
88+ return f2fs_filetype_table[de->file_type];
89+ return DT_UNKNOWN;
90+}
91+
92 static unsigned long dir_block_index(unsigned int level,
93 int dir_level, unsigned int idx)
94 {
95@@ -519,11 +525,7 @@ void f2fs_update_dentry(nid_t ino, umode
96 test_and_set_bit_le(bit_pos + i, (void *)d->bitmap);
97 }
98
99-/*
100- * Caller should grab and release a rwsem by calling f2fs_lock_op() and
101- * f2fs_unlock_op().
102- */
103-int __f2fs_add_link(struct inode *dir, const struct qstr *name,
104+int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
105 struct inode *inode, nid_t ino, umode_t mode)
106 {
107 unsigned int bit_pos;
108@@ -536,28 +538,11 @@ int __f2fs_add_link(struct inode *dir, c
109 struct f2fs_dentry_block *dentry_blk = NULL;
110 struct f2fs_dentry_ptr d;
111 struct page *page = NULL;
112- struct f2fs_filename fname;
113- struct qstr new_name;
114- int slots, err;
115-
116- err = f2fs_fname_setup_filename(dir, name, 0, &fname);
117- if (err)
118- return err;
119-
120- new_name.name = fname_name(&fname);
121- new_name.len = fname_len(&fname);
122-
123- if (f2fs_has_inline_dentry(dir)) {
124- err = f2fs_add_inline_entry(dir, &new_name, inode, ino, mode);
125- if (!err || err != -EAGAIN)
126- goto out;
127- else
128- err = 0;
129- }
130+ int slots, err = 0;
131
132 level = 0;
133- slots = GET_DENTRY_SLOTS(new_name.len);
134- dentry_hash = f2fs_dentry_hash(&new_name, NULL);
135+ slots = GET_DENTRY_SLOTS(new_name->len);
136+ dentry_hash = f2fs_dentry_hash(new_name, NULL);
137
138 current_depth = F2FS_I(dir)->i_current_depth;
139 if (F2FS_I(dir)->chash == dentry_hash) {
140@@ -566,10 +551,8 @@ int __f2fs_add_link(struct inode *dir, c
141 }
142
143 start:
144- if (unlikely(current_depth == MAX_DIR_HASH_DEPTH)) {
145- err = -ENOSPC;
146- goto out;
147- }
148+ if (unlikely(current_depth == MAX_DIR_HASH_DEPTH))
149+ return -ENOSPC;
150
151 /* Increase the depth, if required */
152 if (level == current_depth)
153@@ -583,10 +566,8 @@ start:
154
155 for (block = bidx; block <= (bidx + nblock - 1); block++) {
156 dentry_page = get_new_data_page(dir, NULL, block, true);
157- if (IS_ERR(dentry_page)) {
158- err = PTR_ERR(dentry_page);
159- goto out;
160- }
161+ if (IS_ERR(dentry_page))
162+ return PTR_ERR(dentry_page);
163
164 dentry_blk = kmap(dentry_page);
165 bit_pos = room_for_filename(&dentry_blk->dentry_bitmap,
166@@ -606,7 +587,7 @@ add_dentry:
167
168 if (inode) {
169 down_write(&F2FS_I(inode)->i_sem);
170- page = init_inode_metadata(inode, dir, &new_name, NULL);
171+ page = init_inode_metadata(inode, dir, new_name, NULL);
172 if (IS_ERR(page)) {
173 err = PTR_ERR(page);
174 goto fail;
175@@ -616,7 +597,7 @@ add_dentry:
176 }
177
178 make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1);
179- f2fs_update_dentry(ino, mode, &d, &new_name, dentry_hash, bit_pos);
180+ f2fs_update_dentry(ino, mode, &d, new_name, dentry_hash, bit_pos);
181
182 set_page_dirty(dentry_page);
183
184@@ -638,7 +619,34 @@ fail:
185 }
186 kunmap(dentry_page);
187 f2fs_put_page(dentry_page, 1);
188-out:
189+
190+ return err;
191+}
192+
193+/*
194+ * Caller should grab and release a rwsem by calling f2fs_lock_op() and
195+ * f2fs_unlock_op().
196+ */
197+int __f2fs_add_link(struct inode *dir, const struct qstr *name,
198+ struct inode *inode, nid_t ino, umode_t mode)
199+{
200+ struct f2fs_filename fname;
201+ struct qstr new_name;
202+ int err;
203+
204+ err = f2fs_fname_setup_filename(dir, name, 0, &fname);
205+ if (err)
206+ return err;
207+
208+ new_name.name = fname_name(&fname);
209+ new_name.len = fname_len(&fname);
210+
211+ err = -EAGAIN;
212+ if (f2fs_has_inline_dentry(dir))
213+ err = f2fs_add_inline_entry(dir, &new_name, inode, ino, mode);
214+ if (err == -EAGAIN)
215+ err = f2fs_add_regular_entry(dir, &new_name, inode, ino, mode);
216+
217 f2fs_fname_free_filename(&fname);
218 return err;
219 }
220@@ -792,10 +800,7 @@ bool f2fs_fill_dentries(struct dir_conte
221 break;
222
223 de = &d->dentry[bit_pos];
224- if (de->file_type < F2FS_FT_MAX)
225- d_type = f2fs_filetype_table[de->file_type];
226- else
227- d_type = DT_UNKNOWN;
228+ d_type = get_de_type(de);
229
230 de_name.name = d->filename[bit_pos];
231 de_name.len = le16_to_cpu(de->name_len);
232--- a/fs/f2fs/f2fs.h
233+++ b/fs/f2fs/f2fs.h
234@@ -1677,7 +1677,7 @@ struct dentry *f2fs_get_parent(struct de
235 */
236 extern unsigned char f2fs_filetype_table[F2FS_FT_MAX];
237 void set_de_type(struct f2fs_dir_entry *, umode_t);
238-
239+unsigned char get_de_type(struct f2fs_dir_entry *);
240 struct f2fs_dir_entry *find_target_dentry(struct f2fs_filename *,
241 f2fs_hash_t, int *, struct f2fs_dentry_ptr *);
242 bool f2fs_fill_dentries(struct dir_context *, struct f2fs_dentry_ptr *,
243@@ -1698,6 +1698,8 @@ void f2fs_set_link(struct inode *, struc
244 int update_dent_inode(struct inode *, struct inode *, const struct qstr *);
245 void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *,
246 const struct qstr *, f2fs_hash_t , unsigned int);
247+int f2fs_add_regular_entry(struct inode *, const struct qstr *,
248+ struct inode *, nid_t, umode_t);
249 int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *, nid_t,
250 umode_t);
251 void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *,
252--- a/fs/f2fs/inline.c
253+++ b/fs/f2fs/inline.c
254@@ -367,7 +367,7 @@ int make_empty_inline_dir(struct inode *
255 * NOTE: ipage is grabbed by caller, but if any error occurs, we should
256 * release ipage in this function.
257 */
258-static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
259+static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage,
260 struct f2fs_inline_dentry *inline_dentry)
261 {
262 struct page *page;
263@@ -428,6 +428,98 @@ out:
264 return err;
265 }
266
267+static int f2fs_add_inline_entries(struct inode *dir,
268+ struct f2fs_inline_dentry *inline_dentry)
269+{
270+ struct f2fs_dentry_ptr d;
271+ unsigned long bit_pos = 0;
272+ int err = 0;
273+
274+ make_dentry_ptr(NULL, &d, (void *)inline_dentry, 2);
275+
276+ while (bit_pos < d.max) {
277+ struct f2fs_dir_entry *de;
278+ struct qstr new_name;
279+ nid_t ino;
280+ umode_t fake_mode;
281+
282+ if (!test_bit_le(bit_pos, d.bitmap)) {
283+ bit_pos++;
284+ continue;
285+ }
286+
287+ de = &d.dentry[bit_pos];
288+ new_name.name = d.filename[bit_pos];
289+ new_name.len = de->name_len;
290+
291+ ino = le32_to_cpu(de->ino);
292+ fake_mode = get_de_type(de) << S_SHIFT;
293+
294+ err = f2fs_add_regular_entry(dir, &new_name, NULL,
295+ ino, fake_mode);
296+ if (err)
297+ goto punch_dentry_pages;
298+
299+ if (unlikely(!de->name_len))
300+ d.max = -1;
301+
302+ bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
303+ }
304+ return 0;
305+punch_dentry_pages:
306+ truncate_inode_pages(&dir->i_data, 0);
307+ truncate_blocks(dir, 0, false);
308+ remove_dirty_dir_inode(dir);
309+ return err;
310+}
311+
312+static int f2fs_move_rehashed_dirents(struct inode *dir, struct page *ipage,
313+ struct f2fs_inline_dentry *inline_dentry)
314+{
315+ struct f2fs_inline_dentry *backup_dentry;
316+ int err;
317+
318+ backup_dentry = kmalloc(sizeof(struct f2fs_inline_dentry),
319+ GFP_F2FS_ZERO);
320+ if (!backup_dentry)
321+ return -ENOMEM;
322+
323+ memcpy(backup_dentry, inline_dentry, MAX_INLINE_DATA);
324+ truncate_inline_inode(ipage, 0);
325+
326+ unlock_page(ipage);
327+
328+ err = f2fs_add_inline_entries(dir, backup_dentry);
329+ if (err)
330+ goto recover;
331+
332+ lock_page(ipage);
333+
334+ stat_dec_inline_dir(dir);
335+ clear_inode_flag(F2FS_I(dir), FI_INLINE_DENTRY);
336+ update_inode(dir, ipage);
337+ kfree(backup_dentry);
338+ return 0;
339+recover:
340+ lock_page(ipage);
341+ memcpy(inline_dentry, backup_dentry, MAX_INLINE_DATA);
342+ i_size_write(dir, MAX_INLINE_DATA);
343+ update_inode(dir, ipage);
344+ f2fs_put_page(ipage, 1);
345+
346+ kfree(backup_dentry);
347+ return err;
348+}
349+
350+static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
351+ struct f2fs_inline_dentry *inline_dentry)
352+{
353+ if (!F2FS_I(dir)->i_dir_level)
354+ return f2fs_move_inline_dirents(dir, ipage, inline_dentry);
355+ else
356+ return f2fs_move_rehashed_dirents(dir, ipage, inline_dentry);
357+}
358+
359 int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name,
360 struct inode *inode, nid_t ino, umode_t mode)
361 {
362--- a/include/linux/f2fs_fs.h
363+++ b/include/linux/f2fs_fs.h
364@@ -497,4 +497,6 @@ enum {
365 F2FS_FT_MAX
366 };
367
368+#define S_SHIFT 12
369+
370 #endif /* _LINUX_F2FS_FS_H */