What's in your /etc/fstab?
After years of practice, I think I’ve finally reached my filesystem mountpoint nirvana on Linux.
#
# /etc/fstab: static file system information
#
# <file system> <dir> <type> <options> <dump> <pass>
LABEL=root / btrfs rw,noatime,ssd,space_cache,noautodefrag,compress=zstd,subvolid=263,subvol=@/tw 0 0
LABEL=root /home btrfs rw,noatime,ssd,space_cache,noautodefrag,compress=zstd,subvolid=262,subvol=@/home 0 0
LABEL=data /var btrfs rw,relatime,space_cache,autodefrag,compress=lzo,subvolid=29010,subvol=@/var/tw 0 0
LABEL=data /data btrfs rw,relatime,space_cache,autodefrag,compress=lzo,subvolid=22133,subvol=@/data 0 0
LABEL=container /var/lib/docker btrfs rw,relatime,space_cache,subvolid=6444,subvol=@/var/lib/docker 0 0
LABEL=container /var/lib/containers btrfs rw,relatime,space_cache,subvolid=6151,subvol=@/var/containers 0 0
LABEL=efi /boot/efi vfat rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro 0 2
tmpfs /tmp tmpfs rw,nodev,nosuid,size=10% 0 0
tmpfs /home/suse/Downloads tmpfs rw,nodev,uid=suse,gid=users,size=100m 0 0
There’s a lot to unpack on those few lines, but I’ll try to explain the reasoning for all those options, subvolume structure, and any of the other odd odd choices. Along with a bit on what’s the use of all this.
The Filesystems
Why Btrfs?
I know this will be asked even before I bring up the logic on the filesytem tab. So here’s a bit of back story. Before I even thought of utilizing btrfs for my needs (a decade ago…), I was using LVM as the supreme overlord of all my boxes. I had a full set of ext* Logical Volumes (LV), all with different size constraints to the partitioning I desired. I had almost everything you can think of as broken down to an LV. /var
, /opt
, /var/log
, /etc
, /srv
, /home
, and /boot
were all given their own LV. The reasoning was to constrain the fault tolerance from changes in installs to a minimal and to be able to snapshot a backup of each LV for those cases I did something that I shouldn’t have.
So again, why btrfs? The filesystem gets a lot of bad press for the earlier years of its development cycle. But for all its issues then, the abilities the filesystem have are extremely hard to live without, like subvolumes. Turns out my separate LV separation was imitating subvolume structure of btrfs. So instead of having to create a full logical partitions, the ability was baked in to the filesystem.
Another feature that really sold me for btrfs has to be my most favored prized position: the ability to expand or shrink the size of a btrfs filesystem with the simple btrfs device add
and btrfs device delete
commands. You can basically add any drive you may have laying around to use without having to worry of mirroring the same drive size or dealing with RAID types. Simply add the new drive to your box, boot up and run that sweet btrfs device add
for the new drive to sync and ready to become full (making sure the drive is wipe clean beforehand of course).
I can go on for quite a while over the practicalities of Btrfs, but that is not the point of this post, maybe of another post… Instead, let’s actually continue going here over the other sections.
tmpfs for your Downloads!?
Yes, I have tmpfs for my Downloads directory. The reason is fairly simple. I like to keep my entire home directory organized. However, the Downloads directory has a tendency to become an all encompassing mess of files downloaded. Keeping the directory as a tmpfs requires to move permanent files to where they should go and allowing to not worry about having to delete the files that won’t go anywhere. On your next reboot, it will be wiped clean to start again your download fiasco. The size limit of the directory is also on purpose. I’ve noticed for myself that I tend to download many small files here and there during my computing time. Keeping the size limit at 100 MiB fulfills the requirement of having to organize my home directory if I want to get more ‘download space’. Essentially, if a file is large enough, it will find a home somewhere else, which most likely means that file is permanent. Again, fulfilling the organization requirement.
tmpfs for /tmp too
So while Downloads plays for the organization constraint, /tmp
being tmpfs gives me the luxury of a little speed boost for running applications. Simply put, anything that requires a lot of read/writes but is not permanent should have a tmpfs associated to it. The /tmp
is both to keep anything here cleared on a reboot and to make sure that applications that do use the directory, run just a little bit better.
The Labels
So the first piece you may have noticed is that every drive defined is declared with a label. The labels play a key role in the fstab here. Due to my usage of btrfs, there are times that I may have quite a number of devices added to a btrfs filesystem. Using an UUID can get quite confusing at times as the underlying filesystem may hold more than a few devices. While rare, sometimes even the main drive using an UUID may be swapped out in favor for a faster or better drive. So instead of trying to define the partitioned drive by its UUID or god forbid, device id, it’s simply easier to use a label for the corresponding filesystems. This way, no memorization is required and I know full well what is the purpose of each filesystem by the label given to them.
Going with the labels provided above, here is a quick breakdown of each label:
- root – would entail for anything requiring fast IOPs. Which means the devices associated to root would be very performant devices. So
/home
and/
usually reside here. I used to call this label fast, but ended up shifting to root due to inconsistency with the label names. - data – here is where most of data oriented filesystem things live. Anything like media or large writes would find a home in data.
- container – docker and cri-o tend to like to pollute btrfs with an excess of subvolumes. It is by design they do this for optimization in CoW and how the container hashed changes are expressed, but darn can this balloon up your btrfs subvolumes. This is why you may see subvolid of 29010 for
/var
. So the container filesystem keeps these excess of subvolumes contained in their own label. - efi – the holder of UEFI required partition. Nothing truly special here as most may be familiar with the filesystem and its requirement due to the standard.
The Mount Options
Here goes the true package of the fstab. While most of what’s been discussed is the reasoning for the formatting and choice in filesystem, here is where the optimizations come to play for btrfs. Most of the settings are a mix of standard mount options with btrfs mount options.
The first set of settings that should be looked at are the ones for /
and /home
:
LABEL=root / btrfs rw,noatime,ssd,space_cache,noautodefrag,compress=zstd,subvolid=263,subvol=@/tw 0 0
LABEL=root /home btrfs rw,noatime,ssd,space_cache,noautodefrag,compress=zstd,subvolid=262,subvol=@/home 0 0
- rw is for read/write and is what allows to have a mutable mounted filesystem.
- When using an SSD or NVMe, always run with noatime and ssd. The noatime is to make sure writes are kept at a minimum and ssd is to use settings from btrfs, which also optimizes for the type of drive. Next three are all for optimizations on btrfs.
- space_cache is to optimize reads when reading a block group for memory. Absolutely vital when you want to speed up how btrfs performs and as an added bonus, helps with read operations on a non disk drive.
- noautodefrag is to make sure de-fragmenting the drive is done manually for
/
. - zstd compress is to lower the disk usage of files in the filesystem. The real nice part is that with zstd, you can reach very similar IOPs to native, while still saving in space. It’s absolutely a no brainer and should be everyone’s compression choice in btrfs.
- subvolid and subvol are both for defining the volume id used to mount the subvolume you want. Using both as a precaution of human error rather than a requirement.
The second set would be for the data label data /var
and /data
. Due to similarities, will only break down the differences between data and *root label options:
LABEL=data /var btrfs rw,relatime,space_cache,autodefrag,compress=lzo,subvolid=29010,subvol=@/var/tw 0 0
LABEL=data /data btrfs rw,relatime,space_cache,autodefrag,compress=lzo,subvolid=22133,subvol=@/data 0 0
- relatime in reverse of the need for noatime with faster devices, slower devices benefit greatly from bundles inodes updates for better write and read operations on a disk driver.
- autodefrag is enabled here due to the amount of data held and simultanously the small writes to
/var
. - lzo compression here is due to mostly legacy and the size of the storage. While, I had the luxury of updating my root devices quite regurlarly, I try not cause such changes to the actual data being held. Originally, the compression type was used due to at the time, lzo being the most peformant compression available for large data sets on btrfs.
The last set is one that may encoruage some thoughts; the containers label mount options:
LABEL=container /var/lib/docker btrfs rw,relatime,space_cache,subvolid=6444,subvol=@/var/lib/docker 0 0
LABEL=container /var/lib/containers btrfs rw,relatime,space_cache,subvolid=6151,subvol=@/var/containers 0 0
Since all the other sets explained the mount options, for the containers label mount options, I will instead state why the simplicity. App containers have a tendency to be very write prone and disk storage intensive technology. As such, your options here are to either pay a pretty penny to get a large NVMe for handling such operations or get a measly disk drive to last you a bit longer, but sacrificing speed. Since this isn’t production and just my home box, I settled with disk drives for the container label. Also note, there is no compression used on these devices. It’s completely on purpose. Compression with app containers simply do not mix and you can decrease the performance by considerable margin (most certainly another post some day).
Finally when it comes to the mount used for tmpfs, the differences here are how much memory to use for the mount points. Simply using enough RAM allocated for these mount points without becoming too overbearing on their allocations.
Reasoning of the madness
The main options for the mount options and targets have been discussed in some detail for each label class, but not the why of this madness. The /etc/fstab
structure presented helps keep my machine as stable as possible while also introducing constant changes. You may have noticed that certain subvol
options mount paths point to /tw
. The format is due to the fact I don’t just use one Linux distribution but two: Pop!_OS and Tumbleweed. Being able to swap the OS distribution I use by just a quick restart helps test quite a lot of experimental work, without effecting my /home
directory or actual stability of my development. Things like read-only filesystem architecture design and kernel experimental changes that most certainly destroy an OS, can be done without ever effecting your ability to actually work on the machine. On top of this, I can rollback changes thanks to btrfs’s snapshots and debug issues produced from experiments on an OS, all thanks to the /etc/fstab
structure presented.
So what’s in your /etc/fstab
?