diff options
-rw-r--r-- | fs/f2fs/checkpoint.c | 23 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 2 | ||||
-rw-r--r-- | fs/f2fs/recovery.c | 14 |
3 files changed, 34 insertions, 5 deletions
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index b1de01da1a40..3d1144908ac6 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c | |||
@@ -514,6 +514,29 @@ void remove_dirty_dir_inode(struct inode *inode) | |||
514 | } | 514 | } |
515 | out: | 515 | out: |
516 | spin_unlock(&sbi->dir_inode_lock); | 516 | spin_unlock(&sbi->dir_inode_lock); |
517 | |||
518 | /* Only from the recovery routine */ | ||
519 | if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) | ||
520 | iput(inode); | ||
521 | } | ||
522 | |||
523 | struct inode *check_dirty_dir_inode(struct f2fs_sb_info *sbi, nid_t ino) | ||
524 | { | ||
525 | struct list_head *head = &sbi->dir_inode_list; | ||
526 | struct list_head *this; | ||
527 | struct inode *inode = NULL; | ||
528 | |||
529 | spin_lock(&sbi->dir_inode_lock); | ||
530 | list_for_each(this, head) { | ||
531 | struct dir_inode_entry *entry; | ||
532 | entry = list_entry(this, struct dir_inode_entry, list); | ||
533 | if (entry->inode->i_ino == ino) { | ||
534 | inode = entry->inode; | ||
535 | break; | ||
536 | } | ||
537 | } | ||
538 | spin_unlock(&sbi->dir_inode_lock); | ||
539 | return inode; | ||
517 | } | 540 | } |
518 | 541 | ||
519 | void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) | 542 | void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) |
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 20aab02f2a42..ef6cac8c16a5 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
@@ -846,6 +846,7 @@ enum { | |||
846 | FI_INC_LINK, /* need to increment i_nlink */ | 846 | FI_INC_LINK, /* need to increment i_nlink */ |
847 | FI_ACL_MODE, /* indicate acl mode */ | 847 | FI_ACL_MODE, /* indicate acl mode */ |
848 | FI_NO_ALLOC, /* should not allocate any blocks */ | 848 | FI_NO_ALLOC, /* should not allocate any blocks */ |
849 | FI_DELAY_IPUT, /* used for the recovery */ | ||
849 | }; | 850 | }; |
850 | 851 | ||
851 | static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag) | 852 | static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag) |
@@ -1012,6 +1013,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *); | |||
1012 | int get_valid_checkpoint(struct f2fs_sb_info *); | 1013 | int get_valid_checkpoint(struct f2fs_sb_info *); |
1013 | void set_dirty_dir_page(struct inode *, struct page *); | 1014 | void set_dirty_dir_page(struct inode *, struct page *); |
1014 | void remove_dirty_dir_inode(struct inode *); | 1015 | void remove_dirty_dir_inode(struct inode *); |
1016 | struct inode *check_dirty_dir_inode(struct f2fs_sb_info *, nid_t); | ||
1015 | void sync_dirty_dir_inodes(struct f2fs_sb_info *); | 1017 | void sync_dirty_dir_inodes(struct f2fs_sb_info *); |
1016 | void write_checkpoint(struct f2fs_sb_info *, bool); | 1018 | void write_checkpoint(struct f2fs_sb_info *, bool); |
1017 | void init_orphan_info(struct f2fs_sb_info *); | 1019 | void init_orphan_info(struct f2fs_sb_info *); |
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 4d895149a6f0..23f580397e6c 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c | |||
@@ -42,6 +42,7 @@ static int recover_dentry(struct page *ipage, struct inode *inode) | |||
42 | { | 42 | { |
43 | struct f2fs_node *raw_node = (struct f2fs_node *)kmap(ipage); | 43 | struct f2fs_node *raw_node = (struct f2fs_node *)kmap(ipage); |
44 | struct f2fs_inode *raw_inode = &(raw_node->i); | 44 | struct f2fs_inode *raw_inode = &(raw_node->i); |
45 | nid_t pino = le32_to_cpu(raw_inode->i_pino); | ||
45 | struct qstr name; | 46 | struct qstr name; |
46 | struct f2fs_dir_entry *de; | 47 | struct f2fs_dir_entry *de; |
47 | struct page *page; | 48 | struct page *page; |
@@ -51,10 +52,14 @@ static int recover_dentry(struct page *ipage, struct inode *inode) | |||
51 | if (!is_dent_dnode(ipage)) | 52 | if (!is_dent_dnode(ipage)) |
52 | goto out; | 53 | goto out; |
53 | 54 | ||
54 | dir = f2fs_iget(inode->i_sb, le32_to_cpu(raw_inode->i_pino)); | 55 | dir = check_dirty_dir_inode(F2FS_SB(inode->i_sb), pino); |
55 | if (IS_ERR(dir)) { | 56 | if (!dir) { |
56 | err = PTR_ERR(dir); | 57 | dir = f2fs_iget(inode->i_sb, pino); |
57 | goto out; | 58 | if (IS_ERR(dir)) { |
59 | err = PTR_ERR(dir); | ||
60 | goto out; | ||
61 | } | ||
62 | set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT); | ||
58 | } | 63 | } |
59 | 64 | ||
60 | name.len = le32_to_cpu(raw_inode->i_namelen); | 65 | name.len = le32_to_cpu(raw_inode->i_namelen); |
@@ -67,7 +72,6 @@ static int recover_dentry(struct page *ipage, struct inode *inode) | |||
67 | } else { | 72 | } else { |
68 | err = __f2fs_add_link(dir, &name, inode); | 73 | err = __f2fs_add_link(dir, &name, inode); |
69 | } | 74 | } |
70 | iput(dir); | ||
71 | out: | 75 | out: |
72 | kunmap(ipage); | 76 | kunmap(ipage); |
73 | return err; | 77 | return err; |