diff options
author | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2012-11-14 02:59:04 -0500 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2012-12-10 23:43:41 -0500 |
commit | 6b4ea0160ae236a6561defa28e19f973aedda9ff (patch) | |
tree | 822167900515dd00ff27e759a2264b6395636517 /fs/f2fs | |
parent | 57397d86c62dfee7bf1d60c9960201c78a9c4ec2 (diff) |
f2fs: add core directory operations
this adds core functions to find, add, delete, and link dentries.
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs')
-rw-r--r-- | fs/f2fs/dir.c | 672 | ||||
-rw-r--r-- | fs/f2fs/hash.c | 98 |
2 files changed, 770 insertions, 0 deletions
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c new file mode 100644 index 000000000000..5975568d03df --- /dev/null +++ b/fs/f2fs/dir.c | |||
@@ -0,0 +1,672 @@ | |||
1 | /** | ||
2 | * fs/f2fs/dir.c | ||
3 | * | ||
4 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com/ | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/fs.h> | ||
12 | #include <linux/f2fs_fs.h> | ||
13 | #include "f2fs.h" | ||
14 | #include "acl.h" | ||
15 | |||
16 | static unsigned long dir_blocks(struct inode *inode) | ||
17 | { | ||
18 | return ((unsigned long long) (i_size_read(inode) + PAGE_CACHE_SIZE - 1)) | ||
19 | >> PAGE_CACHE_SHIFT; | ||
20 | } | ||
21 | |||
22 | static unsigned int dir_buckets(unsigned int level) | ||
23 | { | ||
24 | if (level < MAX_DIR_HASH_DEPTH / 2) | ||
25 | return 1 << level; | ||
26 | else | ||
27 | return 1 << ((MAX_DIR_HASH_DEPTH / 2) - 1); | ||
28 | } | ||
29 | |||
30 | static unsigned int bucket_blocks(unsigned int level) | ||
31 | { | ||
32 | if (level < MAX_DIR_HASH_DEPTH / 2) | ||
33 | return 2; | ||
34 | else | ||
35 | return 4; | ||
36 | } | ||
37 | |||
38 | static unsigned char f2fs_filetype_table[F2FS_FT_MAX] = { | ||
39 | [F2FS_FT_UNKNOWN] = DT_UNKNOWN, | ||
40 | [F2FS_FT_REG_FILE] = DT_REG, | ||
41 | [F2FS_FT_DIR] = DT_DIR, | ||
42 | [F2FS_FT_CHRDEV] = DT_CHR, | ||
43 | [F2FS_FT_BLKDEV] = DT_BLK, | ||
44 | [F2FS_FT_FIFO] = DT_FIFO, | ||
45 | [F2FS_FT_SOCK] = DT_SOCK, | ||
46 | [F2FS_FT_SYMLINK] = DT_LNK, | ||
47 | }; | ||
48 | |||
49 | #define S_SHIFT 12 | ||
50 | static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = { | ||
51 | [S_IFREG >> S_SHIFT] = F2FS_FT_REG_FILE, | ||
52 | [S_IFDIR >> S_SHIFT] = F2FS_FT_DIR, | ||
53 | [S_IFCHR >> S_SHIFT] = F2FS_FT_CHRDEV, | ||
54 | [S_IFBLK >> S_SHIFT] = F2FS_FT_BLKDEV, | ||
55 | [S_IFIFO >> S_SHIFT] = F2FS_FT_FIFO, | ||
56 | [S_IFSOCK >> S_SHIFT] = F2FS_FT_SOCK, | ||
57 | [S_IFLNK >> S_SHIFT] = F2FS_FT_SYMLINK, | ||
58 | }; | ||
59 | |||
60 | static void set_de_type(struct f2fs_dir_entry *de, struct inode *inode) | ||
61 | { | ||
62 | mode_t mode = inode->i_mode; | ||
63 | de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT]; | ||
64 | } | ||
65 | |||
66 | static unsigned long dir_block_index(unsigned int level, unsigned int idx) | ||
67 | { | ||
68 | unsigned long i; | ||
69 | unsigned long bidx = 0; | ||
70 | |||
71 | for (i = 0; i < level; i++) | ||
72 | bidx += dir_buckets(i) * bucket_blocks(i); | ||
73 | bidx += idx * bucket_blocks(level); | ||
74 | return bidx; | ||
75 | } | ||
76 | |||
77 | static bool early_match_name(const char *name, int namelen, | ||
78 | f2fs_hash_t namehash, struct f2fs_dir_entry *de) | ||
79 | { | ||
80 | if (le16_to_cpu(de->name_len) != namelen) | ||
81 | return false; | ||
82 | |||
83 | if (le32_to_cpu(de->hash_code) != namehash) | ||
84 | return false; | ||
85 | |||
86 | return true; | ||
87 | } | ||
88 | |||
89 | static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, | ||
90 | const char *name, int namelen, int *max_slots, | ||
91 | f2fs_hash_t namehash, struct page **res_page) | ||
92 | { | ||
93 | struct f2fs_dir_entry *de; | ||
94 | unsigned long bit_pos, end_pos, next_pos; | ||
95 | struct f2fs_dentry_block *dentry_blk = kmap(dentry_page); | ||
96 | int slots; | ||
97 | |||
98 | bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, | ||
99 | NR_DENTRY_IN_BLOCK, 0); | ||
100 | while (bit_pos < NR_DENTRY_IN_BLOCK) { | ||
101 | de = &dentry_blk->dentry[bit_pos]; | ||
102 | slots = (le16_to_cpu(de->name_len) + F2FS_NAME_LEN - 1) / | ||
103 | F2FS_NAME_LEN; | ||
104 | |||
105 | if (early_match_name(name, namelen, namehash, de)) { | ||
106 | if (!memcmp(dentry_blk->filename[bit_pos], | ||
107 | name, namelen)) { | ||
108 | *res_page = dentry_page; | ||
109 | goto found; | ||
110 | } | ||
111 | } | ||
112 | next_pos = bit_pos + slots; | ||
113 | bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, | ||
114 | NR_DENTRY_IN_BLOCK, next_pos); | ||
115 | if (bit_pos >= NR_DENTRY_IN_BLOCK) | ||
116 | end_pos = NR_DENTRY_IN_BLOCK; | ||
117 | else | ||
118 | end_pos = bit_pos; | ||
119 | if (*max_slots < end_pos - next_pos) | ||
120 | *max_slots = end_pos - next_pos; | ||
121 | } | ||
122 | |||
123 | de = NULL; | ||
124 | kunmap(dentry_page); | ||
125 | found: | ||
126 | return de; | ||
127 | } | ||
128 | |||
129 | static struct f2fs_dir_entry *find_in_level(struct inode *dir, | ||
130 | unsigned int level, const char *name, int namelen, | ||
131 | f2fs_hash_t namehash, struct page **res_page) | ||
132 | { | ||
133 | int s = (namelen + F2FS_NAME_LEN - 1) / F2FS_NAME_LEN; | ||
134 | unsigned int nbucket, nblock; | ||
135 | unsigned int bidx, end_block; | ||
136 | struct page *dentry_page; | ||
137 | struct f2fs_dir_entry *de = NULL; | ||
138 | bool room = false; | ||
139 | int max_slots = 0; | ||
140 | |||
141 | BUG_ON(level > MAX_DIR_HASH_DEPTH); | ||
142 | |||
143 | nbucket = dir_buckets(level); | ||
144 | nblock = bucket_blocks(level); | ||
145 | |||
146 | bidx = dir_block_index(level, namehash % nbucket); | ||
147 | end_block = bidx + nblock; | ||
148 | |||
149 | for (; bidx < end_block; bidx++) { | ||
150 | /* no need to allocate new dentry pages to all the indices */ | ||
151 | dentry_page = find_data_page(dir, bidx); | ||
152 | if (IS_ERR(dentry_page)) { | ||
153 | room = true; | ||
154 | continue; | ||
155 | } | ||
156 | |||
157 | de = find_in_block(dentry_page, name, namelen, | ||
158 | &max_slots, namehash, res_page); | ||
159 | if (de) | ||
160 | break; | ||
161 | |||
162 | if (max_slots >= s) | ||
163 | room = true; | ||
164 | f2fs_put_page(dentry_page, 0); | ||
165 | } | ||
166 | |||
167 | if (!de && room && F2FS_I(dir)->chash != namehash) { | ||
168 | F2FS_I(dir)->chash = namehash; | ||
169 | F2FS_I(dir)->clevel = level; | ||
170 | } | ||
171 | |||
172 | return de; | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * Find an entry in the specified directory with the wanted name. | ||
177 | * It returns the page where the entry was found (as a parameter - res_page), | ||
178 | * and the entry itself. Page is returned mapped and unlocked. | ||
179 | * Entry is guaranteed to be valid. | ||
180 | */ | ||
181 | struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir, | ||
182 | struct qstr *child, struct page **res_page) | ||
183 | { | ||
184 | const char *name = child->name; | ||
185 | int namelen = child->len; | ||
186 | unsigned long npages = dir_blocks(dir); | ||
187 | struct f2fs_dir_entry *de = NULL; | ||
188 | f2fs_hash_t name_hash; | ||
189 | unsigned int max_depth; | ||
190 | unsigned int level; | ||
191 | |||
192 | if (npages == 0) | ||
193 | return NULL; | ||
194 | |||
195 | *res_page = NULL; | ||
196 | |||
197 | name_hash = f2fs_dentry_hash(name, namelen); | ||
198 | max_depth = F2FS_I(dir)->i_current_depth; | ||
199 | |||
200 | for (level = 0; level < max_depth; level++) { | ||
201 | de = find_in_level(dir, level, name, | ||
202 | namelen, name_hash, res_page); | ||
203 | if (de) | ||
204 | break; | ||
205 | } | ||
206 | if (!de && F2FS_I(dir)->chash != name_hash) { | ||
207 | F2FS_I(dir)->chash = name_hash; | ||
208 | F2FS_I(dir)->clevel = level - 1; | ||
209 | } | ||
210 | return de; | ||
211 | } | ||
212 | |||
213 | struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p) | ||
214 | { | ||
215 | struct page *page = NULL; | ||
216 | struct f2fs_dir_entry *de = NULL; | ||
217 | struct f2fs_dentry_block *dentry_blk = NULL; | ||
218 | |||
219 | page = get_lock_data_page(dir, 0); | ||
220 | if (IS_ERR(page)) | ||
221 | return NULL; | ||
222 | |||
223 | dentry_blk = kmap(page); | ||
224 | de = &dentry_blk->dentry[1]; | ||
225 | *p = page; | ||
226 | unlock_page(page); | ||
227 | return de; | ||
228 | } | ||
229 | |||
230 | ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr) | ||
231 | { | ||
232 | ino_t res = 0; | ||
233 | struct f2fs_dir_entry *de; | ||
234 | struct page *page; | ||
235 | |||
236 | de = f2fs_find_entry(dir, qstr, &page); | ||
237 | if (de) { | ||
238 | res = le32_to_cpu(de->ino); | ||
239 | kunmap(page); | ||
240 | f2fs_put_page(page, 0); | ||
241 | } | ||
242 | |||
243 | return res; | ||
244 | } | ||
245 | |||
246 | void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, | ||
247 | struct page *page, struct inode *inode) | ||
248 | { | ||
249 | struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); | ||
250 | |||
251 | mutex_lock_op(sbi, DENTRY_OPS); | ||
252 | lock_page(page); | ||
253 | wait_on_page_writeback(page); | ||
254 | de->ino = cpu_to_le32(inode->i_ino); | ||
255 | set_de_type(de, inode); | ||
256 | kunmap(page); | ||
257 | set_page_dirty(page); | ||
258 | dir->i_mtime = dir->i_ctime = CURRENT_TIME; | ||
259 | mark_inode_dirty(dir); | ||
260 | f2fs_put_page(page, 1); | ||
261 | mutex_unlock_op(sbi, DENTRY_OPS); | ||
262 | } | ||
263 | |||
264 | void init_dent_inode(struct dentry *dentry, struct page *ipage) | ||
265 | { | ||
266 | struct inode *dir = dentry->d_parent->d_inode; | ||
267 | struct f2fs_node *rn; | ||
268 | |||
269 | if (IS_ERR(ipage)) | ||
270 | return; | ||
271 | |||
272 | wait_on_page_writeback(ipage); | ||
273 | |||
274 | /* copy dentry info. to this inode page */ | ||
275 | rn = (struct f2fs_node *)page_address(ipage); | ||
276 | rn->i.i_pino = cpu_to_le32(dir->i_ino); | ||
277 | rn->i.i_namelen = cpu_to_le32(dentry->d_name.len); | ||
278 | memcpy(rn->i.i_name, dentry->d_name.name, dentry->d_name.len); | ||
279 | set_page_dirty(ipage); | ||
280 | } | ||
281 | |||
282 | static int init_inode_metadata(struct inode *inode, struct dentry *dentry) | ||
283 | { | ||
284 | struct inode *dir = dentry->d_parent->d_inode; | ||
285 | |||
286 | if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { | ||
287 | int err; | ||
288 | err = new_inode_page(inode, dentry); | ||
289 | if (err) | ||
290 | return err; | ||
291 | |||
292 | if (S_ISDIR(inode->i_mode)) { | ||
293 | err = f2fs_make_empty(inode, dir); | ||
294 | if (err) { | ||
295 | remove_inode_page(inode); | ||
296 | return err; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | err = f2fs_init_acl(inode, dir); | ||
301 | if (err) { | ||
302 | remove_inode_page(inode); | ||
303 | return err; | ||
304 | } | ||
305 | } else { | ||
306 | struct page *ipage; | ||
307 | ipage = get_node_page(F2FS_SB(dir->i_sb), inode->i_ino); | ||
308 | if (IS_ERR(ipage)) | ||
309 | return PTR_ERR(ipage); | ||
310 | init_dent_inode(dentry, ipage); | ||
311 | f2fs_put_page(ipage, 1); | ||
312 | } | ||
313 | if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) { | ||
314 | inc_nlink(inode); | ||
315 | f2fs_write_inode(inode, NULL); | ||
316 | } | ||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static void update_parent_metadata(struct inode *dir, struct inode *inode, | ||
321 | unsigned int current_depth) | ||
322 | { | ||
323 | bool need_dir_update = false; | ||
324 | |||
325 | if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { | ||
326 | if (S_ISDIR(inode->i_mode)) { | ||
327 | inc_nlink(dir); | ||
328 | need_dir_update = true; | ||
329 | } | ||
330 | clear_inode_flag(F2FS_I(inode), FI_NEW_INODE); | ||
331 | } | ||
332 | dir->i_mtime = dir->i_ctime = CURRENT_TIME; | ||
333 | if (F2FS_I(dir)->i_current_depth != current_depth) { | ||
334 | F2FS_I(dir)->i_current_depth = current_depth; | ||
335 | need_dir_update = true; | ||
336 | } | ||
337 | |||
338 | if (need_dir_update) | ||
339 | f2fs_write_inode(dir, NULL); | ||
340 | else | ||
341 | mark_inode_dirty(dir); | ||
342 | |||
343 | if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) | ||
344 | clear_inode_flag(F2FS_I(inode), FI_INC_LINK); | ||
345 | } | ||
346 | |||
347 | static int room_for_filename(struct f2fs_dentry_block *dentry_blk, int slots) | ||
348 | { | ||
349 | int bit_start = 0; | ||
350 | int zero_start, zero_end; | ||
351 | next: | ||
352 | zero_start = find_next_zero_bit_le(&dentry_blk->dentry_bitmap, | ||
353 | NR_DENTRY_IN_BLOCK, | ||
354 | bit_start); | ||
355 | if (zero_start >= NR_DENTRY_IN_BLOCK) | ||
356 | return NR_DENTRY_IN_BLOCK; | ||
357 | |||
358 | zero_end = find_next_bit_le(&dentry_blk->dentry_bitmap, | ||
359 | NR_DENTRY_IN_BLOCK, | ||
360 | zero_start); | ||
361 | if (zero_end - zero_start >= slots) | ||
362 | return zero_start; | ||
363 | |||
364 | bit_start = zero_end + 1; | ||
365 | |||
366 | if (zero_end + 1 >= NR_DENTRY_IN_BLOCK) | ||
367 | return NR_DENTRY_IN_BLOCK; | ||
368 | goto next; | ||
369 | } | ||
370 | |||
371 | int f2fs_add_link(struct dentry *dentry, struct inode *inode) | ||
372 | { | ||
373 | unsigned int bit_pos; | ||
374 | unsigned int level; | ||
375 | unsigned int current_depth; | ||
376 | unsigned long bidx, block; | ||
377 | f2fs_hash_t dentry_hash; | ||
378 | struct f2fs_dir_entry *de; | ||
379 | unsigned int nbucket, nblock; | ||
380 | struct inode *dir = dentry->d_parent->d_inode; | ||
381 | struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); | ||
382 | const char *name = dentry->d_name.name; | ||
383 | int namelen = dentry->d_name.len; | ||
384 | struct page *dentry_page = NULL; | ||
385 | struct f2fs_dentry_block *dentry_blk = NULL; | ||
386 | int slots = (namelen + F2FS_NAME_LEN - 1) / F2FS_NAME_LEN; | ||
387 | int err = 0; | ||
388 | int i; | ||
389 | |||
390 | dentry_hash = f2fs_dentry_hash(name, dentry->d_name.len); | ||
391 | level = 0; | ||
392 | current_depth = F2FS_I(dir)->i_current_depth; | ||
393 | if (F2FS_I(dir)->chash == dentry_hash) { | ||
394 | level = F2FS_I(dir)->clevel; | ||
395 | F2FS_I(dir)->chash = 0; | ||
396 | } | ||
397 | |||
398 | start: | ||
399 | if (current_depth == MAX_DIR_HASH_DEPTH) | ||
400 | return -ENOSPC; | ||
401 | |||
402 | /* Increase the depth, if required */ | ||
403 | if (level == current_depth) | ||
404 | ++current_depth; | ||
405 | |||
406 | nbucket = dir_buckets(level); | ||
407 | nblock = bucket_blocks(level); | ||
408 | |||
409 | bidx = dir_block_index(level, (dentry_hash % nbucket)); | ||
410 | |||
411 | for (block = bidx; block <= (bidx + nblock - 1); block++) { | ||
412 | mutex_lock_op(sbi, DENTRY_OPS); | ||
413 | dentry_page = get_new_data_page(dir, block, true); | ||
414 | if (IS_ERR(dentry_page)) { | ||
415 | mutex_unlock_op(sbi, DENTRY_OPS); | ||
416 | return PTR_ERR(dentry_page); | ||
417 | } | ||
418 | |||
419 | dentry_blk = kmap(dentry_page); | ||
420 | bit_pos = room_for_filename(dentry_blk, slots); | ||
421 | if (bit_pos < NR_DENTRY_IN_BLOCK) | ||
422 | goto add_dentry; | ||
423 | |||
424 | kunmap(dentry_page); | ||
425 | f2fs_put_page(dentry_page, 1); | ||
426 | mutex_unlock_op(sbi, DENTRY_OPS); | ||
427 | } | ||
428 | |||
429 | /* Move to next level to find the empty slot for new dentry */ | ||
430 | ++level; | ||
431 | goto start; | ||
432 | add_dentry: | ||
433 | err = init_inode_metadata(inode, dentry); | ||
434 | if (err) | ||
435 | goto fail; | ||
436 | |||
437 | wait_on_page_writeback(dentry_page); | ||
438 | |||
439 | de = &dentry_blk->dentry[bit_pos]; | ||
440 | de->hash_code = cpu_to_le32(dentry_hash); | ||
441 | de->name_len = cpu_to_le16(namelen); | ||
442 | memcpy(dentry_blk->filename[bit_pos], name, namelen); | ||
443 | de->ino = cpu_to_le32(inode->i_ino); | ||
444 | set_de_type(de, inode); | ||
445 | for (i = 0; i < slots; i++) | ||
446 | test_and_set_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); | ||
447 | set_page_dirty(dentry_page); | ||
448 | update_parent_metadata(dir, inode, current_depth); | ||
449 | fail: | ||
450 | kunmap(dentry_page); | ||
451 | f2fs_put_page(dentry_page, 1); | ||
452 | mutex_unlock_op(sbi, DENTRY_OPS); | ||
453 | return err; | ||
454 | } | ||
455 | |||
456 | /** | ||
457 | * It only removes the dentry from the dentry page,corresponding name | ||
458 | * entry in name page does not need to be touched during deletion. | ||
459 | */ | ||
460 | void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, | ||
461 | struct inode *inode) | ||
462 | { | ||
463 | struct f2fs_dentry_block *dentry_blk; | ||
464 | unsigned int bit_pos; | ||
465 | struct address_space *mapping = page->mapping; | ||
466 | struct inode *dir = mapping->host; | ||
467 | struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); | ||
468 | int slots = (le16_to_cpu(dentry->name_len) + F2FS_NAME_LEN - 1) / | ||
469 | F2FS_NAME_LEN; | ||
470 | void *kaddr = page_address(page); | ||
471 | int i; | ||
472 | |||
473 | mutex_lock_op(sbi, DENTRY_OPS); | ||
474 | |||
475 | lock_page(page); | ||
476 | wait_on_page_writeback(page); | ||
477 | |||
478 | dentry_blk = (struct f2fs_dentry_block *)kaddr; | ||
479 | bit_pos = dentry - (struct f2fs_dir_entry *)dentry_blk->dentry; | ||
480 | for (i = 0; i < slots; i++) | ||
481 | test_and_clear_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); | ||
482 | |||
483 | /* Let's check and deallocate this dentry page */ | ||
484 | bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, | ||
485 | NR_DENTRY_IN_BLOCK, | ||
486 | 0); | ||
487 | kunmap(page); /* kunmap - pair of f2fs_find_entry */ | ||
488 | set_page_dirty(page); | ||
489 | |||
490 | dir->i_ctime = dir->i_mtime = CURRENT_TIME; | ||
491 | |||
492 | if (inode && S_ISDIR(inode->i_mode)) { | ||
493 | drop_nlink(dir); | ||
494 | f2fs_write_inode(dir, NULL); | ||
495 | } else { | ||
496 | mark_inode_dirty(dir); | ||
497 | } | ||
498 | |||
499 | if (inode) { | ||
500 | inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; | ||
501 | drop_nlink(inode); | ||
502 | if (S_ISDIR(inode->i_mode)) { | ||
503 | drop_nlink(inode); | ||
504 | i_size_write(inode, 0); | ||
505 | } | ||
506 | f2fs_write_inode(inode, NULL); | ||
507 | if (inode->i_nlink == 0) | ||
508 | add_orphan_inode(sbi, inode->i_ino); | ||
509 | } | ||
510 | |||
511 | if (bit_pos == NR_DENTRY_IN_BLOCK) { | ||
512 | loff_t page_offset; | ||
513 | truncate_hole(dir, page->index, page->index + 1); | ||
514 | clear_page_dirty_for_io(page); | ||
515 | ClearPageUptodate(page); | ||
516 | dec_page_count(sbi, F2FS_DIRTY_DENTS); | ||
517 | inode_dec_dirty_dents(dir); | ||
518 | page_offset = page->index << PAGE_CACHE_SHIFT; | ||
519 | f2fs_put_page(page, 1); | ||
520 | } else { | ||
521 | f2fs_put_page(page, 1); | ||
522 | } | ||
523 | mutex_unlock_op(sbi, DENTRY_OPS); | ||
524 | } | ||
525 | |||
526 | int f2fs_make_empty(struct inode *inode, struct inode *parent) | ||
527 | { | ||
528 | struct page *dentry_page; | ||
529 | struct f2fs_dentry_block *dentry_blk; | ||
530 | struct f2fs_dir_entry *de; | ||
531 | void *kaddr; | ||
532 | |||
533 | dentry_page = get_new_data_page(inode, 0, true); | ||
534 | if (IS_ERR(dentry_page)) | ||
535 | return PTR_ERR(dentry_page); | ||
536 | |||
537 | kaddr = kmap_atomic(dentry_page); | ||
538 | dentry_blk = (struct f2fs_dentry_block *)kaddr; | ||
539 | |||
540 | de = &dentry_blk->dentry[0]; | ||
541 | de->name_len = cpu_to_le16(1); | ||
542 | de->hash_code = 0; | ||
543 | de->ino = cpu_to_le32(inode->i_ino); | ||
544 | memcpy(dentry_blk->filename[0], ".", 1); | ||
545 | set_de_type(de, inode); | ||
546 | |||
547 | de = &dentry_blk->dentry[1]; | ||
548 | de->hash_code = 0; | ||
549 | de->name_len = cpu_to_le16(2); | ||
550 | de->ino = cpu_to_le32(parent->i_ino); | ||
551 | memcpy(dentry_blk->filename[1], "..", 2); | ||
552 | set_de_type(de, inode); | ||
553 | |||
554 | test_and_set_bit_le(0, &dentry_blk->dentry_bitmap); | ||
555 | test_and_set_bit_le(1, &dentry_blk->dentry_bitmap); | ||
556 | kunmap_atomic(kaddr); | ||
557 | |||
558 | set_page_dirty(dentry_page); | ||
559 | f2fs_put_page(dentry_page, 1); | ||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | bool f2fs_empty_dir(struct inode *dir) | ||
564 | { | ||
565 | unsigned long bidx; | ||
566 | struct page *dentry_page; | ||
567 | unsigned int bit_pos; | ||
568 | struct f2fs_dentry_block *dentry_blk; | ||
569 | unsigned long nblock = dir_blocks(dir); | ||
570 | |||
571 | for (bidx = 0; bidx < nblock; bidx++) { | ||
572 | void *kaddr; | ||
573 | dentry_page = get_lock_data_page(dir, bidx); | ||
574 | if (IS_ERR(dentry_page)) { | ||
575 | if (PTR_ERR(dentry_page) == -ENOENT) | ||
576 | continue; | ||
577 | else | ||
578 | return false; | ||
579 | } | ||
580 | |||
581 | kaddr = kmap_atomic(dentry_page); | ||
582 | dentry_blk = (struct f2fs_dentry_block *)kaddr; | ||
583 | if (bidx == 0) | ||
584 | bit_pos = 2; | ||
585 | else | ||
586 | bit_pos = 0; | ||
587 | bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, | ||
588 | NR_DENTRY_IN_BLOCK, | ||
589 | bit_pos); | ||
590 | kunmap_atomic(kaddr); | ||
591 | |||
592 | f2fs_put_page(dentry_page, 1); | ||
593 | |||
594 | if (bit_pos < NR_DENTRY_IN_BLOCK) | ||
595 | return false; | ||
596 | } | ||
597 | return true; | ||
598 | } | ||
599 | |||
600 | static int f2fs_readdir(struct file *file, void *dirent, filldir_t filldir) | ||
601 | { | ||
602 | unsigned long pos = file->f_pos; | ||
603 | struct inode *inode = file->f_dentry->d_inode; | ||
604 | unsigned long npages = dir_blocks(inode); | ||
605 | unsigned char *types = NULL; | ||
606 | unsigned int bit_pos = 0, start_bit_pos = 0; | ||
607 | int over = 0; | ||
608 | struct f2fs_dentry_block *dentry_blk = NULL; | ||
609 | struct f2fs_dir_entry *de = NULL; | ||
610 | struct page *dentry_page = NULL; | ||
611 | unsigned int n = 0; | ||
612 | unsigned char d_type = DT_UNKNOWN; | ||
613 | int slots; | ||
614 | |||
615 | types = f2fs_filetype_table; | ||
616 | bit_pos = (pos % NR_DENTRY_IN_BLOCK); | ||
617 | n = (pos / NR_DENTRY_IN_BLOCK); | ||
618 | |||
619 | for ( ; n < npages; n++) { | ||
620 | dentry_page = get_lock_data_page(inode, n); | ||
621 | if (IS_ERR(dentry_page)) | ||
622 | continue; | ||
623 | |||
624 | start_bit_pos = bit_pos; | ||
625 | dentry_blk = kmap(dentry_page); | ||
626 | while (bit_pos < NR_DENTRY_IN_BLOCK) { | ||
627 | d_type = DT_UNKNOWN; | ||
628 | bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, | ||
629 | NR_DENTRY_IN_BLOCK, | ||
630 | bit_pos); | ||
631 | if (bit_pos >= NR_DENTRY_IN_BLOCK) | ||
632 | break; | ||
633 | |||
634 | de = &dentry_blk->dentry[bit_pos]; | ||
635 | if (types && de->file_type < F2FS_FT_MAX) | ||
636 | d_type = types[de->file_type]; | ||
637 | |||
638 | over = filldir(dirent, | ||
639 | dentry_blk->filename[bit_pos], | ||
640 | le16_to_cpu(de->name_len), | ||
641 | (n * NR_DENTRY_IN_BLOCK) + bit_pos, | ||
642 | le32_to_cpu(de->ino), d_type); | ||
643 | if (over) { | ||
644 | file->f_pos += bit_pos - start_bit_pos; | ||
645 | goto success; | ||
646 | } | ||
647 | slots = (le16_to_cpu(de->name_len) + F2FS_NAME_LEN - 1) | ||
648 | / F2FS_NAME_LEN; | ||
649 | bit_pos += slots; | ||
650 | } | ||
651 | bit_pos = 0; | ||
652 | file->f_pos = (n + 1) * NR_DENTRY_IN_BLOCK; | ||
653 | kunmap(dentry_page); | ||
654 | f2fs_put_page(dentry_page, 1); | ||
655 | dentry_page = NULL; | ||
656 | } | ||
657 | success: | ||
658 | if (dentry_page && !IS_ERR(dentry_page)) { | ||
659 | kunmap(dentry_page); | ||
660 | f2fs_put_page(dentry_page, 1); | ||
661 | } | ||
662 | |||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | const struct file_operations f2fs_dir_operations = { | ||
667 | .llseek = generic_file_llseek, | ||
668 | .read = generic_read_dir, | ||
669 | .readdir = f2fs_readdir, | ||
670 | .fsync = f2fs_sync_file, | ||
671 | .unlocked_ioctl = f2fs_ioctl, | ||
672 | }; | ||
diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c new file mode 100644 index 000000000000..098a1963d7c7 --- /dev/null +++ b/fs/f2fs/hash.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /** | ||
2 | * fs/f2fs/hash.c | ||
3 | * | ||
4 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com/ | ||
6 | * | ||
7 | * Portions of this code from linux/fs/ext3/hash.c | ||
8 | * | ||
9 | * Copyright (C) 2002 by Theodore Ts'o | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/fs.h> | ||
17 | #include <linux/f2fs_fs.h> | ||
18 | #include <linux/cryptohash.h> | ||
19 | #include <linux/pagemap.h> | ||
20 | |||
21 | #include "f2fs.h" | ||
22 | |||
23 | /* | ||
24 | * Hashing code copied from ext3 | ||
25 | */ | ||
26 | #define DELTA 0x9E3779B9 | ||
27 | |||
28 | static void TEA_transform(unsigned int buf[4], unsigned int const in[]) | ||
29 | { | ||
30 | __u32 sum = 0; | ||
31 | __u32 b0 = buf[0], b1 = buf[1]; | ||
32 | __u32 a = in[0], b = in[1], c = in[2], d = in[3]; | ||
33 | int n = 16; | ||
34 | |||
35 | do { | ||
36 | sum += DELTA; | ||
37 | b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); | ||
38 | b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); | ||
39 | } while (--n); | ||
40 | |||
41 | buf[0] += b0; | ||
42 | buf[1] += b1; | ||
43 | } | ||
44 | |||
45 | static void str2hashbuf(const char *msg, int len, unsigned int *buf, int num) | ||
46 | { | ||
47 | unsigned pad, val; | ||
48 | int i; | ||
49 | |||
50 | pad = (__u32)len | ((__u32)len << 8); | ||
51 | pad |= pad << 16; | ||
52 | |||
53 | val = pad; | ||
54 | if (len > num * 4) | ||
55 | len = num * 4; | ||
56 | for (i = 0; i < len; i++) { | ||
57 | if ((i % 4) == 0) | ||
58 | val = pad; | ||
59 | val = msg[i] + (val << 8); | ||
60 | if ((i % 4) == 3) { | ||
61 | *buf++ = val; | ||
62 | val = pad; | ||
63 | num--; | ||
64 | } | ||
65 | } | ||
66 | if (--num >= 0) | ||
67 | *buf++ = val; | ||
68 | while (--num >= 0) | ||
69 | *buf++ = pad; | ||
70 | } | ||
71 | |||
72 | f2fs_hash_t f2fs_dentry_hash(const char *name, int len) | ||
73 | { | ||
74 | __u32 hash, minor_hash; | ||
75 | f2fs_hash_t f2fs_hash; | ||
76 | const char *p; | ||
77 | __u32 in[8], buf[4]; | ||
78 | |||
79 | /* Initialize the default seed for the hash checksum functions */ | ||
80 | buf[0] = 0x67452301; | ||
81 | buf[1] = 0xefcdab89; | ||
82 | buf[2] = 0x98badcfe; | ||
83 | buf[3] = 0x10325476; | ||
84 | |||
85 | p = name; | ||
86 | while (len > 0) { | ||
87 | str2hashbuf(p, len, in, 4); | ||
88 | TEA_transform(buf, in); | ||
89 | len -= 16; | ||
90 | p += 16; | ||
91 | } | ||
92 | hash = buf[0]; | ||
93 | minor_hash = buf[1]; | ||
94 | |||
95 | f2fs_hash = hash; | ||
96 | f2fs_hash &= ~F2FS_HASH_COL_BIT; | ||
97 | return f2fs_hash; | ||
98 | } | ||