linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] f2fs: fix to avoid touching checkpointed data in get_victim()
@ 2021-03-24  3:18 Chao Yu
  2021-03-24 23:49 ` Jaegeuk Kim
  0 siblings, 1 reply; 10+ messages in thread
From: Chao Yu @ 2021-03-24  3:18 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, chao, Chao Yu

In CP disabling mode, there are two issues when using LFS or SSR | AT_SSR
mode to select victim:

1. LFS is set to find source section during GC, the victim should have
no checkpointed data, since after GC, section could not be set free for
reuse.

Previously, we only check valid chpt blocks in current segment rather
than section, fix it.

2. SSR | AT_SSR are set to find target segment for writes which can be
fully filled by checkpointed and newly written blocks, we should never
select such segment, otherwise it can cause panic or data corruption
during allocation, potential case is described as below:

 a) target segment has 128 ckpt valid blocks
 b) GC migrates 'n' (n < 512) valid blocks to other segment (segment is
    still in dirty list)
 c) GC migrates '512 - n' blocks to target segment (segment has 'n'
    cp_vblocks and '512 - n' vblocks)
 d) 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>
---
v2:
- fix to check checkpointed data in section rather than segment for
LFS mode.
- update commit title and message.
 fs/f2fs/f2fs.h    |  1 +
 fs/f2fs/gc.c      | 28 ++++++++++++++++++++--------
 fs/f2fs/segment.c | 39 ++++++++++++++++++++++++---------------
 fs/f2fs/segment.h | 14 +++++++++++++-
 4 files changed, 58 insertions(+), 24 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index eb154d9cb063..29e634d08a27 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3387,6 +3387,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 d96acc6531f2..4d9616373a4a 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++)
@@ -728,11 +724,27 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
 
 		if (sec_usage_check(sbi, secno))
 			goto next;
+
 		/* Don't touch checkpointed data */
-		if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) &&
-					get_ckpt_valid_blocks(sbi, segno) &&
-					p.alloc_mode == LFS))
-			goto next;
+		if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
+			if (p.alloc_mode == LFS) {
+				/*
+				 * LFS is set to find source section during GC.
+				 * The victim should have no checkpointed data.
+				 */
+				if (get_ckpt_valid_blocks(sbi, segno, true))
+					goto next;
+			} else {
+				/*
+				 * SSR | AT_SSR are set to find target segment
+				 * for writes which can be full by checkpointed
+				 * and newly written blocks.
+				 */
+				if (!segment_has_free_slot(sbi, segno))
+					goto next;
+			}
+		}
+
 		if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
 			goto next;
 
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 6e1a5f5657bf..f6a30856ceda 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -865,7 +865,7 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)
 	mutex_lock(&dirty_i->seglist_lock);
 
 	valid_blocks = get_valid_blocks(sbi, segno, false);
-	ckpt_valid_blocks = get_ckpt_valid_blocks(sbi, segno);
+	ckpt_valid_blocks = get_ckpt_valid_blocks(sbi, segno, false);
 
 	if (valid_blocks == 0 && (!is_sbi_flag_set(sbi, SBI_CP_DISABLED) ||
 		ckpt_valid_blocks == usable_blocks)) {
@@ -950,7 +950,7 @@ static unsigned int get_free_segment(struct f2fs_sb_info *sbi)
 	for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) {
 		if (get_valid_blocks(sbi, segno, false))
 			continue;
-		if (get_ckpt_valid_blocks(sbi, segno))
+		if (get_ckpt_valid_blocks(sbi, segno, false))
 			continue;
 		mutex_unlock(&dirty_i->seglist_lock);
 		return segno;
@@ -2643,6 +2643,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
@@ -2913,19 +2933,8 @@ static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type,
 		get_valid_blocks(sbi, curseg->segno, new_sec))
 		goto alloc;
 
-	if (new_sec) {
-		unsigned int segno = START_SEGNO(curseg->segno);
-		int i;
-
-		for (i = 0; i < sbi->segs_per_sec; i++, segno++) {
-			if (get_ckpt_valid_blocks(sbi, segno))
-				goto alloc;
-		}
-	} else {
-		if (!get_ckpt_valid_blocks(sbi, curseg->segno))
-			return;
-	}
-
+	if (!get_ckpt_valid_blocks(sbi, curseg->segno, new_sec))
+		return;
 alloc:
 	old_segno = curseg->segno;
 	SIT_I(sbi)->s_ops->allocate_segment(sbi, type, true);
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index 144980b62f9e..dab87ecba2b5 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -359,8 +359,20 @@ static inline unsigned int get_valid_blocks(struct f2fs_sb_info *sbi,
 }
 
 static inline unsigned int get_ckpt_valid_blocks(struct f2fs_sb_info *sbi,
-				unsigned int segno)
+				unsigned int segno, bool use_section)
 {
+	if (use_section && __is_large_section(sbi)) {
+		unsigned int start_segno = START_SEGNO(segno);
+		unsigned int blocks = 0;
+		int i;
+
+		for (i = 0; i < sbi->segs_per_sec; i++, start_segno++) {
+			struct seg_entry *se = get_seg_entry(sbi, start_segno);
+
+			blocks += se->ckpt_valid_blocks;
+		}
+		return blocks;
+	}
 	return get_seg_entry(sbi, segno)->ckpt_valid_blocks;
 }
 
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2] f2fs: fix to avoid touching checkpointed data in get_victim()
  2021-03-24  3:18 [PATCH v2] f2fs: fix to avoid touching checkpointed data in get_victim() Chao Yu
@ 2021-03-24 23:49 ` Jaegeuk Kim
  2021-03-25  1:30   ` Chao Yu
  2021-03-26  7:33   ` Chao Yu
  0 siblings, 2 replies; 10+ messages in thread
