aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/f2fs/checkpoint.c33
-rw-r--r--fs/f2fs/f2fs.h6
-rw-r--r--fs/f2fs/recovery.c56
-rw-r--r--fs/f2fs/segment.h5
4 files changed, 58 insertions, 42 deletions
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index d44d287cdae9..a1786d680906 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -72,7 +72,23 @@ out:
72 return page; 72 return page;
73} 73}
74 74
75static inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type) 75struct page *get_meta_page_ra(struct f2fs_sb_info *sbi, pgoff_t index)
76{
77 bool readahead = false;
78 struct page *page;
79
80 page = find_get_page(META_MAPPING(sbi), index);
81 if (!page || (page && !PageUptodate(page)))
82 readahead = true;
83 f2fs_put_page(page, 0);
84
85 if (readahead)
86 ra_meta_pages(sbi, index,
87 MAX_BIO_BLOCKS(max_hw_blocks(sbi)), META_POR);
88 return get_meta_page(sbi, index);
89}
90
91static inline block_t get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
76{ 92{
77 switch (type) { 93 switch (type) {
78 case META_NAT: 94 case META_NAT:
@@ -82,6 +98,8 @@ static inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
82 case META_SSA: 98 case META_SSA:
83 case META_CP: 99 case META_CP:
84 return 0; 100 return 0;
101 case META_POR:
102 return SM_I(sbi)->seg0_blkaddr + TOTAL_BLKS(sbi);
85 default: 103 default:
86 BUG(); 104 BUG();
87 } 105 }
@@ -90,12 +108,13 @@ static inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
90/* 108/*
91 * Readahead CP/NAT/SIT/SSA pages 109 * Readahead CP/NAT/SIT/SSA pages
92 */ 110 */
93int ra_meta_pages(struct f2fs_sb_info *sbi, int start, int nrpages, int type) 111int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type)
94{ 112{
95 block_t prev_blk_addr = 0; 113 block_t prev_blk_addr = 0;
96 struct page *page; 114 struct page *page;
97 int blkno = start; 115 block_t blkno = start;
98 int max_blks = get_max_meta_blks(sbi, type); 116 block_t max_blks = get_max_meta_blks(sbi, type);
117 block_t min_blks = SM_I(sbi)->seg0_blkaddr;
99 118
100 struct f2fs_io_info fio = { 119 struct f2fs_io_info fio = {
101 .type = META, 120 .type = META,
@@ -125,7 +144,11 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, int start, int nrpages, int type)
125 break; 144 break;
126 case META_SSA: 145 case META_SSA:
127 case META_CP: 146 case META_CP:
128 /* get ssa/cp block addr */ 147 case META_POR:
148 if (unlikely(blkno >= max_blks))
149 goto out;
150 if (unlikely(blkno < min_blks))
151 goto out;
129 blk_addr = blkno; 152 blk_addr = blkno;
130 break; 153 break;
131 default: 154 default:
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 8efa170352ff..b6439c3d1744 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -103,7 +103,8 @@ enum {
103 META_CP, 103 META_CP,
104 META_NAT, 104 META_NAT,
105 META_SIT, 105 META_SIT,
106 META_SSA 106 META_SSA,
107 META_POR,
107}; 108};
108 109
109/* for the list of ino */ 110/* for the list of ino */
@@ -1294,7 +1295,8 @@ void destroy_segment_manager_caches(void);
1294 */ 1295 */
1295struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t); 1296struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
1296struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t); 1297struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t);
1297int ra_meta_pages(struct f2fs_sb_info *, int, int, int); 1298struct page *get_meta_page_ra(struct f2fs_sb_info *, pgoff_t);
1299int ra_meta_pages(struct f2fs_sb_info *, block_t, int, int);
1298long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long); 1300long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
1299void add_dirty_inode(struct f2fs_sb_info *, nid_t, int type); 1301void add_dirty_inode(struct f2fs_sb_info *, nid_t, int type);
1300void remove_dirty_inode(struct f2fs_sb_info *, nid_t, int type); 1302void remove_dirty_inode(struct f2fs_sb_info *, nid_t, int type);
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index e587ee128e17..7049a3adc409 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -138,7 +138,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
138{ 138{
139 unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi)); 139 unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
140 struct curseg_info *curseg; 140 struct curseg_info *curseg;
141 struct page *page; 141 struct page *page = NULL;
142 block_t blkaddr; 142 block_t blkaddr;
143 int err = 0; 143 int err = 0;
144 144
@@ -146,20 +146,14 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
146 curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); 146 curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
147 blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); 147 blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
148 148
149 /* read node page */
150 page = alloc_page(GFP_F2FS_ZERO);
151 if (!page)
152 return -ENOMEM;
153 lock_page(page);
154
155 while (1) { 149 while (1) {
156 struct fsync_inode_entry *entry; 150 struct fsync_inode_entry *entry;
157 151
158 err = f2fs_submit_page_bio(sbi, page, blkaddr, READ_SYNC); 152 if (blkaddr < SM_I(sbi)->main_blkaddr ||
159 if (err) 153 blkaddr >= (SM_I(sbi)->seg0_blkaddr + TOTAL_BLKS(sbi)))
160 return err; 154 return 0;
161 155
162 lock_page(page); 156 page = get_meta_page_ra(sbi, blkaddr);
163 157
164 if (cp_ver != cpver_of_node(page)) 158 if (cp_ver != cpver_of_node(page))
165 break; 159 break;
@@ -202,11 +196,9 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
202next: 196next:
203 /* check next segment */ 197 /* check next segment */
204 blkaddr = next_blkaddr_of_node(page); 198 blkaddr = next_blkaddr_of_node(page);
199 f2fs_put_page(page, 1);
205 } 200 }
206 201 f2fs_put_page(page, 1);
207 unlock_page(page);
208 __free_pages(page, 0);
209
210 return err; 202 return err;
211} 203}
212 204
@@ -400,7 +392,7 @@ static int recover_data(struct f2fs_sb_info *sbi,
400{ 392{
401 unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi)); 393 unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
402 struct curseg_info *curseg; 394 struct curseg_info *curseg;
403 struct page *page; 395 struct page *page = NULL;
404 int err = 0; 396 int err = 0;
405 block_t blkaddr; 397 block_t blkaddr;
406 398
@@ -408,32 +400,29 @@ static int recover_data(struct f2fs_sb_info *sbi,
408 curseg = CURSEG_I(sbi, type); 400 curseg = CURSEG_I(sbi, type);
409 blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); 401 blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
410 402
411 /* read node page */
412 page = alloc_page(GFP_F2FS_ZERO);
413 if (!page)
414 return -ENOMEM;
415
416 lock_page(page);
417
418 while (1) { 403 while (1) {
419 struct fsync_inode_entry *entry; 404 struct fsync_inode_entry *entry;
420 405
421 err = f2fs_submit_page_bio(sbi, page, blkaddr, READ_SYNC); 406 if (blkaddr < SM_I(sbi)->main_blkaddr ||
422 if (err) 407 blkaddr >= (SM_I(sbi)->seg0_blkaddr + TOTAL_BLKS(sbi)))
423 return err; 408 break;
424 409
425 lock_page(page); 410 page = get_meta_page_ra(sbi, blkaddr);
426 411
427 if (cp_ver != cpver_of_node(page)) 412 if (cp_ver != cpver_of_node(page)) {
413 f2fs_put_page(page, 1);
428 break; 414 break;
415 }
429 416
430 entry = get_fsync_inode(head, ino_of_node(page)); 417 entry = get_fsync_inode(head, ino_of_node(page));
431 if (!entry) 418 if (!entry)
432 goto next; 419 goto next;
433 420
434 err = do_recover_data(sbi, entry->inode, page, blkaddr); 421 err = do_recover_data(sbi, entry->inode, page, blkaddr);
435 if (err) 422 if (err) {
423 f2fs_put_page(page, 1);
436 break; 424 break;
425 }
437 426
438 if (entry->blkaddr == blkaddr) { 427 if (entry->blkaddr == blkaddr) {
439 iput(entry->inode); 428 iput(entry->inode);
@@ -443,11 +432,8 @@ static int recover_data(struct f2fs_sb_info *sbi,
443next: 432next:
444 /* check next segment */ 433 /* check next segment */
445 blkaddr = next_blkaddr_of_node(page); 434 blkaddr = next_blkaddr_of_node(page);
435 f2fs_put_page(page, 1);
446 } 436 }
447
448 unlock_page(page);
449 __free_pages(page, 0);
450
451 if (!err) 437 if (!err)
452 allocate_new_segments(sbi); 438 allocate_new_segments(sbi);
453 return err; 439 return err;
@@ -493,6 +479,10 @@ out:
493 destroy_fsync_dnodes(&inode_list); 479 destroy_fsync_dnodes(&inode_list);
494 kmem_cache_destroy(fsync_entry_slab); 480 kmem_cache_destroy(fsync_entry_slab);
495 481
482 /* truncate meta pages to be used by the recovery */
483 truncate_inode_pages_range(META_MAPPING(sbi),
484 SM_I(sbi)->main_blkaddr << PAGE_CACHE_SHIFT, -1);
485
496 if (err) { 486 if (err) {
497 truncate_inode_pages_final(NODE_MAPPING(sbi)); 487 truncate_inode_pages_final(NODE_MAPPING(sbi));
498 truncate_inode_pages_final(META_MAPPING(sbi)); 488 truncate_inode_pages_final(META_MAPPING(sbi));
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index 013aed2f3539..c6f37f2fe50e 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -87,6 +87,7 @@
87 (BITS_TO_LONGS(nr) * sizeof(unsigned long)) 87 (BITS_TO_LONGS(nr) * sizeof(unsigned long))
88#define TOTAL_SEGS(sbi) (SM_I(sbi)->main_segments) 88#define TOTAL_SEGS(sbi) (SM_I(sbi)->main_segments)
89#define TOTAL_SECS(sbi) (sbi->total_sections) 89#define TOTAL_SECS(sbi) (sbi->total_sections)
90#define TOTAL_BLKS(sbi) (SM_I(sbi)->segment_count << sbi->log_blocks_per_seg)
90 91
91#define SECTOR_FROM_BLOCK(sbi, blk_addr) \ 92#define SECTOR_FROM_BLOCK(sbi, blk_addr) \
92 (((sector_t)blk_addr) << (sbi)->log_sectors_per_block) 93 (((sector_t)blk_addr) << (sbi)->log_sectors_per_block)
@@ -553,7 +554,7 @@ static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
553static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr) 554static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
554{ 555{
555 struct f2fs_sm_info *sm_info = SM_I(sbi); 556 struct f2fs_sm_info *sm_info = SM_I(sbi);
556 block_t total_blks = sm_info->segment_count << sbi->log_blocks_per_seg; 557 block_t total_blks = TOTAL_BLKS(sbi);
557 block_t start_addr = sm_info->seg0_blkaddr; 558 block_t start_addr = sm_info->seg0_blkaddr;
558 block_t end_addr = start_addr + total_blks - 1; 559 block_t end_addr = start_addr + total_blks - 1;
559 BUG_ON(blk_addr < start_addr); 560 BUG_ON(blk_addr < start_addr);
@@ -606,7 +607,7 @@ static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
606static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr) 607static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
607{ 608{
608 struct f2fs_sm_info *sm_info = SM_I(sbi); 609 struct f2fs_sm_info *sm_info = SM_I(sbi);
609 block_t total_blks = sm_info->segment_count << sbi->log_blocks_per_seg; 610 block_t total_blks = TOTAL_BLKS(sbi);
610 block_t start_addr = sm_info->seg0_blkaddr; 611 block_t start_addr = sm_info->seg0_blkaddr;
611 block_t end_addr = start_addr + total_blks - 1; 612 block_t end_addr = start_addr + total_blks - 1;
612 613