nx_vfsblock_lib.nx
buildroot/runtime/nx_vfsblock_lib.nx
about
nx_vfsblock_lib.nx -- the SOVEREIGN block-backed VFS + write-ahead JOURNAL library (NishiOS rung 4: closes the
FILESYSTEM census gap "block-backed VFS mount + journaling"). ONE on-disk format (NSFS v2) designed once so the
mount gate (nx_vfs_blockfs) and the journal gate (nx_journal) share it -- no format churn, rule-15 DRY.
ON-DISK LAYOUT (NSFS v2, 256B blocks, 1024 blocks = 256KB image; ADDITIVE-ONLY data, rule 13):
block 0 SUPERBLOCK: [0]magic'NSFS' [8]version=2 [16]nblocks [24]next_free [32]j0 [40]nj [48]ino0 [56]ni [64]data0
blocks 1..32 JOURNAL: block 1 = header [0]jmagic'NSJL' [8]seq [16]nrec [24]committed [32]sum [40+8j]target_j (j<27);
blocks 2..28 = record payloads (the FULL new content of the target block = physical redo WAL, jbd2-class)
blocks 33..96 INODE TABLE (64 inodes, one per block): [0]used [8]type(1=dir,0=file) [16]parent [24]size
[32]start(data block#) [40]nblk [48]datasum [64..127]name(63B+NUL). Root = inode 0 (dir, parent -1).
blocks 97.. DATA (bump-allocated contiguous, never reused = history-preserving)
HIERARCHY = the nx_vfs model persisted: children are inodes whose parent field points at the dir inode; path
resolution walks components from root against the ON-DISK inode table. MOUNT = validate superblock (magic+version)
-> REPLAY the journal (crash recovery) -> validate root. WAL protocol: stage payloads+targets -> COMMIT (single
flag write after a checksum over the staged records) -> APPLY to home blocks -> CHECKPOINT (clear committed).
Crash after commit -> replay re-applies (idempotent physical copies). Crash before commit -> txn discarded, home
blocks untouched BY CONSTRUCTION (records live only in the journal region). Corrupt committed txn -> checksum
REFUSES the replay and discards (the jbd2 rule: an unprovable txn is never applied).
Txn cap: 27 record blocks -> journaled creates up to ~25 data blocks (~6.4KB); bigger files go through the direct
path at image-build time. NEVER-BRICK: operates on RAM + an image file, writes 0 firmware. license_tier: ORIGINAL
dependencies 1 imports · 4 importers
imports: nx_syscalls.nx
imported by: nx_journal.nxnx_pabi.nxnx_spore_boot.nxnx_vfs_blockfs.nx
structs
| none |
consts
| 24 | const VB_BS: i64 = 256 |
| 25 | const VB_NB: i64 = 1024 |
| 26 | const VB_MAGIC: i64 = 0x4E534653 |
| 27 | const VB_VER: i64 = 2 |
| 28 | const VB_J0: i64 = 1 |
| 29 | const VB_NJREC: i64 = 27 |
| 30 | const VB_INO0: i64 = 33 |
| 31 | const VB_NI: i64 = 64 |
| 32 | const VB_DATA0: i64 = 97 |
| 33 | const VB_JMAGIC: i64 = 0x4E534A4C |
functions
| 35 | func vb_rd(a: *u8, o: i64) -> i64 { var v: i64=0; var i: i64=0; while i<8 { v=v|((a[o+i] as i64)<<(i*8)); i=i+1 } return v } |
| 36 | func vb_wr(a: *u8, o: i64, v: i64) -> i64 { var i: i64=0; while i<8 { a[o+i]=((v>>(i*8))&255) as u8; i=i+1 } return 0 } |
| 37 | func vb_ino(i: i64) -> i64 { return (VB_INO0+i)*VB_BS } |
| 38 | func vb_sum(a: *u8, off: i64, n: i64) -> i64 { var s: i64=0; var i: i64=0; while i<n { s=s*131+(a[off+i] as i64); i=i+1 } return s } |
| 39 | func vb_nm_set(a: *u8, boff: i64, name: *u8) -> i64 { var i: i64=0; while i<63 { if name[i]==(0 as u8) { a[boff+64+i]=0 as u8; i=63 } else { a[boff+64+i]=name[i]; i=i+1 } } a[boff+64+63]=0 as u8; return 0 } |
| 40 | func vb_nm_eq(a: *u8, boff: i64, name: *u8) -> i64 { var i: i64=0; while i<64 { let cn: i64=name[i] as i64; let cb: i64=a[boff+64+i] as i64; if cn!=cb { return 0 } if cn==0 { return 1 } i=i+1 } return 1 } called by 1: vb_lookup |
| 43 | func vb_format(a: *u8) -> i64 |
| 54 | func vb_mount(a: *u8) -> i64 |
| 66 | func vb_alloc_inode(a: *u8) -> i64 { var i: i64=1; while i<VB_NI { if vb_rd(a,vb_ino(i))==0 { return i } i=i+1 } return 0-1 } |
| 67 | func vb_lookup(a: *u8, parent: i64, name: *u8) -> i64 |
| 72 | func vb_mkdir(a: *u8, parent: i64, name: *u8) -> i64 |
| 81 | func vb_create(a: *u8, parent: i64, name: *u8, data: *u8, len: i64) -> i64 |
| 97 | func vb_resolve(a: *u8, path: *u8) -> i64 |
| 113 | func vb_read(a: *u8, idx: i64, out: *u8) -> i64 |
| 119 | func vb_verify(a: *u8, idx: i64) -> i64 |
| 124 | func vb_lscount(a: *u8, dir: i64) -> i64 { var c: i64=0; var i: i64=0; while i<VB_NI { if vb_rd(a,vb_ino(i))==1 { if vb_rd(a,vb_ino(i)+16)==dir { if i!=dir { c=c+1 } } } i=i+1 } return c } |
| 127 | func vb_save(a: *u8, path: *u8) -> i64 |
| 133 | func vb_load(a: *u8, path: *u8) -> i64 |
| 141 | func vbj_hdr() -> i64 { return VB_J0*VB_BS } |
| 142 | func vbj_rec(j: i64) -> i64 { return (VB_J0+1+j)*VB_BS } |
| 143 | func vbj_begin(a: *u8) -> i64 |
| 150 | func vbj_add(a: *u8, tb: i64, src: *u8, len: i64) -> i64 |
| 160 | func vbj_sumrecs(a: *u8) -> i64 |
| 168 | func vbj_commit(a: *u8) -> i64 { let h: i64=vbj_hdr(); let s: i64=vbj_sumrecs(a); vb_wr(a,h+32,s); vb_wr(a,h+24,1); return 0 } |
| 169 | func vbj_apply(a: *u8) -> i64 |
| 176 | func vbj_checkpoint(a: *u8) -> i64 { let h: i64=vbj_hdr(); vb_wr(a,h+24,0); return 0 } |
| 178 | func vbj_replay(a: *u8) -> i64 |
| 191 | func vbj_mkdir_tx(a: *u8, parent: i64, name: *u8) -> i64 |
| 205 | func vbj_create_tx(a: *u8, parent: i64, name: *u8, data: *u8, len: i64) -> i64 |