From: Jaegeuk Kim @ 2021-03-24 23:49 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, chao

On 03/24, Chao Yu wrote:
> In CP disabling mode, there are two issues when using LFS or SSR | AT_SSR
> mode to select victim:
> 
> 1. LFS is set to find source section during GC, the victim should have
> no checkpointed data, since after GC, section could not be set free for
> reuse.
> 
> Previously, we only check valid chpt blocks in current segment rather
> than section, fix it.
> 
> 2. SSR | AT_SSR are set to find target segment for writes which can be
> fully filled by checkpointed and newly written blocks, we should never
> select such segment, otherwise it can cause panic or data corruption
> during allocation, potential case is described as below:
> 
>  a) target segment has 128 ckpt valid blocks
>  b) GC migrates 'n' (n < 512) valid blocks to other segment (segment is
>     still in dirty list)
>  c) GC migrates '512 - n' blocks to target segment (segment has 'n'
>     cp_vblocks and '512 - n' vblocks)
>  d) 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>
> ---
> v2:
> - fix to check checkpointed data in section rather than segment for
> LFS mode.
> - update commit title and message.
>  fs/f2fs/f2fs.h    |  1 +
>  fs/f2fs/gc.c      | 28 ++++++++++++++++++++--------
>  fs/f2fs/segment.c | 39 ++++++++++++++++++++++++---------------
>  fs/f2fs/segment.h | 14 +++++++++++++-
>  4 files changed, 58 insertions(+), 24 deletions(-)
> 
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index eb154d9cb063..29e634d08a27 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -3387,6 +3387,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 d96acc6531f2..4d9616373a4a 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++)
> @@ -728,11 +724,27 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
>  
>  		if (sec_usage_check(sbi, secno))
>  			goto next;
> +
>  		/* Don't touch checkpointed data */
> -		if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) &&
> -					get_ckpt_valid_blocks(sbi, segno) &&
> -					p.alloc_mode == LFS))
> -			goto next;
> +		if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
> +			if (p.alloc_mode == LFS) {
> +				/*
> +				 * LFS is set to find source section during GC.
> +				 * The victim should have no checkpointed data.
> +				 */
> +				if (get_ckpt_valid_blocks(sbi, segno, true))
> +					goto next;
> +			} else {
> +				/*
> +				 * SSR | AT_SSR are set to find target segment
> +				 * for writes which can be full by checkpointed
> +				 * and newly written blocks.
> +				 */
> +				if (!segment_has_free_slot(sbi, segno))
> +					goto next;
> +			}
> +		}
> +
>  		if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
>  			goto next;
>  
> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
> index 6e1a5f5657bf..f6a30856ceda 100644
> --- a/fs/f2fs/segment.c
> +++ b/fs/f2fs/segment.c
> @@ -865,7 +865,7 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)
>  	mutex_lock(&dirty_i->seglist_lock);
>  
>  	valid_blocks = get_valid_blocks(sbi, segno, false);
> -	ckpt_valid_blocks = get_ckpt_valid_blocks(sbi, segno);
> +	ckpt_valid_blocks = get_ckpt_valid_blocks(sbi, segno, false);
>  
>  	if (valid_blocks == 0 && (!is_sbi_flag_set(sbi, SBI_CP_DISABLED) ||
>  		ckpt_valid_blocks == usable_blocks)) {
> @@ -950,7 +950,7 @@ static unsigned int get_free_segment(struct f2fs_sb_info *sbi)
>  	for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) {
>  		if (get_valid_blocks(sbi, segno, false))
>  			continue;
> -		if (get_ckpt_valid_blocks(sbi, segno))
> +		if (get_ckpt_valid_blocks(sbi, segno, false))
>  			continue;
>  		mutex_unlock(&dirty_i->seglist_lock);
>  		return segno;
> @@ -2643,6 +2643,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);

Should remove this lock.
https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git/commit/?h=dev

