Btrfs: Difference between revisions

Ponder (talk | contribs)
m Scrubbing: Copyedit for grammar & missing small words
Klinger (talk | contribs)
m Tips and tricks: Link to Btrbk
 
(7 intermediate revisions by 4 users not shown)
Line 3: Line 3:
{{note| Use [https://github.com/nix-community/disko/ disko] to manage your NixOS storage layout declaratively. The following shows a manual approach as seen in traditional Linux distributions.}}
{{note| Use [https://github.com/nix-community/disko/ disko] to manage your NixOS storage layout declaratively. The following shows a manual approach as seen in traditional Linux distributions.}}


== Installation ==
= Installation of NixOS on btrfs =


{{note|The following example is for EFI enabled systems. Adjust commands accordingly for a BIOS installation.}}
{{note|The following example is for EFI enabled systems. Adjust commands accordingly for a BIOS installation.}}


=== Partition the disk ===
== Partition the disk ==
<syntaxhighlight lang="console">
<syntaxhighlight lang="console">
# printf "label: gpt\n,550M,U\n,,L\n" | sfdisk /dev/sdX
# printf "label: gpt\n,550M,U\n,,L\n" | sfdisk /dev/sdX
</syntaxhighlight>
</syntaxhighlight>


=== Format partitions and create subvolumes ===
== Format partitions and create subvolumes ==
<syntaxhighlight lang="console">
<syntaxhighlight lang="console">
# nix-shell -p btrfs-progs
# nix-shell -p btrfs-progs
Line 26: Line 26:
</syntaxhighlight>
</syntaxhighlight>


=== Mount the partitions and subvolumes ===
== Mount the partitions and subvolumes ==
<syntaxhighlight lang="console">
<syntaxhighlight lang="console">
# mount -o compress=zstd,subvol=root /dev/sdX2 /mnt
# mount -o compress=zstd,subvol=root /dev/sdX2 /mnt
Line 37: Line 37:
</syntaxhighlight>
</syntaxhighlight>


=== Install NixOS ===
== Install NixOS ==
<syntaxhighlight lang="console">
<syntaxhighlight lang="console">
# nixos-generate-config --root /mnt
# nixos-generate-config --root /mnt
Line 44: Line 44:
</syntaxhighlight>
</syntaxhighlight>


== Configuration ==
= Configuration =


=== Compression ===
== Compression ==


<code>nixos-generate-config --show-hardware-config</code> doesn't detect mount options automatically, so to enable compression, you must specify it and other mount options in a persistent configuration:
<code>nixos-generate-config</code> doesn't detect mount options automatically. To enable compression, you must specify them manually and other mount options in your <code>configuration.nix</code>:


<syntaxhighlight lang="nix">
{{file|/etc/nixos/configuration.nix|nix|
<nowiki>
fileSystems = {
fileSystems = {
   "/".options = [ "compress=zstd" ];
   "/".options = [ "compress=zstd" ];
Line 57: Line 58:
   "/swap".options = [ "noatime" ];
   "/swap".options = [ "noatime" ];
};
};
</syntaxhighlight>
</nowiki>
}}
 
Btrfs supports a few compression algorithms, each with different trade-offs:
 
* <code>zstd</code>: Good compression ratio and performance, especially for general-purpose workloads. You can specify compression levels, as example <code>compress=zstd:3</code>.
 
* <code>lzo</code>: Faster but provides lower compression ratios. Good for low powered systems or where performance is important.
 
* <code>zlib</code>: Higher compression ratio but slower performance. Less commonly used nowadays in favor of zstd.
 
You can find more details on the official [https://btrfs.readthedocs.io/en/latest/Compression.html Btrfs Compression Documentation].
 
{{note| Compression is applied only to newly written data. Existing data won't be compressed unless rewritten. (e.g., <code>btrfs filesystem defrag -r -v -czstd /path</code>)}}
 
== Swap file ==


=== Swap file ===
Creating a separate subvolume for the swap file is optional. It is not required for functionality but can help with organization or snapshot management. Be sure to regenerate your <code>hardware-configuration.nix</code> if you choose to do this.


Optionally, create a separate subvolume for the swap file. Be sure to regenerate your <code>hardware-configuration.nix</code> if you choose to do this.
<syntaxhighlight lang="console">
<syntaxhighlight lang="console">
# mkdir -p /mnt
# mkdir -p /mnt
Line 69: Line 84:
# mkdir /swap
# mkdir /swap
# mount -o noatime,subvol=swap /dev/sdXY /swap
# mount -o noatime,subvol=swap /dev/sdXY /swap
# nixos-generate-config
</syntaxhighlight>
</syntaxhighlight>


Then, create the swap file and adjust its size as desired:
Finally, define a swap file in your configuration and run <code>nixos-rebuild switch</code>:
 
{{file|/etc/nixos/configuration.nix|nix|
<nowiki>
swapDevices = [{
  device = "/swap/swapfile";
  size = 8*1024; # Creates an 8GB swap file
}];
</nowiki>
}}
 
NixOS will automatically create the swap file with the appropriate attributes for Btrfs including disabling copy on write.


<syntaxhighlight lang="console">
{{note| On systems where you do need to manually prepare a swap file on Btrfs, you can use <code>btrfs filesystem mkswapfile</code> utility, e.g.: <br><code># btrfs filesystem mkswapfile --uuid clear /swap/swapfile</code>}}
# btrfs filesystem mkswapfile --size 8g --uuid clear /swap/swapfile
</syntaxhighlight>


Finally, add the swap file to your configuration and <code>nixos-rebuild switch</code>:
For more NixOS swap configuration options, see [[Swap]]. Additonal Btrfs swapfile usage can be found at [https://btrfs.readthedocs.io/en/latest/Swapfile.html the Btrfs docs].
<syntaxhighlight lang="nix">
swapDevices = [ { device = "/swap/swapfile"; } ];
</syntaxhighlight>


=== Scrubbing ===
== Scrubbing ==


Btrfs filesystems by default keep checksums for all files, to monitor if the file has changed due to hardware malfunctions or other external effects.
Btrfs filesystems by default keep checksums for all files, to monitor if the file has changed due to hardware malfunctions or other external effects.
Line 119: Line 141:
You can check the status of the ongoing scrubbing process with the same <code>status</code> command as above.
You can check the status of the ongoing scrubbing process with the same <code>status</code> command as above.


=== Deduplication ===
== Deduplication ==


Files with (partially) equal contents can be deduplicated using [https://github.com/Zygo/bees bees] or [https://github.com/markfasheh/duperemove duperemove].
Files with (partially) equal contents can be deduplicated using [https://github.com/Zygo/bees bees] or [https://github.com/markfasheh/duperemove duperemove].
Line 138: Line 160:
This will run the daemon in the background. To disable auto-start, use <code>systemd.services."beesd@root".wantedBy = lib.mkForce [ ];</code> for each filesystem.
This will run the daemon in the background. To disable auto-start, use <code>systemd.services."beesd@root".wantedBy = lib.mkForce [ ];</code> for each filesystem.


== Usage ==
= Usage =
 
== Subvolumes ==
 
To display all subvolumes within a mounted btrfs filesystem:


=== Subvolume ===
<syntaxhighlight lang="bash">
btrfs subvolume list -t /mnt
</syntaxhighlight>


Create a subvolume
To create a new subvolume at a specified location:


<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
Line 148: Line 176:
</syntaxhighlight>
</syntaxhighlight>


Removing a subvolume
To remove an existing subvolume:


<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
Line 154: Line 182:
</syntaxhighlight>
</syntaxhighlight>


=== Snapshots ===
=== Top level vs nested subvolumes ===
 
In btrfs, subvolumes can be created either at the top level of the filesystem or within other subvolumes
 
* Top level subvolumes are created directly under the filesystem's root. By default, the root volume id is 5. Top level subvolumes are easier to snapshotted, rolled back or destroyed independently. This is good for things such as <code>/home</code> or <code>/nix</code>.
 
* Nested subvolumes are created inside an existing subvolume or directory within the filesystem. All nested subvolumes inherit the mount status of their parent unless mounted seperately. This layout is useful for organizing related subvolumes under a common namespace. For example, a top-level subvolume such as <code>/srv/nfs</code> can contain multiple nested subvolumes like <code>/srv/nfs/export1</code> and <code>/srv/nfs/export2</code>.
 
 


A snapshot in btrfs is simply a subvolume that shares its data (and metadata) with some other subvolume, using btrfs's COW capabilities.
== Snapshots ==


Because of that, there is no special location for snapshots - you need to decide where you want to store them for yourself. It can be a simple directory inside root subvolume, or a directory inside a dedicated "snapshots" subvolume.
A snapshot in btrfs is simply a subvolume that shares its data (and metadata) with some other subvolume, using btrfs's CoW capabilities. Because of that, there is no special location for snapshots and you can decide where you want to store them. It can be a simple directory inside the root subvolume, or a directory inside a dedicated "snapshots" subvolume.


For this example we are going to store snapshots in a simple directory <code>/snapshots</code>, that has to be created beforehand with <code>sudo mkdir /snapshots</code>
For this example we are going to store snapshots in a directory <code>/snapshots</code>, that has to be created beforehand with <code>sudo mkdir /snapshots</code>


Taking a read-only (<code>-r</code>) snapshot called <code>home_snapshot_202302</code> of the subvolume mounted at <code>/home</code>
To take a read-only (<code>-r</code>) snapshot called <code>home_snapshot_202302</code> of the subvolume mounted at <code>/home</code>


<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
Line 168: Line 204:
</syntaxhighlight>
</syntaxhighlight>


You can also snapshot the root subvolume. But keep in mind, that nested subvolumes are '''not''' part of a snapshot. So if you have subvolumes <code>/nix /home</code>, taking snapshot of <code>/</code> will not include them.
You can also snapshot the root subvolume. But keep in mind that nested subvolumes are '''not''' part of a snapshot. So if you have subvolumes <code>/nix /home</code>, taking a snapshot of <code>/</code> will not include them.


<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
Line 174: Line 210:
</syntaxhighlight>
</syntaxhighlight>


Make snapshot read-write again
Make snapshot read-write againː


<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
Line 180: Line 216:
</syntaxhighlight>
</syntaxhighlight>


However, changing read-only property of a snapshot in-place may [//lore.kernel.org/linux-btrfs/06e92a0b-e71b-eb21-edb5-9d2a5513b718@gmail.com/ causes issues] with any future incremental send/receive.
However, changing read-only property of a snapshot in-place may [//lore.kernel.org/linux-btrfs/06e92a0b-e71b-eb21-edb5-9d2a5513b718@gmail.com/ causes issues] with any future incremental send/receive. Instead, a read-only snapshot itself (being a simple subvolume) can be snapshotted again as a read-write snapshot like this:<syntaxhighlight lang="bash">
 
Instead, a read-only snapshot itself (being a simple subvolume) can be snapshoted again as a read-write snapshot like this:
<syntaxhighlight lang="bash">
btrfs subvolume snapshot /snapshots/home_snapshot_202302 /snapshots/home_snapshot_202302_rw
btrfs subvolume snapshot /snapshots/home_snapshot_202302 /snapshots/home_snapshot_202302_rw
</syntaxhighlight>
</syntaxhighlight>


Or it can be restored directly to <code>/home</code> straight away like this:
Or it can be restored directly to <code>/home</code> straight away like this:
{{warning|1=this will delete current <code>/home</code> and restore the snapshot! <code>/home</code> must be unmounted for this operation}}
{{warning|1=this will delete the current <code>/home</code> and restore the snapshot! <code>/home</code> must be unmounted for this operation}}


<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
Line 194: Line 227:
btrfs subvolume snapshot /snapshots/home_snapshot_202302 /home
btrfs subvolume snapshot /snapshots/home_snapshot_202302 /home
</syntaxhighlight>
</syntaxhighlight>
After this you can mount <code>/home</code> again./
After this you can mount <code>/home</code> again.
 


=== Transfer snapshot ===
== Transfer snapshot ==


Sending the snapshot <code>/snapshots/nixos_snapshot_202302</code> compressed to a remote host via ssh at <code>root@192.168.178.110</code> and saving it to a subvolume mounted or directory at <code>/mnt/nixos</code>
Sending the snapshot <code>/snapshots/nixos_snapshot_202302</code> compressed to a remote host via ssh at <code>root@192.168.178.110</code> and saving it to a subvolume mounted on a directory at <code>/mnt/nixos</code>


<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
Line 205: Line 237:
</syntaxhighlight>
</syntaxhighlight>


== Tips and tricks ==
If both the sender and receiver side have Btrfs with the same compression algorithm and level, you can instead use <code>send --compressed-data</code> to avoid decompressing and recompressing the data.
 
= Tips and tricks =
 
== Backup ==
 
[[Btrbk]] is a tool for creating snapshots and remote backups of btrfs subvolumes.
 
== Installation with encryption ==


=== Installation with encryption ===
Using [https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup Luks2]:
Using [https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup Luks2]:
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
Line 215: Line 254:
</syntaxhighlight>
</syntaxhighlight>


You can use any device paritition for your bootloader # Notice that this bootloader is unencrypted on default:
You can use any device partition for your bootloader. Note that this bootloader is unencrypted by default:


<code>
<code>mkfs.vfat -n BOOT "$DISK"p1</code>
mkfs.vfat -n BOOT "$DISK"p1  
</code>


==== Creating Subvolumes ====
=== Creating subvolumes ===


<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
Line 241: Line 278:
Unmount to mount on the subvolumes for the next steps:
Unmount to mount on the subvolumes for the next steps:


<code>
<code>umount /mnt</code>
umount /mnt  
 
</code>
Once the subvolumes have been created, mount them with the desired options.


Once the subvolumes has been created, mount them with the options.
Example with [https://facebook.github.io/zstd/ Zstandard compression] and noatime:
Example with [https://facebook.github.io/zstd/ Zstandard compression] with noatime:
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
mount -o subvol=root,compress=zstd,noatime /dev/mapper/enc /mnt  
mount -o subvol=root,compress=zstd,noatime /dev/mapper/enc /mnt  
Line 288: Line 324:
</syntaxhighlight >
</syntaxhighlight >


=== Convert Ext3/Ext4 system partition to Btrfs ===
== Convert Ext3/Ext4 system partition to Btrfs ==


<div style="border: 1px solid #D33; background: #FFEBEB; padding: 30px; border-radius: 5px; margin: 10px 0px; display: flex; align-items: center;">
<div style="border: 1px solid var(--border-color-error); background: var(--background-color-error-subtle); padding: 30px; border-radius: 5px; margin: 10px 0px; display: flex; align-items: center;">
     <div style="color: #D33; font-size: 40px; margin-right: 15px; background: #FFEBEB; display: flex; line-height: 0;  align-items: center;">⚠</div>
     <div style="color: var(--border-color-error); font-size: 40px; margin-right: 15px; background: var(--background-color-error-subtle); display: flex; line-height: 0;  align-items: center;">⚠</div>
     <div style="color: #D33; font-size: 15px; font-style: normal; font-weight: 400; line-height: normal; text-align: left;">Note that migrating your existing root filesystem can cause data loss or make your system unbootable. Make sure to backup the partition or your files. Proceed only if you know what you're doing!</div>
     <div style="color: var(--border-color-error); font-size: 15px; font-style: normal; font-weight: 400; line-height: normal; text-align: left;">Note that migrating your existing root filesystem can cause data loss or make your system unbootable. Make sure to backup the partition or your files. Proceed only if you know what you're doing!</div>
</div>
</div>


To convert the existing filesystem (Ext3/4) to Btrfs, boot into a NixOS live system and run following command<syntaxhighlight lang="sh">
To convert the existing filesystem (Ext3/4) to Btrfs, boot into a NixOS live system and run the following commandː<syntaxhighlight lang="sh">
fsck -f /dev/sdXY
fsck -f /dev/sdXY
btrfs-convert /dev/sdXY
btrfs-convert /dev/sdXY
</syntaxhighlight>Replace the device path with the target partition. Converting larger filesystems can take a long time.
</syntaxhighlight>Replace the device path with the target partition. Converting larger filesystems can take a long time.


Next, mount the converted filesystem and chroot into it<syntaxhighlight lang="sh">
Next, mount the converted filesystem and chroot into itː<syntaxhighlight lang="sh">
mount /dev/sdXY /mnt
mount /dev/sdXY /mnt
nixos-enter --root /mnt
nixos-enter --root /mnt
Line 311: Line 347:
</syntaxhighlight>Apply the changes<syntaxhighlight lang="sh">
</syntaxhighlight>Apply the changes<syntaxhighlight lang="sh">
nixos-rebuild boot
nixos-rebuild boot
</syntaxhighlight>In case Grub bootloader is used and it doesn't get reinstalled correctly, you can run following command inside chroot<syntaxhighlight lang="sh">
</syntaxhighlight>If the Grub bootloader is used and it doesn't get reinstalled correctly, you can run the following command inside chrootː<syntaxhighlight lang="sh">
grub-install /dev/sdX
grub-install /dev/sdX
</syntaxhighlight>If the conversion went successful and no rollback is required, the backup image which was stored by btrfs-convert can be removed with<syntaxhighlight lang="sh">
</syntaxhighlight>If the conversion was successful and no rollback is required, the backup image which was stored by btrfs-convert can be removed withː<syntaxhighlight lang="sh">
btrfs subvolume delete /btrfs/ext2_saved
btrfs subvolume delete /btrfs/ext2_saved
</syntaxhighlight>
</syntaxhighlight>
[[Category: Configuration]]
[[Category: Configuration]]
[[Category:Filesystem]]
[[Category:Filesystem]]