aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs/segment.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/f2fs/segment.c')
-rw-r--r--fs/f2fs/segment.c101
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 */
97void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) 97static 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)
126static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi) 126static 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)
144void clear_prefree_segments(struct f2fs_sb_info *sbi) 143void 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 */
259static void __add_sum_entry(struct f2fs_sb_info *sbi, int type, 257static 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
314static 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;
334next:
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
364static int is_next_segment_free(struct f2fs_sb_info *sbi, int type) 312static 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);
614out: 558out:
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
618void allocate_new_segments(struct f2fs_sb_info *sbi) 565void 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);