> +	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
> @@ -2913,19 +2933,8 @@ static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type,
>  		get_valid_blocks(sbi, curseg->segno, new_sec))
>  		goto alloc;
>  
> -	if (new_sec) {
> -		unsigned int segno = START_SEGNO(curseg->segno);
> -		int i;
> -
> -		for (i = 0; i < sbi->segs_per_sec; i++, segno++) {
> -			if (get_ckpt_valid_blocks(sbi, segno))
> -				goto alloc;
> -		}
> -	} else {
> -		if (!get_ckpt_valid_blocks(sbi, curseg->segno))
> -			return;
> -	}
> -
> +	if (!get_ckpt_valid_blocks(sbi, curseg->segno, new_sec))
> +		return;
>  alloc:
>  	old_segno = curseg->segno;
>  	SIT_I(sbi)->s_ops->allocate_segment(sbi, type, true);
> diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
> index 144980b62f9e..dab87ecba2b5 100644
> --- a/fs/f2fs/segment.h
> +++ b/fs/f2fs/segment.h
> @@ -359,8 +359,20 @@ static inline unsigned int get_valid_blocks(struct f2fs_sb_info *sbi,
>  }
>  
>  static inline unsigned int get_ckpt_valid_blocks(struct f2fs_sb_info *sbi,
> -				unsigned int segno)
> +				unsigned int segno, bool use_section)
>  {
> +	if (use_section && __is_large_section(sbi)) {
> +		unsigned int start_segno = START_SEGNO(segno);
> +		unsigned int blocks = 0;
> +		int i;
> +
> +		for (i = 0; i < sbi->segs_per_sec; i++, start_segno++) {
> +			struct seg_entry *se = get_seg_entry(sbi, start_segno);
> +
> +			blocks += se->ckpt_valid_blocks;
> +		}
> +		return blocks;
> +	}
>  	return get_seg_entry(sbi, segno)->ckpt_valid_blocks;
>  }
>  
> -- 
> 2.29.2

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2] f2fs: fix to avoid touching checkpointed data in get_victim()
  2021-03-24 23:49 ` Jaegeuk Kim
@ 2021-03-25  1:30   ` Chao Yu
  2021-03-25  1:51     ` Jaegeuk Kim
  2021-03-26  7:33   ` Chao Yu
  1 sibling, 1 reply; 10+ messages in thread
From: Chao Yu @ 2021-03-25  1:30 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel, chao

On 2021/3/25 7:49, Jaegeuk Kim wrote:
> On 03/24, Chao Yu wrote:
>> In CP disabling mode, there are two issues when using LFS or SSR | AT_SSR
>> mode to select victim:
>>
>> 1. LFS is set to find source section during GC, the victim should have
>> no checkpointed data, since after GC, section could not be set free for
>> reuse.
>>
>> Previously, we only check valid chpt blocks in current segment rather
>> than section, fix it.
>>
>> 2. SSR | AT_SSR are set to find target segment for writes which can be
>> fully filled by checkpointed and newly written blocks, we should never
>> select such segment, otherwise it can cause panic or data corruption
>> during allocation, potential case is described as below:
>>
>>   a) target segment has 128 ckpt valid blocks
>>   b) GC migrates 'n' (n < 512) valid blocks to other segment (segment is
>>      still in dirty list)
>>   c) GC migrates '512 - n' blocks to target segment (segment has 'n'
>>      cp_vblocks and '512 - n' vblocks)
>>   d) 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>
>> ---
>> v2:
>> - fix to check checkpointed data in section rather than segment for
>> LFS mode.
>> - update commit title and message.
>>   fs/f2fs/f2fs.h    |  1 +
>>   fs/f2fs/gc.c      | 28 ++++++++++++++++++++--------
>>   fs/f2fs/segment.c | 39 ++++++++++++++++++++++++---------------
>>   fs/f2fs/segment.h | 14 +++++++++++++-
>>   4 files changed, 58 insertions(+), 24 deletions(-)
>>
>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
>> index eb154d9cb063..29e634d08a27 100644
>> --- a/fs/f2fs/f2fs.h
>> +++ b/fs/f2fs/f2fs.h
>> @@ -3387,6 +3387,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 d96acc6531f2..4d9616373a4a 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++)
>> @@ -728,11 +724,27 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
>>   
>>   		if (sec_usage_check(sbi, secno))
>>   			goto next;
>> +
>>   		/* Don't touch checkpointed data */
>> -		if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) &&
>> -					get_ckpt_valid_blocks(sbi, segno) &&
>> -					p.alloc_mode == LFS))
>> -			goto next;
>> +		if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
>> +			if (p.alloc_mode == LFS) {
>> +				/*
>> +				 * LFS is set to find source section during GC.
>> +				 * The victim should have no checkpointed data.
>> +				 */
>> +				if (get_ckpt_valid_blocks(sbi, segno, true))
>> +					goto next;
>> +			} else {
>> +				/*
>> +				 * SSR | AT_SSR are set to find target segment
>> +				 * for writes which can be full by checkpointed
>> +				 * and newly written blocks.
>> +				 */
>> +				if (!segment_has_free_slot(sbi, segno))
>> +					goto next;
>> +			}
>> +		}
>> +
>>   		if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
>>   			goto next;
>>   
>> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
>> index 6e1a5f5657bf..f6a30856ceda 100644
>> --- a/fs/f2fs/segment.c
>> +++ b/fs/f2fs/segment.c
>> @@ -865,7 +865,7 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)
>>   	mutex_lock(&dirty_i->seglist_lock);
>>   
>>   	valid_blocks = get_valid_blocks(sbi, segno, false);
>> -	ckpt_valid_blocks = get_ckpt_valid_blocks(sbi, segno);
>> +	ckpt_valid_blocks = get_ckpt_valid_blocks(sbi, segno, false);
>>   
>>   	if (valid_blocks == 0 && (!is_sbi_flag_set(sbi, SBI_CP_DISABLED) ||
>>   		ckpt_valid_blocks == usable_blocks)) {
>> @@ -950,7 +950,7 @@ static unsigned int get_free_segment(struct f2fs_sb_info *sbi)
>>   	for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) {
>>   		if (get_valid_blocks(sbi, segno, false))
>>   			continue;
>> -		if (get_ckpt_valid_blocks(sbi, segno))
>> +		if (get_ckpt_valid_blocks(sbi, segno, false))
>>   			continue;
>>   		mutex_unlock(&dirty_i->seglist_lock);
>>   		return segno;
>> @@ -2643,6 +2643,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);
> 
> Should remove this lock.
> https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git/commit/?h=dev

