mirror of
https://github.com/RhapsodiOS/RhapsodiOS.git
synced 2026-11-03 22:01:40 -07:00
[GH-ISSUE #58] msdosfs: on 1024-byte-sector labelled partitions the kernel addresses blocks in 512-byte units, corrupting reads and the FAT #51
Labels
No labels
bug
documentation
enhancement
enhancement
good first issue
help wanted
help wanted
pull-request
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
github-starred/RhapsodiOS#51
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @raynorpat on GitHub (Oct 16, 2026).
Original GitHub issue: https://github.com/RhapsodiOS/RhapsodiOS/issues/58
Symptom
On partition
aof a disk whose NeXT label uses 1024-byte sectors (thevm/ffsbench.py build_scratchlayout, like the installed root disk), an msdos volume made correctly by the fixednewfs_msdos(#56; 1024 bytes/sector, passesfsck_msdos -n) mounts, but:fsck_msdosfinds FAT 1 entries at about twice the cluster numbers written in FAT 0.The same tests on a 512-byte-label partition pass: a 3 MB file, a directory and 11 small files written, remounted, read back, and fsck clean.
Cause (from a probe on the guest)
On the 1024-label partition
/dev/rhd1a,DKIOCBLKSIZE/DKIOCNUMBLKSreport 512 × 1048768, which is the whole drive, whileDKIOCGPARTINFO/DKIOCGLABELreport 1024 × 524288. The kernel's msdosfs computes block numbers in 512-byteDEV_BSIZEunits (de_bn2kb/cntobn-style conversions, andbreadwithDEV_BSIZE-based block numbers), but the IDE disk driver interprets a block number on this partition in the label's 1024-byte units. Every metadata and data address is therefore doubled.Reproduce
i386 QEMU guest on a kernel with msdosfs (e.g.
vm/work/stress-phase3/mach_kernel), hd1 fromffsbench.build_scratch:Probe and scripts:
vm/work/issue56/(probe.c).Where to look
bsd/msdosfs/msdosfs_vfsops.cmsdosfs_mountfs(), and how the block numbers it hands tobread/VOP_STRATEGYare scaled. FFS on this kernel uses the device's block size (or the label's) when it converts fragments to device blocks. msdosfs assumes 512 (DEV_BSIZE). Scale by the partition's block size (DKIOCGPARTINFO/DKIOCBLKSIZEon the partition) the wayffs_mountfsdoes.msdosfs_mountfs, reject a volume whose BPB total sectors × bytes per sector exceeds the partition size. Today a half-made or oversized volume mounts silently.Found while fixing #56. Related: #47 (raw-offset handling on i386 IDE), #54, #55.
@raynorpat commented on GitHub (Oct 16, 2026):
Fixed by
883ed93c2(kernel: address msdosfs blocks in the device's block size and refuse volumes larger than the partition), merged into ffs-perf in83e9d741b.Root cause. On the block device, the i386 IDE driver counts
b_blknoin the partition's block size (1024 on these labels):ata_hd_strategypasses it straight to the disk (bsd/dev/ata_hd_registry.m:886-897), andata_hd_sizereports the label block size, whichset_blocksizestores asv_specsize/VOP_DEVBLOCKSIZE. msdosfs hard-codedDEV_BSIZE(512) forpm_BlkPerSec,pm_bnshift,pm_bpcluster,pm_rootdirsize,pm_fatblocksec, the FAT block size (msdosfs_fat.c) and the root directory size (msdosfs_denode.c), so every address was doubled. FFS already scales byVOP_DEVBLOCKSIZE.Fix.
mountmsdosfsusesVOP_DEVBLOCKSIZEeverywhere it usedDEV_BSIZE.DKIOCGPARTINFO).Verified on a kernel with this fix and a rebuilt driverkit (so #47 is included). On a 1024-byte-label and a 512-byte-label partition, with default and
-ssizes:cmp/diff -requal, andfsck_msdos -nclean.stress-fsrw/append/tree/fsync andstress-mmapshared/mixed pass on both msdos mounts.Before the fix, on the same kernel line,
cp -rfailed with EINVAL and fsck found FAT 0/1 mismatches.Limitation. A FAT volume with 512 bytes/sector on a 1024-byte-block partition is refused at mount, not supported. Standard layouts put the FAT at byte 512, which a 1024-unit block device can't address, and #56's newfs already refuses
-S 512there.Not checked: the ppc build and GEMDOS mounts. Separately,
newfs_msdos -S 1024on a 512-byte partition without-ssizes the volume at twice the partition; the new mount check refuses it.