Repository navigation
Add remote write head #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+1,159
−1
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
c868b30
Add fls-wh: a block-device write head for remote system writes
mangelajo b9dd92c
fix: fls-wh protocol robustness and bump write chunks to 8 MiB
mangelajo 1c0651d
fix: DATA error drain over-consumed the failed chunk
mangelajo d40f619
Add ZERO command; CRC from gityf/crc
mangelajo 420dd75
Fix remote I/O recovery and SYNC errors
mangelajo d1b6810
Add remote SIZE query
mangelajo 5e44128
Drop the unused SKIP opcode
mangelajo 520a9cd
Exit on the first ERR instead of recovering
mangelajo 68db822
Validate DATA CRC before writing to the device
mangelajo 85d0ad0
Test that the write head reports ERR and exits immediately
mangelajo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| *.o | ||
| flswh-* | ||
| stubs/*.so_stub.so* |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| FROM fedora:latest | ||
|
|
||
| # gcc: native compiler (runs the native test; system headers) | ||
| # gcc-aarch64-linux-gnu: cross compiler (provides aarch64-linux-gnu-gcc) | ||
| # binutils-aarch64-linux-gnu: GNU ld (provides aarch64-linux-gnu-ld) | ||
| # python3: runs stubs/so_stub.py; make: the build itself | ||
| RUN dnf install -y gcc gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu python3 make \ | ||
| && dnf clean all | ||
|
|
||
| # The Makefile and so_stub.py hardcode the QNX-style tool name; map it | ||
| # to Fedora's. (ld.lld is already named correctly by the lld package.) | ||
| RUN ln -s /usr/bin/aarch64-linux-gnu-gcc /usr/local/bin/aarch64-elf-gcc |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| # fls-wh — a block-device write head, built for a QNX aarch64 target. | ||
| # | ||
| # Built from: | ||
| # - this source (fls-wh.c, start.S) | ||
| # - standard C/POSIX headers (include/) | ||
| # - a minimal JSON symbol manifest (stubs/*.min.json) <- source of truth | ||
| # - open tooling: aarch64-elf-gcc (GCC) + ld.lld (LLVM) + stubs/so_stub.py | ||
| # | ||
| # The stub .so files are build artifacts (gitignored). At runtime, the | ||
| # target's dynamic linker resolves the SONAME (libc.so.5) to the library | ||
| # present on the system. | ||
| # | ||
| # Container build: `make container-build` builds the Containerfile with | ||
| # podman and runs the whole build inside it (fedora + cross toolchain). | ||
| # | ||
| # `make help` prints this file's `##`-annotated targets, grouped by | ||
| # `##@` section headers. | ||
|
|
||
| CC := aarch64-elf-gcc | ||
| LD := ld.lld | ||
| CFLAGS := -I include | ||
| LDFLAGS := -dynamic-linker /usr/lib/ldqnx-64.so.2 | ||
| STUBDIR := stubs | ||
|
|
||
| CONTAINER ?= podman | ||
| IMAGE ?= fls-wh-builder | ||
|
|
||
| # host arch/os for the native binary name (flswh-<arch>-<os>) | ||
| UNAME_M := $(shell uname -m) | ||
| UNAME_S := $(shell uname -s) | ||
| NATIVE_ARCH := $(if $(filter arm64,$(UNAME_M)),aarch64,$(UNAME_M)) | ||
| NATIVE_OS := $(if $(filter Darwin,$(UNAME_S)),darwin,$(if $(filter Linux,$(UNAME_S)),linux,$(UNAME_S))) | ||
| NATIVE_BIN := flswh-$(NATIVE_ARCH)-$(NATIVE_OS) | ||
|
|
||
| .PHONY: all clean stubs native container container-build test help | ||
|
|
||
| ##@ build | ||
| all: flswh-aarch64-qnx7 ## build fls-wh for QNX aarch64 (default) | ||
|
|
||
| flswh-aarch64-qnx7: fls-wh.o start.o stubs ## link the QNX aarch64 binary | ||
| $(LD) -o $@ fls-wh.o start.o -L$(STUBDIR) -l:libc.min.so_stub.so $(LDFLAGS) | ||
|
|
||
| native: $(NATIVE_BIN) ## build fls-wh for the host (system compiler, no stubs) | ||
|
|
||
| $(NATIVE_BIN): fls-wh.c | ||
| cc -O2 $< -o $@ | ||
|
|
||
| # build the minimal stub .so from the minimal JSON (artifacts, gitignored) | ||
| stubs: ## build the stub .so files from the JSON manifests | ||
| python3 stubs/so_stub.py $(STUBDIR)/libc.min.json -o $(STUBDIR)/libc.min.so_stub.so | ||
|
|
||
| fls-wh.o: fls-wh.c | ||
| $(CC) $(CFLAGS) -c $< -o $@ | ||
|
|
||
| start.o: start.S | ||
| $(CC) -c $< -o $@ | ||
|
|
||
| clean: ## remove all build artifacts | ||
| rm -f flswh-* fls-wh.o start.o $(STUBDIR)/*.so_stub.so* | ||
|
|
||
| ##@ test | ||
| test: ## native test: build with the system compiler, run, assert | ||
| python3 test.py | ||
|
|
||
| ##@ container (podman) | ||
| container: ## build the fedora container image | ||
| $(CONTAINER) build -t $(IMAGE) . | ||
|
|
||
| container-build: container ## build fls-wh inside the container (GNU ld) | ||
| $(CONTAINER) run --rm -v $(PWD):/src -w /src $(IMAGE) make \ | ||
| LD=aarch64-linux-gnu-ld STUB_LD=aarch64-linux-gnu-ld | ||
|
|
||
| help: ## show this help | ||
| @awk 'BEGIN {FS = ":.*##"} \ | ||
| /^##@/ { printf "\n\033[1;33m%s\033[0m\n", substr($$0, 5) } \ | ||
| /^[a-zA-Z0-9_-]+:.*##/ { printf " \033[36m%-18s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| # fls-wh — the remote write head | ||
|
|
||
| `fls-wh` is a small C program that runs on a remote system (QNX today; | ||
| extensible to others, e.g. a U-Boot command talking over the network) and | ||
| writes framed commands to a raw block device (e.g. `/dev/emmc0`). It is the | ||
| remote counterpart of the local writer in `src/fls/block_writer.rs` (which | ||
| uses `O_DIRECT` on Linux/macOS). QNX has no `O_DIRECT`, so durability comes | ||
| from an explicit `SYNC` (`fdatasync`; `fsync` on macOS, which has no | ||
| `fdatasync`). | ||
|
|
||
| ## Usage | ||
|
|
||
| ``` | ||
| ./flswh-<arch>-<os> <device> | ||
| ``` | ||
|
|
||
| Opens `<device>` (`O_RDWR`), reports its size (`READY`), then reads framed | ||
| commands from stdin and writes them to the device, emitting framed records to | ||
| stdout. Intended to be driven by a remote client (e.g. over SSH). QUIT or | ||
| EOF exits. | ||
| Device I/O errors are reported (`ERR`), after which the write head exits; | ||
| the client treats any `ERR` as fatal. | ||
|
|
||
| ## Protocol | ||
|
|
||
| Frame (both directions): `[magic:4][opcode:1][payload_len:u32 LE][payload]`, | ||
| little-endian throughout. The magic (`FLSW`) is a sync header: the reader | ||
| scans for it to resync after any corruption. | ||
|
|
||
| | | opcode | | opcode | | ||
| |---|---|---|---| | ||
| | **Requests** | `DATA 0x01` `SEEK 0x03` `SYNC 0x04` `QUIT 0x05` `READ 0x06` `ZERO 0x09` `SIZE 0x0a` | **Responses** | `READY 0x81` `OK 0x82` `PROG 0x83` `ERR 0x84` `DONE 0x85` `READ_DATA 0x86` `SIZE 0x89` | | ||
| | **Reserved** | `AUTH 0x07` `HELLO 0x08` | | `AUTH_RESULT 0x87` `HELLO 0x88` | | ||
|
|
||
| The `READY` payload is `version:u8 + size:u64` (total device bytes, measured | ||
| at open); the protocol version is currently 1. `DATA` is | ||
| `size:u32 + content + crc:u32` (CRC32-IEEE, capped at 8 MiB); the payload is | ||
| staged and CRC-validated before the device is written, so a corrupt chunk | ||
| leaves no bytes behind. | ||
| `READ` is `len:u64` (reads from the current offset, advances it, capped at | ||
| 1 MiB) and returns `READ_DATA` with the bytes. `ZERO` is `len:u64` — writes | ||
| that many zeros from the current offset and advances it, sending only the 8 | ||
| length bytes over the wire (for filling regions without transferring bytes). | ||
|
|
||
| `SIZE` has no request payload and returns `SIZE 0x89` with `size:u64` (the | ||
| same total device bytes measured at open), without changing the cursor. If | ||
| the size could not be determined, it returns `ERR` with the original errno; | ||
| the startup `READY` uses zero for unknown size. | ||
| Before writing an image, the client can use `READY` or `SIZE` to check | ||
| `image_size <= device_size - write_offset` after checking that | ||
| `write_offset <= device_size`. For sparse images, compare the expanded size. | ||
|
|
||
| ## Build | ||
|
|
||
| Binaries are named `flswh-<arch>-<os>` (matching the `fls` artifact scheme): | ||
|
|
||
| - **QNX aarch64** (cross): `make` (or `make -C remote` from the repo root) → `flswh-aarch64-qnx7`. Needs an aarch64 cross gcc toolchain (the Makefile's `aarch64-elf-gcc` + `ld.lld` names map to any gcc cross toolchain; `make container-build` uses Fedora's in a container). | ||
| - **Native** (host, incl. macOS): `make native` → `flswh-<arch>-<os>` (e.g. `flswh-aarch64-darwin`, `flswh-x86_64-linux`). Uses the system compiler and system headers, no stubs. | ||
|
|
||
| ## Test | ||
|
|
||
| `python3 test.py` — builds the source with the system compiler, drives it with | ||
| a framed command script against a temp file, and asserts the records and bytes. |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.