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