The node's single dm-thin pool. On start it materialises two sparse backing
files in scratch_dir (metadata + data), attaches them as writable loop
devices, zeroes the metadata (so the kernel treats it as a fresh pool), and
creates the hyper-thinpool device-mapper pool.
create_external/3 provisions a thin volume whose unwritten blocks read
through to a read-only external origin (the composed image device) and whose
writes land in the pool - the per-VM writable rootfs. Thin device ids are a
bump pointer plus a freed-id stack, mirroring Hyper.Node.Users.
Summary
Functions
Returns a specification to start this module under a supervisor.
Provision a thin volume of sectors over read-only origin_dev.
Remove thin volume name and free its thin device id.
The provisioned ranges of thin device thin_id, from the pool's own
metadata. Because the volume reads through an external origin, provisioned
blocks are exactly the blocks ever written — the divergence a fork publish
must copy, discovered without scanning the device.
Take an internal snapshot of live thin volume origin_name (thin id
origin_id) and activate it as name, sharing the pool's blocks COW-style.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec create_external(String.t(), Path.t(), pos_integer()) :: {:ok, %{dev: Path.t(), id: non_neg_integer()}} | {:error, term()}
Provision a thin volume of sectors over read-only origin_dev.
@spec destroy(String.t(), non_neg_integer()) :: :ok
Remove thin volume name and free its thin device id.
@spec mappings(non_neg_integer()) :: {:ok, %{block_sectors: pos_integer(), ranges: [[non_neg_integer()]]}} | {:error, term()}
The provisioned ranges of thin device thin_id, from the pool's own
metadata. Because the volume reads through an external origin, provisioned
blocks are exactly the blocks ever written — the divergence a fork publish
must copy, discovered without scanning the device.
Reserves the pool's metadata snapshot for the duration of the dump and always releases it (one reserve may exist at a time; this call is serialized by the pool server).
@spec snapshot(String.t(), String.t(), non_neg_integer(), pos_integer(), Path.t()) :: {:ok, %{dev: Path.t(), id: non_neg_integer()}} | {:error, term()}
Take an internal snapshot of live thin volume origin_name (thin id
origin_id) and activate it as name, sharing the pool's blocks COW-style.
dm-thin requires the origin suspended while create_snap is sent; the origin
is resumed on every path out, so a failed snapshot never leaves the parent
VM's I/O frozen. The snapshot is activated with the same external origin
(origin_dev) as its parent — unprovisioned reads must keep resolving
through the composed RO image chain.
@spec start_link(keyword()) :: GenServer.on_start()