From aab316a9a1311f831e12dc00723f2e1ea2008e68 Mon Sep 17 00:00:00 2001 From: surface-camera-build Date: Wed, 23 Sep 2026 17:53:38 -0400 Subject: [PATCH] read: take the log window instead of copying it, and name the boot class bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A coordinate read cost 0.082 ms in a 500-record store and 0.081 ms in a 20,000-record one — flat to a microsecond while the index search does nine probe reads against fifteen. So the device reads are nearly free and the per-call cost is SETUP, and the clearest piece of setup was a copy of the log window into a second buffer on every read. `v3_get` copied it because what the log says borrows it while reading the image needs `&mut image`; that borrow is one field, so moving the field out settles it for nothing. Measured on #82: get 0.082 -> 0.078 ms, spaces 0.339 -> 0.267 ms. That is small in the GUEST, and the guest cannot show the real number: its store carries a log of a few hundred bytes, while the box's log is 132,679 bytes — so the copy this removes costs ~130 KB of memcpy and a ~130 KB allocation per read there, and only the box can measure it. Also names the store's own class bit. `BOOT_FLAGS` was a bare `1 << 7` and read as `TYPE_MASK == 10` ("data type: code") to anything applying `WordFlags` — a latent collision, not a live one, and the resolution is a declaration rather than a move: `WordFlags` is a different field and its sixteen bits are all allocated, so there is no bit to borrow, and the space axis already makes a boot record findable (reserved space 0xFC) without a class bit at all. What it needed was a vocabulary that claims it, which this comment now does. The one bit the two fields share is shared on purpose and by name: 0x0800, `SEALED_FLAG` in `cube-store-seal`, which `WordFlags` calls `ENCRYPTED` — same meaning in both places, which is the pattern rather than the exception. --- drivers/cube/cubelinux_store.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/cube/cubelinux_store.rs b/drivers/cube/cubelinux_store.rs index 8b18be6dd..9ed57e753 100644 --- a/drivers/cube/cubelinux_store.rs +++ b/drivers/cube/cubelinux_store.rs @@ -278,6 +278,18 @@ const BOOT_SPACE: [u8; SPACE_ID_LEN] = [0xFC; SPACE_ID_LEN]; /// The class mask the boot record stamps: `EventFlags::BOOT`, bit 7. The kernel cannot link /// `cube-core`, so the bit is spelled out here and on the userspace side, and the agreement is held /// by `verify-boot-record` — the same shape as the `0xFC` space id, for the same reason. +/// The store class for "the kernel wrote this about its own boot" — the first bit of the store's +/// own class vocabulary. +/// +/// The class field is `v4`'s two bytes in the index entry, and it is **its own 16-bit space**. The +/// reason this is named here instead of borrowed from `cube_core::WordFlags` is that `WordFlags` is a +/// different field whose sixteen bits are all spoken for: reading this bit through it gives +/// `TYPE_MASK == 10`, "data type: code", which is a meaning this bit does not have. A vocabulary +/// belongs to one field, and this field's first vocabulary is `events`. +/// +/// `0x0800` is the one bit this field and `WordFlags` share, deliberately and by name: the sealing +/// layer stamps it here (`SEALED_FLAG` in `cube-store-seal`) and it means encrypted in both places, +/// so the two agree instead of colliding. See `DESIGN-flag-vocabularies.md` §6. const BOOT_FLAGS: u16 = 1 << 7; /// The coordinate the record lives at. One record, the current boot: each boot overwrites the last, @@ -3089,12 +3101,13 @@ unsafe fn v3_get( len: usize, out_flags: *mut u16, ) -> isize { - // The log is owned for the duration: what it says borrows it, and reading the image needs - // `&mut image`. It is what a checkpoint has not folded, so it is small. - let mut log = KVVec::::new(); - if log.extend_from_slice(image.log(), GFP_KERNEL).is_err() { - return -12; // -ENOMEM - } + // The log is *taken*, not copied. It used to be copied into a second buffer because what it says + // borrows it while reading the image needs `&mut image` — but that borrow is one field, and moving + // the field out settles it for nothing. Measured, a coordinate read costs the same in a store + // forty times larger while the index search does nine probe reads against fifteen: the device + // reads are nearly free and the per-call cost is this kind of setup, so a copy of the log window + // on every read is the thing worth removing, not the reads. + let log = core::mem::replace(&mut image.log, KVVec::new()); match log_effect(log.as_slice(), &sp, &key) { Some(Effect::Delete) => return -2, // -ENOENT Some(Effect::Write(value, flags)) => {