# `Hyper.SuidHelper.Dmsetup`
[🔗](https://github.com/harmont-dev/hyper/blob/main/lib/hyper/suid_helper/dmsetup.ex#L1)

device-mapper operations (snapshot / thin), via the setuid helper's `dmsetup` tool.

# `err`

```elixir
@type err() :: Hyper.SuidHelper.err()
```

# `create_snapshot`

```elixir
@spec create_snapshot(String.t(), Path.t(), Path.t(), pos_integer()) ::
  {:ok, Path.t()} | {:error, err()}
```

Create a read-only dm-snapshot device named `name`, layering `cow_dev`
(exception store) over `origin_dev`. `sectors` is the logical size in 512-byte
sectors. Returns the `/dev/mapper/<name>` path.

# `create_snapshot_rw`

```elixir
@spec create_snapshot_rw(String.t(), Path.t(), Path.t(), pos_integer()) ::
  {:ok, Path.t()} | {:error, err()}
```

Create a *writable* dm-snapshot device named `name` over `origin_dev`, with
`cow_dev` as its exception store. Writes to the device land in `cow_dev`,
which is how a fork's delta layer file is populated. Same table as
`create_snapshot/4`, minus `--readonly`.

# `create_thin_external`

```elixir
@spec create_thin_external(
  String.t(),
  Path.t(),
  non_neg_integer(),
  pos_integer(),
  Path.t()
) ::
  {:ok, Path.t()} | {:error, err()}
```

Create a dm-thin volume `name` of `sectors` from thin device id `dev_id` in
`pool_dev`, with `origin_dev` as its read-only external origin. Returns
`/dev/mapper/<name>`.

# `create_thin_pool`

```elixir
@spec create_thin_pool(
  String.t(),
  Path.t(),
  Path.t(),
  pos_integer(),
  pos_integer(),
  non_neg_integer()
) :: {:ok, Path.t()} | {:error, err()}
```

Create a dm-thin pool `name` backed by `meta_dev` (metadata loop) and
`data_dev` (data loop). `sectors` is the data device size; `block_sectors` the
allocation block size; `low_water` the low-water mark in blocks. Returns the
`/dev/mapper/<name>` path.

# `list`

```elixir
@spec list() :: {:ok, [String.t()]} | {:error, err()}
```

Names of every device-mapper device currently present on this host.

# `message`

```elixir
@spec message(String.t(), String.t()) :: :ok | {:error, err()}
```

Send a thin-pool `message` to dm device `name`.

# `remove`

```elixir
@spec remove(String.t()) :: :ok | {:error, err()}
```

Remove the dm device `name`.

# `resume`

```elixir
@spec resume(String.t()) :: :ok | {:error, err()}
```

Resume the suspended dm device `name`.

# `suspend`

```elixir
@spec suspend(String.t()) :: :ok | {:error, err()}
```

Suspend dm device `name`, flushing queued I/O. Pair with `resume/1`.

# `test_system`

```elixir
@spec test_system() :: :ok | {:error, term()}
```

Verify the kernel exposes the dm targets we use (snapshot, thin, thin-pool).

Routes through the setuid helper: `dmsetup targets` opens `/dev/mapper/control`,
which needs root, and the BEAM runs unprivileged. The helper validates its
configured `dmsetup` binary before running it, so a missing or unsafe binary
surfaces here too.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
