Skip to content

Commit 550868a

Browse files
Yongpeng YangJaegeuk Kim
authored andcommitted
f2fs-tools: fix division-by-zero exception during formatting of undersized devices
When formatting a device that is too small , the error handling in f2fs_prepare_super_block() is flawed, leading to a division-by-zero exception. Reproducer: root@vm:~/f2fs-tools# dd if=/dev/zero of=data.6M bs=1M count=6 root@vm:~/f2fs-tools# losetup -f data.6M root@vm:~/f2fs-tools# mkfs.f2fs /dev/loop0 This patch adds a check to verify if the device has enough capacity to store the metadata area. If not, it immediately returns an error to prevent the subsequent division-by-zero exception from being triggered. Signed-off-by: Yongpeng Yang <yangyongpeng@xiaomi.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
1 parent c4933c2 commit 550868a

1 file changed

Lines changed: 23 additions & 9 deletions

File tree

mkfs/f2fs_format.c

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ static int f2fs_prepare_super_block(void)
268268
uint32_t segment_size_bytes, zone_size_bytes;
269269
uint32_t alignment_bytes;
270270
uint32_t sit_segments, nat_segments;
271+
uint32_t segment_count_meta;
271272
uint32_t blocks_for_sit, blocks_for_nat, blocks_for_ssa;
272273
uint32_t total_valid_blks_available;
273274
uint64_t zone_align_start_offset, diff;
@@ -426,9 +427,14 @@ static int f2fs_prepare_super_block(void)
426427
set_sb(nat_blkaddr, get_sb(sit_blkaddr) + get_sb(segment_count_sit) *
427428
c.blks_per_seg);
428429

430+
segment_count_meta = get_sb(segment_count_ckpt) + get_sb(segment_count_sit);
431+
if (get_sb(segment_count) <= segment_count_meta) {
432+
MSG(0, "\tError: segment_count: %u too small, segment_count_meta: %u\n",
433+
get_sb(segment_count), segment_count_meta);
434+
goto too_small;
435+
}
429436
total_valid_blks_available = (get_sb(segment_count) -
430-
(get_sb(segment_count_ckpt) +
431-
get_sb(segment_count_sit))) * c.blks_per_seg;
437+
segment_count_meta) * c.blks_per_seg;
432438

433439
blocks_for_nat = SIZE_ALIGN(total_valid_blks_available,
434440
NAT_ENTRY_PER_BLOCK);
@@ -494,11 +500,16 @@ static int f2fs_prepare_super_block(void)
494500
set_sb(ssa_blkaddr, get_sb(nat_blkaddr) + get_sb(segment_count_nat) *
495501
c.blks_per_seg);
496502

497-
total_valid_blks_available = (get_sb(segment_count) -
498-
(get_sb(segment_count_ckpt) +
503+
segment_count_meta = get_sb(segment_count_ckpt) +
499504
get_sb(segment_count_sit) +
500-
get_sb(segment_count_nat))) *
501-
c.blks_per_seg;
505+
get_sb(segment_count_nat);
506+
if (get_sb(segment_count) <= segment_count_meta) {
507+
MSG(0, "\tError: segment_count: %u too small, segment_count_meta(with nat): %u\n",
508+
get_sb(segment_count), segment_count_meta);
509+
goto too_small;
510+
}
511+
total_valid_blks_available = (get_sb(segment_count) -
512+
segment_count_meta) * c.blks_per_seg;
502513

503514
if (c.feature & F2FS_FEATURE_RO) {
504515
blocks_for_ssa = 0;
@@ -563,10 +574,13 @@ static int f2fs_prepare_super_block(void)
563574
}
564575
}
565576

566-
total_zones = get_sb(segment_count) / (c.segs_per_zone) -
567-
total_meta_zones;
568-
if (total_zones == 0)
577+
total_zones = get_sb(segment_count) / (c.segs_per_zone);
578+
if (total_zones <= total_meta_zones) {
579+
MSG(0, "\tError: total_zones:%u too small, total_meta_zones: %lu\n",
580+
total_zones, total_meta_zones);
569581
goto too_small;
582+
}
583+
total_zones -= total_meta_zones;
570584
set_sb(section_count, total_zones * c.secs_per_zone);
571585

572586
set_sb(segment_count_main, get_sb(section_count) * c.segs_per_sec);

0 commit comments

Comments
 (0)