Files
Derek McGowan f75817eb3b erofs: record where a layer blob is
A layer served from the layer content cache was symlinked into the
snapshot as its layer.erofs. That put a path inside the snapshot
directory aliasing a blob owned by the operator and shared with every
other snapshot of that layer. Everything written to that path went
straight into the cache entry. Each write site then needed its own
guard: the differ had to refuse to apply, Commit had to refuse to
convert through a dangling link, and Remove had to avoid clearing
IMMUTABLE_FL on a file it did not own. A missed guard corrupted content
shared across images. A pruned entry left a dangling link that read as
an absent blob on one path and as populated content on another.

Record where the blob is on the snapshot and mount it from there.
Nothing in the snapshot directory refers to content it does not own. A
stray write creates a local file, conversion cannot reach the cache, and
removal has nothing to follow. The guards Commit and Remove needed for a
symlink are gone. The differ still refuses, on the read-only mounts the
snapshotter hands out.

resolveBlob is the one place a blob is located. It reports whether the
blob is already populated, meaning there is nothing to apply or convert,
and whether it belongs to this snapshot, meaning it may be written.
Mounts are then assembled without consulting the filesystem to find out
what a layer is. A source that does not resolve is an error on every
path, including the parentless path in mounts(). A flattened parent's
device= is resolved the same way.

fsverity is only measured for a blob the snapshot owns. Measuring a
cache entry would require the operator to enable fsverity on content
this snapshotter never wrote. NewSnapshotter already rejects fsverity
together with the layer content cache.

The record is kept in labels outside the containerd.io/snapshot/
namespace. Labels in that namespace are inherited from image
annotations, which would let an image name any path on the host. The
same filter runs on everything the metadata snapshotter passes down. A
client cannot set these labels, and cannot send them back after reading
them through Stat. Commit and Update carry them across.

The dm-verity sidecar is read from beside the cache entry. Nothing is
copied into the snapshot. The sidecar cannot fall out of step with the
blob it pins. An entry required to have one is rejected at Prepare.

Signed-off-by: Derek McGowan <derek@mcg.dev>
2026-09-11 17:49:25 -07:00
..