Oh, correct.

BTW, could you please add 'f2fs_' prefix for segment_has_free_slot()
like we did for other non-static symbols?

Thanks,

> 
>> +	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
>> @@ -2913,19 +2933,8 @@ static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type,
>>   		get_valid_blocks(sbi, curseg->segno, new_sec))
>>   		goto alloc;
>>   
>> -	if (new_sec) {
>> -		unsigned int segno = START_SEGNO(curseg->segno);
>> -		int i;
>> -
>> -		for (i = 0; i < sbi->segs_per_sec; i++, segno++) {
>> -			if (get_ckpt_valid_blocks(sbi, segno))
>> -				goto alloc;
>> -		}
>> -	} else {
>> -		if (!get_ckpt_valid_blocks(sbi, curseg->segno))
>> -			return;
>> -	}
>> -
>> +	if (!get_ckpt_valid_blocks(sbi, curseg->segno, new_sec))
>> +		return;
>>   alloc:
>>   	old_segno = curseg->segno;
>>   	SIT_I(sbi)->s_ops->allocate_segment(sbi, type, true);
>> diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
>> index 144980b62f9e..dab87ecba2b5 100644
>> --- a/fs/f2fs/segment.h
>> +++ b/fs/f2fs/segment.h
>> @@ -359,8 +359,20 @@ static inline unsigned int get_valid_blocks(struct f2fs_sb_info *sbi,
>>   }
>>   
>>   static inline unsigned int get_ckpt_valid_blocks(struct f2fs_sb_info *sbi,
>> -				unsigned int segno)
>> +				unsigned int segno, bool use_section)
>>   {
>> +	if (use_section && __is_large_section(sbi)) {
>> +		unsigned int start_segno = START_SEGNO(segno);
>> +		unsigned int blocks = 0;
>> +		int i;
>> +
>> +		for (i = 0; i < sbi->segs_per_sec; i++, start_segno++) {
>> +			struct seg_entry *se = get_seg_entry(sbi, start_segno);
>> +
>> +			blocks += se->ckpt_valid_blocks;
>> +		}
>> +		return blocks;
>> +	}
>>   	return get_seg_entry(sbi, segno)->ckpt_valid_blocks;
>>   }
>>   
>> -- 
>> 2.29.2
> .
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2] f2fs: fix to avoid touching checkpointed data in get_victim()
  2021-03-25  1:30   ` Chao Yu
@ 2021-03-25  1:51     ` Jaegeuk Kim
  0 siblings, 0 replies; 10+ messages in thread
From: Jaegeuk Kim @ 2021-03-25  1:51 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, chao

On 03/25, Chao Yu wrote:
> On 2021/3/25 7:49, Jaegeuk Kim wrote:
> > On 03/24, Chao Yu wrote:
> > > In CP disabling mode, there are two issues when using LFS or SSR | AT_SSR
> > > mode to select victim:
> > > 
> > > 1. LFS is set to find source section during GC, the victim should have
> > > no checkpointed data, since after GC, section could not be set free for
> > > reuse.
> > > 
> > > Previously, we only check valid chpt blocks in current segment rather
> > > than section, fix it.
> > > 
> > > 2. SSR | AT_SSR are set to find target segment for writes which can be
> > > fully filled by checkpointed and newly written blocks, we should never
> > > select such segment, otherwise it can cause panic or data corruption
> > > during allocation, potential case is described as below:
> > > 
> > >   a) target segment has 128 ckpt valid blocks
> > >   b) GC migrates 'n' (n < 512) valid blocks to other segment (segment is
> > >      still in dirty list)
> > >   c) GC migrates '512 - n' blocks to target segment (segment has 'n'
> > >      cp_vblocks and '512 - n' vblocks)
> > >   d) 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>
> > > ---
> > > v2:
> > > - fix to check checkpointed data in section rather than segment for
> > > LFS mode.
> > > - update commit title and message.
> > >   fs/f2fs/f2fs.h    |  1 +
> > >   fs/f2fs/gc.c      | 28 ++++++++++++++++++++--------
> > >   fs/f2fs/segment.c | 39 ++++++++++++++++++++++++---------------
> > >   fs/f2fs/segment.h | 14 +++++++++++++-
> > >   4 files changed, 58 insertions(+), 24 deletions(-)
> > > 
> > > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> > > index eb154d9cb063..29e634d08a27 100644
> > > --- a/fs/f2fs/f2fs.h
> > > +++ b/fs/f2fs/f2fs.h
> > > @@ -3387,6 +3387,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 d96acc6531f2..4d9616373a4a 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++)
> > > @@ -728,11 +724,27 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
> > >   		if (sec_usage_check(sbi, secno))
> > >   			goto next;
> > > +
> > >   		/* Don't touch checkpointed data */
> > > -		if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) &&
> > > -					get_ckpt_valid_blocks(sbi, segno) &&
> > > -					p.alloc_mode == LFS))
> > > -			goto next;
> > > +		if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
> > > +			if (p.alloc_mode == LFS) {
> > > +				/*
> > > +				 * LFS is set to find source section during GC.
> > > +				 * The victim should have no checkpointed data.
> > > +				 */
> > > +				if (get_ckpt_valid_blocks(sbi, segno, true))
> > > +					goto next;
> > > +			} else {
> > > +				/*
> > > +				 * SSR | AT_SSR are set to find target segment
> > > +				 * for writes which can be full by checkpointed
> > > +				 * and newly written blocks.
> > > +				 */
> > > +				if (!segment_has_free_slot(sbi, segno))
> > > +					goto next;
> > > +			}
> > > +		}
> > > +
> > >   		if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
> > >   			goto next;
> > > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
> > > index 6e1a5f5657bf..f6a30856ceda 100644
> > > --- a/fs/f2fs/segment.c
> > > +++ b/fs/f2fs/segment.c
> > > @@ -865,7 +865,7 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)
> > >   	mutex_lock(&dirty_i->seglist_lock);
> > >   	valid_blocks = get_valid_blocks(sbi, segno, false);
> > > -	ckpt_valid_blocks = get_ckpt_valid_blocks(sbi, segno);
> > > +	ckpt_valid_blocks = get_ckpt_valid_blocks(sbi, segno, false);
> > >   	if (valid_blocks == 0 && (!is_sbi_flag_set(sbi, SBI_CP_DISABLED) ||
> > >   		ckpt_valid_blocks == usable_blocks)) {
> > > @@ -950,7 +950,7 @@ static unsigned int get_free_segment(struct f2fs_sb_info *sbi)
> > >   	for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) {
> > >   		if (get_valid_blocks(sbi, segno, false))
> > >   			continue;
> > > -		if (get_ckpt_valid_blocks(sbi, segno))
> > > +		if (get_ckpt_valid_blocks(sbi, segno, false))
> > >   			continue;
> > >   		mutex_unlock(&dirty_i->seglist_lock);
> > >   		return segno;
> > > @@ -2643,6 +2643,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);
> > 
> > Should remove this lock.
> > https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git/commit/?h=dev
> 
> Oh, correct.
> 
> BTW, could you please add 'f2fs_' prefix for segment_has_free_slot()
> like we did for other non-static symbols?

