The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Chao Yu <chao@kernel.org>
To: 'wallentx <william.allentx@gmail.com>,
	linux-f2fs-devel@lists.sourceforge.net
Cc: chao@kernel.org, jaegeuk@kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH 3/3] f2fs: add mount option to disable shared SIT mirror checks
Date: Sat, 14 Mar 2026 13:14:07 +0800	[thread overview]
Message-ID: <76d4e46c-5c34-4dc4-8aa4-1efbcbe1415f@kernel.org> (raw)
In-Reply-To: <20260309103700.489932-4-william.allentx@gmail.com>

On 2026/3/9 18:37, 'wallentx wrote:
> From: wallentx <william.allentx@gmail.com>
> 
> When CONFIG_F2FS_CHECK_FS=y, zoned shared-SIT mode still keeps
> per-segment cur_valid_map_mir together with auxiliary SIT mirror state
> for runtime consistency checks. After shared SIT maps are introduced,
> that mirror path becomes the next major static memory cost on large
> zoned systems.
> 
> Add shared_sit_check/noshared_sit_check to control that extra mirror
> tracking explicitly. Keep shared_sit_check as the default, limit the
> option to zoned shared-SIT mounts, and reject changing it by remount
> because the mirror state is built at mount time.
> 
> With noshared_sit_check, shared-SIT mode skips cur_valid_map_mir,
> sit_bitmap_mir, and invalid_segmap allocation and their associated
> check paths. This does not disable all CONFIG_F2FS_CHECK_FS behavior; it
> only disables the extra shared-SIT mirror tracking.
> 
> On the same 43-volume HM-SMR test system (~550 TB total) with
> CONFIG_F2FS_CHECK_FS=y, shared SIT with the default mirror path enabled
> reported 27.70 GiB of static F2FS memory. Mounting with
> noshared_sit_check reduced that to 12.10 GiB.

Jaegeuk and me think that we can drop sit bitmap and version bitmap
sanity check, since we haven't got any report for almost a decade.

So how about dropping the bitmaps w/ two separated patch?

Thanks,

