dev: raw disks are 64-bit, so a real drive stops wrapping at 4 GB
struct file already carried a uint64 offset and bread already took a uint64 block number. The narrowing was one boundary in the middle: devsw's read and write took a 32-bit uint, so fileread passed a 64-bit f->off into a 32-bit parameter and the top half was discarded. The effect was not a refusal at 4 GB but silent wraparound past it. A read at 5 GB returned the bytes at 1 GB, reporting success. disk.c had a DISK_MAX_BYTES constant documenting the limit, and nothing anywhere referenced it -- the cap was described but never enforced, which is the worst of the three options. The signature is now uint64 across all nine files that carry it, and diskread/diskwrite no longer narrow the block number on the way to bread. Widening this is a prerequisite for NVMe and for any real disk: namespaces start well above 4 GB and the failure mode reads valid data from the wrong place. Verified end to end rather than by inspection. A 6 GB sparse image with "PAST4GB-MARKER-OK" written at byte 5368709120, attached as /dev/hdb to a ramdisk-root kernel so device 1 was free: # dd if=/dev/hdb bs=4096 skip=1310720 count=1 | od -c | head -2 0000000 P A S T 4 G B - M A R K E R - O Under the old code that offset truncates to 1 GB, where the image is zeroes. The whole path is exercised: f->off, devsw, diskread, bread and ide.c's LBA48. Worth recording for next time: `make ramroot` stages the ESP itself, and running `make esp` afterwards rebuilds the kernel without RAMROOT and silently undoes it. The tell is a 855 KB kernel where a 25 MB one is expected. 110 [ok], no failures, on the default build.
This commit is contained in:
parent
f4107177ea
commit
ad2b321d56
9 changed files with 42 additions and 41 deletions
|
|
@ -198,8 +198,8 @@ int schfs_kreaddir_dev(uint dev, uint64 dir,
|
|||
uint uptime(void);
|
||||
|
||||
// procfs.c
|
||||
int procread(struct inode*, uint, char*, int);
|
||||
int procwrite(struct inode*, uint, char*, int);
|
||||
int procread(struct inode*, uint64, char*, int);
|
||||
int procwrite(struct inode*, uint64, char*, int);
|
||||
// Shared with the /proc filesystem (kernel/fs/procfs.c): one owns the
|
||||
// namespace, the other the content.
|
||||
int proc_gen_global(int id, char *buf, int cap);
|
||||
|
|
@ -208,8 +208,8 @@ void procfs_mount(void);
|
|||
|
||||
// input.c -- raw evdev event devices
|
||||
void inputinit(void);
|
||||
int inputread(struct inode*, uint, char*, int);
|
||||
int inputwrite(struct inode*, uint, char*, int);
|
||||
int inputread(struct inode*, uint64, char*, int);
|
||||
int inputwrite(struct inode*, uint64, char*, int);
|
||||
int inputready(struct inode*);
|
||||
void inputclose(struct inode*);
|
||||
void inputopen(struct inode*);
|
||||
|
|
@ -431,13 +431,13 @@ void fbclose(struct inode*);
|
|||
// Called from sys_mmap: a mapping of /dev/fb0 is a licence to draw with no
|
||||
// further syscalls, so it is the last the kernel hears about it.
|
||||
void fb_mapped(void);
|
||||
int fbread(struct inode*, uint, char*, int);
|
||||
int fbwrite(struct inode*, uint, char*, int);
|
||||
int fbread(struct inode*, uint64, char*, int);
|
||||
int fbwrite(struct inode*, uint64, char*, int);
|
||||
int fb_ioctl(int request, addr_t arg);
|
||||
// dev/disk.c -- /dev/hdN, raw seekable access to a whole disk. The minor is the
|
||||
// IDE device number. Writes bypass every filesystem above them.
|
||||
int diskread(struct inode*, uint, char*, int);
|
||||
int diskwrite(struct inode*, uint, char*, int);
|
||||
int diskread(struct inode*, uint64, char*, int);
|
||||
int diskwrite(struct inode*, uint64, char*, int);
|
||||
// drivers/net/e1000 -- raw Ethernet. No protocol stack above it yet, so these
|
||||
// are the whole interface: queue a frame, take a frame, and the MAC.
|
||||
int e1000_transmit(const void *frame, int len);
|
||||
|
|
|
|||
Loading…
Reference in a new issue