On 11/19/25 14:00, Xiaole He wrote:
[...]

    With default values:
    - blk_size_bytes = 4096
    - c.blks_per_seg = 512
    - c.segs_per_sec = 1
    - c.secs_per_zone = 1
    - zone_size_bytes = blk_size_bytes * c.secs_per_zone
                        * c.segs_per_sec * c.blks_per_seg
                      = 4096 * 1 * 1 * 512 = 2,097,152 bytes (2MB)
    - alignment_bytes = zone_size_bytes (for non-zoned or single device)

    With c.start_sector = 0 (bug case):
    - zone_align_start_offset
        = ((c.start_sector * DEFAULT_SECTOR_SIZE +
           2 * F2FS_BLKSIZE + alignment_bytes - 1) /
           alignment_bytes * alignment_bytes) -
           (c.start_sector * DEFAULT_SECTOR_SIZE)
        = ((0 * 512 + 2 * 4096 + 2,097,152 - 1) /
           2,097,152 * 2,097,152) - (0 * 512)
        = ((8,192 + 2,097,152 - 1) / 2,097,152 * 2,097,152) - 0
        = 2,097,152 - 0 = 2,097,152 bytes (2MB)
    - segment0_blkaddr = zone_align_start_offset / blk_size_bytes
        = 2,097,152 / 4,096 = 512 blocks

    This matches the output "segment0 blkaddr: 512".

    With c.start_sector = 2048 (correct case):
    - zone_align_start_offset
        = ((2048 * 512 + 2 * 4096 + 2,097,152 - 1) /
           2,097,152 * 2,097,152) - (2048 * 512)
        = ((1,048,576 + 8,192 + 2,097,152 - 1) /
           2,097,152 * 2,097,152) - 1,048,576
        = 2,097,152 - 1,048,576 = 1,048,576 bytes (1MB)
    - segment0_blkaddr = zone_align_start_offset / blk_size_bytes
        = 1,048,576 / 4,096 = 256 blocks


Hi, Xiaole,

We are considering if this is also correct for the current resize. The 
resize.f2fs
also does this calculation, but it does not update segment0_blkaddr. As a 
result,
segment_count is 1 section larger than it should be after resizing.

For example, a partition has 2621664 blocks (10G + 224blks) and its start_sector
is 3557152 (in 4K size, 3557152 % 512 = 228). However, the f2fs image is created
separately, its start_sector is 0. Now we are resizing the f2fs image to the
partition.

before: start_sector = 0, zone_align_start_offset = 512 blks
============================================================
block_count                             [0x  2800e0 : 2621664]
section_count                           [0x    13d9 : 5081]
segment_count                           [0x    13ff : 5119]
segment_count_ckpt                      [0x       2 : 2]
segment_count_sit                       [0x       2 : 2]
segment_count_nat                       [0x      18 : 24]
segment_count_ssa                       [0x       a : 10]
segment_count_main                      [0x    13d9 : 5081]
segment0_blkaddr                        [0x     200 : 512]
cp_blkaddr                              [0x     200 : 512]
sit_blkaddr                             [0x     600 : 1536]
nat_blkaddr                             [0x     a00 : 2560]
ssa_blkaddr                             [0x    3a00 : 14848]
main_blkaddr                            [0x    4e00 : 19968]

after: start_sector = 3557152 blks, zone_align_start_offset = 224 blks
======================================================================
block_count                             [0x  2800e0 : 2621664]
section_count                           [0x    13da : 5082]
segment_count                           [0x    1400 : 5120]
segment_count_ckpt                      [0x       2 : 2]
segment_count_sit                       [0x       2 : 2]
segment_count_nat                       [0x      18 : 24]
segment_count_ssa                       [0x       a : 10]
segment_count_main                      [0x    13da : 5082]
segment0_blkaddr                        [0x     200 : 512]
cp_blkaddr                              [0x     200 : 512]
sit_blkaddr                             [0x     600 : 1536]
nat_blkaddr                             [0x     a00 : 2560]
ssa_blkaddr                             [0x    3a00 : 14848]
main_blkaddr                            [0x    4e00 : 19968]

After resizing with HDIO_GETGEO fixed, 
section_count/segment_count/segment_count_main
are 1 section larger than that without HDIO_GETGEO fixed, while segment0_blkaddr
is still 512.

So, we think the following change is still needed. Could you do more test on the
resize scenario?

Otherwise, I think we should keep HDIO_GETGEO not called for resize for now :-(

thanks,
shengyong

[RFT PATCH] resize.f2fs: fix start_sector not starting from 0

Fixes: mkfs.f2fs: fix incorrect start_sector detection due to typo in 
HDIO_GETGEO macro check
Reported-by: Liu Jinbao <[email protected]>
Signed-off-by: Liu Jinbao <[email protected]>
Signed-off-by: Sheng Yong <[email protected]>
---
 fsck/resize.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 54 insertions(+), 2 deletions(-)

diff --git a/fsck/resize.c b/fsck/resize.c
index 58914ec2ab88..e82ddf2ddac5 100644
--- a/fsck/resize.c
+++ b/fsck/resize.c
@@ -22,6 +22,8 @@ static int get_new_sb(struct f2fs_super_block *sb)
                                        get_sb(log_blocks_per_seg));
        uint32_t blks_per_seg = 1 << get_sb(log_blocks_per_seg);
        uint32_t segs_per_zone = get_sb(segs_per_sec) * get_sb(secs_per_zone);
