Create, Snapshot and Delete Subvolumes with btrfs subvolume

Btrfs subvolumes look like directories but behave like separate filesystems, and btrfs subvolume is how you manage them. This guide takes you from inspecting a filesystem to creating a subvolume, snapshotting it read-only, and deleting a disposable one. The examples match btrfs-progs 6.6.3, installed here as package version 6.6.3-1.1build2.

Allow about 15 minutes. You need a mounted Btrfs filesystem and an account allowed to administer it. Substitute an existing mount point for /mnt/btrfs. Commands that change filesystem state are shown with sudo; inspect commands may work without it, depending on permissions.

1. Confirm the filesystem and current subvolumes

Check that the path is really on Btrfs, then list its subvolumes:

$ findmnt -no FSTYPE,OPTIONS /mnt/btrfs
$ sudo btrfs subvolume list -p -u /mnt/btrfs

The first command should begin with btrfs. The second prints an ID, generation, parent information and a path, with UUID fields because of -u. The path shown by list is relative to the filesystem top level, not necessarily to the directory you supplied.

Checkpoint: you have recorded the ID and path of anything you might later change. The top-level subvolume has ID 5 and cannot be removed.

Tip: do not assume a directory is an ordinary directory. A subvolume looks like one, but it is a separate Btrfs hierarchy.

2. Create a working subvolume

Create a new subvolume below the mount point. The destination has to be inside the Btrfs filesystem:

$ sudo btrfs subvolume create /mnt/btrfs/work

On success, btrfs reports the created subvolume. The new directory is usable immediately, but its persistent numeric ID is assigned by Btrfs and is not the directory name. Verify both the path and its metadata:

$ sudo btrfs subvolume show /mnt/btrfs/work
$ sudo btrfs subvolume list /mnt/btrfs

show includes the subvolume ID, UUID, parent ID, creation generation and flags. A normal new subvolume is read-write.

Tip: subvolumes share the filesystem's storage pool unless you configure quotas. Creating another one does not reserve a fixed block device or capacity.

3. Make a read-only snapshot

A snapshot starts with the source subvolume's content and initially shares extents through copy-on-write. Make a read-only one when you need a stable tree for inspection or later send/receive work:

$ sudo btrfs subvolume snapshot -r /mnt/btrfs/work /mnt/btrfs/work-before-change
$ sudo btrfs subvolume show /mnt/btrfs/work-before-change

The -r matters: without it, the snapshot is read-write. Check that Flags shows it as read-only. You can still mount a read-write subvolume read-only, but that mount choice does not change the subvolume's own read-only property.

Now prove it. Write test data only to /mnt/btrfs/work, then compare with the snapshot:

$ sudo sh -c 'printf "%s\n" changed > /mnt/btrfs/work/example.txt'
$ test ! -e /mnt/btrfs/work-before-change/example.txt && echo "snapshot is unchanged"
snapshot is unchanged

Warning: this is a local rollback or comparison point, not a backup. The source and snapshot initially share data blocks, so disk damage or an accident affecting the filesystem can hit both. Keep an independent backup for recovery.

4. Inspect the default subvolume before changing it

Every Btrfs filesystem has a default subvolume, used when it is mounted without an explicit subvol or subvolid. Find it before you touch boot or mount behaviour:

$ sudo btrfs subvolume get-default /mnt/btrfs

Changing the default is an operational decision, not a cosmetic rename. It hides the top-level view on the next mount. If you have deliberately chosen a subvolume ID, the form is:

$ sudo btrfs subvolume set-default SUBVOLUME_ID /mnt/btrfs
$ sudo btrfs subvolume get-default /mnt/btrfs

Replace SUBVOLUME_ID with an ID from list or show.

Warning: do not run this example against a production filesystem until you have checked how its mount units, /etc/fstab entries and recovery procedure refer to the old default.

Recovery: to undo the change, run set-default again with the previously recorded ID.

5. Remove only a confirmed disposable subvolume

Deletion is destructive. First inspect the exact path and its contents, and check that it is not the default subvolume or a source currently in use by send:

$ sudo btrfs subvolume show /mnt/btrfs/work-before-change
$ sudo find /mnt/btrfs/work-before-change -maxdepth 2 -print

When the path is definitely disposable, delete it and ask for a transaction commit before the command returns:

$ sudo btrfs subvolume delete --commit-after /mnt/btrfs/work-before-change
Delete subvolume ...
$ sudo btrfs subvolume list /mnt/btrfs

The directory disappears promptly, but Btrfs removes the data blocks in the background. --commit-after waits for the transaction to be committed; it does not make the deletion reversible.

Warning: there is no ordinary undo command. Restore the subvolume from an independent backup, or recreate it from another snapshot if one exists.

To wait for the deletion work itself to finish, use:

$ sudo btrfs subvolume sync /mnt/btrfs

With no ID, sync waits for the deletion requests known when it starts. It can take a while for a large or heavily shared subvolume.

Tip: the default owner cannot normally delete a subvolume unless the filesystem was mounted with user_subvol_rm_allowed. Using sudo avoids that permission failure but does not bypass the safety checks for a default or active send subvolume.

Common traps

Done means