[f2fs-dev] [PATCH v2 2/2] f2fs: introduce written_map to indicate written datas

2024-04-11 Thread Chao Yu
Currently, __exchange_data_block() will check checkpointed state of data,
if it is not checkpointed, it will try to exchange blkaddrs directly in
dnode.

However, after commit 899fee36fac0 ("f2fs: fix to avoid data corruption
by forbidding SSR overwrite"), in order to disallow SSR allocator to
reuse all written data/node type blocks, all written blocks were set as
checkpointed.

In order to reenable metadata exchange functionality, let's introduce
written_map to indicate all written blocks including checkpointed one,
or newly written and invalidated one, and use it for SSR allocation,
and then ckpt_valid_bitmap can indicate real checkpointed status, and
we can use it correctly in __exchange_data_block().

[testcase]
xfs_io -f /mnt/f2fs/src -c "pwrite 0 2m"
xfs_io -f /mnt/f2fs/dst -c "pwrite 0 2m"
xfs_io /mnt/f2fs/src -c "fiemap -v"
xfs_io /mnt/f2fs/dst -c "fiemap -v"
f2fs_io move_range /mnt/f2fs/src /mnt/f2fs/dst 0 0 2097152
xfs_io /mnt/f2fs/src -c "fiemap -v"
xfs_io /mnt/f2fs/dst -c "fiemap -v"

[before]
/mnt/f2fs/src:
 EXT: FILE-OFFSET  BLOCK-RANGE  TOTAL FLAGS
   0: [0..4095]:   8445952..8450047  4096 0x1001
/mnt/f2fs/dst:
 EXT: FILE-OFFSET  BLOCK-RANGE  TOTAL FLAGS
   0: [0..4095]:   143360..1474554096 0x1001

/mnt/f2fs/src:
/mnt/f2fs/dst:
 EXT: FILE-OFFSET  BLOCK-RANGE  TOTAL FLAGS
   0: [0..4095]:   4284416..4288511  4096 0x1001

[after]
/mnt/f2fs/src:
 EXT: FILE-OFFSET  BLOCK-RANGE  TOTAL FLAGS
   0: [0..4095]:   147456..1515514096 0x1001
/mnt/f2fs/dst:
 EXT: FILE-OFFSET  BLOCK-RANGE  TOTAL FLAGS
   0: [0..4095]:   151552..1556474096 0x1001

/mnt/f2fs/src:
/mnt/f2fs/dst:
 EXT: FILE-OFFSET  BLOCK-RANGE  TOTAL FLAGS
   0: [0..4095]:   147456..1515514096 0x1001

Signed-off-by: Chao Yu 
---
v2:
- introduce written_blocks in struct seg_entry for
ssr allocator.
 fs/f2fs/gc.c  |  2 +-
 fs/f2fs/segment.c | 22 --
 fs/f2fs/segment.h | 19 ++-
 3 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 8852814dab7f..ea7b5ca6f09b 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -366,7 +366,7 @@ static inline unsigned int get_gc_cost(struct f2fs_sb_info 
*sbi,
unsigned int segno, struct victim_sel_policy *p)
 {
if (p->alloc_mode == SSR)
-   return get_seg_entry(sbi, segno)->ckpt_valid_blocks;
+   return get_seg_entry(sbi, segno)->written_blocks;
 
/* alloc_mode == LFS */
if (p->gc_mode == GC_GREEDY)
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index af716925db19..0d110908e383 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2456,12 +2456,13 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, 
block_t blkaddr, int del)
sbi->discard_blks--;
 
/*
-* SSR should never reuse block which is checkpointed
-* or newly invalidated.
+* if CP disabling is enable, it allows SSR to reuse newly
+* invalidated block, otherwise forbidding it to pretect fsyned
+* datas.
 */
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 (!f2fs_test_and_set_bit(offset, se->written_map))
+   se->written_blocks++;
}
} else {
exist = f2fs_test_and_clear_bit(offset, se->cur_valid_map);
@@ -2498,8 +2499,6 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, 
block_t blkaddr, int del)
f2fs_test_and_clear_bit(offset, se->discard_map))
sbi->discard_blks++;
}
-   if (!f2fs_test_bit(offset, se->ckpt_valid_map))
-   se->ckpt_valid_blocks += del;
 
__mark_sit_entry_dirty(sbi, segno);
 
@@ -2847,11 +2846,11 @@ static void __get_segment_bitmap(struct f2fs_sb_info 
*sbi,
struct seg_entry *se = get_seg_entry(sbi, segno);
int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long);
unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map;
-   unsigned long *cur_map = (unsigned long *)se->cur_valid_map;
+   unsigned long *written_map = (unsigned long *)se->written_map;
int i;
 
