fat: multi-sector block transfers (B5a)
The FAT engine read and wrote one sector per device command — one SCSI READ(10)/WRITE(10) over USB Bulk-Only Transport per 512 bytes, so every file read, log write, and cluster fill paid a full USB round trip per sector. The lower stack (runtime.block, the block protocol, usb-storage's read10/write10 + count*block_size data stage) already carried a multi-sector count; only the engine's BlockDevice interface and IpcBlock were single-sector. Widen BlockDevice to move a run of `count` contiguous sectors per call (readBlock/writeBlock kept as count=1 wrappers, so metadata call sites — FAT sectors, directory entries — are untouched). readFile and writeFile now coalesce the aligned full-sector middle of a transfer into one command (capped at the cluster boundary and the 4 KiB bounce = 8 sectors), reading straight into / writing straight from the caller's buffer with no staging copy. Full-sector writes skip the read-modify-write entirely, since they overwrite the whole sector. Partial head/tail sectors keep the per-sector RMW path. IpcBlock passes count through to the block driver and sizes its bounce from engine.max_transfer_sectors (already 4 KiB — no new allocation). A new spc=8 engine test proves runs coalesce (a 21-sector overwrite drops from >=21 writes to <=5) and that reads/writes round-trip byte-identical, including an unaligned offset spanning a cluster boundary. Full QEMU suite 92/92.
This commit is contained in:
+14
-10
@@ -22,20 +22,24 @@ const mount_point = "/mnt/usb";
|
||||
// buffer the driver reads/writes by physical address.
|
||||
const IpcBlock = struct {
|
||||
device: runtime.block.Device,
|
||||
bounce: dma.Region,
|
||||
bounce: dma.Region, // engine.max_transfer_sectors * 512 bytes
|
||||
|
||||
fn readBlock(context: *anyopaque, lba: u64, buffer: []u8) bool {
|
||||
fn readBlocks(context: *anyopaque, lba: u64, count: u32, buffer: []u8) bool {
|
||||
const self: *IpcBlock = @ptrCast(@alignCast(context));
|
||||
if (!self.device.read(lba, 1, self.bounce.physical)) return false;
|
||||
if (count == 0 or count > engine.max_transfer_sectors) return false;
|
||||
const len = count * 512;
|
||||
if (!self.device.read(lba, count, self.bounce.physical)) return false;
|
||||
const source: [*]const u8 = @ptrFromInt(self.bounce.virtual);
|
||||
@memcpy(buffer[0..512], source[0..512]);
|
||||
@memcpy(buffer[0..len], source[0..len]);
|
||||
return true;
|
||||
}
|
||||
fn writeBlock(context: *anyopaque, lba: u64, buffer: []const u8) bool {
|
||||
fn writeBlocks(context: *anyopaque, lba: u64, count: u32, buffer: []const u8) bool {
|
||||
const self: *IpcBlock = @ptrCast(@alignCast(context));
|
||||
if (count == 0 or count > engine.max_transfer_sectors) return false;
|
||||
const len = count * 512;
|
||||
const destination: [*]u8 = @ptrFromInt(self.bounce.virtual);
|
||||
@memcpy(destination[0..512], buffer[0..512]);
|
||||
if (!self.device.write(lba, 1, self.bounce.physical)) return false;
|
||||
@memcpy(destination[0..len], buffer[0..len]);
|
||||
if (!self.device.write(lba, count, self.bounce.physical)) return false;
|
||||
device_dirty = true; // a block reached the device; a close will flush it
|
||||
return true;
|
||||
}
|
||||
@@ -108,15 +112,15 @@ fn tryBringUp() void {
|
||||
_ = runtime.system.write("/system/services/fat: block geometry unavailable\n");
|
||||
return;
|
||||
};
|
||||
const bounce = dma.alloc(4096, dma.coherent) orelse return;
|
||||
const bounce = dma.alloc(engine.max_transfer_sectors * 512, dma.coherent) orelse return;
|
||||
ipc_block = .{ .device = device, .bounce = bounce };
|
||||
|
||||
const block_device = engine.BlockDevice{
|
||||
.context = &ipc_block,
|
||||
.block_size = geometry.block_size,
|
||||
.block_count = geometry.block_count,
|
||||
.readBlockFn = IpcBlock.readBlock,
|
||||
.writeBlockFn = IpcBlock.writeBlock,
|
||||
.readBlocksFn = IpcBlock.readBlocks,
|
||||
.writeBlocksFn = IpcBlock.writeBlocks,
|
||||
};
|
||||
filesystem = engine.FileSystem.mount(block_device) orelse {
|
||||
_ = runtime.system.write("/system/services/fat: not a FAT filesystem\n");
|
||||
|
||||
Reference in New Issue
Block a user