aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk.kim@samsung.com>2013-06-26 20:59:40 -0400
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2013-07-01 19:48:15 -0400
commit763bfe1bc575dcce56dc5c570dc005d94911705f (patch)
tree4588fcb84b11e97a33dc3b75908dc6b0fccc735b /fs/f2fs
parent6cc4af56066d8e9c62584cf61c6ce50fd0ab139a (diff)
f2fs: remove reusing any prefree segments
This patch removes check_prefree_segments initially designed to enhance the performance by narrowing the range of LBA usage across the whole block device. When allocating a new segment, previous f2fs tries to find proper prefree segments, and then, if finds a segment, it reuses the segment for further data or node block allocation. However, I found that this was totally wrong approach since the prefree segments have several data or node blocks that will be used by the roll-forward mechanism operated after sudden-power-off. Let's assume the following scenario. /* write 8MB with fsync */ for (i = 0; i < 2048; i++) { offset = i * 4096; write(fd, offset, 4KB); fsync(fd); } In this case, naive segment allocation sequence will be like: data segment: x, x+1, x+2, x+3 node segment: y, y+1, y+2, y+3. But, if we can reuse prefree segments, the sequence can be like: data segment: x, x+1, y, y+1 node segment: y, y+1, y+2, y+3. Because, y, y+1, and y+2 became prefree segments one by one, and those are reused by data allocation. After conducting this workload, we should consider how to recover the latest inode with its data. If we reuse the prefree segments such as y or y+1, we lost the old node blocks so that f2fs even cannot start roll-forward recovery. Therefore, I suggest that we should remove reusing prefree segments. Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs')
-rw-r--r--fs/f2fs/segment.c56
1 files changed, 1 insertions, 55 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 3ac4d29f0cd4..a86d125a9885 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -309,56 +309,6 @@ static void write_sum_page(struct f2fs_sb_info *sbi,
309 f2fs_put_page(page, 1); 309 f2fs_put_page(page, 1);
310} 310}
311 311
312static unsigned int check_prefree_segments(struct f2fs_sb_info *sbi, int type)
313{
314 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
315 unsigned long *prefree_segmap = dirty_i->dirty_segmap[PRE];
316 unsigned int segno;
317 unsigned int ofs = 0;
318
319 /*
320 * If there is not enough reserved sections,
321 * we should not reuse prefree segments.
322 */
323 if (has_not_enough_free_secs(sbi, 0))
324 return NULL_SEGNO;
325
326 /*
327 * NODE page should not reuse prefree segment,
328 * since those information is used for SPOR.
329 */
330 if (IS_NODESEG(type))
331 return NULL_SEGNO;
332next:
333 segno = find_next_bit(prefree_segmap, TOTAL_SEGS(sbi), ofs);
334 ofs += sbi->segs_per_sec;
335
336 if (segno < TOTAL_SEGS(sbi)) {
337 int i;
338
339 /* skip intermediate segments in a section */
340 if (segno % sbi->segs_per_sec)
341 goto next;
342
343 /* skip if the section is currently used */
344 if (sec_usage_check(sbi, GET_SECNO(sbi, segno)))
345 goto next;
346
347 /* skip if whole section is not prefree */
348 for (i = 1; i < sbi->segs_per_sec; i++)
349 if (!test_bit(segno + i, prefree_segmap))
350 goto next;
351
352 /* skip if whole section was not free at the last checkpoint */
353 for (i = 0; i < sbi->segs_per_sec; i++)
354 if (get_seg_entry(sbi, segno + i)->ckpt_valid_blocks)
355 goto next;
356
357 return segno;
358 }
359 return NULL_SEGNO;
360}
361
362static 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)
363{ 313{
364 struct curseg_info *curseg = CURSEG_I(sbi, type); 314 struct curseg_info *curseg = CURSEG_I(sbi, type);
@@ -597,11 +547,7 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
597 goto out; 547 goto out;
598 } 548 }
599 549
600 curseg->next_segno = check_prefree_segments(sbi, type); 550 if (type == CURSEG_WARM_NODE)
601
602 if (curseg->next_segno != NULL_SEGNO)
603 change_curseg(sbi, type, false);
604 else if (type == CURSEG_WARM_NODE)
605 new_curseg(sbi, type, false); 551 new_curseg(sbi, type, false);
606 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))
607 new_curseg(sbi, type, false); 553 new_curseg(sbi, type, false);