diff options
author | Jaegeuk Kim <jaegeuk@kernel.org> | 2015-03-30 18:07:16 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2015-04-10 18:08:57 -0400 |
commit | 510022a85839a8409d1e6a519bb86ce71a84f30a (patch) | |
tree | 69c0d7bc575c378ee0de42ab03a29c349afb74dc /fs/f2fs | |
parent | c9ef481097d17fb8ff8ea7930ce715b5a676f10f (diff) |
f2fs: add F2FS_INLINE_DOTS to recover missing dot dentries
If f2fs was corrupted with missing dot dentries, it needs to recover them after
fsck.f2fs detection.
The underlying precedure is:
1. The fsck.f2fs remains F2FS_INLINE_DOTS flag in directory inode, if it detects
missing dot dentries.
2. When f2fs looks up the corrupted directory, it triggers f2fs_add_link with
proper inode numbers and their dot and dotdot names.
3. Once f2fs recovers the directory without errors, it removes F2FS_INLINE_DOTS
finally.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs/f2fs')
-rw-r--r-- | fs/f2fs/dir.c | 52 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 22 | ||||
-rw-r--r-- | fs/f2fs/inline.c | 29 | ||||
-rw-r--r-- | fs/f2fs/namei.c | 48 | ||||
-rw-r--r-- | fs/f2fs/recovery.c | 2 |
5 files changed, 111 insertions, 42 deletions
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 4e59c8219dde..906b5876dc27 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c | |||
@@ -59,9 +59,8 @@ static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = { | |||
59 | [S_IFLNK >> S_SHIFT] = F2FS_FT_SYMLINK, | 59 | [S_IFLNK >> S_SHIFT] = F2FS_FT_SYMLINK, |
60 | }; | 60 | }; |
61 | 61 | ||
62 | void set_de_type(struct f2fs_dir_entry *de, struct inode *inode) | 62 | void set_de_type(struct f2fs_dir_entry *de, umode_t mode) |
63 | { | 63 | { |
64 | umode_t mode = inode->i_mode; | ||
65 | de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT]; | 64 | de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT]; |
66 | } | 65 | } |
67 | 66 | ||
@@ -282,7 +281,7 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, | |||
282 | lock_page(page); | 281 | lock_page(page); |
283 | f2fs_wait_on_page_writeback(page, type); | 282 | f2fs_wait_on_page_writeback(page, type); |
284 | de->ino = cpu_to_le32(inode->i_ino); | 283 | de->ino = cpu_to_le32(inode->i_ino); |
285 | set_de_type(de, inode); | 284 | set_de_type(de, inode->i_mode); |
286 | f2fs_dentry_kunmap(dir, page); | 285 | f2fs_dentry_kunmap(dir, page); |
287 | set_page_dirty(page); | 286 | set_page_dirty(page); |
288 | dir->i_mtime = dir->i_ctime = CURRENT_TIME; | 287 | dir->i_mtime = dir->i_ctime = CURRENT_TIME; |
@@ -328,14 +327,14 @@ void do_make_empty_dir(struct inode *inode, struct inode *parent, | |||
328 | de->hash_code = 0; | 327 | de->hash_code = 0; |
329 | de->ino = cpu_to_le32(inode->i_ino); | 328 | de->ino = cpu_to_le32(inode->i_ino); |
330 | memcpy(d->filename[0], ".", 1); | 329 | memcpy(d->filename[0], ".", 1); |
331 | set_de_type(de, inode); | 330 | set_de_type(de, inode->i_mode); |
332 | 331 | ||
333 | de = &d->dentry[1]; | 332 | de = &d->dentry[1]; |
334 | de->hash_code = 0; | 333 | de->hash_code = 0; |
335 | de->name_len = cpu_to_le16(2); | 334 | de->name_len = cpu_to_le16(2); |
336 | de->ino = cpu_to_le32(parent->i_ino); | 335 | de->ino = cpu_to_le32(parent->i_ino); |
337 | memcpy(d->filename[1], "..", 2); | 336 | memcpy(d->filename[1], "..", 2); |
338 | set_de_type(de, inode); | 337 | set_de_type(de, inode->i_mode); |
339 | 338 | ||
340 | test_and_set_bit_le(0, (void *)d->bitmap); | 339 | test_and_set_bit_le(0, (void *)d->bitmap); |
341 | test_and_set_bit_le(1, (void *)d->bitmap); | 340 | test_and_set_bit_le(1, (void *)d->bitmap); |
@@ -432,7 +431,7 @@ error: | |||
432 | void update_parent_metadata(struct inode *dir, struct inode *inode, | 431 | void update_parent_metadata(struct inode *dir, struct inode *inode, |
433 | unsigned int current_depth) | 432 | unsigned int current_depth) |
434 | { | 433 | { |
435 | if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { | 434 | if (inode && is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { |
436 | if (S_ISDIR(inode->i_mode)) { | 435 | if (S_ISDIR(inode->i_mode)) { |
437 | inc_nlink(dir); | 436 | inc_nlink(dir); |
438 | set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); | 437 | set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); |
@@ -447,7 +446,7 @@ void update_parent_metadata(struct inode *dir, struct inode *inode, | |||
447 | set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); | 446 | set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); |
448 | } | 447 | } |
449 | 448 | ||
450 | if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) | 449 | if (inode && is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) |
451 | clear_inode_flag(F2FS_I(inode), FI_INC_LINK); | 450 | clear_inode_flag(F2FS_I(inode), FI_INC_LINK); |
452 | } | 451 | } |
453 | 452 | ||
@@ -471,7 +470,7 @@ next: | |||
471 | goto next; | 470 | goto next; |
472 | } | 471 | } |
473 | 472 | ||
474 | void f2fs_update_dentry(struct inode *inode, struct f2fs_dentry_ptr *d, | 473 | void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d, |
475 | const struct qstr *name, f2fs_hash_t name_hash, | 474 | const struct qstr *name, f2fs_hash_t name_hash, |
476 | unsigned int bit_pos) | 475 | unsigned int bit_pos) |
477 | { | 476 | { |
@@ -483,8 +482,8 @@ void f2fs_update_dentry(struct inode *inode, struct f2fs_dentry_ptr *d, | |||
483 | de->hash_code = name_hash; | 482 | de->hash_code = name_hash; |
484 | de->name_len = cpu_to_le16(name->len); | 483 | de->name_len = cpu_to_le16(name->len); |
485 | memcpy(d->filename[bit_pos], name->name, name->len); | 484 | memcpy(d->filename[bit_pos], name->name, name->len); |
486 | de->ino = cpu_to_le32(inode->i_ino); | 485 | de->ino = cpu_to_le32(ino); |
487 | set_de_type(de, inode); | 486 | set_de_type(de, mode); |
488 | for (i = 0; i < slots; i++) | 487 | for (i = 0; i < slots; i++) |
489 | test_and_set_bit_le(bit_pos + i, (void *)d->bitmap); | 488 | test_and_set_bit_le(bit_pos + i, (void *)d->bitmap); |
490 | } | 489 | } |
@@ -494,7 +493,7 @@ void f2fs_update_dentry(struct inode *inode, struct f2fs_dentry_ptr *d, | |||
494 | * f2fs_unlock_op(). | 493 | * f2fs_unlock_op(). |
495 | */ | 494 | */ |
496 | int __f2fs_add_link(struct inode *dir, const struct qstr *name, | 495 | int __f2fs_add_link(struct inode *dir, const struct qstr *name, |
497 | struct inode *inode) | 496 | struct inode *inode, nid_t ino, umode_t mode) |
498 | { | 497 | { |
499 | unsigned int bit_pos; | 498 | unsigned int bit_pos; |
500 | unsigned int level; | 499 | unsigned int level; |
@@ -507,11 +506,11 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, | |||
507 | struct f2fs_dentry_block *dentry_blk = NULL; | 506 | struct f2fs_dentry_block *dentry_blk = NULL; |
508 | struct f2fs_dentry_ptr d; | 507 | struct f2fs_dentry_ptr d; |
509 | int slots = GET_DENTRY_SLOTS(namelen); | 508 | int slots = GET_DENTRY_SLOTS(namelen); |
510 | struct page *page; | 509 | struct page *page = NULL; |
511 | int err = 0; | 510 | int err = 0; |
512 | 511 | ||
513 | if (f2fs_has_inline_dentry(dir)) { | 512 | if (f2fs_has_inline_dentry(dir)) { |
514 | err = f2fs_add_inline_entry(dir, name, inode); | 513 | err = f2fs_add_inline_entry(dir, name, inode, ino, mode); |
515 | if (!err || err != -EAGAIN) | 514 | if (!err || err != -EAGAIN) |
516 | return err; | 515 | return err; |
517 | else | 516 | else |
@@ -561,26 +560,31 @@ start: | |||
561 | add_dentry: | 560 | add_dentry: |
562 | f2fs_wait_on_page_writeback(dentry_page, DATA); | 561 | f2fs_wait_on_page_writeback(dentry_page, DATA); |
563 | 562 | ||
564 | down_write(&F2FS_I(inode)->i_sem); | 563 | if (inode) { |
565 | page = init_inode_metadata(inode, dir, name, NULL); | 564 | down_write(&F2FS_I(inode)->i_sem); |
566 | if (IS_ERR(page)) { | 565 | page = init_inode_metadata(inode, dir, name, NULL); |
567 | err = PTR_ERR(page); | 566 | if (IS_ERR(page)) { |
568 | goto fail; | 567 | err = PTR_ERR(page); |
568 | goto fail; | ||
569 | } | ||
569 | } | 570 | } |
570 | 571 | ||
571 | make_dentry_ptr(&d, (void *)dentry_blk, 1); | 572 | make_dentry_ptr(&d, (void *)dentry_blk, 1); |
572 | f2fs_update_dentry(inode, &d, name, dentry_hash, bit_pos); | 573 | f2fs_update_dentry(ino, mode, &d, name, dentry_hash, bit_pos); |
573 | 574 | ||
574 | set_page_dirty(dentry_page); | 575 | set_page_dirty(dentry_page); |
575 | 576 | ||
576 | /* we don't need to mark_inode_dirty now */ | 577 | if (inode) { |
577 | F2FS_I(inode)->i_pino = dir->i_ino; | 578 | /* we don't need to mark_inode_dirty now */ |
578 | update_inode(inode, page); | 579 | F2FS_I(inode)->i_pino = dir->i_ino; |
579 | f2fs_put_page(page, 1); | 580 | update_inode(inode, page); |
581 | f2fs_put_page(page, 1); | ||
582 | } | ||
580 | 583 | ||
581 | update_parent_metadata(dir, inode, current_depth); | 584 | update_parent_metadata(dir, inode, current_depth); |
582 | fail: | 585 | fail: |
583 | up_write(&F2FS_I(inode)->i_sem); | 586 | if (inode) |
587 | up_write(&F2FS_I(inode)->i_sem); | ||
584 | 588 | ||
585 | if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { | 589 | if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { |
586 | update_inode_page(dir); | 590 | update_inode_page(dir); |
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 0be198339c3b..053361ace0ec 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
@@ -1246,6 +1246,7 @@ enum { | |||
1246 | FI_FIRST_BLOCK_WRITTEN, /* indicate #0 data block was written */ | 1246 | FI_FIRST_BLOCK_WRITTEN, /* indicate #0 data block was written */ |
1247 | FI_DROP_CACHE, /* drop dirty page cache */ | 1247 | FI_DROP_CACHE, /* drop dirty page cache */ |
1248 | FI_DATA_EXIST, /* indicate data exists */ | 1248 | FI_DATA_EXIST, /* indicate data exists */ |
1249 | FI_INLINE_DOTS, /* indicate inline dot dentries */ | ||
1249 | }; | 1250 | }; |
1250 | 1251 | ||
1251 | static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag) | 1252 | static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag) |
@@ -1282,6 +1283,8 @@ static inline void get_inline_info(struct f2fs_inode_info *fi, | |||
1282 | set_inode_flag(fi, FI_INLINE_DENTRY); | 1283 | set_inode_flag(fi, FI_INLINE_DENTRY); |
1283 | if (ri->i_inline & F2FS_DATA_EXIST) | 1284 | if (ri->i_inline & F2FS_DATA_EXIST) |
1284 | set_inode_flag(fi, FI_DATA_EXIST); | 1285 | set_inode_flag(fi, FI_DATA_EXIST); |
1286 | if (ri->i_inline & F2FS_INLINE_DOTS) | ||
1287 | set_inode_flag(fi, FI_INLINE_DOTS); | ||
1285 | } | 1288 | } |
1286 | 1289 | ||
1287 | static inline void set_raw_inline(struct f2fs_inode_info *fi, | 1290 | static inline void set_raw_inline(struct f2fs_inode_info *fi, |
@@ -1297,6 +1300,8 @@ static inline void set_raw_inline(struct f2fs_inode_info *fi, | |||
1297 | ri->i_inline |= F2FS_INLINE_DENTRY; | 1300 | ri->i_inline |= F2FS_INLINE_DENTRY; |
1298 | if (is_inode_flag_set(fi, FI_DATA_EXIST)) | 1301 | if (is_inode_flag_set(fi, FI_DATA_EXIST)) |
1299 | ri->i_inline |= F2FS_DATA_EXIST; | 1302 | ri->i_inline |= F2FS_DATA_EXIST; |
1303 | if (is_inode_flag_set(fi, FI_INLINE_DOTS)) | ||
1304 | ri->i_inline |= F2FS_INLINE_DOTS; | ||
1300 | } | 1305 | } |
1301 | 1306 | ||
1302 | static inline int f2fs_has_inline_xattr(struct inode *inode) | 1307 | static inline int f2fs_has_inline_xattr(struct inode *inode) |
@@ -1342,6 +1347,11 @@ static inline int f2fs_exist_data(struct inode *inode) | |||
1342 | return is_inode_flag_set(F2FS_I(inode), FI_DATA_EXIST); | 1347 | return is_inode_flag_set(F2FS_I(inode), FI_DATA_EXIST); |
1343 | } | 1348 | } |
1344 | 1349 | ||
1350 | static inline int f2fs_has_inline_dots(struct inode *inode) | ||
1351 | { | ||
1352 | return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DOTS); | ||
1353 | } | ||
1354 | |||
1345 | static inline bool f2fs_is_atomic_file(struct inode *inode) | 1355 | static inline bool f2fs_is_atomic_file(struct inode *inode) |
1346 | { | 1356 | { |
1347 | return is_inode_flag_set(F2FS_I(inode), FI_ATOMIC_FILE); | 1357 | return is_inode_flag_set(F2FS_I(inode), FI_ATOMIC_FILE); |
@@ -1440,7 +1450,7 @@ struct dentry *f2fs_get_parent(struct dentry *child); | |||
1440 | * dir.c | 1450 | * dir.c |
1441 | */ | 1451 | */ |
1442 | extern unsigned char f2fs_filetype_table[F2FS_FT_MAX]; | 1452 | extern unsigned char f2fs_filetype_table[F2FS_FT_MAX]; |
1443 | void set_de_type(struct f2fs_dir_entry *, struct inode *); | 1453 | void set_de_type(struct f2fs_dir_entry *, umode_t); |
1444 | struct f2fs_dir_entry *find_target_dentry(struct qstr *, int *, | 1454 | struct f2fs_dir_entry *find_target_dentry(struct qstr *, int *, |
1445 | struct f2fs_dentry_ptr *); | 1455 | struct f2fs_dentry_ptr *); |
1446 | bool f2fs_fill_dentries(struct dir_context *, struct f2fs_dentry_ptr *, | 1456 | bool f2fs_fill_dentries(struct dir_context *, struct f2fs_dentry_ptr *, |
@@ -1459,9 +1469,10 @@ ino_t f2fs_inode_by_name(struct inode *, struct qstr *); | |||
1459 | void f2fs_set_link(struct inode *, struct f2fs_dir_entry *, | 1469 | void f2fs_set_link(struct inode *, struct f2fs_dir_entry *, |
1460 | struct page *, struct inode *); | 1470 | struct page *, struct inode *); |
1461 | int update_dent_inode(struct inode *, const struct qstr *); | 1471 | int update_dent_inode(struct inode *, const struct qstr *); |
1462 | void f2fs_update_dentry(struct inode *, struct f2fs_dentry_ptr *, | 1472 | void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *, |
1463 | const struct qstr *, f2fs_hash_t , unsigned int); | 1473 | const struct qstr *, f2fs_hash_t , unsigned int); |
1464 | int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *); | 1474 | int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *, nid_t, |
1475 | umode_t); | ||
1465 | void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *, | 1476 | void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *, |
1466 | struct inode *); | 1477 | struct inode *); |
1467 | int f2fs_do_tmpfile(struct inode *, struct inode *); | 1478 | int f2fs_do_tmpfile(struct inode *, struct inode *); |
@@ -1471,7 +1482,7 @@ bool f2fs_empty_dir(struct inode *); | |||
1471 | static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode) | 1482 | static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode) |
1472 | { | 1483 | { |
1473 | return __f2fs_add_link(dentry->d_parent->d_inode, &dentry->d_name, | 1484 | return __f2fs_add_link(dentry->d_parent->d_inode, &dentry->d_name, |
1474 | inode); | 1485 | inode, inode->i_ino, inode->i_mode); |
1475 | } | 1486 | } |
1476 | 1487 | ||
1477 | /* | 1488 | /* |
@@ -1792,7 +1803,8 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *, struct qstr *, | |||
1792 | struct page **); | 1803 | struct page **); |
1793 | struct f2fs_dir_entry *f2fs_parent_inline_dir(struct inode *, struct page **); | 1804 | struct f2fs_dir_entry *f2fs_parent_inline_dir(struct inode *, struct page **); |
1794 | int make_empty_inline_dir(struct inode *inode, struct inode *, struct page *); | 1805 | int make_empty_inline_dir(struct inode *inode, struct inode *, struct page *); |
1795 | int f2fs_add_inline_entry(struct inode *, const struct qstr *, struct inode *); | 1806 | int f2fs_add_inline_entry(struct inode *, const struct qstr *, struct inode *, |
1807 | nid_t, umode_t); | ||
1796 | void f2fs_delete_inline_entry(struct f2fs_dir_entry *, struct page *, | 1808 | void f2fs_delete_inline_entry(struct f2fs_dir_entry *, struct page *, |
1797 | struct inode *, struct inode *); | 1809 | struct inode *, struct inode *); |
1798 | bool f2fs_empty_inline_dir(struct inode *); | 1810 | bool f2fs_empty_inline_dir(struct inode *); |
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 8241a87046c3..8140e4f0e538 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c | |||
@@ -390,7 +390,7 @@ out: | |||
390 | } | 390 | } |
391 | 391 | ||
392 | int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, | 392 | int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, |
393 | struct inode *inode) | 393 | struct inode *inode, nid_t ino, umode_t mode) |
394 | { | 394 | { |
395 | struct f2fs_sb_info *sbi = F2FS_I_SB(dir); | 395 | struct f2fs_sb_info *sbi = F2FS_I_SB(dir); |
396 | struct page *ipage; | 396 | struct page *ipage; |
@@ -400,7 +400,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, | |||
400 | struct f2fs_inline_dentry *dentry_blk = NULL; | 400 | struct f2fs_inline_dentry *dentry_blk = NULL; |
401 | struct f2fs_dentry_ptr d; | 401 | struct f2fs_dentry_ptr d; |
402 | int slots = GET_DENTRY_SLOTS(namelen); | 402 | int slots = GET_DENTRY_SLOTS(namelen); |
403 | struct page *page; | 403 | struct page *page = NULL; |
404 | int err = 0; | 404 | int err = 0; |
405 | 405 | ||
406 | ipage = get_node_page(sbi, dir->i_ino); | 406 | ipage = get_node_page(sbi, dir->i_ino); |
@@ -417,29 +417,34 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, | |||
417 | goto out; | 417 | goto out; |
418 | } | 418 | } |
419 | 419 | ||
420 | down_write(&F2FS_I(inode)->i_sem); | 420 | if (inode) { |
421 | page = init_inode_metadata(inode, dir, name, ipage); | 421 | down_write(&F2FS_I(inode)->i_sem); |
422 | if (IS_ERR(page)) { | 422 | page = init_inode_metadata(inode, dir, name, ipage); |
423 | err = PTR_ERR(page); | 423 | if (IS_ERR(page)) { |
424 | goto fail; | 424 | err = PTR_ERR(page); |
425 | goto fail; | ||
426 | } | ||
425 | } | 427 | } |
426 | 428 | ||
427 | f2fs_wait_on_page_writeback(ipage, NODE); | 429 | f2fs_wait_on_page_writeback(ipage, NODE); |
428 | 430 | ||
429 | name_hash = f2fs_dentry_hash(name); | 431 | name_hash = f2fs_dentry_hash(name); |
430 | make_dentry_ptr(&d, (void *)dentry_blk, 2); | 432 | make_dentry_ptr(&d, (void *)dentry_blk, 2); |
431 | f2fs_update_dentry(inode, &d, name, name_hash, bit_pos); | 433 | f2fs_update_dentry(ino, mode, &d, name, name_hash, bit_pos); |
432 | 434 | ||
433 | set_page_dirty(ipage); | 435 | set_page_dirty(ipage); |
434 | 436 | ||
435 | /* we don't need to mark_inode_dirty now */ | 437 | /* we don't need to mark_inode_dirty now */ |
436 | F2FS_I(inode)->i_pino = dir->i_ino; | 438 | if (inode) { |
437 | update_inode(inode, page); | 439 | F2FS_I(inode)->i_pino = dir->i_ino; |
438 | f2fs_put_page(page, 1); | 440 | update_inode(inode, page); |
441 | f2fs_put_page(page, 1); | ||
442 | } | ||
439 | 443 | ||
440 | update_parent_metadata(dir, inode, 0); | 444 | update_parent_metadata(dir, inode, 0); |
441 | fail: | 445 | fail: |
442 | up_write(&F2FS_I(inode)->i_sem); | 446 | if (inode) |
447 | up_write(&F2FS_I(inode)->i_sem); | ||
443 | 448 | ||
444 | if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { | 449 | if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { |
445 | update_inode(dir, ipage); | 450 | update_inode(dir, ipage); |
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 1e2ae21bd6b6..8055e30eb14d 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c | |||
@@ -187,6 +187,44 @@ struct dentry *f2fs_get_parent(struct dentry *child) | |||
187 | return d_obtain_alias(f2fs_iget(child->d_inode->i_sb, ino)); | 187 | return d_obtain_alias(f2fs_iget(child->d_inode->i_sb, ino)); |
188 | } | 188 | } |
189 | 189 | ||
190 | static int __recover_dot_dentries(struct inode *dir, nid_t pino) | ||
191 | { | ||
192 | struct f2fs_sb_info *sbi = F2FS_I_SB(dir); | ||
193 | struct qstr dot = QSTR_INIT(".", 1); | ||
194 | struct qstr dotdot = QSTR_INIT("..", 2); | ||
195 | struct f2fs_dir_entry *de; | ||
196 | struct page *page; | ||
197 | int err = 0; | ||
198 | |||
199 | f2fs_lock_op(sbi); | ||
200 | |||
201 | de = f2fs_find_entry(dir, &dot, &page); | ||
202 | if (de) { | ||
203 | f2fs_dentry_kunmap(dir, page); | ||
204 | f2fs_put_page(page, 0); | ||
205 | } else { | ||
206 | err = __f2fs_add_link(dir, &dot, NULL, dir->i_ino, S_IFDIR); | ||
207 | if (err) | ||
208 | goto out; | ||
209 | } | ||
210 | |||
211 | de = f2fs_find_entry(dir, &dotdot, &page); | ||
212 | if (de) { | ||
213 | f2fs_dentry_kunmap(dir, page); | ||
214 | f2fs_put_page(page, 0); | ||
215 | } else { | ||
216 | err = __f2fs_add_link(dir, &dotdot, NULL, pino, S_IFDIR); | ||
217 | } | ||
218 | out: | ||
219 | if (!err) { | ||
220 | clear_inode_flag(F2FS_I(dir), FI_INLINE_DOTS); | ||
221 | mark_inode_dirty(dir); | ||
222 | } | ||
223 | |||
224 | f2fs_unlock_op(sbi); | ||
225 | return err; | ||
226 | } | ||
227 | |||
190 | static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, | 228 | static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, |
191 | unsigned int flags) | 229 | unsigned int flags) |
192 | { | 230 | { |
@@ -206,6 +244,16 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, | |||
206 | inode = f2fs_iget(dir->i_sb, ino); | 244 | inode = f2fs_iget(dir->i_sb, ino); |
207 | if (IS_ERR(inode)) | 245 | if (IS_ERR(inode)) |
208 | return ERR_CAST(inode); | 246 | return ERR_CAST(inode); |
247 | |||
248 | if (f2fs_has_inline_dots(inode)) { | ||
249 | int err; | ||
250 | |||
251 | err = __recover_dot_dentries(inode, dir->i_ino); | ||
252 | if (err) { | ||
253 | iget_failed(inode); | ||
254 | return ERR_PTR(err); | ||
255 | } | ||
256 | } | ||
209 | } | 257 | } |
210 | 258 | ||
211 | return d_splice_alias(inode, dentry); | 259 | return d_splice_alias(inode, dentry); |
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index c69de88a6453..679c465e9def 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c | |||
@@ -115,7 +115,7 @@ retry: | |||
115 | iput(einode); | 115 | iput(einode); |
116 | goto retry; | 116 | goto retry; |
117 | } | 117 | } |
118 | err = __f2fs_add_link(dir, &name, inode); | 118 | err = __f2fs_add_link(dir, &name, inode, inode->i_ino, inode->i_mode); |
119 | if (err) | 119 | if (err) |
120 | goto out_err; | 120 | goto out_err; |
121 | 121 | ||