diff options
Diffstat (limited to 'fs/f2fs/segment.c')
-rw-r--r-- | fs/f2fs/segment.c | 101 |
1 files changed, 25 insertions, 76 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index d8e84e49a5c3..a86d125a9885 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c | |||
@@ -94,7 +94,7 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, | |||
94 | * Adding dirty entry into seglist is not critical operation. | 94 | * Adding dirty entry into seglist is not critical operation. |
95 | * If a given segment is one of current working segments, it won't be added. | 95 | * If a given segment is one of current working segments, it won't be added. |
96 | */ | 96 | */ |
97 | void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) | 97 | static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) |
98 | { | 98 | { |
99 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); | 99 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); |
100 | unsigned short valid_blocks; | 100 | unsigned short valid_blocks; |
@@ -126,17 +126,16 @@ void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) | |||
126 | static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi) | 126 | static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi) |
127 | { | 127 | { |
128 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); | 128 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); |
129 | unsigned int segno, offset = 0; | 129 | unsigned int segno = -1; |
130 | unsigned int total_segs = TOTAL_SEGS(sbi); | 130 | unsigned int total_segs = TOTAL_SEGS(sbi); |
131 | 131 | ||
132 | mutex_lock(&dirty_i->seglist_lock); | 132 | mutex_lock(&dirty_i->seglist_lock); |
133 | while (1) { | 133 | while (1) { |
134 | segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs, | 134 | segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs, |
135 | offset); | 135 | segno + 1); |
136 | if (segno >= total_segs) | 136 | if (segno >= total_segs) |
137 | break; | 137 | break; |
138 | __set_test_and_free(sbi, segno); | 138 | __set_test_and_free(sbi, segno); |
139 | offset = segno + 1; | ||
140 | } | 139 | } |
141 | mutex_unlock(&dirty_i->seglist_lock); | 140 | mutex_unlock(&dirty_i->seglist_lock); |
142 | } | 141 | } |
@@ -144,17 +143,16 @@ static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi) | |||
144 | void clear_prefree_segments(struct f2fs_sb_info *sbi) | 143 | void clear_prefree_segments(struct f2fs_sb_info *sbi) |
145 | { | 144 | { |
146 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); | 145 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); |
147 | unsigned int segno, offset = 0; | 146 | unsigned int segno = -1; |
148 | unsigned int total_segs = TOTAL_SEGS(sbi); | 147 | unsigned int total_segs = TOTAL_SEGS(sbi); |
149 | 148 | ||
150 | mutex_lock(&dirty_i->seglist_lock); | 149 | mutex_lock(&dirty_i->seglist_lock); |
151 | while (1) { | 150 | while (1) { |
152 | segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs, | 151 | segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs, |
153 | offset); | 152 | segno + 1); |
154 | if (segno >= total_segs) | 153 | if (segno >= total_segs) |
155 | break; | 154 | break; |
156 | 155 | ||
157 | offset = segno + 1; | ||
158 | if (test_and_clear_bit(segno, dirty_i->dirty_segmap[PRE])) | 156 | if (test_and_clear_bit(segno, dirty_i->dirty_segmap[PRE])) |
159 | dirty_i->nr_dirty[PRE]--; | 157 | dirty_i->nr_dirty[PRE]--; |
160 | 158 | ||
@@ -257,11 +255,11 @@ void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) | |||
257 | * This function should be resided under the curseg_mutex lock | 255 | * This function should be resided under the curseg_mutex lock |
258 | */ | 256 | */ |
259 | static void __add_sum_entry(struct f2fs_sb_info *sbi, int type, | 257 | static void __add_sum_entry(struct f2fs_sb_info *sbi, int type, |
260 | struct f2fs_summary *sum, unsigned short offset) | 258 | struct f2fs_summary *sum) |
261 | { | 259 | { |
262 | struct curseg_info *curseg = CURSEG_I(sbi, type); | 260 | struct curseg_info *curseg = CURSEG_I(sbi, type); |
263 | void *addr = curseg->sum_blk; | 261 | void *addr = curseg->sum_blk; |
264 | addr += offset * sizeof(struct f2fs_summary); | 262 | addr += curseg->next_blkoff * sizeof(struct f2fs_summary); |
265 | memcpy(addr, sum, sizeof(struct f2fs_summary)); | 263 | memcpy(addr, sum, sizeof(struct f2fs_summary)); |
266 | return; | 264 | return; |
267 | } | 265 | } |
@@ -311,64 +309,14 @@ static void write_sum_page(struct f2fs_sb_info *sbi, | |||
311 | f2fs_put_page(page, 1); | 309 | f2fs_put_page(page, 1); |
312 | } | 310 | } |
313 | 311 | ||
314 | static unsigned int check_prefree_segments(struct f2fs_sb_info *sbi, int type) | ||
315 | { | ||
316 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); | ||
317 | unsigned long *prefree_segmap = dirty_i->dirty_segmap[PRE]; | ||
318 | unsigned int segno; | ||
319 | unsigned int ofs = 0; | ||
320 | |||
321 | /* | ||
322 | * If there is not enough reserved sections, | ||
323 | * we should not reuse prefree segments. | ||
324 | */ | ||
325 | if (has_not_enough_free_secs(sbi, 0)) | ||
326 | return NULL_SEGNO; | ||
327 | |||
328 | /* | ||
329 | * NODE page should not reuse prefree segment, | ||
330 | * since those information is used for SPOR. | ||
331 | */ | ||
332 | if (IS_NODESEG(type)) | ||
333 | return NULL_SEGNO; | ||
334 | next: | ||
335 | segno = find_next_bit(prefree_segmap, TOTAL_SEGS(sbi), ofs); | ||
336 | ofs += sbi->segs_per_sec; | ||
337 | |||
338 | if (segno < TOTAL_SEGS(sbi)) { | ||
339 | int i; | ||
340 | |||
341 | /* skip intermediate segments in a section */ | ||
342 | if (segno % sbi->segs_per_sec) | ||
343 | goto next; | ||
344 | |||
345 | /* skip if the section is currently used */ | ||
346 | if (sec_usage_check(sbi, GET_SECNO(sbi, segno))) | ||
347 | goto next; | ||
348 | |||
349 | /* skip if whole section is not prefree */ | ||
350 | for (i = 1; i < sbi->segs_per_sec; i++) | ||
351 | if (!test_bit(segno + i, prefree_segmap)) | ||
352 | goto next; | ||
353 | |||
354 | /* skip if whole section was not free at the last checkpoint */ | ||
355 | for (i = 0; i < sbi->segs_per_sec; i++) | ||
356 | if (get_seg_entry(sbi, segno + i)->ckpt_valid_blocks) | ||
357 | goto next; | ||
358 | |||
359 | return segno; | ||
360 | } | ||
361 | return NULL_SEGNO; | ||
362 | } | ||
363 | |||
364 | static int is_next_segment_free(struct f2fs_sb_info *sbi, int type) | 312 | static int is_next_segment_free(struct f2fs_sb_info *sbi, int type) |
365 | { | 313 | { |
366 | struct curseg_info *curseg = CURSEG_I(sbi, type); | 314 | struct curseg_info *curseg = CURSEG_I(sbi, type); |
367 | unsigned int segno = curseg->segno; | 315 | unsigned int segno = curseg->segno + 1; |
368 | struct free_segmap_info *free_i = FREE_I(sbi); | 316 | struct free_segmap_info *free_i = FREE_I(sbi); |
369 | 317 | ||
370 | if (segno + 1 < TOTAL_SEGS(sbi) && (segno + 1) % sbi->segs_per_sec) | 318 | if (segno < TOTAL_SEGS(sbi) && segno % sbi->segs_per_sec) |
371 | return !test_bit(segno + 1, free_i->free_segmap); | 319 | return !test_bit(segno, free_i->free_segmap); |
372 | return 0; | 320 | return 0; |
373 | } | 321 | } |
374 | 322 | ||
@@ -495,7 +443,7 @@ static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec) | |||
495 | int dir = ALLOC_LEFT; | 443 | int dir = ALLOC_LEFT; |
496 | 444 | ||
497 | write_sum_page(sbi, curseg->sum_blk, | 445 | write_sum_page(sbi, curseg->sum_blk, |
498 | GET_SUM_BLOCK(sbi, curseg->segno)); | 446 | GET_SUM_BLOCK(sbi, segno)); |
499 | if (type == CURSEG_WARM_DATA || type == CURSEG_COLD_DATA) | 447 | if (type == CURSEG_WARM_DATA || type == CURSEG_COLD_DATA) |
500 | dir = ALLOC_RIGHT; | 448 | dir = ALLOC_RIGHT; |
501 | 449 | ||
@@ -599,11 +547,7 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi, | |||
599 | goto out; | 547 | goto out; |
600 | } | 548 | } |
601 | 549 | ||
602 | curseg->next_segno = check_prefree_segments(sbi, type); | 550 | if (type == CURSEG_WARM_NODE) |
603 | |||
604 | if (curseg->next_segno != NULL_SEGNO) | ||
605 | change_curseg(sbi, type, false); | ||
606 | else if (type == CURSEG_WARM_NODE) | ||
607 | new_curseg(sbi, type, false); | 551 | new_curseg(sbi, type, false); |
608 | else if (curseg->alloc_type == LFS && is_next_segment_free(sbi, type)) | 552 | else if (curseg->alloc_type == LFS && is_next_segment_free(sbi, type)) |
609 | new_curseg(sbi, type, false); | 553 | new_curseg(sbi, type, false); |
@@ -612,7 +556,10 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi, | |||
612 | else | 556 | else |
613 | new_curseg(sbi, type, false); | 557 | new_curseg(sbi, type, false); |
614 | out: | 558 | out: |
559 | #ifdef CONFIG_F2FS_STAT_FS | ||
615 | sbi->segment_count[curseg->alloc_type]++; | 560 | sbi->segment_count[curseg->alloc_type]++; |
561 | #endif | ||
562 | return; | ||
616 | } | 563 | } |
617 | 564 | ||
618 | void allocate_new_segments(struct f2fs_sb_info *sbi) | 565 | void allocate_new_segments(struct f2fs_sb_info *sbi) |
@@ -795,7 +742,7 @@ static int __get_segment_type_6(struct page *page, enum page_type p_type) | |||
795 | 742 | ||
796 | if (S_ISDIR(inode->i_mode)) | 743 | if (S_ISDIR(inode->i_mode)) |
797 | return CURSEG_HOT_DATA; | 744 | return CURSEG_HOT_DATA; |
798 | else if (is_cold_data(page) || is_cold_file(inode)) | 745 | else if (is_cold_data(page) || file_is_cold(inode)) |
799 | return CURSEG_COLD_DATA; | 746 | return CURSEG_COLD_DATA; |
800 | else | 747 | else |
801 | return CURSEG_WARM_DATA; | 748 | return CURSEG_WARM_DATA; |
@@ -844,11 +791,13 @@ static void do_write_page(struct f2fs_sb_info *sbi, struct page *page, | |||
844 | * because, this function updates a summary entry in the | 791 | * because, this function updates a summary entry in the |
845 | * current summary block. | 792 | * current summary block. |
846 | */ | 793 | */ |
847 | __add_sum_entry(sbi, type, sum, curseg->next_blkoff); | 794 | __add_sum_entry(sbi, type, sum); |
848 | 795 | ||
849 | mutex_lock(&sit_i->sentry_lock); | 796 | mutex_lock(&sit_i->sentry_lock); |
850 | __refresh_next_blkoff(sbi, curseg); | 797 | __refresh_next_blkoff(sbi, curseg); |
798 | #ifdef CONFIG_F2FS_STAT_FS | ||
851 | sbi->block_count[curseg->alloc_type]++; | 799 | sbi->block_count[curseg->alloc_type]++; |
800 | #endif | ||
852 | 801 | ||
853 | /* | 802 | /* |
854 | * SIT information should be updated before segment allocation, | 803 | * SIT information should be updated before segment allocation, |
@@ -943,7 +892,7 @@ void recover_data_page(struct f2fs_sb_info *sbi, | |||
943 | 892 | ||
944 | curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, new_blkaddr) & | 893 | curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, new_blkaddr) & |
945 | (sbi->blocks_per_seg - 1); | 894 | (sbi->blocks_per_seg - 1); |
946 | __add_sum_entry(sbi, type, sum, curseg->next_blkoff); | 895 | __add_sum_entry(sbi, type, sum); |
947 | 896 | ||
948 | refresh_sit_entry(sbi, old_blkaddr, new_blkaddr); | 897 | refresh_sit_entry(sbi, old_blkaddr, new_blkaddr); |
949 | 898 | ||
@@ -980,7 +929,7 @@ void rewrite_node_page(struct f2fs_sb_info *sbi, | |||
980 | } | 929 | } |
981 | curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, new_blkaddr) & | 930 | curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, new_blkaddr) & |
982 | (sbi->blocks_per_seg - 1); | 931 | (sbi->blocks_per_seg - 1); |
983 | __add_sum_entry(sbi, type, sum, curseg->next_blkoff); | 932 | __add_sum_entry(sbi, type, sum); |
984 | 933 | ||
985 | /* change the current log to the next block addr in advance */ | 934 | /* change the current log to the next block addr in advance */ |
986 | if (next_segno != segno) { | 935 | if (next_segno != segno) { |
@@ -1579,13 +1528,13 @@ static void init_dirty_segmap(struct f2fs_sb_info *sbi) | |||
1579 | { | 1528 | { |
1580 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); | 1529 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); |
1581 | struct free_segmap_info *free_i = FREE_I(sbi); | 1530 | struct free_segmap_info *free_i = FREE_I(sbi); |
1582 | unsigned int segno = 0, offset = 0; | 1531 | unsigned int segno = 0, offset = 0, total_segs = TOTAL_SEGS(sbi); |
1583 | unsigned short valid_blocks; | 1532 | unsigned short valid_blocks; |
1584 | 1533 | ||
1585 | while (segno < TOTAL_SEGS(sbi)) { | 1534 | while (1) { |
1586 | /* find dirty segment based on free segmap */ | 1535 | /* find dirty segment based on free segmap */ |
1587 | segno = find_next_inuse(free_i, TOTAL_SEGS(sbi), offset); | 1536 | segno = find_next_inuse(free_i, total_segs, offset); |
1588 | if (segno >= TOTAL_SEGS(sbi)) | 1537 | if (segno >= total_segs) |
1589 | break; | 1538 | break; |
1590 | offset = segno + 1; | 1539 | offset = segno + 1; |
1591 | valid_blocks = get_valid_blocks(sbi, segno, 0); | 1540 | valid_blocks = get_valid_blocks(sbi, segno, 0); |