Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: March 26, 2024
Similar to /etc/mtab, the /etc/fstab (FileSystem TABle) file is a way to define filesystem mount points and options. In addition, it’s usually employed during boot to mount most entries automatically. Due to the fundamental role of the filesystem in computing, knowing how to mount according to the use case and conditions can be paramount.
In this tutorial, we explore the /etc/fstab file and the options it provides for mounting. First, we briefly refresh our knowledge about /etc/fstab. After that, we turn to the filesystem and device specification field details. Finally, we explore the options that most entries in /etc/fstab support.
We tested the code in this tutorial on Debian 12 (Bookworm) with GNU Bash 5.2.15. Unless otherwise specified, it should work in most POSIX-compliant environments.
Essentially, /etc/fstab is a text file with one entry per line that employs the usual octothorp for comments:
$ cat /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# systemd generates mount units based on this file, see systemd.mount(5).
# Please run 'systemctl daemon-reload' after making changes here.
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/sda1 during installation
UUID=0384f97c-c436-4f80-914e-bd26674d32fc / ext4 errors=remount-ro 0 1
# /tmp was on /dev/sda7 during installation
UUID=349107bc-693f-4e74-6660-2986bedcd49c /tmp ext4 defaults 0 2
# /var was on /dev/sda5 during installation
UUID=bc7e309f-ead1-4301-0f1b-dcc795bd877f /var ext4 defaults 0 2
# swap was on /dev/sda6 during installation
UUID=8acf3237-7b40-45b8-b666-cf534dfb8181 none swap sw 0 0
/dev/sr0 /media/cdrom0 udf,iso9660 user,noauto 0 0
As we can already notice, each line has several fields:
Further, the comments hint that systemd employs /etc/fstab for its mount units. Hence, performing a daemon-reload after changes to /etc/fstab is a good idea.
While there are alternatives to this mounting method, they either rely on fstab similar to systemd.automount or are older like /etc/autofs/.
Since the type, dump, and pass fields are fairly basic to understand and use, let’s check the last two, and more complex, fields.
Linux refers to filesystem devices in four main ways:
Notably, we can specify both a LABEL and PARTLABEL similar to UUID and PARTUUID. The PART* identifiers usually mean we work with a GUID Partition Table (GPT).
In any case, a UUID usually preserves better stability over time.
If we migrate from an HDD to an SSD, the device path may change. Even if we switch around cables to different storage media within a system, we might still end up with an incorrect path like /dev/sda1 instead of /dev/sdb1.
When dealing with labels, ambiguity is often the biggest problem. Another is support since not all filesystems understand labeling. This can also lead to a mix between labels and paths in /etc/fstab, which can be confusing.
On the other hand, a UUID is a generated string that a system uses to refer to a partition. This is based on the partition instead of the underlying device and doesn’t change as long as the partition metadata remains the same. In fact, we can usually preserve a UUID even when modifying the definition of a given partition, but this isn’t often recommended.
Lastly, a hardware block device ID is often based on the actual hardware ID, so it can also serve as a good and stable way to reference a device or partition. Still, unlike UUID, it’s linked to the physical medium.
Different scenarios may require verifying the entries in fstab:
Failing to register a bad change or lack thereof may result in a critical filesystem like / root not mounting. This may leave the system in recovery mode at best or require special tools to restore at worst.
Perhaps the central and more complex part of the /etc/fstab file is the options column that defines specific modifications to the behavior of a given mount. These are supplied to the standard mount command.
Let’s explore them.
Notably, we only look at options that apply to any filesystem, regardless of whether all filesystems recognize them. There are many other specific options that depend on the filesystem type.
In most cases, the last specified option overwrites its counterparts earlier in the list, even if they are implied.
Often, we encounter only defaults in the options column. This isn’t a specific setting but a set of common options:
Let’s delve into those and other options.
The auto option can be used with most entries:
$ cat /etc/fstab
[...]
UUID=633ebbcc-4ae0-48ab-a4e2-c08666547564 /initx ext4 auto 0 0
When an entry includes auto, the filesystem should be mounted during boot.
Further, if we issue mount with the –all (-a) flag, the system attempts to mount all auto entries:
$ mount --all
This way, we don’t need to specify each mount separately.
Since defaults includes auto, we can deduce that this is the more common option.
However, there are cases when we might want to use noauto and explicitly prevent automatic mounts.
Let’s see an example:
$ cat /etc/fstab
[...]
UUID=e46741f7-70c0-4eca-b797-f3c4d3df6a87 /var/kubernetes ext4 noauto 0 0
In this case, we have a mount that contains Kubernetes data. Since Kubernetes might not start for a while or at all after the system boots, it’s usually a better idea to perform this mount manually from the script that initializes Kubernetes itself.
By default, the mount command enables the [exec]ution of files on new mounts. This is usually preferred since storage is often universal and aims to accommodate multiple scenarios.
Depending on the contents of a filesystem, we may want to prevent binary file execution with noexec:
In these instances, we can still set a file as executable, but we wouldn’t be able to actually run it.
$ mount
[...]
/dev/sdx8 on /backup type ext4 (rw,noexec,relatime)
$ cd /backup
$ chmod +x script.sh
$ ls -lh
total 13K
-rwxr-xr-x 1 root root 50 Mar 22 06:56 script.sh
$ ./script.sh
-bash: ./script.sh: Permission denied
Although the executable bit is set on script.sh, we get a Permission denied error during execution.
Still, we can use an executable from an exec filesystem to run the noexec-filesystem script:
$ bash script.sh
Success.
In this case, we employ the bash interpreter from /bin/ on the root filesystem.
The async option is the default as it optimizes performance and extends the lifespan of storage media. Filesystem drivers achieve this mainly through multiple threads and buffering.
Depending on the way storage is used, we can prefer to set its input and output as [sync]hronized, which implies several conditions:
In general, sync prioritizes safety over performance. The sync option only affects ext*, *fat, ufs and xfs filesystems.
Notably, dirsync is similar, but only affects directory updates for some system calls: creat(), link(), unlink(), symlink(), mkdir(), rmdir(), mknod(), and rename().
Character and block devices are files that represent access points to devices. Of course, to have such a file, a device needs proper drivers or recognition by the Linux kernel. The main distinction between the two is the way they handle data: by character or by block.
For example, /dev/sda is a way to refer to, read from, write to, and generally manipulate the first storage drive. The same goes for devices like /dev/ttyS*, but also /dev/char/10:1 and similar.
Whether we want a filesystem to recognize character and block device files as such (dev) or not (nodev) depends on the way we intend to use that filesystem. In general, if we don’t expect such files, but enable their recognition, it can become a vulnerability.
Several options relate to security and permissions.
The main way to prevent any writes to a filesystem is to use the ro option, which performs a read-only mount. On the other hand, the default rw enables both reading and writing.
Further, the suid option allows the use and interpretation of suid and sgid bits for running executables with elevated privileges. Since this mechanism can provide a loophole around the regular permissions, we might want to use nosuid and disable it.
Similar to the configuration for other special files, the nosymfollow option disables following symbolic links during path resolution but doesn’t prevent their creation.
When it comes to users that can perform a particular mount there are several ways to manage them:
Notably, the user, group, owner, and users options also imply several others:
Lastly, the context, fscontext, defcontext, and rootcontext options enable the specification of extended attributes in some filesystems that don’t natively support them.
In terms of performance, multiple options can disable certain filesystem features to decrease wear and increase speed and throughput. Often, such settings come down to metadata updates.
For example, lazytime forces the filesystem to only work on access, modify, and change times in-memory. With this buffering, storage writes are significantly reduced at the cost of potential data loss, since timestamps are only written to storage in one of four cases:
As expected, nolazytime disables lazytime.
Specifically for access times, noatime (implies nodiratime) prevents inode updates for access times on any filesystem object. This is the default option. On the other hand, we can add atime to force these updates at the cost of performance. The *dir* relatives of atime and noatime function the same way, but only affect directories. Unlike other options, noatime disables diratime, which is normally the default.
If we do need to update access times, but only if they are currently before the modify or change times, we can use relatime.
Another performance setting is iversion (with its counterpart noiversion) that keeps track of inode versions in the i_version field on each update.
The X-* and x-* custom options are both ways to pass comments or userspace options to applications. The main difference between them is that X-* options are stored in userspace. Usually, the suggested format for either is similar to [X|x]-appname.option
For instance, the X-mount.mkdir option makes mount create a directory for the mount point if it doesn’t exist. In addition, we can provide the optional octal mode (default is 0755) of the directory. Another example is the X-mount.subdir option, which points to a subdirectory instead of the root of a filesystem to mount.
In this article, we explored the /etc/fstab file and most filesystem-agnostic options it supports.
In conclusion, automated filesystem mounts are essential to any system, so knowing how to manage their options can be critical.