+       uint32_t blk_size_bytes = 1 << get_sb(log_blocksize);
+       unsigned int old_seg0_blkaddr, new_seg0_blkaddr;
set_sb(block_count, c.target_sectors >>
                                get_sb(log_sectors_per_block));
@@ -33,6 +35,19 @@ static int get_new_sb(struct f2fs_super_block *sb)
                zone_size_bytes * zone_size_bytes -
                (uint64_t) c.start_sector * DEFAULT_SECTOR_SIZE;
+ old_seg0_blkaddr = get_sb(segment0_blkaddr);
+       new_seg0_blkaddr = zone_align_start_offset / blk_size_bytes;
+       /*
+        * new_seg0_blkaddr must be larger than old_seg0_blkaddr, otherwise
+        * migration metadata will be overlapped.
+        */
+       while (new_seg0_blkaddr < old_seg0_blkaddr)
+               new_seg0_blkaddr += blks_per_seg;
+       zone_align_start_offset = new_seg0_blkaddr * blk_size_bytes;
+       set_sb(segment0_blkaddr, new_seg0_blkaddr);
+       sb->cp_blkaddr = sb->segment0_blkaddr;
+       set_sb(sit_blkaddr, get_sb(segment0_blkaddr) + 
get_sb(segment_count_ckpt) * c.blks_per_seg);
+
        set_sb(segment_count, (c.target_sectors * c.sector_size -
                                zone_align_start_offset) / segment_size_bytes /
                                c.segs_per_sec * c.segs_per_sec);
@@ -628,6 +643,35 @@ static int f2fs_resize_check(struct f2fs_sb_info *sbi, 
struct f2fs_super_block *
        return 0;
 }
+static void migrate_cp(struct f2fs_sb_info *sbi, struct f2fs_super_block *new_sb)
+{
+       struct f2fs_super_block *sb = sbi->raw_super;
+       block_t old_end, new_end;
+       int count, ret;
+       char *blk = calloc(F2FS_BLKSIZE, 1);
+
+       ASSERT(blk != NULL);
+       count = get_sb(segment_count_ckpt) * sbi->blocks_per_seg;
+       old_end = get_sb(cp_blkaddr) + count - 1;
+       new_end = get_newsb(cp_blkaddr) + count - 1;
+       for (; count > 0; count--) {
+               ret = dev_read_block(blk, old_end);
+               ASSERT(ret >= 0);
+               ret = dev_write_block(blk, new_end, WRITE_LIFE_NONE);
+               ASSERT(ret >= 0);
+               old_end--;
+               new_end--;
+       }
+       /*
+        * All cp packs are migrated to new position, it is safe to change
+        * cp_blkaddr in old sb so that rebuild_checkpoint() can get the
+        * correct cp_blkaddr
+        */
+       MSG(0, "Info: Done to migrate CP blocks: cp_blkaddr = 0x%x -> 0x%x\n",
+               sb->cp_blkaddr, new_sb->cp_blkaddr);
+       sb->cp_blkaddr = new_sb->cp_blkaddr;
+}
+
 static int f2fs_resize_grow(struct f2fs_sb_info *sbi)
 {
        struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
@@ -664,13 +708,20 @@ static int f2fs_resize_grow(struct f2fs_sb_info *sbi)
                        get_sb(log_blocks_per_seg)) + get_sb(main_blkaddr);
err = -EAGAIN;
-       if (new_main_blkaddr < end_blkaddr) {
+       /*
+        * main_blkaddr may be updated, if it is not aligned with the old
+        * image, defragment will change the consistency between data/node
+        * block and SIT/NAT/SSA.
+        */
+       if (new_main_blkaddr < end_blkaddr &&
+           OFFSET_IN_SEG(sbi, new_main_blkaddr) == 0) {
                err = f2fs_defragment(sbi, old_main_blkaddr, offset,
                                                new_main_blkaddr, 0);
                if (!err)
                        offset_seg = offset >> get_sb(log_blocks_per_seg);
                MSG(0, "Try to do defragement: %s\n", err ? "Skip": "Done");
-       }
+       } else
+               MSG(0, "do not defrag\n");
        /* move whole data region */
        if (err)
                migrate_main(sbi, offset);
@@ -678,6 +729,7 @@ static int f2fs_resize_grow(struct f2fs_sb_info *sbi)
        migrate_ssa(sbi, new_sb, offset_seg);
        migrate_nat(sbi, new_sb);
        migrate_sit(sbi, new_sb, offset_seg);
+       migrate_cp(sbi, new_sb);
        rebuild_checkpoint(sbi, new_sb, offset_seg);
        update_superblock(new_sb, SB_MASK_ALL);
        print_raw_sb_info(sb);
--
2.43.0




_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to