Ruled 2026-10-07. BLOCK, BUFFER, UPDATE, SAVE-BUFFERS and EMPTY-BUFFERS are each one kernel request on port 0, by block number only. The node has a window of four slots in its memory, as a v3 VM has; the kernel copies blocks into it, keeps the record of which block is in which slot, and decides when a block is written (v4/system/blocks.c). The node keeps no record and gives the kernel no address, so a request cannot overwrite the node's code. When a block is written stays FORTH-79's: UPDATE marks it. When the chain of devices changes the slots are let go, as in v3. The window is 512 cells more than the two buffers were; the dictionary space ends that much lower, at 13824. MESH.md 8.5 had said, from the review, that a v3 VM's BLOCK is the kernel's buffer. It is not, and the section now says what was reported, what v3 does, and what was ruled. make -C v4 test, sanitize and hosted-check pass; amd64, aarch64 and riscv64 boot, POST 538 of 538, the same hashes on all six: logs/20261007-092835, -093112, -093456. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
85 lines
4.0 KiB
C
85 lines
4.0 KiB
C
/* blocks.h -- a node asks its kernel for a block.
|
|
* docs/v4.0.0/MESH.md section 8, docs/v4.0.0/ENGINE.md 3.3,
|
|
* docs/v4.0.0/V3-PARITY.md 1d.
|
|
*
|
|
* A node only ever asks for a block by number, and it asks the kernel: a
|
|
* request written to the port where its kernel is, as any kernel word is.
|
|
* This is v3's way (v3/src/word_source/block_words.c). The node has a
|
|
* WINDOW in its memory, V4_BLOCK_SLOTS slots of 256 cells, as a v3 VM has
|
|
* four slots of 1 KiB at the top of its memory. The kernel keeps the
|
|
* record of which block is in which slot and does all the copying, and it
|
|
* writes into the window and nowhere else in the node. The requests, the
|
|
* same for every node:
|
|
*
|
|
* V4_REQ_BLOCK ( n -- waddr status ) the slot that holds block n, read
|
|
* from storage if it is not in one
|
|
* V4_REQ_BUFFER ( n -- waddr status ) a slot for block n, of zeros if it
|
|
* is not in one: nothing is read
|
|
* V4_REQ_UPDATE ( -- status ) the block most recently asked for
|
|
* is marked changed
|
|
* V4_REQ_SAVE_BUFFERS ( -- status ) every block marked is written
|
|
* V4_REQ_EMPTY_BUFFERS ( -- ) every slot is let go; nothing is
|
|
* written
|
|
*
|
|
* Their numbers are below zero: the requests a host names for its own
|
|
* words (KERNEL-WORD) count up from 1.
|
|
*
|
|
* waddr is the word address of the slot, or 0 when the status is not 0.
|
|
* The status is 0; or V4_BLOCK_RANGE, there is no such block; or
|
|
* V4_BLOCK_REFUSED: storage would not have a block that had to be written,
|
|
* the stack did not hold the request's argument, or the window is not all
|
|
* in the node's memory.
|
|
*
|
|
* WHEN A BLOCK IS WRITTEN is FORTH-79's: UPDATE marks it, and it is written
|
|
* by SAVE-BUFFERS or when its slot is wanted for another block. (v3's
|
|
* UPDATE copies the slot to the kernel at once; the standard is followed.)
|
|
* A slot whose block is not marked is taken before one whose block is. A
|
|
* block that storage would not take is let go of: its slot is empty.
|
|
*
|
|
* When the kernel's chain of devices changes, everything in the slots is
|
|
* let go and nothing of it is written, as v3 does (blk_vm_check_epoch).
|
|
*
|
|
* A block is 1024 bytes and 256 cells, four bytes to a cell, the first
|
|
* lowest, whatever the cell width: a block read leaves the rest of each
|
|
* cell zero, and a write takes the low 32 bits.
|
|
*
|
|
* The blocks are the kernel's block subsystem's (v3/src/block_subsystem.c).
|
|
* Who may have which block is not checked here yet (MESH.md 8.4).
|
|
*/
|
|
#ifndef V4_BLOCKS_H
|
|
#define V4_BLOCKS_H
|
|
|
|
#include "v4/node.h"
|
|
|
|
#define V4_REQ_BLOCK (-1)
|
|
#define V4_REQ_BUFFER (-2)
|
|
#define V4_REQ_UPDATE (-3)
|
|
#define V4_REQ_SAVE_BUFFERS (-4)
|
|
#define V4_REQ_EMPTY_BUFFERS (-5)
|
|
|
|
#define V4_BLOCK_OK 0
|
|
#define V4_BLOCK_REFUSED 2
|
|
#define V4_BLOCK_RANGE 3
|
|
|
|
#define V4_BLOCK_SLOTS 4u
|
|
|
|
/* What the kernel keeps for one node. */
|
|
typedef struct {
|
|
v4_cell window; /* word address of the first slot */
|
|
uint32_t block[V4_BLOCK_SLOTS]; /* the block in each slot; 0: none */
|
|
unsigned char changed[V4_BLOCK_SLOTS]; /* UPDATEd and not yet written */
|
|
unsigned next; /* where the search for a slot to take begins */
|
|
int last; /* the slot most recently asked for; -1: none */
|
|
uint64_t epoch; /* the chain as it was when the slots were filled */
|
|
} v4_blocks;
|
|
|
|
/* A node's window is at `window`, and nothing is in it. */
|
|
void v4_blocks_init(v4_blocks *w, v4_cell window);
|
|
|
|
/* If `request` is one of the five, serve it for the node and return 1.
|
|
* Otherwise touch nothing and return 0. The node is stopped, blocked at
|
|
* its port, when this is called. */
|
|
int v4_blocks_serve(v4_blocks *w, v4_node *n, v4_cell request);
|
|
|
|
#endif /* V4_BLOCKS_H */
|