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 2/3] f2fs: reduce zoned LFS memory by sharing SIT valid maps
Date: Sat, 14 Mar 2026 13:08:53 +0800 [thread overview]
Message-ID: <66ab8be1-606a-416e-88cd-ced415867473@kernel.org> (raw)
In-Reply-To: <20260309103700.489932-3-william.allentx@gmail.com>
Hi wallentx,
Thanks for your contribution!
On 2026/3/9 18:36, 'wallentx wrote:
> From: wallentx <william.allentx@gmail.com>
>
> For zoned devices, F2FS only allows LFS mode. In that configuration SSR
> is not used, IPU is not allowed, and discard defaults to section
> granularity. Even so, F2FS still allocates per-segment cur/ckpt valid
> maps for every segment, including the common cases where a segment is
> trivially empty or trivially full.
>
> Reduce that overhead by introducing shared zero/full SIT valid maps for
> zoned LFS. Empty inactive segments point at the shared zero map, full
> inactive segments point at the shared full map, and only active or
> partially valid segments keep private maps. Update SIT rebuild and
> runtime updates to move segments between shared and private maps safely,
> and retire replaced private maps with RCU.
>
> Also invalidate scanned SIT metadata pages after mount-time rebuild so
> META_MAPPING does not retain the full SIT scan, update memory reporting
> to reflect the new layout, and reject checkpoint=disable because its
> checkpoint-era validity accounting does not fit the collapsed shared-SIT
> representation.
I think that will be a problem, since checkpoint=disable is used in Android
product, we can not fail to apply mount option for shared sit map.
Can we make this feature optional?
Thanks,
>
> On a test system with 43 HM-SMR zoned volumes (~550 TB total),
> CONFIG_F2FS_CHECK_FS=y, and this patch applied on top of jaegeuk/f2fs
> dev at 5f04e90eedd0, static F2FS memory dropped from 58.91 GiB to
> 27.70 GiB.
>
> Signed-off-by: wallentx <william.allentx@gmail.com>
> ---
> fs/f2fs/debug.c | 20 ++-
> fs/f2fs/f2fs.h | 6 +
> fs/f2fs/segment.c | 338 ++++++++++++++++++++++++++++++++++++++++++----
> fs/f2fs/segment.h | 3 +
> fs/f2fs/super.c | 4 +
> fs/f2fs/sysfs.c | 3 +-
> 6 files changed, 341 insertions(+), 33 deletions(-)
>
> diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
> index af88db8fdb71..d8bfdac5c1e4 100644
> --- a/fs/f2fs/debug.c
> +++ b/fs/f2fs/debug.c
> @@ -319,9 +319,23 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
> si->base_mem += sizeof(struct sit_info);
> si->base_mem += MAIN_SEGS(sbi) * sizeof(struct seg_entry);
> si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi));
> - si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
> - si->base_mem += SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
> - si->base_mem += SIT_VBLOCK_MAP_SIZE;
> +
> + if (f2fs_use_shared_sit_map(sbi)) {
> + /* shared cur/ckpt maps (zero + full bitmaps) */
> + 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
> + if (f2fs_block_unit_discard(sbi))
> + si->base_mem += SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
> + } else {
> + si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
> + si->base_mem += SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
> + si->base_mem += SIT_VBLOCK_MAP_SIZE;
> + }
> +
> if (__is_large_section(sbi))
> si->base_mem += MAIN_SECS(sbi) * sizeof(struct sec_entry);
> si->base_mem += __bitmap_size(sbi, SIT_BITMAP);
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 8942b2a63cfd..11f3601ffd34 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -4914,6 +4914,12 @@ static inline bool f2fs_lfs_mode(struct f2fs_sb_info *sbi)
> return F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS;
> }
>
> +/* Share SIT valid maps only for zoned LFS. */
> +static inline bool f2fs_use_shared_sit_map(struct f2fs_sb_info *sbi)
> +{
> + return f2fs_sb_has_blkzoned(sbi) && f2fs_lfs_mode(sbi);
> +}
> +
> static inline bool f2fs_is_sequential_zone_area(struct f2fs_sb_info *sbi,
> block_t blkaddr)
> {
> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
> index c9cfc8f17698..0dab6b16ba56 100644
> --- a/fs/f2fs/segment.c
> +++ b/fs/f2fs/segment.c
> @@ -31,6 +31,24 @@ static struct kmem_cache *discard_entry_slab;
> static struct kmem_cache *discard_cmd_slab;
> static struct kmem_cache *sit_entry_set_slab;
> static struct kmem_cache *revoke_entry_slab;
> +static struct kmem_cache *sit_bitmap_slab;
> +
> +struct f2fs_sit_bitmap {
> + struct rcu_head rcu;
> + unsigned char map[SIT_VBLOCK_MAP_SIZE];
> +};
> +
> +static void f2fs_free_sit_bitmap_rcu(struct rcu_head *rcu)
> +{
> + struct f2fs_sit_bitmap *b = container_of(rcu, struct f2fs_sit_bitmap, 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)
> {
> @@ -2444,6 +2462,31 @@ static int update_sit_entry_for_release(struct f2fs_sb_info *sbi, struct seg_ent
>
> f2fs_bug_on(sbi, GET_SEGNO(sbi, blkaddr) != GET_SEGNO(sbi, blkaddr + del_count - 1));
>
> + if (f2fs_use_shared_sit_map(sbi)) {
> + struct sit_info *sit_i = SIT_I(sbi);
> +
> + if (se->cur_valid_map == sit_i->bitmap_full) {
> + struct f2fs_sit_bitmap *b = f2fs_kmem_cache_alloc(sit_bitmap_slab,
> + GFP_NOFS, true, sbi);
> + 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
> + } 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,
> + GFP_NOFS, true, sbi);
> + 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
> + }
> + }
> +
> for (i = 0; i < del_count; i++) {
> exist = f2fs_test_and_clear_bit(offset + i, se->cur_valid_map);
> #ifdef CONFIG_F2FS_CHECK_FS
> @@ -2478,10 +2521,18 @@ static int update_sit_entry_for_release(struct f2fs_sb_info *sbi, struct seg_ent
> f2fs_test_and_clear_bit(offset + i, se->discard_map))
> sbi->discard_blks++;
>
> - if (!f2fs_test_bit(offset + i, se->ckpt_valid_map)) {
> - se->ckpt_valid_blocks -= 1;
> - if (__is_large_section(sbi))
> - get_sec_entry(sbi, segno)->ckpt_valid_blocks -= 1;
> + if (se->cur_valid_map != se->ckpt_valid_map) {
> + if (!f2fs_test_bit(offset + i, se->ckpt_valid_map)) {
> + se->ckpt_valid_blocks -= 1;
> + if (__is_large_section(sbi))
> + get_sec_entry(sbi, segno)->ckpt_valid_blocks -= 1;
> + }
> + } else {
> + if (exist) {
> + se->ckpt_valid_blocks -= 1;
> + if (__is_large_section(sbi))
> + get_sec_entry(sbi, segno)->ckpt_valid_blocks -= 1;
> + }
> }
> }
>
> @@ -2499,6 +2550,31 @@ static int update_sit_entry_for_alloc(struct f2fs_sb_info *sbi, struct seg_entry
> bool mir_exist;
> #endif
>
> + if (f2fs_use_shared_sit_map(sbi)) {
> + struct sit_info *sit_i = SIT_I(sbi);
> +
> + if (se->cur_valid_map == sit_i->bitmap_zero) {
> + struct f2fs_sit_bitmap *b = f2fs_kmem_cache_alloc(sit_bitmap_slab,
> + GFP_NOFS, true, sbi);
> + 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
> + } 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,
> + GFP_NOFS, true, sbi);
> + 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
> + }
> + }
> +
> exist = f2fs_test_and_set_bit(offset, se->cur_valid_map);
> #ifdef CONFIG_F2FS_CHECK_FS
> mir_exist = f2fs_test_and_set_bit(offset,
> @@ -2525,14 +2601,23 @@ static int update_sit_entry_for_alloc(struct f2fs_sb_info *sbi, struct seg_entry
> * or newly invalidated.
> */
> if (!is_sbi_flag_set(sbi, SBI_CP_DISABLED)) {
> - if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map)) {
> - se->ckpt_valid_blocks++;
> - if (__is_large_section(sbi))
> - get_sec_entry(sbi, segno)->ckpt_valid_blocks++;
> + if (se->cur_valid_map != se->ckpt_valid_map) {
> + if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map)) {
> + se->ckpt_valid_blocks++;
> + if (__is_large_section(sbi))
> + get_sec_entry(sbi, segno)->ckpt_valid_blocks++;
> + }
> + } else {
> + if (!exist) {
> + se->ckpt_valid_blocks++;
> + if (__is_large_section(sbi))
> + get_sec_entry(sbi, segno)->ckpt_valid_blocks++;
> + }
> }
> }
>
> - if (!f2fs_test_bit(offset, se->ckpt_valid_map)) {
> + if (se->cur_valid_map != se->ckpt_valid_map &&
> + !f2fs_test_bit(offset, se->ckpt_valid_map)) {
> se->ckpt_valid_blocks += del;
> if (__is_large_section(sbi))
> get_sec_entry(sbi, segno)->ckpt_valid_blocks += del;
> @@ -2582,6 +2667,40 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
>
> if (__is_large_section(sbi))
> get_sec_entry(sbi, segno)->valid_blocks += del;
> +
> + if (f2fs_use_shared_sit_map(sbi)) {
> + struct sit_info *sit_i = SIT_I(sbi);
> +
> + if (new_vblocks == 0 &&
> + se->cur_valid_map != sit_i->bitmap_zero) {
> + void *old_map = se->cur_valid_map;
> +
> + 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
> + 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);
> + }
> + } else if (new_vblocks == BLKS_PER_SEG(sbi) &&
> + se->cur_valid_map != sit_i->bitmap_full) {
> + void *old_map = se->cur_valid_map;
> +
> + 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
> + 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);
> + }
> + }
> + }
> }
>
> void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr,
> @@ -4812,6 +4931,7 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
> char *src_bitmap, *bitmap;
> unsigned int bitmap_size, main_bitmap_size, sit_bitmap_size;
> unsigned int discard_map = f2fs_block_unit_discard(sbi) ? 1 : 0;
> + bool share_map = f2fs_use_shared_sit_map(sbi);
>
> /* allocate memory for SIT information */
> sit_i = f2fs_kzalloc(sbi, sizeof(struct sit_info), GFP_KERNEL);
> @@ -4838,28 +4958,73 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
> #else
> bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * (2 + discard_map);
> #endif
> - sit_i->bitmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
> - if (!sit_i->bitmap)
> - return -ENOMEM;
> -
> - bitmap = sit_i->bitmap;
>
> - for (start = 0; start < MAIN_SEGS(sbi); start++) {
> - rcu_assign_pointer(sit_i->sentries[start].cur_valid_map,
> - bitmap);
> - bitmap += SIT_VBLOCK_MAP_SIZE;
> + if (share_map) {
> + sit_i->bitmap_zero = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
> + if (!sit_i->bitmap_zero)
> + return -ENOMEM;
> + sit_i->bitmap_full = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
> + if (!sit_i->bitmap_full) {
> + kfree(sit_i->bitmap_zero);
> + sit_i->bitmap_zero = NULL;
> + return -ENOMEM;
> + }
> + memset(sit_i->bitmap_full, 0xff, SIT_VBLOCK_MAP_SIZE);
>
> - sit_i->sentries[start].ckpt_valid_map = bitmap;
> - bitmap += 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
> + if (bitmap_size) {
> + sit_i->bitmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
> + if (!sit_i->bitmap) {
> + kfree(sit_i->bitmap_full);
> + kfree(sit_i->bitmap_zero);
> + sit_i->bitmap_full = NULL;
> + sit_i->bitmap_zero = NULL;
> + return -ENOMEM;
> + }
> + bitmap = sit_i->bitmap;
> + }
>
> + for (start = 0; start < MAIN_SEGS(sbi); start++) {
> + rcu_assign_pointer(sit_i->sentries[start].cur_valid_map,
> + sit_i->bitmap_zero);
> + 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;
> + 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;
> + bitmap += SIT_VBLOCK_MAP_SIZE;
> + }
> + }
> + } else {
> + sit_i->bitmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
> + if (!sit_i->bitmap)
> + return -ENOMEM;
> +
> + bitmap = sit_i->bitmap;
> +
> + for (start = 0; start < MAIN_SEGS(sbi); start++) {
> + rcu_assign_pointer(sit_i->sentries[start].cur_valid_map, bitmap);
> + bitmap += SIT_VBLOCK_MAP_SIZE;
>
> - if (discard_map) {
> - sit_i->sentries[start].discard_map = bitmap;
> + sit_i->sentries[start].ckpt_valid_map = bitmap;
> bitmap += SIT_VBLOCK_MAP_SIZE;
> +
> +#ifdef CONFIG_F2FS_CHECK_FS
> + 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;
> + bitmap += SIT_VBLOCK_MAP_SIZE;
> + }
> }
> }
>
> @@ -5009,7 +5174,39 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
> err = check_block_count(sbi, start, &sit);
> if (err)
> return err;
> - seg_info_from_raw_sit(se, &sit);
> +
> + if (f2fs_use_shared_sit_map(sbi)) {
> + unsigned int vblocks = GET_SIT_VBLOCKS(&sit);
> + unsigned char *map = NULL;
> + bool is_active = is_curseg(sbi, start);
> +
> + if (vblocks == 0 && !is_active) {
> + map = sit_i->bitmap_zero;
> + } else if (vblocks == BLKS_PER_SEG(sbi) && !is_active) {
> + map = sit_i->bitmap_full;
> + } else {
> + struct f2fs_sit_bitmap *b =
> + f2fs_kmem_cache_alloc(sit_bitmap_slab,
> + GFP_KERNEL,
> + false, sbi);
> + if (!b)
> + return -ENOMEM;
> + map = b->map;
> + memcpy(map, sit.valid_map, SIT_VBLOCK_MAP_SIZE);
> + }
> +
> + se->valid_blocks = vblocks;
> + se->ckpt_valid_blocks = vblocks;
> + 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);
> +#endif
> + se->type = GET_SIT_TYPE(&sit);
> + se->mtime = le64_to_cpu(sit.mtime);
> + } else {
> + seg_info_from_raw_sit(se, &sit);
> + }
>
> if (se->type >= NR_PERSISTENT_LOG) {
> f2fs_err(sbi, "Invalid segment type: %u, segno: %u",
> @@ -5039,6 +5236,15 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
> get_sec_entry(sbi, start)->valid_blocks +=
> se->valid_blocks;
> }
> + if (f2fs_use_shared_sit_map(sbi)) {
> + pgoff_t start_addr = sit_i->sit_base_addr + start_blk;
> + pgoff_t end_addr = start_addr + readed - 1;
> + pgoff_t alt_start_addr = start_addr + sit_i->sit_blocks;
> + pgoff_t alt_end_addr = alt_start_addr + readed - 1;
> +
> + invalidate_mapping_pages(META_MAPPING(sbi), start_addr, end_addr);
> + invalidate_mapping_pages(META_MAPPING(sbi), alt_start_addr, alt_end_addr);
> + }
> start_blk += readed;
> } while (start_blk < sit_blk_cnt);
>
> @@ -5065,7 +5271,52 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
> err = check_block_count(sbi, start, &sit);
> if (err)
> break;
> - seg_info_from_raw_sit(se, &sit);
> +
> + if (f2fs_use_shared_sit_map(sbi)) {
> + unsigned int vblocks = GET_SIT_VBLOCKS(&sit);
> + unsigned char *map = se->cur_valid_map;
> + bool is_active = is_curseg(sbi, start);
> +
> + 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_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;
> + } else {
> + if (map == sit_i->bitmap_zero ||
> + map == sit_i->bitmap_full) {
> + struct f2fs_sit_bitmap *b =
> + f2fs_kmem_cache_alloc(sit_bitmap_slab,
> + GFP_KERNEL,
> + false, sbi);
> + if (!b) {
> + up_read(&curseg->journal_rwsem);
> + return -ENOMEM;
> + }
> + map = b->map;
> + }
> + memcpy(map, sit.valid_map, SIT_VBLOCK_MAP_SIZE);
> + }
> +
> + se->valid_blocks = vblocks;
> + se->ckpt_valid_blocks = vblocks;
> + 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);
> +#endif
> + se->type = GET_SIT_TYPE(&sit);
> + se->mtime = le64_to_cpu(sit.mtime);
> + } else {
> + seg_info_from_raw_sit(se, &sit);
> + }
>
> if (se->type >= NR_PERSISTENT_LOG) {
> f2fs_err(sbi, "Invalid segment type: %u, segno: %u",
> @@ -5844,8 +6095,30 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi)
> if (!sit_i)
> return;
>
> - if (sit_i->sentries)
> - kvfree(sit_i->bitmap);
> + if (sit_i->sentries) {
> + 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];
> +
> + 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);
> + }
> + }
> + kfree(sit_i->bitmap_zero);
> + kfree(sit_i->bitmap_full);
> + if (sit_i->bitmap)
> + kvfree(sit_i->bitmap);
> + } else {
> + kvfree(sit_i->bitmap);
> + }
> + }
> kfree(sit_i->tmp_map);
>
> kvfree(sit_i->sentries);
> @@ -5898,8 +6171,16 @@ int __init f2fs_create_segment_manager_caches(void)
> sizeof(struct revoke_entry));
> if (!revoke_entry_slab)
> goto destroy_sit_entry_set;
> +
> + sit_bitmap_slab = f2fs_kmem_cache_create("f2fs_sit_bitmap",
> + sizeof(struct f2fs_sit_bitmap));
> + if (!sit_bitmap_slab)
> + goto destroy_revoke_entry;
> +
> return 0;
>
> +destroy_revoke_entry:
> + kmem_cache_destroy(revoke_entry_slab);
> destroy_sit_entry_set:
> kmem_cache_destroy(sit_entry_set_slab);
> destroy_discard_cmd:
> @@ -5916,4 +6197,5 @@ void f2fs_destroy_segment_manager_caches(void)
> kmem_cache_destroy(discard_cmd_slab);
> kmem_cache_destroy(discard_entry_slab);
> kmem_cache_destroy(revoke_entry_slab);
> + kmem_cache_destroy(sit_bitmap_slab);
> }
> diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
> index 068845660b0f..cb45cfa7a658 100644
> --- a/fs/f2fs/segment.h
> +++ b/fs/f2fs/segment.h
> @@ -233,6 +233,9 @@ struct sit_info {
> unsigned long long dirty_max_mtime; /* rerange candidates in GC_AT */
>
> unsigned int last_victim[MAX_GC_POLICY]; /* last victim segment # */
> +
> + unsigned char *bitmap_zero; /* shared zero bitmap */
> + unsigned char *bitmap_full; /* shared full bitmap */
> };
>
> struct free_segmap_info {
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index 8774c60b4be4..83ce88ce12cb 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -2617,6 +2617,10 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
> f2fs_err(sbi, "checkpoint=disable on readonly fs");
> return -EINVAL;
> }
> + if (f2fs_use_shared_sit_map(sbi)) {
> + f2fs_err(sbi, "checkpoint=disable is not supported in zoned shared SIT mode");
> + return -EOPNOTSUPP;
> + }
> sbi->sb->s_flags |= SB_ACTIVE;
>
> /* check if we need more GC first */
> diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
> index 9c79f7b63583..2baf349721c9 100644
> --- a/fs/f2fs/sysfs.c
> +++ b/fs/f2fs/sysfs.c
> @@ -1788,8 +1788,7 @@ static int __maybe_unused segment_bits_seq_show(struct seq_file *seq,
> seq_printf(seq, "%d|%-3u|", se->type, se->valid_blocks);
>
> rcu_read_lock();
> - memcpy(map, rcu_dereference(se->cur_valid_map),
> - SIT_VBLOCK_MAP_SIZE);
> + memcpy(map, rcu_dereference(se->cur_valid_map), SIT_VBLOCK_MAP_SIZE);
> rcu_read_unlock();
>
> for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++)
next prev parent reply other threads:[~2026-03-14 5:08 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 [this message]
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
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=66ab8be1-606a-416e-88cd-ced415867473@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