Added.

> 
> Thanks,
> 
> > 
> > > +	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
> > > @@ -2913,19 +2933,8 @@ static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type,
> > >   		get_valid_blocks(sbi, curseg->segno, new_sec))
> > >   		goto alloc;
> > > -	if (new_sec) {
> > > -		unsigned int segno = START_SEGNO(curseg->segno);
> > > -		int i;
> > > -
> > > -		for (i = 0; i < sbi->segs_per_sec; i++, segno++) {
> > > -			if (get_ckpt_valid_blocks(sbi, segno))
> > > -				goto alloc;
> > > -		}
> > > -	} else {
> > > -		if (!get_ckpt_valid_blocks(sbi, curseg->segno))
> > > -			return;
> > > -	}
> > > -
> > > +	if (!get_ckpt_valid_blocks(sbi, curseg->segno, new_sec))
> > > +		return;
> > >   alloc:
> > >   	old_segno = curseg->segno;
> > >   	SIT_I(sbi)->s_ops->allocate_segment(sbi, type, true);
> > > diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
> > > index 144980b62f9e..dab87ecba2b5 100644
> > > --- a/fs/f2fs/segment.h
> > > +++ b/fs/f2fs/segment.h
> > > @@ -359,8 +359,20 @@ static inline unsigned int get_valid_blocks(struct f2fs_sb_info *sbi,
> > >   }
> > >   static inline unsigned int get_ckpt_valid_blocks(struct f2fs_sb_info *sbi,
> > > -				unsigned int segno)
> > > +				unsigned int segno, bool use_section)
> > >   {
> > > +	if (use_section && __is_large_section(sbi)) {
> > > +		unsigned int start_segno = START_SEGNO(segno);
> > > +		unsigned int blocks = 0;
> > > +		int i;
> > > +
> > > +		for (i = 0; i < sbi->segs_per_sec; i++, start_segno++) {
> > > +			struct seg_entry *se = get_seg_entry(sbi, start_segno);
> > > +
> > > +			blocks += se->ckpt_valid_blocks;
> > > +		}
> > > +		return blocks;
> > > +	}
> > >   	return get_seg_entry(sbi, segno)->ckpt_valid_blocks;
> > >   }
> > > -- 
> > > 2.29.2
> > .
> > 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2] f2fs: fix to avoid touching checkpointed data in get_victim()
  2021-03-24 23:49 ` Jaegeuk Kim
  2021-03-25  1:30   ` Chao Yu
@ 2021-03-26  7:33   ` Chao Yu
  2021-04-11  7:01     ` Chao Yu
  1 sibling, 1 reply; 10+ messages in thread
From: Chao Yu @ 2021-03-26  7:33 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel, chao

On 2021/3/25 7:49, Jaegeuk Kim wrote:
> On 03/24, Chao Yu wrote:
>> In CP disabling mode, there are two issues when using LFS or SSR | AT_SSR
>> mode to select victim:
>>
>> 1. LFS is set to find source section during GC, the victim should have
>> no checkpointed data, since after GC, section could not be set free for
>> reuse.
>>
>> Previously, we only check valid chpt blocks in current segment rather
>> than section, fix it.
>>
>> 2. SSR | AT_SSR are set to find target segment for writes which can be
>> fully filled by checkpointed and newly written blocks, we should never
>> select such segment, otherwise it can cause panic or data corruption
>> during allocation, potential case is described as below:
>>
>>   a) target segment has 128 ckpt valid blocks
>>   b) GC migrates 'n' (n < 512) valid blocks to other segment (segment is
>>      still in dirty list)

