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 | ||
