Re: [f2fs-dev] [PATCH 5/5] f2fs: do not __punch_discard_cmd in lfs mode
How about change test_opt(sbi, LFS) to f2fs_sb_has_blkzoned(sbi->sb) in this patch, which can avoid punch discard (creating small discard) in zoned block device. On 2018/7/13 11:26, Chao Yu wrote: On 2018/7/12 23:09, Yunlong Song wrote: In lfs mode, it is better to submit and wait for discard of the new_blkaddr's overall section, rather than punch it which makes more small discards and is not friendly with flash alignment. And f2fs does not have to wait discard of each new_blkaddr except for the start_block of each section with this patch. For non-zoned block device, unaligned discard can be allowed; and if synchronous discard is very slow, it will block block allocator here, rather than that, I prefer just punch 4k lba of discard entry for performance. If you don't want to encounter this condition, I suggest issue large size discard more quickly. Thanks, Signed-off-by: Yunlong Song --- fs/f2fs/segment.c | 76 ++- fs/f2fs/segment.h | 7 - 2 files changed, 75 insertions(+), 8 deletions(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index f6c20e0..bce321a 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -893,7 +893,19 @@ static void __remove_discard_cmd(struct f2fs_sb_info *sbi, static void f2fs_submit_discard_endio(struct bio *bio) { struct discard_cmd *dc = (struct discard_cmd *)bio->bi_private; + struct f2fs_sb_info *sbi = F2FS_SB(dc->bdev->bd_super); + if (test_opt(sbi, LFS)) { + unsigned int segno = GET_SEGNO(sbi, dc->lstart); + unsigned int secno = GET_SEC_FROM_SEG(sbi, segno); + int cnt = (dc->len >> sbi->log_blocks_per_seg) / + sbi->segs_per_sec; + + while (cnt--) { + set_bit(secno, FREE_I(sbi)->discard_secmap); + secno++; + } + } dc->error = blk_status_to_errno(bio->bi_status); dc->state = D_DONE; complete_all(>wait); @@ -1349,8 +1361,15 @@ static void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr) dc = (struct discard_cmd *)f2fs_lookup_rb_tree(>root, NULL, blkaddr); if (dc) { - if (dc->state == D_PREP) { + if (dc->state == D_PREP && !test_opt(sbi, LFS)) __punch_discard_cmd(sbi, dc, blkaddr); + else if (dc->state == D_PREP && test_opt(sbi, LFS)) { + struct discard_policy dpolicy; + + __init_discard_policy(sbi, , DPOLICY_FORCE, 1); + __submit_discard_cmd(sbi, , dc); + dc->ref++; + need_wait = true; } else { dc->ref++; need_wait = true; @@ -2071,9 +2090,10 @@ static void get_new_segment(struct f2fs_sb_info *sbi, unsigned int hint = GET_SEC_FROM_SEG(sbi, *newseg); unsigned int old_zoneno = GET_ZONE_FROM_SEG(sbi, *newseg); unsigned int left_start = hint; - bool init = true; + bool init = true, check_discard = test_opt(sbi, LFS) ? true : false; int go_left = 0; int i; + unsigned long *free_secmap; spin_lock(_i->segmap_lock); @@ -2084,11 +2104,25 @@ static void get_new_segment(struct f2fs_sb_info *sbi, goto got_it; } find_other_zone: - secno = find_next_zero_bit(free_i->free_secmap, MAIN_SECS(sbi), hint); + if (check_discard) { + int entries = f2fs_bitmap_size(MAIN_SECS(sbi)) / sizeof(unsigned long); + + free_secmap = free_i->tmp_secmap; + for (i = 0; i < entries; i++) + free_secmap[i] = (!(free_i->free_secmap[i] ^ + free_i->discard_secmap[i])) | free_i->free_secmap[i]; + } else + free_secmap = free_i->free_secmap; + + secno = find_next_zero_bit(free_secmap, MAIN_SECS(sbi), hint); if (secno >= MAIN_SECS(sbi)) { if (dir == ALLOC_RIGHT) { - secno = find_next_zero_bit(free_i->free_secmap, + secno = find_next_zero_bit(free_secmap, MAIN_SECS(sbi), 0); + if (secno >= MAIN_SECS(sbi) && check_discard) { + check_discard = false; + goto find_other_zone; + } f2fs_bug_on(sbi, secno >= MAIN_SECS(sbi)); } else { go_left = 1; @@ -2098,13 +2132,17 @@ static void get_new_segment(struct f2fs_sb_info *sbi, if (go_left == 0) goto skip_left; - while (test_bit(left_start, free_i->free_secmap)) { + while (test_bit(left_start, free_secmap)) { if (left_start
Re: [f2fs-dev] [PATCH 5/5] f2fs: do not __punch_discard_cmd in lfs mode
On 2018/7/12 23:09, Yunlong Song wrote: > In lfs mode, it is better to submit and wait for discard of the > new_blkaddr's overall section, rather than punch it which makes > more small discards and is not friendly with flash alignment. And > f2fs does not have to wait discard of each new_blkaddr except for the > start_block of each section with this patch. For non-zoned block device, unaligned discard can be allowed; and if synchronous discard is very slow, it will block block allocator here, rather than that, I prefer just punch 4k lba of discard entry for performance. If you don't want to encounter this condition, I suggest issue large size discard more quickly. Thanks, > > Signed-off-by: Yunlong Song > --- > fs/f2fs/segment.c | 76 > ++- > fs/f2fs/segment.h | 7 - > 2 files changed, 75 insertions(+), 8 deletions(-) > > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > index f6c20e0..bce321a 100644 > --- a/fs/f2fs/segment.c > +++ b/fs/f2fs/segment.c > @@ -893,7 +893,19 @@ static void __remove_discard_cmd(struct f2fs_sb_info > *sbi, > static void f2fs_submit_discard_endio(struct bio *bio) > { > struct discard_cmd *dc = (struct discard_cmd *)bio->bi_private; > + struct f2fs_sb_info *sbi = F2FS_SB(dc->bdev->bd_super); > > + if (test_opt(sbi, LFS)) { > + unsigned int segno = GET_SEGNO(sbi, dc->lstart); > + unsigned int secno = GET_SEC_FROM_SEG(sbi, segno); > + int cnt = (dc->len >> sbi->log_blocks_per_seg) / > + sbi->segs_per_sec; > + > + while (cnt--) { > + set_bit(secno, FREE_I(sbi)->discard_secmap); > + secno++; > + } > + } > dc->error = blk_status_to_errno(bio->bi_status); > dc->state = D_DONE; > complete_all(>wait); > @@ -1349,8 +1361,15 @@ static void f2fs_wait_discard_bio(struct f2fs_sb_info > *sbi, block_t blkaddr) > dc = (struct discard_cmd *)f2fs_lookup_rb_tree(>root, > NULL, blkaddr); > if (dc) { > - if (dc->state == D_PREP) { > + if (dc->state == D_PREP && !test_opt(sbi, LFS)) > __punch_discard_cmd(sbi, dc, blkaddr); > + else if (dc->state == D_PREP && test_opt(sbi, LFS)) { > + struct discard_policy dpolicy; > + > + __init_discard_policy(sbi, , DPOLICY_FORCE, 1); > + __submit_discard_cmd(sbi, , dc); > + dc->ref++; > + need_wait = true; > } else { > dc->ref++; > need_wait = true; > @@ -2071,9 +2090,10 @@ static void get_new_segment(struct f2fs_sb_info *sbi, > unsigned int hint = GET_SEC_FROM_SEG(sbi, *newseg); > unsigned int old_zoneno = GET_ZONE_FROM_SEG(sbi, *newseg); > unsigned int left_start = hint; > - bool init = true; > + bool init = true, check_discard = test_opt(sbi, LFS) ? true : false; > int go_left = 0; > int i; > + unsigned long *free_secmap; > > spin_lock(_i->segmap_lock); > > @@ -2084,11 +2104,25 @@ static void get_new_segment(struct f2fs_sb_info *sbi, > goto got_it; > } > find_other_zone: > - secno = find_next_zero_bit(free_i->free_secmap, MAIN_SECS(sbi), hint); > + if (check_discard) { > + int entries = f2fs_bitmap_size(MAIN_SECS(sbi)) / > sizeof(unsigned long); > + > + free_secmap = free_i->tmp_secmap; > + for (i = 0; i < entries; i++) > + free_secmap[i] = (!(free_i->free_secmap[i] ^ > + free_i->discard_secmap[i])) | > free_i->free_secmap[i]; > + } else > + free_secmap = free_i->free_secmap; > + > + secno = find_next_zero_bit(free_secmap, MAIN_SECS(sbi), hint); > if (secno >= MAIN_SECS(sbi)) { > if (dir == ALLOC_RIGHT) { > - secno = find_next_zero_bit(free_i->free_secmap, > + secno = find_next_zero_bit(free_secmap, > MAIN_SECS(sbi), 0); > + if (secno >= MAIN_SECS(sbi) && check_discard) { > + check_discard = false; > + goto find_other_zone; > + } > f2fs_bug_on(sbi, secno >= MAIN_SECS(sbi)); > } else { > go_left = 1; > @@ -2098,13 +2132,17 @@ static void get_new_segment(struct f2fs_sb_info *sbi, > if (go_left == 0) > goto skip_left; > > - while (test_bit(left_start, free_i->free_secmap)) { > + while (test_bit(left_start, free_secmap)) { > if (left_start > 0) { > left_start--; > continue; > } > -
[f2fs-dev] [PATCH 5/5] f2fs: do not __punch_discard_cmd in lfs mode
In lfs mode, it is better to submit and wait for discard of the new_blkaddr's overall section, rather than punch it which makes more small discards and is not friendly with flash alignment. And f2fs does not have to wait discard of each new_blkaddr except for the start_block of each section with this patch. Signed-off-by: Yunlong Song --- fs/f2fs/segment.c | 76 ++- fs/f2fs/segment.h | 7 - 2 files changed, 75 insertions(+), 8 deletions(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index f6c20e0..bce321a 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -893,7 +893,19 @@ static void __remove_discard_cmd(struct f2fs_sb_info *sbi, static void f2fs_submit_discard_endio(struct bio *bio) { struct discard_cmd *dc = (struct discard_cmd *)bio->bi_private; + struct f2fs_sb_info *sbi = F2FS_SB(dc->bdev->bd_super); + if (test_opt(sbi, LFS)) { + unsigned int segno = GET_SEGNO(sbi, dc->lstart); + unsigned int secno = GET_SEC_FROM_SEG(sbi, segno); + int cnt = (dc->len >> sbi->log_blocks_per_seg) / + sbi->segs_per_sec; + + while (cnt--) { + set_bit(secno, FREE_I(sbi)->discard_secmap); + secno++; + } + } dc->error = blk_status_to_errno(bio->bi_status); dc->state = D_DONE; complete_all(>wait); @@ -1349,8 +1361,15 @@ static void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr) dc = (struct discard_cmd *)f2fs_lookup_rb_tree(>root, NULL, blkaddr); if (dc) { - if (dc->state == D_PREP) { + if (dc->state == D_PREP && !test_opt(sbi, LFS)) __punch_discard_cmd(sbi, dc, blkaddr); + else if (dc->state == D_PREP && test_opt(sbi, LFS)) { + struct discard_policy dpolicy; + + __init_discard_policy(sbi, , DPOLICY_FORCE, 1); + __submit_discard_cmd(sbi, , dc); + dc->ref++; + need_wait = true; } else { dc->ref++; need_wait = true; @@ -2071,9 +2090,10 @@ static void get_new_segment(struct f2fs_sb_info *sbi, unsigned int hint = GET_SEC_FROM_SEG(sbi, *newseg); unsigned int old_zoneno = GET_ZONE_FROM_SEG(sbi, *newseg); unsigned int left_start = hint; - bool init = true; + bool init = true, check_discard = test_opt(sbi, LFS) ? true : false; int go_left = 0; int i; + unsigned long *free_secmap; spin_lock(_i->segmap_lock); @@ -2084,11 +2104,25 @@ static void get_new_segment(struct f2fs_sb_info *sbi, goto got_it; } find_other_zone: - secno = find_next_zero_bit(free_i->free_secmap, MAIN_SECS(sbi), hint); + if (check_discard) { + int entries = f2fs_bitmap_size(MAIN_SECS(sbi)) / sizeof(unsigned long); + + free_secmap = free_i->tmp_secmap; + for (i = 0; i < entries; i++) + free_secmap[i] = (!(free_i->free_secmap[i] ^ + free_i->discard_secmap[i])) | free_i->free_secmap[i]; + } else + free_secmap = free_i->free_secmap; + + secno = find_next_zero_bit(free_secmap, MAIN_SECS(sbi), hint); if (secno >= MAIN_SECS(sbi)) { if (dir == ALLOC_RIGHT) { - secno = find_next_zero_bit(free_i->free_secmap, + secno = find_next_zero_bit(free_secmap, MAIN_SECS(sbi), 0); + if (secno >= MAIN_SECS(sbi) && check_discard) { + check_discard = false; + goto find_other_zone; + } f2fs_bug_on(sbi, secno >= MAIN_SECS(sbi)); } else { go_left = 1; @@ -2098,13 +2132,17 @@ static void get_new_segment(struct f2fs_sb_info *sbi, if (go_left == 0) goto skip_left; - while (test_bit(left_start, free_i->free_secmap)) { + while (test_bit(left_start, free_secmap)) { if (left_start > 0) { left_start--; continue; } - left_start = find_next_zero_bit(free_i->free_secmap, + left_start = find_next_zero_bit(free_secmap, MAIN_SECS(sbi), 0); + if (left_start >= MAIN_SECS(sbi) && check_discard) { + check_discard = false; + goto find_other_zone; + } f2fs_bug_on(sbi, left_start >= MAIN_SECS(sbi));