I missed to change 128 to n, so comments should be updated as below:

   a) target segment has 'n' (n < 512) ckpt valid blocks
   b) GC migrates 'n' valid blocks to other segment (segment is still
      in dirty list)

Thanks,

>>   c) GC migrates '512 - n' blocks to target segment (segment has 'n'
>>      cp_vblocks and '512 - n' vblocks)
>>   d) If GC selects target segment via {AT,}SSR allocator, however there
>>      is no free space in targe segment.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2] f2fs: fix to avoid touching checkpointed data in get_victim()
  2021-03-26  7:33   ` Chao Yu
@ 2021-04-11  7:01     ` Chao Yu
  2021-04-13  2:59       ` Jaegeuk Kim
  0 siblings, 1 reply; 10+ messages in thread
From: Chao Yu @ 2021-04-11  7:01 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel

Hi Jaegeuk,

Could you please help to merge below cleanup diff into original patch?
or merge this separately if it is too late since it is near rc7.

 From 5a342a8f332a1b3281ec0e2b4d41b5287689c8ed Mon Sep 17 00:00:00 2001
From: Chao Yu <yuchao0@huawei.com>
Date: Sun, 11 Apr 2021 14:29:34 +0800
Subject: [PATCH] f2fs: avoid duplicated codes for cleanup

f2fs_segment_has_free_slot() was copied from __next_free_blkoff(),
the main implementation of them is almost the same, clean up them to
reuse common code as much as possible.

Signed-off-by: Chao Yu <yuchao0@huawei.com>
---
  fs/f2fs/segment.c | 32 ++++++++++----------------------
  1 file changed, 10 insertions(+), 22 deletions(-)

diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index b33273aa5c22..bd9056165d62 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2627,22 +2627,20 @@ static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
  	curseg->alloc_type = LFS;
  }

-static void __next_free_blkoff(struct f2fs_sb_info *sbi,
-			struct curseg_info *seg, block_t start)
+static int __next_free_blkoff(struct f2fs_sb_info *sbi,
+					int segno, block_t start)
  {
-	struct seg_entry *se = get_seg_entry(sbi, seg->segno);
+	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;
+	int i;

  	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, start);
-
-	seg->next_blkoff = pos;
+	return __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, start);
  }

  /*
@@ -2654,26 +2652,16 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi,
  				struct curseg_info *seg)
  {
  	if (seg->alloc_type == SSR)
-		__next_free_blkoff(sbi, seg, seg->next_blkoff + 1);
+		seg->next_blkoff =
+			__next_free_blkoff(sbi, seg->segno,
+						seg->next_blkoff + 1);
  	else
  		seg->next_blkoff++;
  }

  bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno)
  {
-	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;
-
-	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);
-
-	return pos < sbi->blocks_per_seg;
+	return __next_free_blkoff(sbi, segno, 0) < sbi->blocks_per_seg;
  }

  /*
@@ -2701,7 +2689,7 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type, bool flush)

  	reset_curseg(sbi, type, 1);
  	curseg->alloc_type = SSR;
-	__next_free_blkoff(sbi, curseg, 0);
+	__next_free_blkoff(sbi, curseg->segno, 0);

  	sum_page = f2fs_get_sum_page(sbi, new_segno);
  	if (IS_ERR(sum_page)) {
-- 
2.22.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2] f2fs: fix to avoid touching checkpointed data in get_victim()
  2021-04-11  7:01     ` Chao Yu
@ 2021-04-13  2:59       ` Jaegeuk Kim
  2021-04-13  3:04         ` [f2fs-dev] " Chao Yu
                           ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Jaegeuk Kim @ 2021-04-13  2:59 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel

On 04/11, Chao Yu wrote:
> Hi Jaegeuk,
> 
> Could you please help to merge below cleanup diff into original patch?
> or merge this separately if it is too late since it is near rc7.

I didn't review this tho, this gives an error in xfstests/083.

