Using copy on write filesystems in practice
Anyone who only knows the ext4 versus XFS comparison misses the real payoff of Btrfs: subvolumes as independently managed file trees, and snapshots that appear in milliseconds thanks to copy on write. Used correctly, this becomes a safety net before every risky deployment, without a separate backup tool.
Table of Contents
- 1. Why copy on write changes volume management
- 2. Creating and understanding subvolumes
- 3. Creating snapshots: read only versus read write
- 4. Practical case: rollback before risky deployments
- 5. Essential btrfs commands for everyday use
- 6. Disk space and CoW: what a snapshot really costs
- 7. Automating snapshots instead of maintaining them by hand
- 8. Best practices for a sensible subvolume layout
- 9. Common pitfalls in production use
- 10. Summary
- 11. FAQ
1. Why copy on write changes volume management
Classic filesystems such as ext4 overwrite data blocks in place when saving, which makes snapshots technically expensive and usually requires an extra layer such as LVM. Btrfs takes a different approach: every change to a block is written as a new copy, while the old block stays around as long as something still references it. This exact principle is what makes snapshots on Btrfs cheap enough to create before every single package update or deployment without a second thought.
Subvolumes are not a replacement for partitions, but independent, named file trees inside a single Btrfs filesystem that can be mounted, snapshotted, and deleted independently of each other. A typical server layout creates separate subvolumes for root, for home, and for database directories, so that a snapshot of root never accidentally freezes terabytes of application data that already have their own backup strategy in place.
2. Creating and understanding subvolumes
A new subvolume is created with a single command and then behaves like a regular directory, while internally being managed as its own B tree with its own tree ID. This independence is why a subvolume can be mounted, unmounted, or set as the default subvolume for the whole filesystem mount on its own, something many distributions rely on for the root subvolume.
One important practical point: a subvolume shares the available free space with every other subvolume on the same filesystem, so there is no fixed size allocation like with a classic partition, unless quotas are configured. That simplifies planning considerably, because space does not need to be split up front and instead gets consumed dynamically wherever it is actually needed.
# Create a new subvolume for the MySQL data directory
btrfs subvolume create /mnt/data/mysql
# List all subvolumes on the filesystem
btrfs subvolume list /mnt/data
# Show details for a single subvolume, including UUID and parent reference
btrfs subvolume show /mnt/data/mysql
3. Creating snapshots: read only versus read write
A snapshot is technically nothing more than another subvolume whose file tree exactly matches the source subvolume at the moment it was taken, without a single data block being copied. Only once a file changes in either the original or the snapshot does copy on write kick in and write the changed block anew, while the old block remains visible unchanged in the other subvolume.
For rollback purposes, read only snapshots are the right choice, because they guarantee the frozen state cannot accidentally be modified, while read write snapshots make sense when work should continue directly inside the snapshot, for example to test a configuration change without touching the original.
# Create a read only snapshot of the root subvolume
btrfs subvolume snapshot -r / /.snapshots/root-2026-08-08
# Create a read write snapshot for experimental changes
btrfs subvolume snapshot / /.snapshots/root-testing
# Check whether a subvolume is read only
btrfs property get /.snapshots/root-2026-08-08 ro
4. Practical case: rollback before risky deployments
Before every larger Magento deployment, kernel update, or package upgrade, a read only snapshot of the affected subvolume is a worthwhile final safeguard. If the deployment fails or the server behaves unexpectedly afterward, the previous state can be restored without an elaborate restore procedure, because the snapshot already sits fully on disk instead of needing to be unpacked from a backup archive.
The actual rollback works by renaming or deleting the current subvolume and putting the snapshot in its place as a writable subvolume instead. For a root subvolume referenced by the bootloader, a single entry in the bootloader configuration pointing at the snapshot subvolume ID is often enough, so a reboot alone loads the previous state again.
# Move the current, broken subvolume out of the way
mv /mnt/data/mysql /mnt/data/mysql-broken
# Put the snapshot in its place as a writable subvolume
btrfs subvolume snapshot /.snapshots/mysql-pre-deploy /mnt/data/mysql
# Remove the broken subvolume permanently once verified
btrfs subvolume delete /mnt/data/mysql-broken
5. Essential btrfs commands for everyday use
Besides creating and deleting subvolumes, a handful of other commands belong in every Btrfs administrator's standard toolkit. The call btrfs filesystem show gives an overview of every device involved in a filesystem, while btrfs filesystem usage provides a far more detailed breakdown of used, free, and allocated space than the classic df ever could.
A deleted subvolume does not disappear immediately, but is first marked as orphaned and then removed in the background by the kernel's cleaner thread, which can take several minutes for very large snapshots and should be accounted for in scripts that immediately rely on freed up disk space afterward.
# Show devices and sizes for a Btrfs filesystem
btrfs filesystem show /mnt/data
# Detailed disk space breakdown, including allocation
btrfs filesystem usage /mnt/data
# Check for pending background deletion of subvolumes
btrfs subvolume sync /mnt/data
6. Disk space and CoW: what a snapshot really costs
Right after creation, a snapshot costs practically no additional disk space, since it fully shares every data block with the original. Actual consumption only grows over time, proportional to the amount of blocks changed in either the original or the snapshot since it was taken, which is why a snapshot on a heavily write intensive database directory binds space far faster than one on a fairly static configuration directory.
The classic du command is unsuitable for judging this overhead, because it counts every file individually without accounting for the fact that many blocks are shared across several subvolumes. A look at the qgroup statistics is far more reliable, separating exclusively held disk space per subvolume from shared disk space and giving a much more realistic picture of how much space a deletion would actually free up.
# Enable quota groups to see exclusive vs. shared disk space
btrfs quota enable /mnt/data
# Show exclusively held and shared disk space per subvolume
btrfs qgroup show -pcre /mnt/data
7. Automating snapshots instead of maintaining them by hand
Manually created snapshots before a deployment make sense, but they are no substitute for a regular snapshot strategy during day to day operation. Tools such as snapper take over both the scheduled creation and, more importantly, the cleanup of old snapshots according to configurable retention rules, so the number of hourly, daily, and weekly snapshots does not grow unchecked and eat up available disk space.
Anyone who wants to avoid extra tooling can achieve a comparable effect with a simple cron job and a script that deletes older snapshots by timestamp right after creating a new one. In both cases, cleanup must run just as reliably as creation, since an unbounded number of snapshots noticeably slows down operations such as btrfs balance.
#!/usr/bin/env bash
# scripts/btrfs-snapshot-rotate.sh: create daily snapshot, drop old ones
set -euo pipefail
TS=$(date +%Y-%m-%d)
btrfs subvolume snapshot -r /mnt/data/mysql /.snapshots/mysql-$TS
# Remove snapshots older than 7 days
find /.snapshots -maxdepth 1 -name 'mysql-*' -mtime +7 \
-exec btrfs subvolume delete {} \;
8. Best practices for a sensible subvolume layout
A well thought out layout separates areas that genuinely benefit from snapshots from areas that should deliberately be excluded. The root subvolume, configuration directories, and application code classically belong in the snapshotted area, while log directories and temporary data are often kept as separate subvolumes without regular snapshots, since they change constantly and would needlessly increase snapshot overhead.
Database directories deserve special attention: MySQL and similar systems write many small, scattered changes, which leads to fragmentation on a copy on write filesystem. For such directories, the nodatacow attribute is worth setting, disabling copy on write for individual files or directories and noticeably reducing fragmentation, at the cost of checksumming and snapshot efficiency for exactly that area.
9. Common pitfalls in production use
The most important principle first: a snapshot is not a backup as long as it sits on the same physical storage device. A disk failure destroys the original and every snapshot alike, which is why snapshots should always be understood as a complement to a real offsite backup, never as a replacement for one.
Another pitfall involves nodatacow combined with snapshots: once a snapshot of a file with that attribute exists, the very next write still triggers copy on write exactly once, since the snapshot would otherwise become inconsistent. Anyone using nodatacow for database files should set the attribute before the first write ever happens, ideally right when the directory is created, rather than applying it retroactively to database files that are already populated.
| Command | Purpose | Typical use | Note |
|---|---|---|---|
| btrfs subvolume snapshot -r | Create a read only snapshot | Rollback safeguard before deployment | No data block gets copied |
| btrfs subvolume snapshot | Create a read write snapshot | Experimental changes without touching the original | Changes stay local to the snapshot |
| btrfs qgroup show | Analyze disk space per subvolume | Clarify how much space a deletion would free | Requires quotas enabled beforehand |
| btrfs subvolume delete | Remove a subvolume or snapshot | Cleanup after a successful rollback | Deletion runs asynchronously in the background |
| btrfs property set ro | Toggle write protection | Make a snapshot writable again afterward | Handle rollback relevant snapshots with care |
Mironsoft
Server administration, Docker hosts, and performance tuning
Linux servers nobody on the team really understands anymore?
We handle setup, hardening, and performance tuning of Linux servers and Docker hosts for Magento deployments, documented and traceable instead of grown and unclear.
Server Audit
Review the existing server configuration for security gaps and performance bottlenecks.
Docker Host Setup
Set up and secure production-ready Docker environments for Magento cleanly.
Monitoring & Tuning
Measure resource usage and tune systemd, kernel, and services with purpose.
10. Summary
Btrfs Snapshots
Core concept
Copy on write allows snapshots without data copying in milliseconds
Practical value
Read only snapshot before every risky deployment as rollback safeguard
Disk space
Grows only with actual changes, analyzed via qgroups rather than du
Most important rule
A snapshot never replaces an offsite backup on separate storage