diff options
-rw-r--r-- | fs/f2fs/checkpoint.c | 33 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 6 | ||||
-rw-r--r-- | fs/f2fs/recovery.c | 56 | ||||
-rw-r--r-- | fs/f2fs/segment.h | 5 |
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 | ||
75 | static inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type) | 75 | struct 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 | |||
91 | static 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 | */ |
93 | int ra_meta_pages(struct f2fs_sb_info *sbi, int start, int nrpages, int type) | 111 | int 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 | */ |
1295 | struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t); | 1296 | struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t); |
1296 | struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t); | 1297 | struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t); |
1297 | int ra_meta_pages(struct f2fs_sb_info *, int, int, int); | 1298 | struct page *get_meta_page_ra(struct f2fs_sb_info *, pgoff_t); |
1299 | int ra_meta_pages(struct f2fs_sb_info *, block_t, int, int); | ||
1298 | long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long); | 1300 | long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long); |
1299 | void add_dirty_inode(struct f2fs_sb_info *, nid_t, int type); | 1301 | void add_dirty_inode(struct f2fs_sb_info *, nid_t, int type); |
1300 | void remove_dirty_inode(struct f2fs_sb_info *, nid_t, int type); | 1302 | void 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) | |||
202 | next: | 196 | next: |
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, | |||
443 | next: | 432 | next: |
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) | |||
553 | static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr) | 554 | static 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) | |||
606 | static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr) | 607 | static 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 | ||