> 
> From 5a342a8f332a1b3281ec0e2b4d41b5287689c8ed Mon Sep 17 00:00:00 2001
> From: Chao Yu <yuchao0@huawei.com>
> Date: Sun, 11 Apr 2021 14:29:34 +0800
> Subject: [PATCH] f2fs: avoid duplicated codes for cleanup
> 
> f2fs_segment_has_free_slot() was copied from __next_free_blkoff(),
> the main implementation of them is almost the same, clean up them to
> reuse common code as much as possible.
> 
> Signed-off-by: Chao Yu <yuchao0@huawei.com>
> ---
>  fs/f2fs/segment.c | 32 ++++++++++----------------------
>  1 file changed, 10 insertions(+), 22 deletions(-)
> 
> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
> index b33273aa5c22..bd9056165d62 100644
> --- a/fs/f2fs/segment.c
> +++ b/fs/f2fs/segment.c
> @@ -2627,22 +2627,20 @@ static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
>  	curseg->alloc_type = LFS;
>  }
> 
> -static void __next_free_blkoff(struct f2fs_sb_info *sbi,
> -			struct curseg_info *seg, block_t start)
> +static int __next_free_blkoff(struct f2fs_sb_info *sbi,
> +					int segno, block_t start)
>  {
> -	struct seg_entry *se = get_seg_entry(sbi, seg->segno);
> +	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;
> +	int i;
> 
>  	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, start);
> -
> -	seg->next_blkoff = pos;
> +	return __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, start);
>  }
> 
>  /*
> @@ -2654,26 +2652,16 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi,
>  				struct curseg_info *seg)
>  {
>  	if (seg->alloc_type == SSR)
> -		__next_free_blkoff(sbi, seg, seg->next_blkoff + 1);
> +		seg->next_blkoff =
> +			__next_free_blkoff(sbi, seg->segno,
> +						seg->next_blkoff + 1);
>  	else
>  		seg->next_blkoff++;
>  }
> 
>  bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno)
>  {
> -	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;
> -
> -	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);
> -
> -	return pos < sbi->blocks_per_seg;
> +	return __next_free_blkoff(sbi, segno, 0) < sbi->blocks_per_seg;
>  }
> 
>  /*
> @@ -2701,7 +2689,7 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type, bool flush)
> 
>  	reset_curseg(sbi, type, 1);
>  	curseg->alloc_type = SSR;
> -	__next_free_blkoff(sbi, curseg, 0);
> +	__next_free_blkoff(sbi, curseg->segno, 0);
> 
>  	sum_page = f2fs_get_sum_page(sbi, new_segno);
>  	if (IS_ERR(sum_page)) {
> -- 
> 2.22.1

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [f2fs-dev] [PATCH v2] f2fs: fix to avoid touching checkpointed data in get_victim()
  2021-04-13  2:59       ` Jaegeuk Kim
@ 2021-04-13  3:04         ` Chao Yu
  2021-04-13  3:23         ` Chao Yu
  2021-04-13  9:56         ` Chao Yu
  2 siblings, 0 replies; 10+ messages in thread
From: Chao Yu @ 2021-04-13  3:04 UTC (permalink / raw)
  To: Jaegeuk Kim, Chao Yu; +Cc: linux-kernel, linux-f2fs-devel

On 2021/4/13 10:59, Jaegeuk Kim wrote:
> On 04/11, Chao Yu wrote:
>> Hi Jaegeuk,
>>
>> Could you please help to merge below cleanup diff into original patch?
>> or merge this separately if it is too late since it is near rc7.
> 
> I didn't review this tho, this gives an error in xfstests/083.

My bad, I hit this issue too, let me check this.

Thanks,

> 
>>
>>  From 5a342a8f332a1b3281ec0e2b4d41b5287689c8ed Mon Sep 17 00:00:00 2001
>> From: Chao Yu <yuchao0@huawei.com>
>> Date: Sun, 11 Apr 2021 14:29:34 +0800
>> Subject: [PATCH] f2fs: avoid duplicated codes for cleanup
>>
>> f2fs_segment_has_free_slot() was copied from __next_free_blkoff(),
>> the main implementation of them is almost the same, clean up them to
>> reuse common code as much as possible.
>>
>> Signed-off-by: Chao Yu <yuchao0@huawei.com>
>> ---
>>   fs/f2fs/segment.c | 32 ++++++++++----------------------
>>   1 file changed, 10 insertions(+), 22 deletions(-)
>>
>> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
>> index b33273aa5c22..bd9056165d62 100644
>> --- a/fs/f2fs/segment.c
>> +++ b/fs/f2fs/segment.c
>> @@ -2627,22 +2627,20 @@ static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
>>   	curseg->alloc_type = LFS;
>>   }
>>
>> -static void __next_free_blkoff(struct f2fs_sb_info *sbi,
>> -			struct curseg_info *seg, block_t start)
>> +static int __next_free_blkoff(struct f2fs_sb_info *sbi,
>> +					int segno, block_t start)
>>   {
>> -	struct seg_entry *se = get_seg_entry(sbi, seg->segno);
>> +	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;
>> +	int i;
>>
>>   	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, start);
>> -
>> -	seg->next_blkoff = pos;
>> +	return __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, start);
>>   }
>>
>>   /*
>> @@ -2654,26 +2652,16 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi,
>>   				struct curseg_info *seg)
>>   {
>>   	if (seg->alloc_type == SSR)
>> -		__next_free_blkoff(sbi, seg, seg->next_blkoff + 1);
>> +		seg->next_blkoff =
>> +			__next_free_blkoff(sbi, seg->segno,
>> +						seg->next_blkoff + 1);
>>   	else
>>   		seg->next_blkoff++;
>>   }
>>
>>   bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno)
>>   {
>> -	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;
>> -
>> -	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);
>> -
>> -	return pos < sbi->blocks_per_seg;
>> +	return __next_free_blkoff(sbi, segno, 0) < sbi->blocks_per_seg;
>>   }
>>
>>   /*
>> @@ -2701,7 +2689,7 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type, bool flush)
>>
>>   	reset_curseg(sbi, type, 1);
>>   	curseg->alloc_type = SSR;
>> -	__next_free_blkoff(sbi, curseg, 0);
>> +	__next_free_blkoff(sbi, curseg->segno, 0);
>>
>>   	sum_page = f2fs_get_sum_page(sbi, new_segno);
>>   	if (IS_ERR(sum_page)) {
>> -- 
>> 2.22.1
> 
> 
> _______________________________________________
> Linux-f2fs-devel mailing list
> Linux-f2fs-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
> .
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [f2fs-dev] [PATCH v2] f2fs: fix to avoid touching checkpointed data in get_victim()
  2021-04-13  2:59       ` Jaegeuk Kim
  2021-04-13  3:04         ` [f2fs-dev] " Chao Yu
@ 2021-04-13  3:23         ` Chao Yu
  2021-04-13  9:56         ` Chao Yu
  2 siblings, 0 replies; 10+ messages in thread
From: Chao Yu @ 2021-04-13  3:23 UTC (permalink / raw)
  To: Jaegeuk Kim, Chao Yu; +Cc: linux-kernel, linux-f2fs-devel

On 2021/4/13 10:59, Jaegeuk Kim wrote:
> @@ -2701,7 +2689,7 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type, bool flush)
> 
>   	reset_curseg(sbi, type, 1);
>   	curseg->alloc_type = SSR;
> -	__next_free_blkoff(sbi, curseg, 0);
> +	__next_free_blkoff(sbi, curseg->segno, 0);

Forgot to assign curseg->next_blkoff here, I checked generic/083, it passed,
let me run all testcases.

Thanks,

> 
>   	sum_page = f2fs_get_sum_page(sbi, new_segno);
>   	if (IS_ERR(sum_page)) {

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [f2fs-dev] [PATCH v2] f2fs: fix to avoid touching checkpointed data in get_victim()
  2021-04-13  2:59       ` Jaegeuk Kim
  2021-04-13  3:04         ` [f2fs-dev] " Chao Yu
  2021-04-13  3:23         ` Chao Yu
@ 2021-04-13  9:56         ` Chao Yu
  2 siblings, 0 replies; 10+ messages in thread
From: Chao Yu @ 2021-04-13  9:56 UTC (permalink / raw)
  To: Jaegeuk Kim, Chao Yu; +Cc: linux-kernel, linux-f2fs-devel

On 2021/4/13 10:59, Jaegeuk Kim wrote:
> On 04/11, Chao Yu wrote:
>> Hi Jaegeuk,
>>
>> Could you please help to merge below cleanup diff into original patch?
>> or merge this separately if it is too late since it is near rc7.
> 
> I didn't review this tho, this gives an error in xfstests/083.
> 

 From 59c2bd34fb0c77bcede2af7e5d308c014c544a1e Mon Sep 17 00:00:00 2001
From: Chao Yu <yuchao0@huawei.com>
Date: Sun, 11 Apr 2021 14:29:34 +0800
Subject: [PATCH] f2fs: avoid duplicated codes for cleanup

f2fs_segment_has_free_slot() was copied and modified from
__next_free_blkoff(), they are almost the same, clean up to
reuse common code as much as possible.

Signed-off-by: Chao Yu <yuchao0@huawei.com>
---
- fix to assign .next_blkoff in change_curseg()
  fs/f2fs/segment.c | 32 ++++++++++----------------------
  1 file changed, 10 insertions(+), 22 deletions(-)

diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index d6c6c13feb43..6e740ecf0814 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2638,22 +2638,20 @@ static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
  	curseg->alloc_type = LFS;
  }

-static void __next_free_blkoff(struct f2fs_sb_info *sbi,
-			struct curseg_info *seg, block_t start)
+static int __next_free_blkoff(struct f2fs_sb_info *sbi,
+					int segno, block_t start)
  {
-	struct seg_entry *se = get_seg_entry(sbi, seg->segno);
+	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;
+	int i;

  	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, start);
-
-	seg->next_blkoff = pos;
+	return __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, start);
  }

  /*
@@ -2665,26 +2663,16 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi,
  				struct curseg_info *seg)
  {
  	if (seg->alloc_type == SSR)
-		__next_free_blkoff(sbi, seg, seg->next_blkoff + 1);
+		seg->next_blkoff =
+			__next_free_blkoff(sbi, seg->segno,
+						seg->next_blkoff + 1);
  	else
  		seg->next_blkoff++;
  }

  bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno)
  {
-	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;
-
-	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);
-
-	return pos < sbi->blocks_per_seg;
+	return __next_free_blkoff(sbi, segno, 0) < sbi->blocks_per_seg;
  }

  /*
@@ -2712,7 +2700,7 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type, bool flush)

  	reset_curseg(sbi, type, 1);
  	curseg->alloc_type = SSR;
-	__next_free_blkoff(sbi, curseg, 0);
+	curseg->next_blkoff = __next_free_blkoff(sbi, curseg->segno, 0);

  	sum_page = f2fs_get_sum_page(sbi, new_segno);
  	if (IS_ERR(sum_page)) {
-- 
2.29.2


^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2021-04-13  9:56 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-24  3:18 [PATCH v2] f2fs: fix to avoid touching checkpointed data in get_victim() Chao Yu
2021-03-24 23:49 ` Jaegeuk Kim
2021-03-25  1:30   ` Chao Yu
2021-03-25  1:51     ` Jaegeuk Kim
2021-03-26  7:33   ` Chao Yu
2021-04-11  7:01     ` Chao Yu
2021-04-13  2:59       ` Jaegeuk Kim
2021-04-13  3:04         ` [f2fs-dev] " Chao Yu
2021-04-13  3:23         ` Chao Yu
2021-04-13  9:56         ` Chao Yu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).