for (i = 0; i < entries; i++)
-   target_map[i] = ckpt_map[i] | cur_map[i];
+   target_map[i] = ckpt_map[i] | written_map[i];
 }
 
 static int __next_free_blkoff(struct f2fs_sb_info *sbi, unsigned long *bitmap,
@@ -4512,9 +4511,9 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
return -ENOMEM;
 
 #ifdef CONFIG_F2FS_CHECK_FS
-   bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * (3 + discard_map);
+   bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * (4 + discard_map);
 

[f2fs-dev] [PATCH v2 2/2] f2fs: introduce written_map to indicate written datas

2024-04-07 Thread Chao Yu
Currently, __exchange_data_block() will check checkpointed state of data,
if it is not checkpointed, it will try to exchange blkaddrs directly in
dnode.

However, after commit 899fee36fac0 ("f2fs: fix to avoid data corruption
by forbidding SSR overwrite"), in order to disallow SSR allocator to
reuse all written data/node type blocks, all written blocks were set as
checkpointed.

In order to reenable metadata exchange functionality, let's introduce
written_map to indicate all written blocks including checkpointed one,
or newly written and invalidated one, and use it for SSR allocation,
and then ckpt_valid_bitmap can indicate real checkpointed status, and
we can use it correctly in __exchange_data_block().

[testcase]
xfs_io -f /mnt/f2fs/src -c "pwrite 0 2m"
xfs_io -f /mnt/f2fs/dst -c "pwrite 0 2m"
xfs_io /mnt/f2fs/src -c "fiemap -v"
xfs_io /mnt/f2fs/dst -c "fiemap -v"
f2fs_io move_range /mnt/f2fs/src /mnt/f2fs/dst 0 0 2097152
xfs_io /mnt/f2fs/src -c "fiemap -v"
xfs_io /mnt/f2fs/dst -c "fiemap -v"

[before]
/mnt/f2fs/src:
 EXT: FILE-OFFSET  BLOCK-RANGE  TOTAL FLAGS
   0: [0..4095]:   8445952..8450047  4096 0x1001
/mnt/f2fs/dst:
 EXT: FILE-OFFSET  BLOCK-RANGE  TOTAL FLAGS
   0: [0..4095]:   143360..1474554096 0x1001

/mnt/f2fs/src:
/mnt/f2fs/dst:
 EXT: FILE-OFFSET  BLOCK-RANGE  TOTAL FLAGS
   0: [0..4095]:   4284416..4288511  4096 0x1001

[after]
/mnt/f2fs/src:
 EXT: FILE-OFFSET  BLOCK-RANGE  TOTAL FLAGS
   0: [0..4095]:   147456..1515514096 0x1001
/mnt/f2fs/dst:
 EXT: FILE-OFFSET  BLOCK-RANGE  TOTAL FLAGS
   0: [0..4095]:   151552..1556474096 0x1001

/mnt/f2fs/src:
/mnt/f2fs/dst:
 EXT: FILE-OFFSET  BLOCK-RANGE  TOTAL FLAGS
   0: [0..4095]:   147456..1515514096 0x1001

Signed-off-by: Chao Yu 
---
v2:
- rebase to last dev-test branch
 fs/f2fs/segment.c | 24 
 fs/f2fs/segment.h |  6 ++
 2 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 9039d60c989d..86436033c730 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2456,13 +2456,12 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, 
block_t blkaddr, int del)
sbi->discard_blks--;
 
/*
-* SSR should never reuse block which is checkpointed
-* or newly invalidated.
+* if CP disabling is enable, it allows SSR to reuse newly
+* invalidated block, otherwise forbidding it to pretect fsyned
+* datas.
 */
-   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_sbi_flag_set(sbi, SBI_CP_DISABLED))
+   f2fs_set_bit(offset, se->written_map);
} else {
exist = f2fs_test_and_clear_bit(offset, se->cur_valid_map);
 #ifdef CONFIG_F2FS_CHECK_FS
@@ -2498,8 +2497,6 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, 
block_t blkaddr, int del)
f2fs_test_and_clear_bit(offset, se->discard_map))
sbi->discard_blks++;
}
-   if (!f2fs_test_bit(offset, se->ckpt_valid_map))
-   se->ckpt_valid_blocks += del;
 
__mark_sit_entry_dirty(sbi, segno);
 
@@ -2847,11 +2844,11 @@ static void __get_segment_bitmap(struct f2fs_sb_info 
*sbi,
struct seg_entry *se = get_seg_entry(sbi, segno);
int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long);
unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map;
-   unsigned long *cur_map = (unsigned long *)se->cur_valid_map;
+   unsigned long *written_map = (unsigned long *)se->written_map;
int i;
 
for (i = 0; i < entries; i++)
-   target_map[i] = ckpt_map[i] | cur_map[i];
+   target_map[i] = ckpt_map[i] | written_map[i];
 }
 
 static int __next_free_blkoff(struct f2fs_sb_info *sbi, unsigned long *bitmap,
@@ -4510,9 +4507,9 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
return -ENOMEM;
 
 #ifdef CONFIG_F2FS_CHECK_FS
-   bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * (3 + discard_map);
+   bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * (4 + discard_map);
 #else
-   bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * (2 + discard_map);
+   bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * (3 + discard_map);
 #endif
sit_i->bitmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
if (!sit_i->bitmap)
@@ -4527,6 +4524,9 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
sit_i->sentries[start].ckpt_valid_map = bitmap;
bitmap += SIT_VBLOCK_MAP_SIZE;
 
+   sit_i->sentries[start].written_map = bitmap;
+   bitmap += SIT_VBLOCK_MAP_SIZE;
+