kd_write() went through bread(), so every block a write allocated was read from the disk first and then replaced whole. That was a quarter of the disk operations of a SchFS write. bgetblk() is bread() without the read, as Linux's getblk() is. 1 MB on AHCI under QEMU: 2.0 -> 2.8 MB/s in 4 KB writes, 4.5 -> 5.6 MB/s in 64 KB ones. 3 MB of random data written and copied through the cache's evictions reads back with the same md5. The 63 KB/s seen earlier is the legacy IDE driver on QEMU's default machine, at about 10 ms per emulated PIO write; the same disk on AHCI (q35) is 40 times faster. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
74 lines
3.8 KiB
C
74 lines
3.8 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
#pragma once
|
|
|
|
// Block devices that are found rather than assumed.
|
|
//
|
|
// The first four device numbers are fixed and always were: IDE 0 and 1, the
|
|
// ramdisk, the first USB stick. Everything since -- a SATA disk behind AHCI,
|
|
// an NVMe namespace, and every partition on any of them -- registers here at
|
|
// probe time and is handed the next free number from BLKDEV_FIRST.
|
|
//
|
|
// A partition is a block device in its own right, with block 0 at its first
|
|
// sector. That is the whole of partition support from a filesystem's side:
|
|
// SchFS on /dev/sata0p2 sees a volume that starts at zero, exactly as it would
|
|
// on a whole disk, and needs to know nothing about GPT -- which is also what
|
|
// a Linux driver for SchFS will see when it is handed /dev/sda2.
|
|
|
|
#define BLKDEV_FIRST 4
|
|
#define NBLKDEV 16 // so device numbers stay below SCHFS_DEV (64)
|
|
|
|
// The GPT partition type of a SchFS volume, as it is written and printed:
|
|
// 47138FA9-B79C-47A6-9F7D-AC1F7F572D5E. sgdisk and fdisk accept it as is.
|
|
// Generated for SchFS on 2026-10-22; nothing else uses it.
|
|
#define SCHFS_GPT_TYPE "47138FA9-B79C-47A6-9F7D-AC1F7F572D5E"
|
|
|
|
// What a driver supplies. `rw` moves `count` of the device's own sectors at
|
|
// `lba` to or from `buf`, a kernel address; it is never asked for more than
|
|
// BSIZE bytes at once. Returns 0, or -1 if the device refused.
|
|
struct blkdev_ops {
|
|
int (*rw)(void *priv, uint64 lba, uint32 count, void *buf, int write);
|
|
int (*flush)(void *priv); // 0 when there is nothing to flush
|
|
};
|
|
|
|
// Register a whole disk. Its partition table, if it has one, is read here and
|
|
// every partition registered after it. Returns the disk's device number, or
|
|
// -1 if the table is full.
|
|
int blkdev_register(const char *name, const struct blkdev_ops *ops,
|
|
void *priv, uint64 nsectors, uint32 secsize);
|
|
|
|
// The disk has gone -- a USB stick pulled out. Removes it and every partition
|
|
// on it, and drops whatever the buffer cache still holds for them, so that a
|
|
// different disk given the same number later is not served the old one's
|
|
// blocks. A filesystem still mounted from it fails on its next access.
|
|
void blkdev_unregister(int dev);
|
|
void binval(uint dev); // kernel/dev/bio.c
|
|
struct buf *bgetblk(uint dev, uint64 blockno); // bread() without the read
|
|
|
|
int blkdev_present(uint dev);
|
|
void blkdev_rw(struct buf *b);
|
|
int blkdev_flush(uint dev);
|
|
|
|
// For the root probe: the registered devices in order, partitions after the
|
|
// disk they are on. Returns the device number of the i'th, or -1 past the end.
|
|
int blkdev_nth(int i);
|
|
const char *blkdev_name(uint dev);
|
|
// 1 for a partition typed SCHFS_GPT_TYPE, 0 for anything that might be SchFS,
|
|
// and -1 for one whose type says it cannot be -- an EFI system partition, an
|
|
// MBR FAT type. The root probe takes 1 and then 0, so -1 is never tried: a
|
|
// FAT partition is mounted as FAT (kernel/fs/fat), not offered as a root.
|
|
int blkdev_is_schfs(uint dev);
|
|
|
|
int blkdev_info(char *buf, int cap); // /proc/partitions
|
|
|
|
// Sectors straight to and from a filesystem's own buffer, for one that does
|
|
// not go through the buffer cache. kernel/fs/fat is: FAT addresses 512-byte
|
|
// sectors, a partition need not be a whole number of 4 KB blocks, and a
|
|
// cache block hanging over the end of one is a write into the next.
|
|
//
|
|
// `lba` counts the device's own sectors from the start of the partition, and
|
|
// the transfer is at most BSIZE bytes. Returns 0, or -1 for a transfer out of
|
|
// range or one the device refused -- it does not panic, because a USB stick
|
|
// can leave in the middle of one.
|
|
int blkdev_xfer(uint dev, uint64 lba, uint32 count, void *buf, int write);
|
|
// Size in sectors and sector size; 0 if there is no such device.
|
|
uint64 blkdev_sectors(uint dev, uint32 *secsize);
|