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..147455    4096 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..151551    4096 0x1001
/mnt/f2fs/dst:
 EXT: FILE-OFFSET      BLOCK-RANGE      TOTAL FLAGS
   0: [0..4095]:       151552..155647    4096 0x1001

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

Signed-off-by: Chao Yu <c...@kernel.org>
---
 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 ecb9ee80d5e0..ec3288381397 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,
@@ -4529,9 +4526,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)
@@ -4546,6 +4543,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;
+
 #ifdef CONFIG_F2FS_CHECK_FS
                sit_i->sentries[start].cur_valid_map_mir = bitmap;
                bitmap += SIT_VBLOCK_MAP_SIZE;
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index 08d667e6a36f..eda04d9ed5a5 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -205,6 +205,10 @@ struct seg_entry {
         * checkpoint pack. This information is used by the SSR mode.
         */
        unsigned char *ckpt_valid_map;  /* validity bitmap of blocks last cp */
+       unsigned char *written_map;     /*
+                                        * blocks were written, including newly
+                                        * invalidated data
+                                        */
        unsigned char *discard_map;
        unsigned long long mtime;       /* modification time of the segment */
 };
@@ -370,6 +374,7 @@ static inline void seg_info_from_raw_sit(struct seg_entry 
*se,
        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);
+       memcpy(se->written_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);
 #endif
@@ -412,6 +417,7 @@ static inline void seg_info_to_raw_sit(struct seg_entry *se,
        __seg_info_to_raw_sit(se, rs);
 
        memcpy(se->ckpt_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
+       memcpy(se->written_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
        se->ckpt_valid_blocks = se->valid_blocks;
 }
 
-- 
2.40.1



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to