> 
> Signed-off-by: wallentx <william.allentx@gmail.com>
> ---
>   Documentation/filesystems/f2fs.rst |  11 ++
>   fs/f2fs/debug.c                    |   7 +-
>   fs/f2fs/f2fs.h                     |  16 +++
>   fs/f2fs/gc.c                       |  29 ++--
>   fs/f2fs/segment.c                  | 213 ++++++++++++++++-------------
>   fs/f2fs/segment.h                  |  28 ++--
>   fs/f2fs/super.c                    |  21 +++
>   7 files changed, 204 insertions(+), 121 deletions(-)
> 
> diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst
> index 7e4031631286..3ca191f92309 100644
> --- a/Documentation/filesystems/f2fs.rst
> +++ b/Documentation/filesystems/f2fs.rst
> @@ -363,6 +363,17 @@ memory=%s		 Control memory mode. This supports "normal" and "low" modes.
>   			 Because of the nature of low memory devices, in this mode, f2fs
>   			 will try to save memory sometimes by sacrificing performance.
>   			 "normal" mode is the default mode and same as before.
> +shared_sit_check/
> +noshared_sit_check	 Enable or disable extra SIT mirror consistency checks in
> +			 zoned shared-SIT mode. This only affects zoned devices
> +			 mounted with ``mode=lfs``, where shared SIT valid maps are
> +			 used. ``shared_sit_check`` is enabled by default. Setting
> +			 ``noshared_sit_check`` reduces memory usage when the kernel
> +			 is built with ``CONFIG_F2FS_CHECK_FS=y`` by skipping the
> +			 per-segment SIT mirror tracking. This option has no effect
> +			 when shared SIT maps are not in use and cannot be changed
> +			 by remount. To use a different setting, unmount and
> +			 mount again with the new option.
>   age_extent_cache	 Enable an age extent cache based on rb-tree. It records
>   			 data block update frequency of the extent per inode, in
>   			 order to provide better temperature hints for data block
> diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
> index d8bfdac5c1e4..ed6e03b42836 100644
> --- a/fs/f2fs/debug.c
> +++ b/fs/f2fs/debug.c
> @@ -325,9 +325,10 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
>   		si->base_mem += SIT_VBLOCK_MAP_SIZE * 2;
>   		/* Approximate private bitmaps for active logs */
>   		si->base_mem += SIT_VBLOCK_MAP_SIZE * NR_CURSEG_TYPE;
> -#ifdef CONFIG_F2FS_CHECK_FS
> -		si->base_mem += SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
> -#endif
> +	#ifdef CONFIG_F2FS_CHECK_FS
> +			if (f2fs_sit_check_enabled(sbi))
> +				si->base_mem += SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
> +	#endif
>   		if (f2fs_block_unit_discard(sbi))
>   			si->base_mem += SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
>   	} else {
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 11f3601ffd34..d8526103d86a 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -130,6 +130,7 @@ enum f2fs_mount_opt {
>   	F2FS_MOUNT_COMPRESS_CACHE,
>   	F2FS_MOUNT_AGE_EXTENT_CACHE,
>   	F2FS_MOUNT_NAT_BITS,
> +	F2FS_MOUNT_SHARED_SIT_CHECK,
>   	F2FS_MOUNT_INLINECRYPT,
>   	/*
>   	 * Some f2fs environments expect to be able to pass the "lazytime" option
> @@ -4920,6 +4921,21 @@ static inline bool f2fs_use_shared_sit_map(struct f2fs_sb_info *sbi)
>   	return f2fs_sb_has_blkzoned(sbi) && f2fs_lfs_mode(sbi);
>   }
>   
> +/*
> + * shared_sit_check is a mount-time escape hatch for the extra SIT mirror
> + * tracking kept by CONFIG_F2FS_CHECK_FS in zoned shared-SIT mode.
> + */
> +static inline bool f2fs_sit_check_enabled(struct f2fs_sb_info *sbi)
> +{
> +	if (!IS_ENABLED(CONFIG_F2FS_CHECK_FS))
> +		return false;
> +
> +	if (!f2fs_use_shared_sit_map(sbi))
> +		return true;
> +
> +	return test_opt(sbi, SHARED_SIT_CHECK);
> +}
> +
>   static inline bool f2fs_is_sequential_zone_area(struct f2fs_sb_info *sbi,
>   					  block_t blkaddr)
>   {
> diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
> index 80b8500fa987..1decb0caea1b 100644
> --- a/fs/f2fs/gc.c
> +++ b/fs/f2fs/gc.c
> @@ -877,15 +877,16 @@ int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result,
>   		p.offset = segno + p.ofs_unit;
>   		nsearched++;
>   
> -#ifdef CONFIG_F2FS_CHECK_FS
> -		/*
> -		 * skip selecting the invalid segno (that is failed due to block
> -		 * validity check failure during GC) to avoid endless GC loop in
> -		 * such cases.
> -		 */
> -		if (test_bit(segno, sm->invalid_segmap))
> -			goto next;
> -#endif
> +	#ifdef CONFIG_F2FS_CHECK_FS
> +			/*
> +			 * skip selecting the invalid segno (that is failed due to block
> +			 * validity check failure during GC) to avoid endless GC loop in
> +			 * such cases.
> +			 */
> +			if (f2fs_sit_check_enabled(sbi) &&
> +			    test_bit(segno, sm->invalid_segmap))
> +				goto next;
> +	#endif
>   
>   		secno = GET_SEC_FROM_SEG(sbi, segno);
>   
> @@ -1197,18 +1198,20 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
>   	f2fs_folio_put(node_folio, true);
>   
>   	if (source_blkaddr != blkaddr) {
> -#ifdef CONFIG_F2FS_CHECK_FS
> +	#ifdef CONFIG_F2FS_CHECK_FS
>   		unsigned int segno = GET_SEGNO(sbi, blkaddr);
>   		unsigned long offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr);
>   
> -		if (unlikely(check_valid_map(sbi, segno, offset))) {
> +		if (f2fs_sit_check_enabled(sbi) &&
> +		    unlikely(check_valid_map(sbi, segno, offset))) {
>   			if (!test_and_set_bit(segno, SIT_I(sbi)->invalid_segmap)) {
> -				f2fs_err(sbi, "mismatched blkaddr %u (source_blkaddr %u) in seg %u",
> +				f2fs_err(sbi,
> +					 "mismatched blkaddr %u (source_blkaddr %u) in seg %u",
>   					 blkaddr, source_blkaddr, segno);
>   				set_sbi_flag(sbi, SBI_NEED_FSCK);
>   			}
>   		}
> -#endif
> +	#endif
>   		return false;
>   	}
>   	return true;
> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
> index 0dab6b16ba56..dce66eec2a5f 100644
> --- a/fs/f2fs/segment.c
> +++ b/fs/f2fs/segment.c
> @@ -38,6 +38,11 @@ struct f2fs_sit_bitmap {
>   	unsigned char map[SIT_VBLOCK_MAP_SIZE];
>   };
>   
> +static inline struct f2fs_sit_bitmap *f2fs_sit_bitmap_from_map(void *map)
> +{
> +	return container_of(map, struct f2fs_sit_bitmap, map);
> +}
> +
>   static void f2fs_free_sit_bitmap_rcu(struct rcu_head *rcu)
>   {
>   	struct f2fs_sit_bitmap *b = container_of(rcu, struct f2fs_sit_bitmap, rcu);
> @@ -45,11 +50,6 @@ static void f2fs_free_sit_bitmap_rcu(struct rcu_head *rcu)
>   	kmem_cache_free(sit_bitmap_slab, b);
>   }
>   
> -static struct f2fs_sit_bitmap *f2fs_sit_bitmap_from_map(void *map)
> -{
> -	return container_of(map, struct f2fs_sit_bitmap, map);
> -}
> -
>   static unsigned long __reverse_ulong(unsigned char *str)
>   {
>   	unsigned long tmp = 0;
> @@ -845,9 +845,10 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
>   		if (valid_blocks == 0) {
>   			clear_bit(GET_SEC_FROM_SEG(sbi, segno),
>   						dirty_i->victim_secmap);
> -#ifdef CONFIG_F2FS_CHECK_FS
> -			clear_bit(segno, SIT_I(sbi)->invalid_segmap);
> -#endif
> +	#ifdef CONFIG_F2FS_CHECK_FS
> +			if (f2fs_sit_check_enabled(sbi))
> +				clear_bit(segno, SIT_I(sbi)->invalid_segmap);
> +	#endif
>   		}
>   		if (__is_large_section(sbi)) {
>   			unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
> @@ -2471,9 +2472,10 @@ static int update_sit_entry_for_release(struct f2fs_sb_info *sbi, struct seg_ent
>   			memset(b->map, 0xff, SIT_VBLOCK_MAP_SIZE);
>   			rcu_assign_pointer(se->cur_valid_map, b->map);
>   			se->ckpt_valid_map = b->map;
> -#ifdef CONFIG_F2FS_CHECK_FS
> -			memcpy(se->cur_valid_map_mir, b->map, SIT_VBLOCK_MAP_SIZE);
> -#endif
> +	#ifdef CONFIG_F2FS_CHECK_FS
> +			if (f2fs_sit_check_enabled(sbi))
> +				memcpy(se->cur_valid_map_mir, b->map, SIT_VBLOCK_MAP_SIZE);
> +	#endif
>   		} else if (se->cur_valid_map == sit_i->bitmap_zero) {
>   			/* Should not happen, freeing empty segment */
>   			struct f2fs_sit_bitmap *b = f2fs_kmem_cache_alloc(sit_bitmap_slab,
> @@ -2481,23 +2483,27 @@ static int update_sit_entry_for_release(struct f2fs_sb_info *sbi, struct seg_ent
>   			memset(b->map, 0, SIT_VBLOCK_MAP_SIZE);
>   			rcu_assign_pointer(se->cur_valid_map, b->map);
>   			se->ckpt_valid_map = b->map;
> -#ifdef CONFIG_F2FS_CHECK_FS
> -			memcpy(se->cur_valid_map_mir, b->map, SIT_VBLOCK_MAP_SIZE);
> -#endif
> +	#ifdef CONFIG_F2FS_CHECK_FS
> +			if (f2fs_sit_check_enabled(sbi))
> +				memcpy(se->cur_valid_map_mir, b->map, SIT_VBLOCK_MAP_SIZE);
> +	#endif
>   		}
>   	}
>   
>   	for (i = 0; i < del_count; i++) {
>   		exist = f2fs_test_and_clear_bit(offset + i, se->cur_valid_map);
> -#ifdef CONFIG_F2FS_CHECK_FS
> -		mir_exist = f2fs_test_and_clear_bit(offset + i,
> -						se->cur_valid_map_mir);
> -		if (unlikely(exist != mir_exist)) {
> -			f2fs_err(sbi, "Inconsistent error when clearing bitmap, blk:%u, old bit:%d",
> -				blkaddr + i, exist);
> -			f2fs_bug_on(sbi, 1);
> -		}
> -#endif
> +	#ifdef CONFIG_F2FS_CHECK_FS
> +			if (f2fs_sit_check_enabled(sbi)) {
> +				mir_exist = f2fs_test_and_clear_bit(offset + i,
> +								    se->cur_valid_map_mir);
> +				if (unlikely(exist != mir_exist)) {
> +					f2fs_err(sbi,
> +						 "Inconsistent error when clearing bitmap, blk:%u, old bit:%d",
> +						 blkaddr + i, exist);
> +					f2fs_bug_on(sbi, 1);
> +				}
> +			}
> +	#endif
>   		if (unlikely(!exist)) {
>   			f2fs_err(sbi, "Bitmap was wrongly cleared, blk:%u", blkaddr + i);
>   			f2fs_bug_on(sbi, 1);
> @@ -2559,9 +2565,10 @@ static int update_sit_entry_for_alloc(struct f2fs_sb_info *sbi, struct seg_entry
>   			memset(b->map, 0, SIT_VBLOCK_MAP_SIZE);
>   			rcu_assign_pointer(se->cur_valid_map, b->map);
>   			se->ckpt_valid_map = b->map;
> -#ifdef CONFIG_F2FS_CHECK_FS
> -			memcpy(se->cur_valid_map_mir, b->map, SIT_VBLOCK_MAP_SIZE);
> -#endif
> +	#ifdef CONFIG_F2FS_CHECK_FS
> +			if (f2fs_sit_check_enabled(sbi))
> +				memcpy(se->cur_valid_map_mir, b->map, SIT_VBLOCK_MAP_SIZE);
> +	#endif
>   		} else if (se->cur_valid_map == sit_i->bitmap_full) {
>   			/* Should not happen in LFS alloc, but for safety */
>   			struct f2fs_sit_bitmap *b = f2fs_kmem_cache_alloc(sit_bitmap_slab,
> @@ -2569,22 +2576,26 @@ static int update_sit_entry_for_alloc(struct f2fs_sb_info *sbi, struct seg_entry
>   			memset(b->map, 0xff, SIT_VBLOCK_MAP_SIZE);
>   			rcu_assign_pointer(se->cur_valid_map, b->map);
>   			se->ckpt_valid_map = b->map;
> -#ifdef CONFIG_F2FS_CHECK_FS
> -			memcpy(se->cur_valid_map_mir, b->map, SIT_VBLOCK_MAP_SIZE);
> -#endif
> +	#ifdef CONFIG_F2FS_CHECK_FS
> +			if (f2fs_sit_check_enabled(sbi))
> +				memcpy(se->cur_valid_map_mir, b->map, SIT_VBLOCK_MAP_SIZE);
> +	#endif
>   		}
>   	}
>   
>   	exist = f2fs_test_and_set_bit(offset, se->cur_valid_map);
> -#ifdef CONFIG_F2FS_CHECK_FS
> -	mir_exist = f2fs_test_and_set_bit(offset,
> -					se->cur_valid_map_mir);
> -	if (unlikely(exist != mir_exist)) {
> -		f2fs_err(sbi, "Inconsistent error when setting bitmap, blk:%u, old bit:%d",
> -			blkaddr, exist);
> -		f2fs_bug_on(sbi, 1);
> +	#ifdef CONFIG_F2FS_CHECK_FS
> +	if (f2fs_sit_check_enabled(sbi)) {
> +		mir_exist = f2fs_test_and_set_bit(offset,
> +						  se->cur_valid_map_mir);
> +		if (unlikely(exist != mir_exist)) {
> +			f2fs_err(sbi,
> +				 "Inconsistent error when setting bitmap, blk:%u, old bit:%d",
> +				 blkaddr, exist);
> +			f2fs_bug_on(sbi, 1);
> +		}
>   	}
> -#endif
> +	#endif
>   	if (unlikely(exist)) {
>   		f2fs_err(sbi, "Bitmap was wrongly set, blk:%u", blkaddr);
>   		f2fs_bug_on(sbi, 1);
> @@ -2677,13 +2688,15 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
>   
>   			rcu_assign_pointer(se->cur_valid_map, sit_i->bitmap_zero);
>   			se->ckpt_valid_map = sit_i->bitmap_zero;
> -#ifdef CONFIG_F2FS_CHECK_FS
> -			memset(se->cur_valid_map_mir, 0, SIT_VBLOCK_MAP_SIZE);
> -#endif
> +	#ifdef CONFIG_F2FS_CHECK_FS
> +			if (f2fs_sit_check_enabled(sbi))
> +				memset(se->cur_valid_map_mir, 0, SIT_VBLOCK_MAP_SIZE);
> +	#endif
>   			if (old_map != sit_i->bitmap_zero &&
>   			    old_map != sit_i->bitmap_full) {
> -				call_rcu(&f2fs_sit_bitmap_from_map(old_map)->rcu,
> -					 f2fs_free_sit_bitmap_rcu);
> +				struct f2fs_sit_bitmap *b =
> +					f2fs_sit_bitmap_from_map(old_map);
> +				call_rcu(&b->rcu, f2fs_free_sit_bitmap_rcu);
>   			}
>   		} else if (new_vblocks == BLKS_PER_SEG(sbi) &&
>   				se->cur_valid_map != sit_i->bitmap_full) {
> @@ -2691,13 +2704,15 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
>   
>   			rcu_assign_pointer(se->cur_valid_map, sit_i->bitmap_full);
>   			se->ckpt_valid_map = sit_i->bitmap_full;
> -#ifdef CONFIG_F2FS_CHECK_FS
> -			memset(se->cur_valid_map_mir, 0xff, SIT_VBLOCK_MAP_SIZE);
> -#endif
> +	#ifdef CONFIG_F2FS_CHECK_FS
> +			if (f2fs_sit_check_enabled(sbi))
> +				memset(se->cur_valid_map_mir, 0xff, SIT_VBLOCK_MAP_SIZE);
> +	#endif
>   			if (old_map != sit_i->bitmap_zero &&
>   			    old_map != sit_i->bitmap_full) {
> -				call_rcu(&f2fs_sit_bitmap_from_map(old_map)->rcu,
> -					 f2fs_free_sit_bitmap_rcu);
> +				struct f2fs_sit_bitmap *b =
> +					f2fs_sit_bitmap_from_map(old_map);
> +				call_rcu(&b->rcu, f2fs_free_sit_bitmap_rcu);
>   			}
>   		}
>   	}
> @@ -4701,7 +4716,7 @@ static struct folio *get_next_sit_folio(struct f2fs_sb_info *sbi,
>   	seg_info_to_sit_folio(sbi, folio, start);
>   
>   	folio_mark_dirty(folio);
> -	set_to_next_sit(sit_i, start);
> +				set_to_next_sit(sbi, sit_i, start);
>   
>   	return folio;
>   }
> @@ -4857,11 +4872,12 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
>   			int offset, sit_offset;
>   
>   			se = get_seg_entry(sbi, segno);
> -#ifdef CONFIG_F2FS_CHECK_FS
> -			if (memcmp(se->cur_valid_map, se->cur_valid_map_mir,
> -						SIT_VBLOCK_MAP_SIZE))
> +	#ifdef CONFIG_F2FS_CHECK_FS
> +			if (f2fs_sit_check_enabled(sbi) &&
> +			    memcmp(se->cur_valid_map, se->cur_valid_map_mir,
> +				   SIT_VBLOCK_MAP_SIZE))
>   				f2fs_bug_on(sbi, 1);
> -#endif
> +	#endif
>   
>   			/* add discard candidates */
>   			if (!(cpc->reason & CP_DISCARD)) {
> @@ -4953,11 +4969,8 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
>   	if (!sit_i->dirty_sentries_bitmap)
>   		return -ENOMEM;
>   
> -#ifdef CONFIG_F2FS_CHECK_FS
> -	bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * (3 + discard_map);
> -#else
> -	bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * (2 + discard_map);
> -#endif
> +	bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE *
> +			(2 + discard_map + f2fs_sit_check_enabled(sbi));
>   
>   	if (share_map) {
>   		sit_i->bitmap_zero = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
> @@ -4971,10 +4984,9 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
>   		}
>   		memset(sit_i->bitmap_full, 0xff, SIT_VBLOCK_MAP_SIZE);
>   
> -		bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * discard_map;
> -#ifdef CONFIG_F2FS_CHECK_FS
> -		bitmap_size += MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE;
> -#endif
> +			bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * discard_map;
> +			if (f2fs_sit_check_enabled(sbi))
> +				bitmap_size += MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE;
>   		if (bitmap_size) {
>   			sit_i->bitmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
>   			if (!sit_i->bitmap) {
> @@ -4993,9 +5005,10 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
>   			sit_i->sentries[start].ckpt_valid_map =
>   						sit_i->bitmap_zero;
>   #ifdef CONFIG_F2FS_CHECK_FS
> -			sit_i->sentries[start].cur_valid_map_mir =
> -						bitmap;
> -			bitmap += SIT_VBLOCK_MAP_SIZE;
> +			if (f2fs_sit_check_enabled(sbi)) {
> +				sit_i->sentries[start].cur_valid_map_mir = bitmap;
> +				bitmap += SIT_VBLOCK_MAP_SIZE;
> +			}
>   #endif
>   			if (discard_map) {
>   				sit_i->sentries[start].discard_map = bitmap;
> @@ -5017,8 +5030,10 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
>   			bitmap += SIT_VBLOCK_MAP_SIZE;
>   
>   #ifdef CONFIG_F2FS_CHECK_FS
> -			sit_i->sentries[start].cur_valid_map_mir = bitmap;
> -			bitmap += SIT_VBLOCK_MAP_SIZE;
> +			if (f2fs_sit_check_enabled(sbi)) {
> +				sit_i->sentries[start].cur_valid_map_mir = bitmap;
> +				bitmap += SIT_VBLOCK_MAP_SIZE;
> +			}
>   #endif
>   
>   			if (discard_map) {
> @@ -5052,16 +5067,20 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
>   	if (!sit_i->sit_bitmap)
>   		return -ENOMEM;
>   
> -#ifdef CONFIG_F2FS_CHECK_FS
> -	sit_i->sit_bitmap_mir = kmemdup(src_bitmap,
> -					sit_bitmap_size, GFP_KERNEL);
> -	if (!sit_i->sit_bitmap_mir)
> -		return -ENOMEM;
> +	#ifdef CONFIG_F2FS_CHECK_FS
> +	if (f2fs_sit_check_enabled(sbi)) {
> +		sit_i->sit_bitmap_mir = kmemdup(src_bitmap,
> +						sit_bitmap_size,
> +						GFP_KERNEL);
> +		if (!sit_i->sit_bitmap_mir)
> +			return -ENOMEM;
>   
> -	sit_i->invalid_segmap = f2fs_kvzalloc(sbi,
> -					main_bitmap_size, GFP_KERNEL);
> -	if (!sit_i->invalid_segmap)
> -		return -ENOMEM;
> +		sit_i->invalid_segmap = f2fs_kvzalloc(sbi,
> +						      main_bitmap_size,
> +						      GFP_KERNEL);
> +		if (!sit_i->invalid_segmap)
> +			return -ENOMEM;
> +	}
>   #endif
>   
>   	sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr);
> @@ -5200,12 +5219,13 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
>   				rcu_assign_pointer(se->cur_valid_map, map);
>   				se->ckpt_valid_map = map;
>   #ifdef CONFIG_F2FS_CHECK_FS
> -				memcpy(se->cur_valid_map_mir, map, SIT_VBLOCK_MAP_SIZE);
> +				if (f2fs_sit_check_enabled(sbi))
> +					memcpy(se->cur_valid_map_mir, map, SIT_VBLOCK_MAP_SIZE);
>   #endif
>   				se->type = GET_SIT_TYPE(&sit);
>   				se->mtime = le64_to_cpu(sit.mtime);
>   			} else {
> -				seg_info_from_raw_sit(se, &sit);
> +				seg_info_from_raw_sit(sbi, se, &sit);
>   			}
>   
>   			if (se->type >= NR_PERSISTENT_LOG) {
> @@ -5279,15 +5299,19 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
>   
>   			if (vblocks == 0 && !is_active) {
>   				if (map != sit_i->bitmap_zero &&
> -				    map != sit_i->bitmap_full)
> -					kmem_cache_free(sit_bitmap_slab,
> -							f2fs_sit_bitmap_from_map(map));
> +				    map != sit_i->bitmap_full) {
> +					struct f2fs_sit_bitmap *b =
> +						f2fs_sit_bitmap_from_map(map);
> +					kmem_cache_free(sit_bitmap_slab, b);
> +				}
>   				map = sit_i->bitmap_zero;
>   			} else if (vblocks == BLKS_PER_SEG(sbi) && !is_active) {
>   				if (map != sit_i->bitmap_zero &&
> -				    map != sit_i->bitmap_full)
> -					kmem_cache_free(sit_bitmap_slab,
> -							f2fs_sit_bitmap_from_map(map));
> +				    map != sit_i->bitmap_full) {
> +					struct f2fs_sit_bitmap *b =
> +						f2fs_sit_bitmap_from_map(map);
> +					kmem_cache_free(sit_bitmap_slab, b);
> +				}
>   				map = sit_i->bitmap_full;
>   			} else {
>   				if (map == sit_i->bitmap_zero ||
> @@ -5310,12 +5334,13 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
>   			rcu_assign_pointer(se->cur_valid_map, map);
>   			se->ckpt_valid_map = map;
>   #ifdef CONFIG_F2FS_CHECK_FS
> -			memcpy(se->cur_valid_map_mir, map, SIT_VBLOCK_MAP_SIZE);
> +			if (f2fs_sit_check_enabled(sbi))
> +				memcpy(se->cur_valid_map_mir, map, SIT_VBLOCK_MAP_SIZE);
>   #endif
>   			se->type = GET_SIT_TYPE(&sit);
>   			se->mtime = le64_to_cpu(sit.mtime);
>   		} else {
> -			seg_info_from_raw_sit(se, &sit);
> +			seg_info_from_raw_sit(sbi, se, &sit);
>   		}
>   
>   		if (se->type >= NR_PERSISTENT_LOG) {
> @@ -6099,18 +6124,18 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi)
>   		if (f2fs_use_shared_sit_map(sbi)) {
>   			unsigned int start;
>   
> -			for (start = 0; start < MAIN_SEGS(sbi); start++) {
> -				struct seg_entry *se = &sit_i->sentries[start];
> +				for (start = 0; start < MAIN_SEGS(sbi); start++) {
> +					struct seg_entry *se = &sit_i->sentries[start];
>   
> -				if (se->cur_valid_map &&
> -				    se->cur_valid_map != sit_i->bitmap_zero &&
> -				    se->cur_valid_map != sit_i->bitmap_full) {
> -					struct f2fs_sit_bitmap *b;
> +					if (se->cur_valid_map &&
> +					    se->cur_valid_map != sit_i->bitmap_zero &&
> +					    se->cur_valid_map != sit_i->bitmap_full) {
> +						struct f2fs_sit_bitmap *b;
>   
> -					b = f2fs_sit_bitmap_from_map(se->cur_valid_map);
> -					kmem_cache_free(sit_bitmap_slab, b);
> +						b = f2fs_sit_bitmap_from_map(se->cur_valid_map);
> +						kmem_cache_free(sit_bitmap_slab, b);
> +					}
>   				}
> -			}
>   			kfree(sit_i->bitmap_zero);
>   			kfree(sit_i->bitmap_full);
>   			if (sit_i->bitmap)
> diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
> index cb45cfa7a658..0f4445375ed1 100644
> --- a/fs/f2fs/segment.h
> +++ b/fs/f2fs/segment.h
> @@ -404,15 +404,17 @@ static inline void sanity_check_valid_blocks(struct f2fs_sb_info *sbi,
>   {
>   }
>   #endif
> -static inline void seg_info_from_raw_sit(struct seg_entry *se,
> -					struct f2fs_sit_entry *rs)
> +static inline void seg_info_from_raw_sit(struct f2fs_sb_info *sbi,
> +					 struct seg_entry *se,
> +					 struct f2fs_sit_entry *rs)
>   {
>   	se->valid_blocks = GET_SIT_VBLOCKS(rs);
>   	se->ckpt_valid_blocks = GET_SIT_VBLOCKS(rs);
>   	memcpy(se->cur_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
>   	memcpy(se->ckpt_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
>   #ifdef CONFIG_F2FS_CHECK_FS
> -	memcpy(se->cur_valid_map_mir, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
> +	if (f2fs_sit_check_enabled(sbi))
> +		memcpy(se->cur_valid_map_mir, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
>   #endif
>   	se->type = GET_SIT_TYPE(rs);
>   	se->mtime = le64_to_cpu(rs->mtime);
> @@ -558,11 +560,12 @@ static inline void get_sit_bitmap(struct f2fs_sb_info *sbi,
>   {
>   	struct sit_info *sit_i = SIT_I(sbi);
>   
> -#ifdef CONFIG_F2FS_CHECK_FS
> -	if (memcmp(sit_i->sit_bitmap, sit_i->sit_bitmap_mir,
> -						sit_i->bitmap_size))
> +	#ifdef CONFIG_F2FS_CHECK_FS
> +	if (f2fs_sit_check_enabled(sbi) &&
> +	    memcmp(sit_i->sit_bitmap, sit_i->sit_bitmap_mir,
> +		   sit_i->bitmap_size))
>   		f2fs_bug_on(sbi, 1);
> -#endif
> +	#endif
>   	memcpy(dst_addr, sit_i->sit_bitmap, sit_i->bitmap_size);
>   }
>   
> @@ -904,8 +907,9 @@ static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi,
>   	f2fs_bug_on(sbi, !valid_main_segno(sbi, start));
>   
>   #ifdef CONFIG_F2FS_CHECK_FS
> -	if (f2fs_test_bit(offset, sit_i->sit_bitmap) !=
> -			f2fs_test_bit(offset, sit_i->sit_bitmap_mir))
> +	if (f2fs_sit_check_enabled(sbi) &&
> +	    f2fs_test_bit(offset, sit_i->sit_bitmap) !=
> +				f2fs_test_bit(offset, sit_i->sit_bitmap_mir))
>   		f2fs_bug_on(sbi, 1);
>   #endif
>   
> @@ -929,13 +933,15 @@ static inline pgoff_t next_sit_addr(struct f2fs_sb_info *sbi,
>   	return block_addr + sit_i->sit_base_addr;
>   }
>   
> -static inline void set_to_next_sit(struct sit_info *sit_i, unsigned int start)
> +static inline void set_to_next_sit(struct f2fs_sb_info *sbi,
> +				   struct sit_info *sit_i, unsigned int start)
>   {
>   	unsigned int block_off = SIT_BLOCK_OFFSET(start);
>   
>   	f2fs_change_bit(block_off, sit_i->sit_bitmap);
>   #ifdef CONFIG_F2FS_CHECK_FS
> -	f2fs_change_bit(block_off, sit_i->sit_bitmap_mir);
> +	if (f2fs_sit_check_enabled(sbi))
> +		f2fs_change_bit(block_off, sit_i->sit_bitmap_mir);
>   #endif
>   }
>   
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index 83ce88ce12cb..e2bb5d0ab3e1 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -228,6 +228,7 @@ enum {
>   	Opt_gc_merge,
>   	Opt_discard_unit,
>   	Opt_memory_mode,
> +	Opt_shared_sit_check,
>   	Opt_age_extent_cache,
>   	Opt_errors,
>   	Opt_nat_bits,
> @@ -359,6 +360,7 @@ static const struct fs_parameter_spec f2fs_param_specs[] = {
>   	fsparam_flag_no("gc_merge", Opt_gc_merge),
>   	fsparam_enum("discard_unit", Opt_discard_unit, f2fs_param_discard_unit),
>   	fsparam_enum("memory", Opt_memory_mode, f2fs_param_memory_mode),
> +	fsparam_flag_no("shared_sit_check", Opt_shared_sit_check),
>   	fsparam_flag("age_extent_cache", Opt_age_extent_cache),
>   	fsparam_enum("errors", Opt_errors, f2fs_param_errors),
>   	fsparam_enum("lookup_mode", Opt_lookup_mode, f2fs_param_lookup_mode),
> @@ -1217,6 +1219,12 @@ static int f2fs_parse_param(struct fs_context *fc, struct fs_parameter *param)
>   		F2FS_CTX_INFO(ctx).memory_mode = result.uint_32;
>   		ctx->spec_mask |= F2FS_SPEC_memory_mode;
>   		break;
> +	case Opt_shared_sit_check:
> +		if (result.negated)
> +			ctx_clear_opt(ctx, F2FS_MOUNT_SHARED_SIT_CHECK);
> +		else
> +			ctx_set_opt(ctx, F2FS_MOUNT_SHARED_SIT_CHECK);
> +		break;
>   	case Opt_age_extent_cache:
>   		ctx_set_opt(ctx, F2FS_MOUNT_AGE_EXTENT_CACHE);
>   		break;
> @@ -2514,6 +2522,11 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
>   	else if (F2FS_OPTION(sbi).memory_mode == MEMORY_MODE_LOW)
>   		seq_printf(seq, ",memory=%s", "low");
>   
> +	if (test_opt(sbi, SHARED_SIT_CHECK))
> +		seq_puts(seq, ",shared_sit_check");
> +	else
> +		seq_puts(seq, ",noshared_sit_check");
> +
>   	if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_READONLY)
>   		seq_printf(seq, ",errors=%s", "remount-ro");
>   	else if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_CONTINUE)
> @@ -2573,6 +2586,7 @@ static void default_options(struct f2fs_sb_info *sbi, bool remount)
>   	F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_ON;
>   	F2FS_OPTION(sbi).memory_mode = MEMORY_MODE_NORMAL;
>   	F2FS_OPTION(sbi).errors = MOUNT_ERRORS_CONTINUE;
> +	set_opt(sbi, SHARED_SIT_CHECK);
>   
>   	set_opt(sbi, INLINE_XATTR);
>   	set_opt(sbi, INLINE_DATA);
> @@ -2782,6 +2796,7 @@ static int __f2fs_remount(struct fs_context *fc, struct super_block *sb)
>   	bool no_compress_cache = !test_opt(sbi, COMPRESS_CACHE);
>   	bool block_unit_discard = f2fs_block_unit_discard(sbi);
>   	bool no_nat_bits = !test_opt(sbi, NAT_BITS);
> +	bool shared_sit_check = test_opt(sbi, SHARED_SIT_CHECK);
>   #ifdef CONFIG_QUOTA
>   	int i, j;
>   #endif
> @@ -2904,6 +2919,12 @@ static int __f2fs_remount(struct fs_context *fc, struct super_block *sb)
>   		goto restore_opts;
>   	}
>   
> +	if (shared_sit_check != !!test_opt(sbi, SHARED_SIT_CHECK)) {
> +		err = -EINVAL;
> +		f2fs_warn(sbi, "switch shared_sit_check option is not allowed");
> +		goto restore_opts;
> +	}
> +
>   	if ((flags & SB_RDONLY) && test_opt(sbi, DISABLE_CHECKPOINT)) {
>   		err = -EINVAL;
>   		f2fs_warn(sbi, "disabling checkpoint not compatible with read-only");


      reply	other threads:[~2026-03-14  5:14 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-09 10:36 [RFC PATCH 0/3] f2fs: reduce zoned LFS memory by sharing SIT valid maps 'wallentx
2026-03-09 10:36 ` [RFC PATCH 1/3] f2fs: prepare cur_valid_map for safe lockless access 'wallentx
2026-03-09 10:36 ` [RFC PATCH 2/3] f2fs: reduce zoned LFS memory by sharing SIT valid maps 'wallentx
2026-03-14  5:08   ` Chao Yu
2026-03-09 10:37 ` [RFC PATCH 3/3] f2fs: add mount option to disable shared SIT mirror checks 'wallentx
2026-03-14  5:14   ` Chao Yu [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=76d4e46c-5c34-4dc4-8aa4-1efbcbe1415f@kernel.org \
    --to=chao@kernel.org \
    --cc=jaegeuk@kernel.org \
    --cc=linux-f2fs-devel@lists.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=william.allentx@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox