B1: a boot area on the disk, reserved by arithmetic that was already there

The first rung of booting from disk. A boot area is blocks between the
superblock and the directory that the filesystem never allocates and never
sees, and NOTHING WAS ADDED TO RESERVE THEM: both implementations work out
the first usable block as directoryStart + directoryBlocks, and
directoryStart has always been a field rather than a constant. Formatting
with the directory moved up reserves everything below it. Neither allocator
changed, on either side.

Two new superblock fields in bytes that were reserved: bootBlocks at 14,
per slot, and bootSlot at 16. A disk made before this has zero in both,
which reads as "no boot area" - true, and the same shape as the version two
parent field, where the value an older disk already held was the right
answer without conversion.

TWO SLOTS, ALWAYS. A boot slot is raw blocks with no entry to rename, so
the write-a-temporary-and-rename ordering that protects every file cannot
protect it, and a machine interrupted while updating its only slot would
not boot at all - the one failure on this disk with no way back. Writing
the slot that is not live and then moving one byte makes that a machine
that boots what it had before.

bootBlocks and directoryStart say the same thing from two sides, so a disk
where they disagree is refused rather than guessed at, as is one naming a
slot that does not exist.

Checked where it matters: the HOST formats a disk with a boot area and the
MACHINE fills it, then the reserved blocks are compared against zero. The
machine's allocator is the one that had no idea any of this was happening,
which is what makes that the check worth having. Six host checks besides,
including both halves of the superblock disagreeing.
This commit is contained in:
Anachronaut
2026-08-26 22:58:45 -04:00
parent 0a2965bc63
commit 612bd1b97c
5 changed files with 162 additions and 9 deletions
+31 -1
View File
@@ -51,13 +51,43 @@
// 8 2 First directory block
// 10 2 Blocks the directory occupies
// 12 2 Free blocks, a cache rather than the authority
// 14 Reserved to the end of the block
// 14 2 Blocks in each boot slot, or zero for a disk that cannot be booted
// 16 1 Which boot slot is live, 0 or 1
// 17 Reserved to the end of the block
#define SBFS_SUPER_VERSION 4
#define SBFS_SUPER_DISK 6
#define SBFS_SUPER_DIRSTART 8
#define SBFS_SUPER_DIRBLOCKS 10
#define SBFS_SUPER_FREE 12
#define SBFS_SUPER_BOOTBLOCKS 14
#define SBFS_SUPER_BOOTSLOT 16
// ---- The boot area ----
//
// Blocks between the superblock and the directory, which the filesystem never allocates
// and never sees. Nothing had to be added to make room for them: both implementations
// work out the first usable data block as directoryStart + directoryBlocks, and
// directoryStart is a field rather than a constant, so moving the directory up reserves
// everything below it by arithmetic that was already there.
//
// A DISK MADE BEFORE THIS HAS ZERO HERE, which reads as "no boot area", which is true.
// The same shape as the version two parent field: the value an older disk already holds
// is the correct answer rather than something needing conversion.
//
// TWO SLOTS, ALWAYS, and the reason is that a boot slot is raw blocks. A file being
// rewritten is protected by writing a temporary and renaming it, and there is no name
// here to rename - so a machine interrupted while updating its only boot slot would not
// boot at all, which is the one failure on this disk with no way back. Writing the slot
// that is not live and then moving one byte turns that into a machine that boots the
// version it had before.
//
// block 0 the superblock
// 1 .. bootBlocks slot 0
// bootBlocks+1 .. 2*bootBlocks slot 1
// directoryStart .. the directory, and then files
#define SBFS_BOOT_SLOTS 2
#define SBFS_FIRST_BOOT_BLOCK 1
// ---- Directory entries ----
//