aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk.kim@samsung.com>2013-03-20 06:01:06 -0400
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2013-03-26 20:16:06 -0400
commit6ead114232f786e3ef7a034c8617f2a4df8e5226 (patch)
tree4ce177b708f8e98b148658a21d35fbec8bdc1e6b /fs/f2fs
parent111d2495a8a8fbd8e3bb0f1c1c60f977b1386249 (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.h2
-rw-r--r--fs/f2fs/recovery.c46
-rw-r--r--fs/f2fs/super.c9
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 */
1030void recover_fsync_data(struct f2fs_sb_info *); 1030int recover_fsync_data(struct f2fs_sb_info *);
1031bool space_for_roll_forward(struct f2fs_sb_info *); 1031bool 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
240static void do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, 237static 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
303static void recover_data(struct f2fs_sb_info *sbi, 303static 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:
349out: 354out:
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
355void recover_fsync_data(struct f2fs_sb_info *sbi) 362int 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));
378out: 387out:
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);