Some checks failed
Check / eval (push) Has been cancelled
The machine flake's git-tracked settings file is system state, not "theme" only — rename it to state.json. CLI becomes nomarchy-state-sync with a nomarchy-theme-sync symlink for scripts and muscle memory. Eval (mkFlake, doctor, lifecycle) still accepts theme-state.json; the next write migrates to state.json and removes the legacy file. Documented in MIGRATION.md; drop the CLI alias after release notes.
479 lines
19 KiB
Markdown
479 lines
19 KiB
Markdown
# Migrating an existing NixOS machine to Nomarchy (no reinstall)
|
||
|
||
If your machine already runs NixOS, you do **not** need the installer or a
|
||
reformat to adopt Nomarchy. Nomarchy is a flake; "installing" it onto an
|
||
existing NixOS box means pointing `nixos-rebuild` at a Nomarchy‑based flake
|
||
that reuses your current `hardware-configuration.nix`. Nothing repartitions,
|
||
and your `/home` is never written to by an activation.
|
||
|
||
This guide is written generically, with **TuringMachine** — a Lenovo AMD
|
||
Ryzen 7840U / Radeon 780M laptop, LUKS + btrfs, systemd‑boot — as the
|
||
concrete worked example. Substitute your own values where called out.
|
||
|
||
> **The promise:** every step below is reversible. You keep three
|
||
> independent rollback nets (NixOS generations, a btrfs snapshot, and the
|
||
> fact that `nixos-rebuild test` never changes the boot default), and your
|
||
> files live on a separate subvolume that no config switch touches.
|
||
|
||
---
|
||
|
||
## 0. Is your machine a good candidate?
|
||
|
||
Migration is cleanest when your machine already matches Nomarchy's
|
||
assumptions. Check each:
|
||
|
||
| Nomarchy expects | Check it | If it differs |
|
||
|---|---|---|
|
||
| **systemd‑boot** | `bootctl status` → "Product: systemd‑boot" | GRUB works too; keep your loader config in `system.nix` |
|
||
| **btrfs** with `@`/`@home` subvolumes | `findmnt -t btrfs` | ext4/xfs boot fine — you just don't get snapshots |
|
||
| `@snapshots` + `@home-snapshots` subvols | in `findmnt` output | snapper features need them; create them or skip snapshots |
|
||
| **LUKS** (optional, themed prompt) | `lsblk -f` shows `crypto_LUKS` | none — LUKS is optional |
|
||
| Already a **flake** config | `test -f /etc/nixos/flake.nix` | fine either way; you'll write a fresh flake regardless |
|
||
|
||
**Installer vs migration snapshot layout.** A fresh Nomarchy install
|
||
(disko) creates a top-level `@snapshots` subvolume mounted at
|
||
`/.snapshots`, then a first-boot oneshot makes a *nested*
|
||
`/home/.snapshots` under `@home` for snapper's home timeline — it does
|
||
**not** create a separate top-level `@home-snapshots`. Migration machines
|
||
(e.g. TuringMachine) may already use top-level `@snapshots` **and**
|
||
`@home-snapshots`; that is fine. Snapper only needs a `.snapshots` path
|
||
under each tracked subvolume (`/` and `/home`), so either layout works —
|
||
reuse what you have, or create the missing pieces if you want snapper
|
||
without reformatting.
|
||
|
||
TuringMachine matches all of these, including the `@snapshots` /
|
||
`@home-snapshots` subvolumes — so snapper works with zero disk work.
|
||
|
||
**Version note.** Nomarchy pins `nixos-26.05`. If you're on an older release
|
||
(TuringMachine is on **25.11**), the migration folds a one‑release upgrade
|
||
into the switch. That's normal and supported — read the
|
||
[NixOS 26.05 release notes](https://nixos.org/manual/nixos/stable/release-notes)
|
||
for option/package renames, and lean on generations if something regresses.
|
||
|
||
---
|
||
|
||
## 1. The two rules that protect your data
|
||
|
||
1. **Never bump `system.stateVersion`.** It is an on‑disk/service
|
||
compatibility marker tied to when the machine was *first installed* — not
|
||
the nixpkgs version. Nomarchy's template ships `26.05`; you **must** change
|
||
it back to your machine's original value. Find yours:
|
||
|
||
```console
|
||
$ nixos-option system.stateVersion # or: nix eval .#nixosConfigurations.<host>.config.system.stateVersion
|
||
"24.11"
|
||
```
|
||
|
||
*(TuringMachine: `24.11`.)*
|
||
|
||
2. **`/home` is never touched by an activation.** A `nixos-rebuild switch`
|
||
swaps the system generation; your data subvolume is untouched. The Phase 0
|
||
snapshot is belt‑and‑suspenders, not a necessity for file safety.
|
||
|
||
---
|
||
|
||
## Phase 0 — Safety net (nothing changes yet)
|
||
|
||
```bash
|
||
# Read-only btrfs snapshots of root and home — instant rollback targets.
|
||
sudo btrfs subvolume snapshot -r / /.snapshots/pre-nomarchy-root
|
||
sudo btrfs subvolume snapshot -r /home /home/.snapshots/pre-nomarchy-home
|
||
|
||
# Freeze your current config as a clean git baseline.
|
||
cd /etc/nixos && git add -A && git commit -m "pre-nomarchy baseline" || true
|
||
```
|
||
|
||
You are currently booted in a known‑good generation; it remains in the
|
||
systemd‑boot menu throughout. Worst case at any later step: reboot and pick
|
||
it.
|
||
|
||
---
|
||
|
||
## Phase 1 — Build the Nomarchy flake alongside (no switch)
|
||
|
||
Stand the new config up in a working directory and **build** it without
|
||
activating. This is the real safety line: iterate here until it builds green
|
||
before anything touches the running system.
|
||
|
||
```bash
|
||
git clone https://git.bemagri.xyz/bernardo/nomarchy.git ~/nomarchy-migrate
|
||
cd ~/nomarchy-migrate
|
||
# Or start from the downstream template:
|
||
# nix flake init -t "git+https://git.bemagri.xyz/bernardo/nomarchy.git?ref=v1"
|
||
# (produces flake.nix/system.nix/home.nix/…)
|
||
```
|
||
|
||
A Nomarchy downstream flake owns exactly five files. Assemble them:
|
||
|
||
### `hardware-configuration.nix` — reuse yours unchanged
|
||
|
||
Copy your **existing** hardware config in verbatim. This is what preserves
|
||
your disks, LUKS, btrfs subvolumes and swap — the reason no reinstall is
|
||
needed.
|
||
|
||
```bash
|
||
cp /etc/nixos/hosts/TuringMachine/hardware-configuration.nix ./hardware-configuration.nix
|
||
```
|
||
|
||
### `flake.nix` — one `mkFlake` call (from the template)
|
||
|
||
```nix
|
||
{
|
||
description = "TuringMachine — Nomarchy";
|
||
inputs.nomarchy.url = "git+https://git.bemagri.xyz/bernardo/nomarchy.git?ref=v1";
|
||
|
||
outputs = { nomarchy, ... }:
|
||
nomarchy.lib.mkFlake {
|
||
src = ./.;
|
||
username = "bernardo"; # <- your login name
|
||
# Optional nixos-hardware profile(s) for your model. For an AMD laptop:
|
||
# hardwareProfile = [ "common-cpu-amd-pstate" "common-gpu-amd" "common-pc-laptop-ssd" ];
|
||
# Names: https://github.com/NixOS/nixos-hardware (verify before use)
|
||
# Full hardware story (firmware, fingerprint, unsupported machines):
|
||
# docs/HARDWARE.md in the Nomarchy repo
|
||
};
|
||
}
|
||
```
|
||
|
||
### `system.nix` — machine specifics + your decisions
|
||
|
||
This is where your three migration decisions land: **PPD power (no
|
||
ryzenadj)**, **no Secure Boot**, and the **stateVersion override**.
|
||
|
||
```nix
|
||
{ pkgs, username, ... }:
|
||
|
||
{
|
||
# Plain systemd-boot — no lanzaboote / Secure Boot.
|
||
boot.loader.systemd-boot.enable = true;
|
||
boot.loader.efi.canTouchEfiVariables = true;
|
||
|
||
networking.hostName = "TuringMachine";
|
||
time.timeZone = "Europe/London"; # your zone
|
||
i18n.defaultLocale = "en_US.UTF-8";
|
||
|
||
users.users.${username} = {
|
||
isNormalUser = true;
|
||
extraGroups = [ "wheel" "networkmanager" "video" "input" ];
|
||
};
|
||
|
||
# ── Power: Nomarchy's PPD (drops all custom ryzenadj/TLP tuning) ──────
|
||
nomarchy.system.power = {
|
||
enable = true;
|
||
backend = "ppd"; # power-profiles-daemon
|
||
laptop = true;
|
||
batteryChargeLimit = 80; # optional longevity cap
|
||
};
|
||
|
||
# ── AMD 7840U / Radeon 780M ──────────────────────────────────────────
|
||
nomarchy.hardware.amd.enable = true; # amd-pstate + radeonsi VA-API
|
||
# nomarchy.hardware.amd.rocm.enable = true; # opt-in GPU compute (multi-GB)
|
||
|
||
# Auto-login is NOT set here: it lives in state.json
|
||
# (settings.greeter.autoLogin) so System › Auto-login can move it — a line
|
||
# here would outrank the state and pin it. Turn it on after the first boot
|
||
# with `nomarchy-autologin on` (what nomarchy-install seeds on encrypted
|
||
# installs: the LUKS passphrase already gates access).
|
||
|
||
# CRITICAL: keep your ORIGINAL install's value — never Nomarchy's 26.05.
|
||
system.stateVersion = "24.11";
|
||
}
|
||
```
|
||
|
||
> **Dropped on purpose (decisions 1 & 2):** your old
|
||
> `modules/services/power-management.nix` ryzenadj stack, the `lanzaboote`
|
||
> input, and the `power-max`/`power-stealth` scripts. PPD's
|
||
> performance/balanced/power‑saver profiles (switchable from the Waybar
|
||
> battery/profile icons and `nomarchy-menu`) replace them.
|
||
|
||
### `home.nix` — your apps on top of Nomarchy's desktop
|
||
|
||
Start from the template's `home.nix` (it ships the default app set) and add
|
||
your personal packages/config. Carry over anything you still want (e.g. your
|
||
emacs setup).
|
||
|
||
```nix
|
||
{ pkgs, lib, ... }:
|
||
|
||
{
|
||
# Nomarchy hardcodes home.stateVersion = "26.05". Moving home-manager's
|
||
# stateVersion is low-risk, but if you want to pin your original:
|
||
home.stateVersion = lib.mkForce "24.11";
|
||
|
||
home.packages = with pkgs; [
|
||
# your extras — e.g. emacs, language toolchains, …
|
||
];
|
||
}
|
||
```
|
||
|
||
### `state.json`
|
||
|
||
Copy the template's `state.json` (or let `nomarchy-menu theme` write
|
||
it after the switch). Your old `nomarchy-state.nix` prototype (schema
|
||
`nomarchy.theme = "nord"` …) is **retired** — the current distro uses this
|
||
JSON. `nord` is a shipped Nomarchy theme, so you lose nothing.
|
||
|
||
### The build gate
|
||
|
||
```bash
|
||
nixos-rebuild build --flake ~/nomarchy-migrate#default
|
||
```
|
||
|
||
Zero activation — this only evaluates and builds the system closure. Fix any
|
||
eval/build error here, in isolation, before touching the running machine.
|
||
Expect to resolve a few 25.11→26.05 option renames.
|
||
|
||
---
|
||
|
||
## Phase 2 — Reversible activation
|
||
|
||
```bash
|
||
# Activates now, but does NOT become the boot default. If the session
|
||
# breaks, REBOOT and you are back in your old generation, untouched.
|
||
sudo nixos-rebuild test --flake ~/nomarchy-migrate#default
|
||
|
||
# Bring the desktop (home-manager) up BEFORE the first graphical login.
|
||
# Hyprland without an HM generation shows the yellow "autogenerated
|
||
# config" banner (and no Nomarchy theming) — finish this step first.
|
||
home-manager switch --flake ~/nomarchy-migrate#bernardo -b bak
|
||
```
|
||
|
||
Log into Hyprland and sanity‑check: Waybar renders, `SUPER+M` opens the
|
||
menu, theming is coherent, `SUPER+?` shows the cheatsheet, **no** yellow
|
||
Hyprland autogenerated banner. Confirm the machine‑specific things you
|
||
care about still work — suspend/hibernate, the AMD GPU (`vainfo` →
|
||
radeonsi), display brightness.
|
||
|
||
You should also get a one-shot **You're set** toast (menu / themes /
|
||
keys). If it never appears: `systemctl --user status nomarchy-first-boot`
|
||
and re-try with
|
||
`nomarchy-state-sync set settings.firstBootShown false --no-switch`
|
||
then log out/in.
|
||
|
||
If anything is wrong: **reboot → old generation.** Nothing is committed as
|
||
default yet.
|
||
|
||
---
|
||
|
||
## Phase 3 — Reconcile
|
||
|
||
- **Power:** verify `powerprofilesctl get` works and the Waybar battery /
|
||
power‑profile icons open the power menu. Your ryzenadj scripts are gone;
|
||
if you miss a specific TDP behaviour, that's a follow‑up, not a blocker.
|
||
- **Theme:** `nomarchy-menu theme` → pick a preset (writes
|
||
`state.json`).
|
||
- **Snapshots:** `nomarchy-menu` → System → Snapshots should see your
|
||
existing `@snapshots` subvolume.
|
||
- **Fingerprint:** `fingerprint.enable = true` only starts **fprintd**
|
||
(enrollment). Login/sudo finger auth is **`fingerprint.pam`** and is
|
||
opt-in — leave it commented until you've enrolled. NixOS defaults PAM
|
||
on whenever fprintd is enabled; Nomarchy forces PAM to follow the
|
||
`pam` flag, but only after a **system** rebuild. Verify with
|
||
`grep pam_fprintd /etc/pam.d/sudo` (should be empty when pam is off).
|
||
With pam on, the prompt accepts password *or* finger in parallel by
|
||
default (`fingerprint.parallel = false` for stock sequential) — see
|
||
HARDWARE.md §5.
|
||
- **Browser profiles:** Nomarchy does not manage Chromium/Firefox state.
|
||
Bookmarks/extensions live under `~/.config/chromium` (or
|
||
`~/.config/google-chrome` / ungoogled paths if that was your previous
|
||
browser). **If your old Home Manager config declared
|
||
`programs.chromium.extensions`, carry that block into `home.nix`
|
||
*before* first launch** — HM installs those via
|
||
`External Extensions/*.json`, and when the JSONs vanish Chromium
|
||
treats every extension as externally uninstalled and deletes it
|
||
**together with its stored data** (`Local Extension Settings` —
|
||
wallet vaults, password-manager pairings). Bookmarks survive, which
|
||
makes it look minor; it isn't. Recovery: close the browser, copy
|
||
`Default/Local Extension Settings/<id>` (plus any
|
||
`Default/IndexedDB/chrome-extension_<id>_*`) back from your Phase-0
|
||
`pre-nomarchy-home` snapshot, then reinstall each extension — from
|
||
the Web Store (ids are stable, so the data reattaches) or by
|
||
re-declaring the ids if you want them declarative again.
|
||
- **VPN:** NetworkManager connections survive under
|
||
`/etc/NetworkManager` and your home. System › VPN lists NM
|
||
`vpn`/`wireguard` profiles; import any that lived outside NM.
|
||
Tailscale is opt-in (`nomarchy.services.tailscale.enable`).
|
||
- **Secrets/services:** if you relied on agenix‑managed secrets for a
|
||
service, layer `agenix` back into `system.nix` as a machine‑specific
|
||
import (Nomarchy doesn't manage secrets). If you don't need them, leave
|
||
them out — this is a full cutover.
|
||
|
||
---
|
||
|
||
## Phase 4 — Cutover
|
||
|
||
Once a test boot is solid:
|
||
|
||
```bash
|
||
# Move the flake to its canonical home and make it the boot default.
|
||
mv ~/nomarchy-migrate ~/.nomarchy
|
||
sudo nixos-rebuild switch --flake ~/.nomarchy#default
|
||
home-manager switch --flake ~/.nomarchy#bernardo
|
||
|
||
# Point /etc/nixos at the flake (optional but conventional).
|
||
sudo mv /etc/nixos /etc/nixos.pre-nomarchy
|
||
sudo ln -s ~/.nomarchy /etc/nixos
|
||
```
|
||
|
||
From here you're on the standard Nomarchy update flow: `sys-update` (lock +
|
||
system) then `home-update` (desktop) — always in that order (a lock bump
|
||
before the home switch, or desktop changes are skipped against the old
|
||
lock).
|
||
|
||
---
|
||
|
||
## Rollback, at any point
|
||
|
||
| Net | How |
|
||
|---|---|
|
||
| **NixOS generation** | Reboot → pick the previous entry in the systemd‑boot menu. |
|
||
| **`nixos-rebuild test`** | Never sets the boot default; a reboot reverts it. |
|
||
| **btrfs snapshot** | Restore `/.snapshots/pre-nomarchy-root` (see `docs/RECOVERY.md`). |
|
||
| **git baseline** | `/etc/nixos.pre-nomarchy` (and the pre‑nomarchy commit) is your old config verbatim. |
|
||
|
||
`/home` is untouched by all of the above.
|
||
|
||
---
|
||
|
||
## Post‑migration cleanup (once you're confident)
|
||
|
||
- Delete the safety snapshots: `sudo btrfs subvolume delete /.snapshots/pre-nomarchy-root` (and the home one).
|
||
- Remove `/etc/nixos.pre-nomarchy` and the old per‑host modules you cut
|
||
(ryzenadj power‑management, lanzaboote, the `nomarchy-state.nix`
|
||
prototype).
|
||
- Prune old generations: `sudo nix-collect-garbage -d`.
|
||
|
||
---
|
||
|
||
## Enabling hibernation on an existing machine (no reinstall)
|
||
|
||
New Nomarchy installs are hibernation-ready out of the box — the installer
|
||
defaults the swapfile to **= RAM** on its own `@swap` subvolume and wires the
|
||
resume offset. This section is for machines that have **no hibernate swap**:
|
||
one installed with `swap = 0`, one migrated here whose reused
|
||
`hardware-configuration.nix` carries no swapfile, or an older install
|
||
predating the default. If `swapon --show` already lists `/swap/swapfile`,
|
||
you have nothing to do.
|
||
|
||
Hibernation writes RAM to disk, and zram (compressed *RAM*) can't hold that
|
||
image across a power-off — so you need a real disk swap ≥ the RAM you use.
|
||
Nomarchy puts it on an `@swap` subvolume *inside* the encrypted volume, so
|
||
the image is encrypted at rest and the initrd LUKS unlock gates resume.
|
||
|
||
> **Reversible:** this is one subvolume plus four config lines. Remove them
|
||
> and rebuild — or just boot the previous generation — to undo. `/home` is
|
||
> never touched.
|
||
|
||
Worked example below is **this machine**: LUKS mapper `cryptroot`, btrfs `@`.
|
||
Substitute your own device/UUID/offset where shown.
|
||
|
||
### 1. Size and locate
|
||
|
||
```bash
|
||
# Swap = RAM, rounded up to whole GiB (matches the installer default).
|
||
ram_gb=$(awk '/MemTotal/ {print int(($2 + 1048575) / 1048576)}' /proc/meminfo)
|
||
|
||
# The decrypted BTRFS device backing / (strip the [subvol] suffix) and its
|
||
# filesystem UUID — the same UUID resolves to the mapper once initrd unlocks.
|
||
dev=$(findmnt -no SOURCE / | sed 's/\[.*//') # e.g. /dev/mapper/cryptroot
|
||
fsuuid=$(findmnt -no UUID /) # e.g. d8e2b02d-…
|
||
echo "swap=${ram_gb}G dev=$dev uuid=$fsuuid"
|
||
```
|
||
|
||
### 2. Create the `@swap` subvolume + swapfile
|
||
|
||
```bash
|
||
# Create the subvolume at the BTRFS top level (subvolid=5), beside @, @home…
|
||
sudo mkdir -p /mnt/btrfs-top
|
||
sudo mount -o subvolid=5 "$dev" /mnt/btrfs-top
|
||
sudo btrfs subvolume create /mnt/btrfs-top/@swap
|
||
sudo umount /mnt/btrfs-top && sudo rmdir /mnt/btrfs-top
|
||
|
||
# Mount it and create the swapfile. `mkswapfile` applies the BTRFS NOCOW
|
||
# requirements automatically (a copy-on-write swapfile would corrupt).
|
||
sudo mkdir -p /swap
|
||
sudo mount -o subvol=@swap,noatime "$dev" /swap
|
||
sudo btrfs filesystem mkswapfile --size "${ram_gb}g" --uuid clear /swap/swapfile
|
||
```
|
||
|
||
### 3. Read the resume offset
|
||
|
||
```bash
|
||
sudo btrfs inspect-internal map-swapfile -r /swap/swapfile # prints the offset
|
||
```
|
||
|
||
### 4. Wire it into `system.nix`
|
||
|
||
Add these to your machine's `system.nix`, substituting your `$fsuuid` and the
|
||
offset from step 3. The `fileSystems."/swap"` mount is **required** on this
|
||
path — a fresh install inherits it from disko-generated
|
||
`hardware-configuration.nix`, but a hand edit must declare it so `/swap` is
|
||
mounted before swap activates:
|
||
|
||
```nix
|
||
# Hibernation: encrypted swapfile on the @swap subvolume.
|
||
fileSystems."/swap" = {
|
||
device = "/dev/disk/by-uuid/<fsuuid>";
|
||
fsType = "btrfs";
|
||
options = [ "subvol=@swap" "noatime" ];
|
||
};
|
||
swapDevices = [{ device = "/swap/swapfile"; }];
|
||
boot.resumeDevice = "/dev/disk/by-uuid/<fsuuid>";
|
||
boot.kernelParams = [ "resume_offset=<offset>" ];
|
||
```
|
||
|
||
zram stays on by default (Nomarchy sets `zramSwap` at priority 100 in
|
||
`modules/nixos/oom.nix`); this disk swapfile sits lower, so day-to-day
|
||
paging stays in compressed RAM and the file is reserved for the hibernate
|
||
image — exactly the intent.
|
||
|
||
### 5. Rebuild and test
|
||
|
||
```bash
|
||
sudo nixos-rebuild switch --flake ~/.nomarchy#default
|
||
systemctl hibernate # or nomarchy-menu → Power → Hibernate
|
||
```
|
||
|
||
The machine powers off; on the next boot you unlock LUKS once and land back
|
||
in your session. If you get a *fresh* boot instead, the usual cause is a
|
||
wrong `resume_offset` or a swapfile smaller than in-use RAM — re-read the
|
||
offset (step 3) and confirm `swap ≥ RAM`.
|
||
|
||
**No LUKS?** Same steps; `dev`/`$fsuuid` point at the plain BTRFS partition
|
||
and the image is unencrypted at rest. **`swap = 0` opt-out** stays valid — if
|
||
you don't want hibernation, skip all of this; the Power-menu Hibernate row
|
||
just reports that no swap is configured.
|
||
|
||
---
|
||
|
||
## State file rename (`theme-state.json` → `state.json`, #107)
|
||
|
||
The machine flake's git-tracked state file is **`state.json`** (appearance +
|
||
menu settings). Older checkouts may still have `theme-state.json`.
|
||
|
||
- **Eval:** `lib.mkFlake` and the reader accept either name (prefer
|
||
`state.json`).
|
||
- **Write:** `nomarchy-state-sync` (and the menu) always write `state.json`
|
||
and remove a leftover `theme-state.json` so you never have two sources.
|
||
- **CLI:** `nomarchy-state-sync` is the real name; `nomarchy-theme-sync`
|
||
remains a symlink for scripts and muscle memory. Drop the alias after the
|
||
next stable release notes call it out.
|
||
|
||
No action required on pull: the next theme apply or menu write migrates you.
|
||
To migrate by hand: `mv theme-state.json state.json && git add state.json`
|
||
(and `git rm theme-state.json` if it was tracked).
|
||
|
||
---
|
||
|
||
## TuringMachine — the decisions, at a glance
|
||
|
||
| Item | Choice |
|
||
|---|---|
|
||
| Power | Nomarchy **PPD** (`backend = "ppd"`); **all ryzenadj/TLP tuning dropped** |
|
||
| Secure Boot | **Off** — plain systemd‑boot, `lanzaboote` dropped |
|
||
| Scope | **Full cutover** to Nomarchy's structure |
|
||
| `system.stateVersion` | **`24.11`** (preserved from original install) |
|
||
| Hardware | `nomarchy.hardware.amd.enable = true` (7840U / Radeon 780M) |
|
||
| Bootloader | systemd‑boot (unchanged — already matched) |
|
||
| Filesystem | LUKS + btrfs, existing subvolumes reused (incl. snapshot subvols) |
|