# mvirt 0.14.13

migrations: no
wire: unchanged
rev: 2cde371e1f6f595e227d0963aefc6709a4d9640a

0.14.13 — the largest write the device invites was the one it refused

0.14.12 stopped the guest wedging on its first journal commit. It then got far
enough to hit the defect underneath: its largest legal write came back S_IOERR,
ext4 remounted the root read-only about five seconds into boot, and every service
that has to write failed with it — sshd's host keys, logind, user-sessions, both
gettys, cloud-final. The VM reached `multi-user.target` and had nothing running on
it. From the recorded console:

  I/O error, dev vda, sector 1933312 op 0x1:(WRITE) flags 0x4800 phys_seg 126
  EXT4-fs (vda1): failed to convert unwritten extents to written extents
                  -- potential data loss!  (inode 24, error -5)
  EXT4-fs (vda1): Remounting filesystem read-only

`phys_seg 126` is exactly the `seg_max` the device advertised. virtio-blk frames
every request with a 16-byte header descriptor and a status descriptor, so a guest
that uses all 126 data segments hands the backend 128 descriptors — and the parse
compared that total against the very constant it had advertised as `seg_max`. The
contract the device offers and the limit it enforces differed by exactly the two
framing descriptors, in the direction that makes the offer a lie.

- `MAX_CHAIN_DESCRIPTORS = 128` is what the parse enforces on the whole chain.
- `MAX_SEGMENTS = MAX_CHAIN_DESCRIPTORS - 2` is what `seg_max` advertises.
- The test now asserts the direction that was broken and untested: a chain of
  header + `seg_max` + status must be ACCEPTED. It is red against the old
  single-constant form.

This could not be observed before 0.14.12. While the driver's ring overflowed
first, no chain that long was ever built, so the cap was never reached — one defect
kept the other invisible.


## Upgrading

Point your flake's `mvirt` input at this release and redeploy the control-plane
host first, then each node in turn:

```
nix run .#colmena -- apply boot --reboot --on <control-plane host>
nix run .#colmena -- apply boot --reboot --on <node>   # one at a time
```

This release adds no migrations, so the control-plane host rolls back the same way
a node does: boot the previous NixOS generation.
