mirror of
https://github.com/RhapsodiOS/RhapsodiOS.git
synced 2026-11-03 22:01:40 -07:00
[GH-ISSUE #47] kernel: i386 raw disk I/O drops the low 512 bytes of the offset (odd-sector reads/writes hit the sector below) #42
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#42
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 14, 2026).
Original GitHub issue: https://github.com/RhapsodiOS/RhapsodiOS/issues/47
Symptom
On the i386 IDE disk, a raw-device (
/dev/rhdNx) read or write at an offset that is an odd multiple of 512 bytes silently uses the sector below it. The low 512 bytes of the offset are dropped. The device reports 512-byte sectors (DEV_BSIZE= 512,DKIOCBLKSIZE= 512), so 512-aligned I/O should work.Reproduced with
ddon the scratch disk after filling it with a sector-keyed pattern:A read at byte 1536 returns the data that lives at byte 1024. Writes are misplaced the same way.
Found by the stress suite's new
stress-disk(ffs-perf branch,src/Commands/stress/disk):verify: with 512-byte-aligned offsets it FAILs every run, seeds 1, 2 and 3. It even FAILs on regions the writer never touched, because reads at odd-sector offsets come back from the wrong place.rand: it passes only because its write and its read-back are misplaced identically.Impact
Anything doing raw I/O at odd-sector offsets reads or writes the wrong sector, silently. That covers fsck/newfs/dump-style tools, disk labelling, and databases using raw partitions. Writes land one sector early and overwrite data that belongs to the previous sector.
Where to look (unverified)
physio()(bsd/kern/kern_physio.c:156) computesbp->b_blkno = uio->uio_offset / blocksizeusing theblocksizeits caller passes. If the i386 IDE disk's raw read/write entry passes 1024 instead of 512, the offset is rounded down to 1 KB. A logical, partition or fragment size, or a driverkitIODiskPartition/IOLogicalDiskblock size, would do it.physio(compare the ppcATADiskKernel.m:254/276calls).IODiskPartition/IOLogicalDiskin driverkit: how the logical block size relates to the physical one (IOLogicalDisk.m:715-716).A fix should make raw transfers honour 512-byte offsets, or reject misaligned ones with EINVAL rather than silently rounding.
Regression test
On the dev guest:
Once the stress-disk safety fix round lands,
verifythere FAILs withoff=until this is fixed.Related: #41, #45, #46, also found by the stress suite.
@raynorpat commented on GitHub (Oct 14, 2026):
Root cause: the raw read/write entry points passed
[disk blockSize]tophysio. For a labelled partition that is the label's logical block size (1024 on the scratch disk), even thoughDKIOCBLKSIZEreports 512.physiotherefore floored the offset to 1 KB, and a read at byte 1536 started at 1024.Fix, on branch
issue-47(commit4f3c58658), not yet merged:ata_hd_read/ata_hd_writecallphysiowithDEV_BSIZEand return EINVAL for offsets that are not a multiple of 512.ata_hd_strategyturnsphysiobuffers (B_PHYS|B_RAW) into a byte offset and calls a newIOLogicalDisk asyncTransfer:byteOffset:.... It reblocks when the request is not aligned to the physical block size.MAX_REBLOCK_SIZEis raised from 2048 to 4096, so 4K sectors fit.Tested on i386 QEMU with a snapshot of the v2 image and a scratch hd1: the stock kernel reproduced the bug (reads at
skip=0..7gave S1,S1,S3,S3,S5,S5,S7,S7). With the fix, reads and writes at odd-sector offsets hit the right sectors and the full image compared identical.newfs,fsck, mount and file copies on hd1a were clean, and the machine booted to multi-user.Not tested: the EINVAL check was added after the last kernel build, so it is uncompiled. The cluster-I/O path on a 1024-label disk, ppc, and an actual 4K disk are also untested.
@raynorpat commented on GitHub (Oct 15, 2026):
Fixed by
4f3c58658(kernel: honour 512-byte raw disk offsets on i386 IDE and reject sub-sector ones with EINVAL), merged into the ffs-perf branch inb6820ec8f. It reaches master when ffs-perf is merged.