diff options
author | Jaegeuk Kim <jaegeuk@kernel.org> | 2014-09-15 19:46:08 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2014-09-23 14:10:16 -0400 |
commit | 441ac5cb323a47b0a665f77f7cd6f76aacbdf21c (patch) | |
tree | b8aca7fbc39d37a06123c491438ad5b82a241af0 /fs/f2fs/recovery.c | |
parent | 88bd02c9472a166b706284a34a84f1243322d782 (diff) |
f2fs: fix roll-forward missing scenarios
We can summarize the roll forward recovery scenarios as follows.
[Term] F: fsync_mark, D: dentry_mark
1. inode(x) | CP | inode(x) | dnode(F)
-> Update the latest inode(x).
2. inode(x) | CP | inode(F) | dnode(F)
-> No problem.
3. inode(x) | CP | dnode(F) | inode(x)
-> Recover to the latest dnode(F), and drop the last inode(x)
4. inode(x) | CP | dnode(F) | inode(F)
-> No problem.
5. CP | inode(x) | dnode(F)
-> The inode(DF) was missing. Should drop this dnode(F).
6. CP | inode(DF) | dnode(F)
-> No problem.
7. CP | dnode(F) | inode(DF)
-> If f2fs_iget fails, then goto next to find inode(DF).
8. CP | dnode(F) | inode(x)
-> If f2fs_iget fails, then goto next to find inode(DF).
But it will fail due to no inode(DF).
So, this patch adds some missing points such as #1, #5, #7, and #8.
Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs/f2fs/recovery.c')
-rw-r--r-- | fs/f2fs/recovery.c | 71 |
1 files changed, 60 insertions, 11 deletions
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 7049a3adc409..39832833c02f 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c | |||
@@ -14,6 +14,37 @@ | |||
14 | #include "node.h" | 14 | #include "node.h" |
15 | #include "segment.h" | 15 | #include "segment.h" |
16 | 16 | ||
17 | /* | ||
18 | * Roll forward recovery scenarios. | ||
19 | * | ||
20 | * [Term] F: fsync_mark, D: dentry_mark | ||
21 | * | ||
22 | * 1. inode(x) | CP | inode(x) | dnode(F) | ||
23 | * -> Update the latest inode(x). | ||
24 | * | ||
25 | * 2. inode(x) | CP | inode(F) | dnode(F) | ||
26 | * -> No problem. | ||
27 | * | ||
28 | * 3. inode(x) | CP | dnode(F) | inode(x) | ||
29 | * -> Recover to the latest dnode(F), and drop the last inode(x) | ||
30 | * | ||
31 | * 4. inode(x) | CP | dnode(F) | inode(F) | ||
32 | * -> No problem. | ||
33 | * | ||
34 | * 5. CP | inode(x) | dnode(F) | ||
35 | * -> The inode(DF) was missing. Should drop this dnode(F). | ||
36 | * | ||
37 | * 6. CP | inode(DF) | dnode(F) | ||
38 | * -> No problem. | ||
39 | * | ||
40 | * 7. CP | dnode(F) | inode(DF) | ||
41 | * -> If f2fs_iget fails, then goto next to find inode(DF). | ||
42 | * | ||
43 | * 8. CP | dnode(F) | inode(x) | ||
44 | * -> If f2fs_iget fails, then goto next to find inode(DF). | ||
45 | * But it will fail due to no inode(DF). | ||
46 | */ | ||
47 | |||
17 | static struct kmem_cache *fsync_entry_slab; | 48 | static struct kmem_cache *fsync_entry_slab; |
18 | 49 | ||
19 | bool space_for_roll_forward(struct f2fs_sb_info *sbi) | 50 | bool space_for_roll_forward(struct f2fs_sb_info *sbi) |
@@ -110,27 +141,32 @@ out: | |||
110 | return err; | 141 | return err; |
111 | } | 142 | } |
112 | 143 | ||
113 | static int recover_inode(struct inode *inode, struct page *node_page) | 144 | static void __recover_inode(struct inode *inode, struct page *page) |
114 | { | 145 | { |
115 | struct f2fs_inode *raw_inode = F2FS_INODE(node_page); | 146 | struct f2fs_inode *raw = F2FS_INODE(page); |
147 | |||
148 | inode->i_mode = le16_to_cpu(raw->i_mode); | ||
149 | i_size_write(inode, le64_to_cpu(raw->i_size)); | ||
150 | inode->i_atime.tv_sec = le64_to_cpu(raw->i_mtime); | ||
151 | inode->i_ctime.tv_sec = le64_to_cpu(raw->i_ctime); | ||
152 | inode->i_mtime.tv_sec = le64_to_cpu(raw->i_mtime); | ||
153 | inode->i_atime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec); | ||
154 | inode->i_ctime.tv_nsec = le32_to_cpu(raw->i_ctime_nsec); | ||
155 | inode->i_mtime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec); | ||
156 | } | ||
116 | 157 | ||
158 | static int recover_inode(struct inode *inode, struct page *node_page) | ||
159 | { | ||
117 | if (!IS_INODE(node_page)) | 160 | if (!IS_INODE(node_page)) |
118 | return 0; | 161 | return 0; |
119 | 162 | ||
120 | inode->i_mode = le16_to_cpu(raw_inode->i_mode); | 163 | __recover_inode(inode, node_page); |
121 | i_size_write(inode, le64_to_cpu(raw_inode->i_size)); | ||
122 | inode->i_atime.tv_sec = le64_to_cpu(raw_inode->i_mtime); | ||
123 | inode->i_ctime.tv_sec = le64_to_cpu(raw_inode->i_ctime); | ||
124 | inode->i_mtime.tv_sec = le64_to_cpu(raw_inode->i_mtime); | ||
125 | inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); | ||
126 | inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_ctime_nsec); | ||
127 | inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); | ||
128 | 164 | ||
129 | if (is_dent_dnode(node_page)) | 165 | if (is_dent_dnode(node_page)) |
130 | return recover_dentry(node_page, inode); | 166 | return recover_dentry(node_page, inode); |
131 | 167 | ||
132 | f2fs_msg(inode->i_sb, KERN_NOTICE, "recover_inode: ino = %x, name = %s", | 168 | f2fs_msg(inode->i_sb, KERN_NOTICE, "recover_inode: ino = %x, name = %s", |
133 | ino_of_node(node_page), raw_inode->i_name); | 169 | ino_of_node(node_page), F2FS_INODE(node_page)->i_name); |
134 | return 0; | 170 | return 0; |
135 | } | 171 | } |
136 | 172 | ||
@@ -180,10 +216,16 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) | |||
180 | break; | 216 | break; |
181 | } | 217 | } |
182 | 218 | ||
219 | /* | ||
220 | * CP | dnode(F) | inode(DF) | ||
221 | * For this case, we should not give up now. | ||
222 | */ | ||
183 | entry->inode = f2fs_iget(sbi->sb, ino_of_node(page)); | 223 | entry->inode = f2fs_iget(sbi->sb, ino_of_node(page)); |
184 | if (IS_ERR(entry->inode)) { | 224 | if (IS_ERR(entry->inode)) { |
185 | err = PTR_ERR(entry->inode); | 225 | err = PTR_ERR(entry->inode); |
186 | kmem_cache_free(fsync_entry_slab, entry); | 226 | kmem_cache_free(fsync_entry_slab, entry); |
227 | if (err == -ENOENT) | ||
228 | goto next; | ||
187 | break; | 229 | break; |
188 | } | 230 | } |
189 | list_add_tail(&entry->list, head); | 231 | list_add_tail(&entry->list, head); |
@@ -417,6 +459,13 @@ static int recover_data(struct f2fs_sb_info *sbi, | |||
417 | entry = get_fsync_inode(head, ino_of_node(page)); | 459 | entry = get_fsync_inode(head, ino_of_node(page)); |
418 | if (!entry) | 460 | if (!entry) |
419 | goto next; | 461 | goto next; |
462 | /* | ||
463 | * inode(x) | CP | inode(x) | dnode(F) | ||
464 | * In this case, we can lose the latest inode(x). | ||
465 | * So, call __recover_inode for the inode update. | ||
466 | */ | ||
467 | if (IS_INODE(page)) | ||
468 | __recover_inode(entry->inode, page); | ||
420 | 469 | ||
421 | err = do_recover_data(sbi, entry->inode, page, blkaddr); | 470 | err = do_recover_data(sbi, entry->inode, page, blkaddr); |
422 | if (err) { | 471 | if (err) { |