diff options
author | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-03-20 06:01:06 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-03-26 20:16:06 -0400 |
commit | 6ead114232f786e3ef7a034c8617f2a4df8e5226 (patch) | |
tree | 4ce177b708f8e98b148658a21d35fbec8bdc1e6b /fs/f2fs | |
parent | 111d2495a8a8fbd8e3bb0f1c1c60f977b1386249 (diff) |
f2fs: fix the recovery flow to handle errors correctly
We should handle errors during the recovery flow correctly.
For example, if we get -ENOMEM, we should report a mount failure instead of
conducting the remained mount procedure.
Reviewed-by: Namjae Jeon <namjae.jeon@samsung.com>
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs')
-rw-r--r-- | fs/f2fs/f2fs.h | 2 | ||||
-rw-r--r-- | fs/f2fs/recovery.c | 46 | ||||
-rw-r--r-- | fs/f2fs/super.c | 9 |
3 files changed, 36 insertions, 21 deletions
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 5bb87e0216f5..109e12d21a36 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
@@ -1027,7 +1027,7 @@ void destroy_gc_caches(void); | |||
1027 | /* | 1027 | /* |
1028 | * recovery.c | 1028 | * recovery.c |
1029 | */ | 1029 | */ |
1030 | void recover_fsync_data(struct f2fs_sb_info *); | 1030 | int recover_fsync_data(struct f2fs_sb_info *); |
1031 | bool space_for_roll_forward(struct f2fs_sb_info *); | 1031 | bool space_for_roll_forward(struct f2fs_sb_info *); |
1032 | 1032 | ||
1033 | /* | 1033 | /* |
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 2d86eb26c493..61bdaa755906 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c | |||
@@ -118,10 +118,8 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) | |||
118 | 118 | ||
119 | lock_page(page); | 119 | lock_page(page); |
120 | 120 | ||
121 | if (cp_ver != cpver_of_node(page)) { | 121 | if (cp_ver != cpver_of_node(page)) |
122 | err = -EINVAL; | ||
123 | goto unlock_out; | 122 | goto unlock_out; |
124 | } | ||
125 | 123 | ||
126 | if (!is_fsync_dnode(page)) | 124 | if (!is_fsync_dnode(page)) |
127 | goto next; | 125 | goto next; |
@@ -134,10 +132,9 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) | |||
134 | FI_INC_LINK); | 132 | FI_INC_LINK); |
135 | } else { | 133 | } else { |
136 | if (IS_INODE(page) && is_dent_dnode(page)) { | 134 | if (IS_INODE(page) && is_dent_dnode(page)) { |
137 | if (recover_inode_page(sbi, page)) { | 135 | err = recover_inode_page(sbi, page); |
138 | err = -ENOMEM; | 136 | if (err) |
139 | goto unlock_out; | 137 | goto unlock_out; |
140 | } | ||
141 | } | 138 | } |
142 | 139 | ||
143 | /* add this fsync inode to the list */ | 140 | /* add this fsync inode to the list */ |
@@ -237,13 +234,14 @@ static void check_index_in_prev_nodes(struct f2fs_sb_info *sbi, | |||
237 | iput(inode); | 234 | iput(inode); |
238 | } | 235 | } |
239 | 236 | ||
240 | static void do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, | 237 | static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, |
241 | struct page *page, block_t blkaddr) | 238 | struct page *page, block_t blkaddr) |
242 | { | 239 | { |
243 | unsigned int start, end; | 240 | unsigned int start, end; |
244 | struct dnode_of_data dn; | 241 | struct dnode_of_data dn; |
245 | struct f2fs_summary sum; | 242 | struct f2fs_summary sum; |
246 | struct node_info ni; | 243 | struct node_info ni; |
244 | int err = 0; | ||
247 | 245 | ||
248 | start = start_bidx_of_node(ofs_of_node(page)); | 246 | start = start_bidx_of_node(ofs_of_node(page)); |
249 | if (IS_INODE(page)) | 247 | if (IS_INODE(page)) |
@@ -252,8 +250,9 @@ static void do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, | |||
252 | end = start + ADDRS_PER_BLOCK; | 250 | end = start + ADDRS_PER_BLOCK; |
253 | 251 | ||
254 | set_new_dnode(&dn, inode, NULL, NULL, 0); | 252 | set_new_dnode(&dn, inode, NULL, NULL, 0); |
255 | if (get_dnode_of_data(&dn, start, ALLOC_NODE)) | 253 | err = get_dnode_of_data(&dn, start, ALLOC_NODE); |
256 | return; | 254 | if (err) |
255 | return err; | ||
257 | 256 | ||
258 | wait_on_page_writeback(dn.node_page); | 257 | wait_on_page_writeback(dn.node_page); |
259 | 258 | ||
@@ -298,14 +297,16 @@ static void do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, | |||
298 | 297 | ||
299 | recover_node_page(sbi, dn.node_page, &sum, &ni, blkaddr); | 298 | recover_node_page(sbi, dn.node_page, &sum, &ni, blkaddr); |
300 | f2fs_put_dnode(&dn); | 299 | f2fs_put_dnode(&dn); |
300 | return 0; | ||
301 | } | 301 | } |
302 | 302 | ||
303 | static void recover_data(struct f2fs_sb_info *sbi, | 303 | static int recover_data(struct f2fs_sb_info *sbi, |
304 | struct list_head *head, int type) | 304 | struct list_head *head, int type) |
305 | { | 305 | { |
306 | unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver); | 306 | unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver); |
307 | struct curseg_info *curseg; | 307 | struct curseg_info *curseg; |
308 | struct page *page; | 308 | struct page *page; |
309 | int err = 0; | ||
309 | block_t blkaddr; | 310 | block_t blkaddr; |
310 | 311 | ||
311 | /* get node pages in the current segment */ | 312 | /* get node pages in the current segment */ |
@@ -315,13 +316,15 @@ static void recover_data(struct f2fs_sb_info *sbi, | |||
315 | /* read node page */ | 316 | /* read node page */ |
316 | page = alloc_page(GFP_NOFS | __GFP_ZERO); | 317 | page = alloc_page(GFP_NOFS | __GFP_ZERO); |
317 | if (IS_ERR(page)) | 318 | if (IS_ERR(page)) |
318 | return; | 319 | return -ENOMEM; |
320 | |||
319 | lock_page(page); | 321 | lock_page(page); |
320 | 322 | ||
321 | while (1) { | 323 | while (1) { |
322 | struct fsync_inode_entry *entry; | 324 | struct fsync_inode_entry *entry; |
323 | 325 | ||
324 | if (f2fs_readpage(sbi, page, blkaddr, READ_SYNC)) | 326 | err = f2fs_readpage(sbi, page, blkaddr, READ_SYNC); |
327 | if (err) | ||
325 | goto out; | 328 | goto out; |
326 | 329 | ||
327 | lock_page(page); | 330 | lock_page(page); |
@@ -333,7 +336,9 @@ static void recover_data(struct f2fs_sb_info *sbi, | |||
333 | if (!entry) | 336 | if (!entry) |
334 | goto next; | 337 | goto next; |
335 | 338 | ||
336 | do_recover_data(sbi, entry->inode, page, blkaddr); | 339 | err = do_recover_data(sbi, entry->inode, page, blkaddr); |
340 | if (err) | ||
341 | goto out; | ||
337 | 342 | ||
338 | if (entry->blkaddr == blkaddr) { | 343 | if (entry->blkaddr == blkaddr) { |
339 | iput(entry->inode); | 344 | iput(entry->inode); |
@@ -349,22 +354,26 @@ unlock_out: | |||
349 | out: | 354 | out: |
350 | __free_pages(page, 0); | 355 | __free_pages(page, 0); |
351 | 356 | ||
352 | allocate_new_segments(sbi); | 357 | if (!err) |
358 | allocate_new_segments(sbi); | ||
359 | return err; | ||
353 | } | 360 | } |
354 | 361 | ||
355 | void recover_fsync_data(struct f2fs_sb_info *sbi) | 362 | int recover_fsync_data(struct f2fs_sb_info *sbi) |
356 | { | 363 | { |
357 | struct list_head inode_list; | 364 | struct list_head inode_list; |
365 | int err; | ||
358 | 366 | ||
359 | fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry", | 367 | fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry", |
360 | sizeof(struct fsync_inode_entry), NULL); | 368 | sizeof(struct fsync_inode_entry), NULL); |
361 | if (unlikely(!fsync_entry_slab)) | 369 | if (unlikely(!fsync_entry_slab)) |
362 | return; | 370 | return -ENOMEM; |
363 | 371 | ||
364 | INIT_LIST_HEAD(&inode_list); | 372 | INIT_LIST_HEAD(&inode_list); |
365 | 373 | ||
366 | /* step #1: find fsynced inode numbers */ | 374 | /* step #1: find fsynced inode numbers */ |
367 | if (find_fsync_dnodes(sbi, &inode_list)) | 375 | err = find_fsync_dnodes(sbi, &inode_list); |
376 | if (err) | ||
368 | goto out; | 377 | goto out; |
369 | 378 | ||
370 | if (list_empty(&inode_list)) | 379 | if (list_empty(&inode_list)) |
@@ -372,11 +381,12 @@ void recover_fsync_data(struct f2fs_sb_info *sbi) | |||
372 | 381 | ||
373 | /* step #2: recover data */ | 382 | /* step #2: recover data */ |
374 | sbi->por_doing = 1; | 383 | sbi->por_doing = 1; |
375 | recover_data(sbi, &inode_list, CURSEG_WARM_NODE); | 384 | err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE); |
376 | sbi->por_doing = 0; | 385 | sbi->por_doing = 0; |
377 | BUG_ON(!list_empty(&inode_list)); | 386 | BUG_ON(!list_empty(&inode_list)); |
378 | out: | 387 | out: |
379 | destroy_fsync_dnodes(sbi, &inode_list); | 388 | destroy_fsync_dnodes(sbi, &inode_list); |
380 | kmem_cache_destroy(fsync_entry_slab); | 389 | kmem_cache_destroy(fsync_entry_slab); |
381 | write_checkpoint(sbi, false); | 390 | write_checkpoint(sbi, false); |
391 | return err; | ||
382 | } | 392 | } |
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index c9ef88da0723..252890ef8dbc 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c | |||
@@ -642,8 +642,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
642 | } | 642 | } |
643 | 643 | ||
644 | /* recover fsynced data */ | 644 | /* recover fsynced data */ |
645 | if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) | 645 | if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) { |
646 | recover_fsync_data(sbi); | 646 | err = recover_fsync_data(sbi); |
647 | if (err) { | ||
648 | f2fs_msg(sb, KERN_ERR, "Failed to recover fsync data"); | ||
649 | goto free_root_inode; | ||
650 | } | ||
651 | } | ||
647 | 652 | ||
648 | /* After POR, we can run background GC thread */ | 653 | /* After POR, we can run background GC thread */ |
649 | err = start_gc_thread(sbi); | 654 | err = start_gc_thread(sbi); |