* [PATCH RFC] f2fs: fix to avoid selecting full segment w/ {AT,}SSR allocator
@ 2021-02-20 9:40 Chao Yu
2021-02-22 13:43 ` Chao Yu
2021-03-18 17:17 ` Jaegeuk Kim
0 siblings, 2 replies; 8+ messages in thread
From: Chao Yu @ 2021-02-20 9:40 UTC (permalink / raw)
To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, chao, Chao Yu
In cp disabling mode, there could be a condition
- target segment has 128 ckpt valid blocks
- GC migrates 128 valid blocks to other segment (segment is still in
dirty list)
- GC migrates 384 blocks to target segment (segment has 128 cp_vblocks
and 384 vblocks)
- If GC selects target segment via {AT,}SSR allocator, however there is
no free space in targe segment.
Fixes: 4354994f097d ("f2fs: checkpoint disabling")
Fixes: 093749e296e2 ("f2fs: support age threshold based garbage collection")
Signed-off-by: Chao Yu <yuchao0@huawei.com>
---
fs/f2fs/f2fs.h | 1 +
fs/f2fs/gc.c | 17 +++++++++++++----
fs/f2fs/segment.c | 20 ++++++++++++++++++++
3 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index ed7807103c8e..9c753eff0814 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3376,6 +3376,7 @@ block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi);
int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable);
void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi);
int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra);
+bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno);
void f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi);
void f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi);
void f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi);
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 86ba8ed0b8a7..a1d8062cdace 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -392,10 +392,6 @@ static void add_victim_entry(struct f2fs_sb_info *sbi,
if (p->gc_mode == GC_AT &&
get_valid_blocks(sbi, segno, true) == 0)
return;
-
- if (p->alloc_mode == AT_SSR &&
- get_seg_entry(sbi, segno)->ckpt_valid_blocks == 0)
- return;
}
for (i = 0; i < sbi->segs_per_sec; i++)
@@ -736,6 +732,19 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
goto next;
+ if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
+ /*
+ * to avoid selecting candidate which has below valid
+ * block distribution:
+ * partial blocks are valid and all left ones are valid
+ * in previous checkpoint.
+ */
+ if (p.alloc_mode == SSR || p.alloc_mode == AT_SSR) {
+ if (!segment_has_free_slot(sbi, segno))
+ goto next;
+ }
+ }
+
if (is_atgc) {
add_victim_entry(sbi, &p, segno);
goto next;
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 2d5a82c4ca15..deaf57e13125 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2650,6 +2650,26 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi,
seg->next_blkoff++;
}
+bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno)
+{
+ struct sit_info *sit = SIT_I(sbi);
+ struct seg_entry *se = get_seg_entry(sbi, segno);
+ int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long);
+ unsigned long *target_map = SIT_I(sbi)->tmp_map;
+ unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map;
+ unsigned long *cur_map = (unsigned long *)se->cur_valid_map;
+ int i, pos;
+
+ down_write(&sit->sentry_lock);
+ for (i = 0; i < entries; i++)
+ target_map[i] = ckpt_map[i] | cur_map[i];
+
+ pos = __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, 0);
+ up_write(&sit->sentry_lock);
+
+ return pos < sbi->blocks_per_seg;
+}
+
/*
* This function always allocates a used segment(from dirty seglist) by SSR
* manner, so it should recover the existing segment information of valid blocks
--
2.29.2
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH RFC] f2fs: fix to avoid selecting full segment w/ {AT,}SSR allocator 2021-02-20 9:40 [PATCH RFC] f2fs: fix to avoid selecting full segment w/ {AT,}SSR allocator Chao Yu @ 2021-02-22 13:43 ` Chao Yu 2021-02-23 12:26 ` Chao Yu 2021-03-18 17:17 ` Jaegeuk Kim 1 sibling, 1 reply; 8+ messages in thread From: Chao Yu @ 2021-02-22 13:43 UTC (permalink / raw) To: Chao Yu, jaegeuk; +Cc: linux-f2fs-devel, linux-kernel Ping, On 2021/2/20 17:40, Chao Yu wrote: > In cp disabling mode, there could be a condition > - target segment has 128 ckpt valid blocks > - GC migrates 128 valid blocks to other segment (segment is still in > dirty list) > - GC migrates 384 blocks to target segment (segment has 128 cp_vblocks > and 384 vblocks) > - If GC selects target segment via {AT,}SSR allocator, however there is > no free space in targe segment. > > Fixes: 4354994f097d ("f2fs: checkpoint disabling") > Fixes: 093749e296e2 ("f2fs: support age threshold based garbage collection") > Signed-off-by: Chao Yu <yuchao0@huawei.com> > --- > fs/f2fs/f2fs.h | 1 + > fs/f2fs/gc.c | 17 +++++++++++++---- > fs/f2fs/segment.c | 20 ++++++++++++++++++++ > 3 files changed, 34 insertions(+), 4 deletions(-) > > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h > index ed7807103c8e..9c753eff0814 100644 > --- a/fs/f2fs/f2fs.h > +++ b/fs/f2fs/f2fs.h > @@ -3376,6 +3376,7 @@ block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi); > int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable); > void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi); > int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra); > +bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno); > void f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi); > void f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi); > void f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi); > diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c > index 86ba8ed0b8a7..a1d8062cdace 100644 > --- a/fs/f2fs/gc.c > +++ b/fs/f2fs/gc.c > @@ -392,10 +392,6 @@ static void add_victim_entry(struct f2fs_sb_info *sbi, > if (p->gc_mode == GC_AT && > get_valid_blocks(sbi, segno, true) == 0) > return; > - > - if (p->alloc_mode == AT_SSR && > - get_seg_entry(sbi, segno)->ckpt_valid_blocks == 0) > - return; > } > > for (i = 0; i < sbi->segs_per_sec; i++) > @@ -736,6 +732,19 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, > if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) > goto next; > > + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { > + /* > + * to avoid selecting candidate which has below valid > + * block distribution: > + * partial blocks are valid and all left ones are valid > + * in previous checkpoint. > + */ > + if (p.alloc_mode == SSR || p.alloc_mode == AT_SSR) { > + if (!segment_has_free_slot(sbi, segno)) > + goto next; > + } > + } > + > if (is_atgc) { > add_victim_entry(sbi, &p, segno); > goto next; > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > index 2d5a82c4ca15..deaf57e13125 100644 > --- a/fs/f2fs/segment.c > +++ b/fs/f2fs/segment.c > @@ -2650,6 +2650,26 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, > seg->next_blkoff++; > } > > +bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno) > +{ > + struct sit_info *sit = SIT_I(sbi); > + struct seg_entry *se = get_seg_entry(sbi, segno); > + int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); > + unsigned long *target_map = SIT_I(sbi)->tmp_map; > + unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; > + unsigned long *cur_map = (unsigned long *)se->cur_valid_map; > + int i, pos; > + > + down_write(&sit->sentry_lock); > + for (i = 0; i < entries; i++) > + target_map[i] = ckpt_map[i] | cur_map[i]; > + > + pos = __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, 0); > + up_write(&sit->sentry_lock); > + > + return pos < sbi->blocks_per_seg; > +} > + > /* > * This function always allocates a used segment(from dirty seglist) by SSR > * manner, so it should recover the existing segment information of valid blocks > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFC] f2fs: fix to avoid selecting full segment w/ {AT,}SSR allocator 2021-02-22 13:43 ` Chao Yu @ 2021-02-23 12:26 ` Chao Yu 2021-02-28 5:10 ` Jaegeuk Kim 0 siblings, 1 reply; 8+ messages in thread From: Chao Yu @ 2021-02-23 12:26 UTC (permalink / raw) To: jaegeuk; +Cc: Chao Yu, linux-f2fs-devel, linux-kernel Jaegeuk, Could you please help to review this patch? since I doubt that this issue can happen in real world... :( Thanks, On 2021/2/22 21:43, Chao Yu wrote: > Ping, > > On 2021/2/20 17:40, Chao Yu wrote: >> In cp disabling mode, there could be a condition >> - target segment has 128 ckpt valid blocks >> - GC migrates 128 valid blocks to other segment (segment is still in >> dirty list) >> - GC migrates 384 blocks to target segment (segment has 128 cp_vblocks >> and 384 vblocks) >> - If GC selects target segment via {AT,}SSR allocator, however there is >> no free space in targe segment. >> >> Fixes: 4354994f097d ("f2fs: checkpoint disabling") >> Fixes: 093749e296e2 ("f2fs: support age threshold based garbage collection") >> Signed-off-by: Chao Yu <yuchao0@huawei.com> >> --- >> fs/f2fs/f2fs.h | 1 + >> fs/f2fs/gc.c | 17 +++++++++++++---- >> fs/f2fs/segment.c | 20 ++++++++++++++++++++ >> 3 files changed, 34 insertions(+), 4 deletions(-) >> >> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h >> index ed7807103c8e..9c753eff0814 100644 >> --- a/fs/f2fs/f2fs.h >> +++ b/fs/f2fs/f2fs.h >> @@ -3376,6 +3376,7 @@ block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi); >> int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable); >> void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi); >> int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra); >> +bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno); >> void f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi); >> void f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi); >> void f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi); >> diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c >> index 86ba8ed0b8a7..a1d8062cdace 100644 >> --- a/fs/f2fs/gc.c >> +++ b/fs/f2fs/gc.c >> @@ -392,10 +392,6 @@ static void add_victim_entry(struct f2fs_sb_info *sbi, >> if (p->gc_mode == GC_AT && >> get_valid_blocks(sbi, segno, true) == 0) >> return; >> - >> - if (p->alloc_mode == AT_SSR && >> - get_seg_entry(sbi, segno)->ckpt_valid_blocks == 0) >> - return; >> } >> >> for (i = 0; i < sbi->segs_per_sec; i++) >> @@ -736,6 +732,19 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, >> if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) >> goto next; >> >> + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { >> + /* >> + * to avoid selecting candidate which has below valid >> + * block distribution: >> + * partial blocks are valid and all left ones are valid >> + * in previous checkpoint. >> + */ >> + if (p.alloc_mode == SSR || p.alloc_mode == AT_SSR) { >> + if (!segment_has_free_slot(sbi, segno)) >> + goto next; >> + } >> + } >> + >> if (is_atgc) { >> add_victim_entry(sbi, &p, segno); >> goto next; >> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c >> index 2d5a82c4ca15..deaf57e13125 100644 >> --- a/fs/f2fs/segment.c >> +++ b/fs/f2fs/segment.c >> @@ -2650,6 +2650,26 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, >> seg->next_blkoff++; >> } >> >> +bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno) >> +{ >> + struct sit_info *sit = SIT_I(sbi); >> + struct seg_entry *se = get_seg_entry(sbi, segno); >> + int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); >> + unsigned long *target_map = SIT_I(sbi)->tmp_map; >> + unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; >> + unsigned long *cur_map = (unsigned long *)se->cur_valid_map; >> + int i, pos; >> + >> + down_write(&sit->sentry_lock); >> + for (i = 0; i < entries; i++) >> + target_map[i] = ckpt_map[i] | cur_map[i]; >> + >> + pos = __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, 0); >> + up_write(&sit->sentry_lock); >> + >> + return pos < sbi->blocks_per_seg; >> +} >> + >> /* >> * This function always allocates a used segment(from dirty seglist) by SSR >> * manner, so it should recover the existing segment information of valid blocks >> > . > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFC] f2fs: fix to avoid selecting full segment w/ {AT,}SSR allocator 2021-02-23 12:26 ` Chao Yu @ 2021-02-28 5:10 ` Jaegeuk Kim 0 siblings, 0 replies; 8+ messages in thread From: Jaegeuk Kim @ 2021-02-28 5:10 UTC (permalink / raw) To: Chao Yu; +Cc: Chao Yu, linux-f2fs-devel, linux-kernel On 02/23, Chao Yu wrote: > Jaegeuk, > > Could you please help to review this patch? since I doubt that this > issue can happen in real world... :( Let me take a look as soon as I have some time. Sorry for the delay. > > Thanks, > > On 2021/2/22 21:43, Chao Yu wrote: > > Ping, > > > > On 2021/2/20 17:40, Chao Yu wrote: > > > In cp disabling mode, there could be a condition > > > - target segment has 128 ckpt valid blocks > > > - GC migrates 128 valid blocks to other segment (segment is still in > > > dirty list) > > > - GC migrates 384 blocks to target segment (segment has 128 cp_vblocks > > > and 384 vblocks) > > > - If GC selects target segment via {AT,}SSR allocator, however there is > > > no free space in targe segment. > > > > > > Fixes: 4354994f097d ("f2fs: checkpoint disabling") > > > Fixes: 093749e296e2 ("f2fs: support age threshold based garbage collection") > > > Signed-off-by: Chao Yu <yuchao0@huawei.com> > > > --- > > > fs/f2fs/f2fs.h | 1 + > > > fs/f2fs/gc.c | 17 +++++++++++++---- > > > fs/f2fs/segment.c | 20 ++++++++++++++++++++ > > > 3 files changed, 34 insertions(+), 4 deletions(-) > > > > > > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h > > > index ed7807103c8e..9c753eff0814 100644 > > > --- a/fs/f2fs/f2fs.h > > > +++ b/fs/f2fs/f2fs.h > > > @@ -3376,6 +3376,7 @@ block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi); > > > int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable); > > > void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi); > > > int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra); > > > +bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno); > > > void f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi); > > > void f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi); > > > void f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi); > > > diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c > > > index 86ba8ed0b8a7..a1d8062cdace 100644 > > > --- a/fs/f2fs/gc.c > > > +++ b/fs/f2fs/gc.c > > > @@ -392,10 +392,6 @@ static void add_victim_entry(struct f2fs_sb_info *sbi, > > > if (p->gc_mode == GC_AT && > > > get_valid_blocks(sbi, segno, true) == 0) > > > return; > > > - > > > - if (p->alloc_mode == AT_SSR && > > > - get_seg_entry(sbi, segno)->ckpt_valid_blocks == 0) > > > - return; > > > } > > > for (i = 0; i < sbi->segs_per_sec; i++) > > > @@ -736,6 +732,19 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, > > > if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) > > > goto next; > > > + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { > > > + /* > > > + * to avoid selecting candidate which has below valid > > > + * block distribution: > > > + * partial blocks are valid and all left ones are valid > > > + * in previous checkpoint. > > > + */ > > > + if (p.alloc_mode == SSR || p.alloc_mode == AT_SSR) { > > > + if (!segment_has_free_slot(sbi, segno)) > > > + goto next; > > > + } > > > + } > > > + > > > if (is_atgc) { > > > add_victim_entry(sbi, &p, segno); > > > goto next; > > > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > > > index 2d5a82c4ca15..deaf57e13125 100644 > > > --- a/fs/f2fs/segment.c > > > +++ b/fs/f2fs/segment.c > > > @@ -2650,6 +2650,26 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, > > > seg->next_blkoff++; > > > } > > > +bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno) > > > +{ > > > + struct sit_info *sit = SIT_I(sbi); > > > + struct seg_entry *se = get_seg_entry(sbi, segno); > > > + int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); > > > + unsigned long *target_map = SIT_I(sbi)->tmp_map; > > > + unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; > > > + unsigned long *cur_map = (unsigned long *)se->cur_valid_map; > > > + int i, pos; > > > + > > > + down_write(&sit->sentry_lock); > > > + for (i = 0; i < entries; i++) > > > + target_map[i] = ckpt_map[i] | cur_map[i]; > > > + > > > + pos = __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, 0); > > > + up_write(&sit->sentry_lock); > > > + > > > + return pos < sbi->blocks_per_seg; > > > +} > > > + > > > /* > > > * This function always allocates a used segment(from dirty seglist) by SSR > > > * manner, so it should recover the existing segment information of valid blocks > > > > > . > > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFC] f2fs: fix to avoid selecting full segment w/ {AT,}SSR allocator 2021-02-20 9:40 [PATCH RFC] f2fs: fix to avoid selecting full segment w/ {AT,}SSR allocator Chao Yu 2021-02-22 13:43 ` Chao Yu @ 2021-03-18 17:17 ` Jaegeuk Kim 2021-03-19 2:31 ` Chao Yu 1 sibling, 1 reply; 8+ messages in thread From: Jaegeuk Kim @ 2021-03-18 17:17 UTC (permalink / raw) To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, chao On 02/20, Chao Yu wrote: > In cp disabling mode, there could be a condition > - target segment has 128 ckpt valid blocks > - GC migrates 128 valid blocks to other segment (segment is still in > dirty list) > - GC migrates 384 blocks to target segment (segment has 128 cp_vblocks > and 384 vblocks) > - If GC selects target segment via {AT,}SSR allocator, however there is > no free space in targe segment. > > Fixes: 4354994f097d ("f2fs: checkpoint disabling") > Fixes: 093749e296e2 ("f2fs: support age threshold based garbage collection") > Signed-off-by: Chao Yu <yuchao0@huawei.com> > --- > fs/f2fs/f2fs.h | 1 + > fs/f2fs/gc.c | 17 +++++++++++++---- > fs/f2fs/segment.c | 20 ++++++++++++++++++++ > 3 files changed, 34 insertions(+), 4 deletions(-) > > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h > index ed7807103c8e..9c753eff0814 100644 > --- a/fs/f2fs/f2fs.h > +++ b/fs/f2fs/f2fs.h > @@ -3376,6 +3376,7 @@ block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi); > int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable); > void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi); > int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra); > +bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno); > void f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi); > void f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi); > void f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi); > diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c > index 86ba8ed0b8a7..a1d8062cdace 100644 > --- a/fs/f2fs/gc.c > +++ b/fs/f2fs/gc.c > @@ -392,10 +392,6 @@ static void add_victim_entry(struct f2fs_sb_info *sbi, > if (p->gc_mode == GC_AT && > get_valid_blocks(sbi, segno, true) == 0) > return; > - > - if (p->alloc_mode == AT_SSR && > - get_seg_entry(sbi, segno)->ckpt_valid_blocks == 0) > - return; > } > > for (i = 0; i < sbi->segs_per_sec; i++) > @@ -736,6 +732,19 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, > if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) > goto next; > > + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { > + /* > + * to avoid selecting candidate which has below valid > + * block distribution: > + * partial blocks are valid and all left ones are valid > + * in previous checkpoint. > + */ > + if (p.alloc_mode == SSR || p.alloc_mode == AT_SSR) { > + if (!segment_has_free_slot(sbi, segno)) > + goto next; Do we need to change this to check free_slot instead of get_ckpt_valid_blocks()? 732 if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) && 733 get_ckpt_valid_blocks(sbi, segno) && 734 p.alloc_mode == LFS)) > + } > + } > + > if (is_atgc) { > add_victim_entry(sbi, &p, segno); > goto next; > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > index 2d5a82c4ca15..deaf57e13125 100644 > --- a/fs/f2fs/segment.c > +++ b/fs/f2fs/segment.c > @@ -2650,6 +2650,26 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, > seg->next_blkoff++; > } > > +bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno) > +{ > + struct sit_info *sit = SIT_I(sbi); > + struct seg_entry *se = get_seg_entry(sbi, segno); > + int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); > + unsigned long *target_map = SIT_I(sbi)->tmp_map; > + unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; > + unsigned long *cur_map = (unsigned long *)se->cur_valid_map; > + int i, pos; > + > + down_write(&sit->sentry_lock); > + for (i = 0; i < entries; i++) > + target_map[i] = ckpt_map[i] | cur_map[i]; > + > + pos = __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, 0); > + up_write(&sit->sentry_lock); > + > + return pos < sbi->blocks_per_seg; > +} > + > /* > * This function always allocates a used segment(from dirty seglist) by SSR > * manner, so it should recover the existing segment information of valid blocks > -- > 2.29.2 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFC] f2fs: fix to avoid selecting full segment w/ {AT,}SSR allocator 2021-03-18 17:17 ` Jaegeuk Kim @ 2021-03-19 2:31 ` Chao Yu 2021-03-23 22:59 ` Jaegeuk Kim 0 siblings, 1 reply; 8+ messages in thread From: Chao Yu @ 2021-03-19 2:31 UTC (permalink / raw) To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel, chao On 2021/3/19 1:17, Jaegeuk Kim wrote: > On 02/20, Chao Yu wrote: >> In cp disabling mode, there could be a condition >> - target segment has 128 ckpt valid blocks >> - GC migrates 128 valid blocks to other segment (segment is still in >> dirty list) >> - GC migrates 384 blocks to target segment (segment has 128 cp_vblocks >> and 384 vblocks) >> - If GC selects target segment via {AT,}SSR allocator, however there is >> no free space in targe segment. >> >> Fixes: 4354994f097d ("f2fs: checkpoint disabling") >> Fixes: 093749e296e2 ("f2fs: support age threshold based garbage collection") >> Signed-off-by: Chao Yu <yuchao0@huawei.com> >> --- >> fs/f2fs/f2fs.h | 1 + >> fs/f2fs/gc.c | 17 +++++++++++++---- >> fs/f2fs/segment.c | 20 ++++++++++++++++++++ >> 3 files changed, 34 insertions(+), 4 deletions(-) >> >> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h >> index ed7807103c8e..9c753eff0814 100644 >> --- a/fs/f2fs/f2fs.h >> +++ b/fs/f2fs/f2fs.h >> @@ -3376,6 +3376,7 @@ block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi); >> int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable); >> void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi); >> int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra); >> +bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno); >> void f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi); >> void f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi); >> void f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi); >> diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c >> index 86ba8ed0b8a7..a1d8062cdace 100644 >> --- a/fs/f2fs/gc.c >> +++ b/fs/f2fs/gc.c >> @@ -392,10 +392,6 @@ static void add_victim_entry(struct f2fs_sb_info *sbi, >> if (p->gc_mode == GC_AT && >> get_valid_blocks(sbi, segno, true) == 0) >> return; >> - >> - if (p->alloc_mode == AT_SSR && >> - get_seg_entry(sbi, segno)->ckpt_valid_blocks == 0) >> - return; >> } >> >> for (i = 0; i < sbi->segs_per_sec; i++) >> @@ -736,6 +732,19 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, >> if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) >> goto next; >> >> + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { >> + /* >> + * to avoid selecting candidate which has below valid >> + * block distribution: >> + * partial blocks are valid and all left ones are valid >> + * in previous checkpoint. >> + */ >> + if (p.alloc_mode == SSR || p.alloc_mode == AT_SSR) { >> + if (!segment_has_free_slot(sbi, segno)) >> + goto next; > > Do we need to change this to check free_slot instead of get_ckpt_valid_blocks()? Jaegeuk, LFS was assigned only for GC case, in this case we are trying to select source section, rather than target segment for SSR/AT_SSR case, so we don't need to check free_slot. - f2fs_gc - __get_victim - get_victim(sbi, victim, gc_type, NO_CHECK_TYPE, LFS, 0); > > 732 if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) && > 733 get_ckpt_valid_blocks(sbi, segno) && > 734 p.alloc_mode == LFS)) BTW, in LFS mode, GC wants to find source section rather than segment, so we should change to check valid ckpt blocks in every segment of targe section here? Thanks, > > >> + } >> + } >> + >> if (is_atgc) { >> add_victim_entry(sbi, &p, segno); >> goto next; >> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c >> index 2d5a82c4ca15..deaf57e13125 100644 >> --- a/fs/f2fs/segment.c >> +++ b/fs/f2fs/segment.c >> @@ -2650,6 +2650,26 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, >> seg->next_blkoff++; >> } >> >> +bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno) >> +{ >> + struct sit_info *sit = SIT_I(sbi); >> + struct seg_entry *se = get_seg_entry(sbi, segno); >> + int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); >> + unsigned long *target_map = SIT_I(sbi)->tmp_map; >> + unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; >> + unsigned long *cur_map = (unsigned long *)se->cur_valid_map; >> + int i, pos; >> + >> + down_write(&sit->sentry_lock); >> + for (i = 0; i < entries; i++) >> + target_map[i] = ckpt_map[i] | cur_map[i]; >> + >> + pos = __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, 0); >> + up_write(&sit->sentry_lock); >> + >> + return pos < sbi->blocks_per_seg; >> +} >> + >> /* >> * This function always allocates a used segment(from dirty seglist) by SSR >> * manner, so it should recover the existing segment information of valid blocks >> -- >> 2.29.2 > . > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFC] f2fs: fix to avoid selecting full segment w/ {AT,}SSR allocator 2021-03-19 2:31 ` Chao Yu @ 2021-03-23 22:59 ` Jaegeuk Kim 2021-03-24 3:28 ` Chao Yu 0 siblings, 1 reply; 8+ messages in thread From: Jaegeuk Kim @ 2021-03-23 22:59 UTC (permalink / raw) To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, chao On 03/19, Chao Yu wrote: > On 2021/3/19 1:17, Jaegeuk Kim wrote: > > On 02/20, Chao Yu wrote: > > > In cp disabling mode, there could be a condition > > > - target segment has 128 ckpt valid blocks > > > - GC migrates 128 valid blocks to other segment (segment is still in > > > dirty list) > > > - GC migrates 384 blocks to target segment (segment has 128 cp_vblocks > > > and 384 vblocks) > > > - If GC selects target segment via {AT,}SSR allocator, however there is > > > no free space in targe segment. > > > > > > Fixes: 4354994f097d ("f2fs: checkpoint disabling") > > > Fixes: 093749e296e2 ("f2fs: support age threshold based garbage collection") > > > Signed-off-by: Chao Yu <yuchao0@huawei.com> > > > --- > > > fs/f2fs/f2fs.h | 1 + > > > fs/f2fs/gc.c | 17 +++++++++++++---- > > > fs/f2fs/segment.c | 20 ++++++++++++++++++++ > > > 3 files changed, 34 insertions(+), 4 deletions(-) > > > > > > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h > > > index ed7807103c8e..9c753eff0814 100644 > > > --- a/fs/f2fs/f2fs.h > > > +++ b/fs/f2fs/f2fs.h > > > @@ -3376,6 +3376,7 @@ block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi); > > > int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable); > > > void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi); > > > int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra); > > > +bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno); > > > void f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi); > > > void f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi); > > > void f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi); > > > diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c > > > index 86ba8ed0b8a7..a1d8062cdace 100644 > > > --- a/fs/f2fs/gc.c > > > +++ b/fs/f2fs/gc.c > > > @@ -392,10 +392,6 @@ static void add_victim_entry(struct f2fs_sb_info *sbi, > > > if (p->gc_mode == GC_AT && > > > get_valid_blocks(sbi, segno, true) == 0) > > > return; > > > - > > > - if (p->alloc_mode == AT_SSR && > > > - get_seg_entry(sbi, segno)->ckpt_valid_blocks == 0) > > > - return; > > > } > > > for (i = 0; i < sbi->segs_per_sec; i++) > > > @@ -736,6 +732,19 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, > > > if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) > > > goto next; > > > + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { > > > + /* > > > + * to avoid selecting candidate which has below valid > > > + * block distribution: > > > + * partial blocks are valid and all left ones are valid > > > + * in previous checkpoint. > > > + */ > > > + if (p.alloc_mode == SSR || p.alloc_mode == AT_SSR) { > > > + if (!segment_has_free_slot(sbi, segno)) > > > + goto next; > > > > Do we need to change this to check free_slot instead of get_ckpt_valid_blocks()? > > Jaegeuk, > > LFS was assigned only for GC case, in this case we are trying to select source > section, rather than target segment for SSR/AT_SSR case, so we don't need to > check free_slot. > > - f2fs_gc > - __get_victim > - get_victim(sbi, victim, gc_type, NO_CHECK_TYPE, LFS, 0); > > > > > 732 if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) && > > 733 get_ckpt_valid_blocks(sbi, segno) && > > 734 p.alloc_mode == LFS)) > > BTW, in LFS mode, GC wants to find source section rather than segment, so we > should change to check valid ckpt blocks in every segment of targe section here? Alright. I refactored a bit on this patch with new one. Could you please take a look? https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git/commit/?h=dev&id=00152bd7cabd69b4615ebead823ff23887b0e0f7 Thanks, > > Thanks, > > > > > > > > + } > > > + } > > > + > > > if (is_atgc) { > > > add_victim_entry(sbi, &p, segno); > > > goto next; > > > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > > > index 2d5a82c4ca15..deaf57e13125 100644 > > > --- a/fs/f2fs/segment.c > > > +++ b/fs/f2fs/segment.c > > > @@ -2650,6 +2650,26 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, > > > seg->next_blkoff++; > > > } > > > +bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno) > > > +{ > > > + struct sit_info *sit = SIT_I(sbi); > > > + struct seg_entry *se = get_seg_entry(sbi, segno); > > > + int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); > > > + unsigned long *target_map = SIT_I(sbi)->tmp_map; > > > + unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; > > > + unsigned long *cur_map = (unsigned long *)se->cur_valid_map; > > > + int i, pos; > > > + > > > + down_write(&sit->sentry_lock); > > > + for (i = 0; i < entries; i++) > > > + target_map[i] = ckpt_map[i] | cur_map[i]; > > > + > > > + pos = __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, 0); > > > + up_write(&sit->sentry_lock); > > > + > > > + return pos < sbi->blocks_per_seg; > > > +} > > > + > > > /* > > > * This function always allocates a used segment(from dirty seglist) by SSR > > > * manner, so it should recover the existing segment information of valid blocks > > > -- > > > 2.29.2 > > . > > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFC] f2fs: fix to avoid selecting full segment w/ {AT,}SSR allocator 2021-03-23 22:59 ` Jaegeuk Kim @ 2021-03-24 3:28 ` Chao Yu 0 siblings, 0 replies; 8+ messages in thread From: Chao Yu @ 2021-03-24 3:28 UTC (permalink / raw) To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel, chao On 2021/3/24 6:59, Jaegeuk Kim wrote: > On 03/19, Chao Yu wrote: >> On 2021/3/19 1:17, Jaegeuk Kim wrote: >>> On 02/20, Chao Yu wrote: >>>> In cp disabling mode, there could be a condition >>>> - target segment has 128 ckpt valid blocks >>>> - GC migrates 128 valid blocks to other segment (segment is still in >>>> dirty list) >>>> - GC migrates 384 blocks to target segment (segment has 128 cp_vblocks >>>> and 384 vblocks) >>>> - If GC selects target segment via {AT,}SSR allocator, however there is >>>> no free space in targe segment. >>>> >>>> Fixes: 4354994f097d ("f2fs: checkpoint disabling") >>>> Fixes: 093749e296e2 ("f2fs: support age threshold based garbage collection") >>>> Signed-off-by: Chao Yu <yuchao0@huawei.com> >>>> --- >>>> fs/f2fs/f2fs.h | 1 + >>>> fs/f2fs/gc.c | 17 +++++++++++++---- >>>> fs/f2fs/segment.c | 20 ++++++++++++++++++++ >>>> 3 files changed, 34 insertions(+), 4 deletions(-) >>>> >>>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h >>>> index ed7807103c8e..9c753eff0814 100644 >>>> --- a/fs/f2fs/f2fs.h >>>> +++ b/fs/f2fs/f2fs.h >>>> @@ -3376,6 +3376,7 @@ block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi); >>>> int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable); >>>> void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi); >>>> int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra); >>>> +bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno); >>>> void f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi); >>>> void f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi); >>>> void f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi); >>>> diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c >>>> index 86ba8ed0b8a7..a1d8062cdace 100644 >>>> --- a/fs/f2fs/gc.c >>>> +++ b/fs/f2fs/gc.c >>>> @@ -392,10 +392,6 @@ static void add_victim_entry(struct f2fs_sb_info *sbi, >>>> if (p->gc_mode == GC_AT && >>>> get_valid_blocks(sbi, segno, true) == 0) >>>> return; >>>> - >>>> - if (p->alloc_mode == AT_SSR && >>>> - get_seg_entry(sbi, segno)->ckpt_valid_blocks == 0) >>>> - return; >>>> } >>>> for (i = 0; i < sbi->segs_per_sec; i++) >>>> @@ -736,6 +732,19 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, >>>> if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) >>>> goto next; >>>> + if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { >>>> + /* >>>> + * to avoid selecting candidate which has below valid >>>> + * block distribution: >>>> + * partial blocks are valid and all left ones are valid >>>> + * in previous checkpoint. >>>> + */ >>>> + if (p.alloc_mode == SSR || p.alloc_mode == AT_SSR) { >>>> + if (!segment_has_free_slot(sbi, segno)) >>>> + goto next; >>> >>> Do we need to change this to check free_slot instead of get_ckpt_valid_blocks()? >> >> Jaegeuk, >> >> LFS was assigned only for GC case, in this case we are trying to select source >> section, rather than target segment for SSR/AT_SSR case, so we don't need to >> check free_slot. >> >> - f2fs_gc >> - __get_victim >> - get_victim(sbi, victim, gc_type, NO_CHECK_TYPE, LFS, 0); >> >>> >>> 732 if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) && >>> 733 get_ckpt_valid_blocks(sbi, segno) && >>> 734 p.alloc_mode == LFS)) >> >> BTW, in LFS mode, GC wants to find source section rather than segment, so we >> should change to check valid ckpt blocks in every segment of targe section here? > > Alright. I refactored a bit on this patch with new one. Could you please take a look? > > https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git/commit/?h=dev&id=00152bd7cabd69b4615ebead823ff23887b0e0f7 I see, newly added comment looks good to me. One more concern is commit title and commit message is out-of-update, I've revised it in v2: https://lore.kernel.org/linux-f2fs-devel/20210324031828.67133-1-yuchao0@huawei.com/T/#u Thanks, > > Thanks, > >> >> Thanks, >> >>> >>> >>>> + } >>>> + } >>>> + >>>> if (is_atgc) { >>>> add_victim_entry(sbi, &p, segno); >>>> goto next; >>>> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c >>>> index 2d5a82c4ca15..deaf57e13125 100644 >>>> --- a/fs/f2fs/segment.c >>>> +++ b/fs/f2fs/segment.c >>>> @@ -2650,6 +2650,26 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, >>>> seg->next_blkoff++; >>>> } >>>> +bool segment_has_free_slot(struct f2fs_sb_info *sbi, int segno) >>>> +{ >>>> + struct sit_info *sit = SIT_I(sbi); >>>> + struct seg_entry *se = get_seg_entry(sbi, segno); >>>> + int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); >>>> + unsigned long *target_map = SIT_I(sbi)->tmp_map; >>>> + unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; >>>> + unsigned long *cur_map = (unsigned long *)se->cur_valid_map; >>>> + int i, pos; >>>> + >>>> + down_write(&sit->sentry_lock); >>>> + for (i = 0; i < entries; i++) >>>> + target_map[i] = ckpt_map[i] | cur_map[i]; >>>> + >>>> + pos = __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, 0); >>>> + up_write(&sit->sentry_lock); >>>> + >>>> + return pos < sbi->blocks_per_seg; >>>> +} >>>> + >>>> /* >>>> * This function always allocates a used segment(from dirty seglist) by SSR >>>> * manner, so it should recover the existing segment information of valid blocks >>>> -- >>>> 2.29.2 >>> . >>> > . > ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2021-03-24 3:28 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-02-20 9:40 [PATCH RFC] f2fs: fix to avoid selecting full segment w/ {AT,}SSR allocator Chao Yu
2021-02-22 13:43 ` Chao Yu
2021-02-23 12:26 ` Chao Yu
2021-02-28 5:10 ` Jaegeuk Kim
2021-03-18 17:17 ` Jaegeuk Kim
2021-03-19 2:31 ` Chao Yu
2021-03-23 22:59 ` Jaegeuk Kim
2021-03-24 3:28 ` Chao Yu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox