Mounting filesystems on Linux is simple, right? Just use mount(8), specify the recurring stuff in fstab(5), and everything’s peachy. For both better and worse, there’s more to it than that. Filesystem dependencies are handled by systemd and tools like udev(7), udisks2, and GIO provide userspace access to devices. Imagine not having to be root to access your flash drive? Okay, you’re probably aware that root isn’t necessary for such a thing, but that’s because there’s tools that take care of that for you.

I’ve been working through understanding the different components of this for a while now, but recently put most of it together addressing an important concept. That is mount options. Switching to Btrfs as my default filesystem and using it for my backups, I wanted to improve the default mount options. And, I wanted do have these defaults applied in userspace, not just in fstab(5) or when using mount(8). I’ve accumulated my knowledge on the subject here and describe exactly how to set Btrfs mount options to your liking, whichever way you might want.

Tutorial

This tutorial walks through the menagerie of methods for mounting a Btrfs volume with a specific set of mount options. The reference operating system is Ubuntu 18.04. It will underscore several available approaches specific to the kernel and userspace levels. You should have a fairly strong understanding of Linux, the command-line, and filesystems. I expect you to understand mount options.

Setup

This walk-through uses a mount point under the standard mount directory for your user. The mount point is /run/media/$USER/backups. This mount point must exist before we begin. Create this directory as follows.

sudo mkdir -p /run/media/$USER/backups

The rest of the tutorial will use $USER to substitute your username on the command-line. Command-line output will use my username, jordan, instead to reflect the output when I run the command. Your username will appear instead of jordan.

This tutorial also uses a USB connected storage device which appears as sdb. Your device could be under the same name in the device tree or it might use a different name. To locate your USB device, examine the output of lsblk.

lsblk
NAME           MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
sda              8:0    0   1.8T  0 disk
├─sda1           8:1    0   976M  0 part  /boot
└─sda2           8:2    0   1.8T  0 part
  └─sda2_crypt 253:0    0   1.8T  0 crypt /opt
sdb              8:16   0 931.5G  0 disk  (1)
└─sdb1           8:17   0 931.5G  0 part
sr0             11:0    1  1024M  0 rom
1 This is my 1 TB external hard drive.

The device used in the examples has a single partition, sdb1, formatted as Btrfs. If you would like to follow along with your own device, you can format your device as follows.

This will effectively obfuscate any data on the drive making it very difficult or impossible to recover.

  1. Wipe any existing partition tables on the flash drive and generate a new one.

    The set of gdisk commands, consisting of cgdisk(8), gdisk(8), and sgdisk(8), manipulate GUID partition tables, also known as GPT's. Older {master-boot-records}, MBR's, are instead managed with fdisk(8) and its similarly named friends. Here, the sgdisk(8) command is used to partition the flash drive using the newer GPT format without requiring any user interaction.

    sudo sgdisk -Z -n 0:0:0 -c 0:"Black WD HDD" /dev/sdb
    GPT data structures destroyed! You may now partition the disk using fdisk or
    other utilities.
    Setting name!
    partNum is 0
    The operation has completed successfully.

    The -Z flag zaps any existing MBR and GPT partition tables into oblivion. Then, the -n flag creates a new partition given the partition number, starting sector, and ending sector separated by colons. Zeros used here represent default values. The first zero sets the partition number to the next available number, which is one since this is the first partition on the flash drive. The next two zeros designate the starting sector of the largest block and the last sector of that same block, creating a single partition which effectively takes up the entirety of the flash drive. The -c flag labels the new partition which is indicated by the 0:. The label here provides a basic description of the disk.

  2. Format the partition with Btrfs.

    Here I label the volume with a descriptive name of the disk and its purpose.

    sudo mkfs -t btrfs -L "Black WD EasyStore External HDD - My Backups" /dev/sdb1
    btrfs-progs v4.15.1
    See http://btrfs.wiki.kernel.org for more information.
    
    Label:              Black WD EasyStore External HDD - My Backups
    UUID:               13177899-cb85-45b7-99b6-b76e2fc41f44 (1)
    Node size:          16384
    Sector size:        4096
    Filesystem size:    931.48GiB
    Block group profiles:
      Data:             single            8.00MiB
      Metadata:         DUP               1.00GiB
      System:           DUP               8.00MiB
    SSD detected:       no
    Incompat features:  extref, skinny-metadata
    Number of devices:  1
    Devices:
       ID        SIZE  PATH
        1   931.48GiB  /dev/sdb1
    1 Note the UUID here for use in later examples.
  3. Then mount the volume.

    sudo mount -o noatime,autodefrag,compress=zstd,commit=120 \
      /dev/sdb1 \
      /run/media/$USER/backups
  4. Create a subvolume for storing backups.

    sudo btrfs subvolume create /run/media/$USER/backups/my-backups
    Create subvolume '/run/media/jordan/backups/my-backups'
  5. Set the current user as the owner of the subvolume.

    sudo chown $USER:$USER /run/media/$USER/backups/my-backups
  6. Umount the volume.

    sudo umount /run/media/$USER/backups
  7. If you didn’t note your volume’s UUID, you can do so with the following command.

    lsblk -no uuid /dev/sdb1
    13177899-cb85-45b7-99b6-b76e2fc41f44

System-level Mounting

At the system-level, the primary ways to management mounts are mount(8), fstab(5), and systemd. Each of these is discussed below.

mount

Old faithful and ever present, mount(8) is ubiquitous. Use it to mount a filesystem as root giving it a comma-separated list of options preceded by the -o flag, the device, and the mountpoint. To mount the Btrfs subvolume named backups on the block device /dev/sdb1 to /run/media/$USER/backups with several mount options, use the following command.

sudo mount -o noatime,autodefrag,compress=zstd,commit=120,subvol=my-backups \
  '/dev/disk/by-label/Black\x20WD\x20EasyStore\x20External\x20HDD\x20-\x20My\x20Backups' \
  /run/media/$USER/backups

To unmount the device, use the umount command with the device path or the path of the mount point. Here, the previously mounted device is unmounted.

sudo umount /run/media/$USER/backups

Easy, right?

fstab

To automatically mount something, fstab(5) is the de facto standard. The previous command can be translated to the following entry in fstab.

UUID=13177899-cb85-45b7-99b6-b76e2fc41f44 /run/media/jordan/backups btrfs defaults,nofail,noauto,noatime,autodefrag,compress=zstd,commit=120,subvol=my-backups 0 0

To avoid throwing a wrench in the entire boot process, include the nofail mount option if this is a removable drive of some kind. This tells the system it’s okay if the drive is missing when its booting up. The defaults option includes the auto option which mounts the volume automatically while booting. Adding the noauto option disables this.

Now this subvolume will be mounted with the appropriate options when the system is booted up. Or, at least, it should…​ Always verify your fstab file after modifying it with findmnt --verify. Here I include the --verbose flag as well and abbreviate the output.

findmnt --verify --verbose
/
   [ ] target exists
   [ ] VFS options: noatime
   [ ] FS options: autodefrag,compress=zstd,commit=120,subvol=root
   [ ] source /dev/mapper/sda2_crypt exists
   [W] cannot detect on-disk filesystem type
   [W] recommended root FS passno is 1 (current is 0)

...

/run/media/jordan/backups
   [ ] target exists
   [ ] VFS options: noatime
   [ ] FS options: autodefrag,compress=zstd,commit=120,subvol=my-backups
   [ ] userspace options: nofail,noauto
   [ ] UUID=13177899-cb85-45b7-99b6-b76e2fc41f44 translated to /dev/sdb1
   [ ] source /dev/sdb1 exists
   [W] cannot detect on-disk filesystem type

0 parse errors, 0 errors, 17 warnings

There’s no errors and the warnings don’t appear to be anything serious. Everything should be alright.

Previously when using the mount command, each mount option had to be specified. When mounting a matching entry in fstab, the mount options in fstab are applied automatically. The following command will mount the volume using the mount options specified in fstab for /run/media/$USER/backups.

sudo mount /run/media/$USER/backups

systemd

This is where things start to get complicated. systemd handles dependencies among all sorts of services whether that’s during boot or during runtime. Some things require mounting filesystems, so systemd exposes an interface for specifying and managing these dependencies. The primary unit file for this is the systemd.mount(5) unit.

A companion unit file type exists systemd.automount(5) which, if created, controls automatically mounting the mount point. The automount functionality will automatically mount a volume in an on-demand fashion. When the volume is first accessed, it is mounted as necessary. A timeout may be specified to automatically unmount the volume after a period of time.

An important aspect the mount unit convention is the required naming scheme. The file names of mount and automount units must correspond to the mount point of where the volume will be mounted. The file name is appropriately transformed to remove troublesome characters. Most notably, `/’s are replaced with `-’s.

Generated

systemd integrates nicely enough with fstab such that it automatically generates these mount units from their entries. Being able to inspect the mount units on a system can come in handy, so here’s how.

Having just edited fstab, systemd will not generate an entry for /run/media/jordan/backups until the system reboots. I don’t want to reboot, so I’ll just reload the necessary components before examining the generated unit files.

  1. Reload systemd.

    sudo systemctl daemon-reload
  2. Restart the local-fs target.

    sudo systemctl restart local-fs.target
  3. Use the systemctl subcommand list-unit-files and specify the mount type with the -t flag to list all mount unit files.

    systemctl list-unit-files -t mount
    UNIT FILE                      STATE
    -.mount                        generated
    \x2esnapshots.mount            generated
    boot.mount                     generated
    dev-hugepages.mount            static
    dev-mqueue.mount               static
    home.mount                     generated
    run-media-jordan-backups.mount generated (1)
    opt.mount                      generated
    proc-sys-fs-binfmt_misc.mount  static
    root.mount                     generated
    srv.mount                      generated
    swap.mount                     generated
    sys-fs-fuse-connections.mount  static
    sys-kernel-config.mount        static
    sys-kernel-debug.mount         static
    tmp.mount                      generated
    usr-local.mount                generated
    var.mount                      generated
    
    18 unit files listed.
    1 The mount unit run-media-jordan-backups.mount corresponds to the mount point /run/media/jordan/backups and the corresponding fstab entry added previously.

To view the contents of a mount unit file, pass the name of the unit to systemctl after the subcommand cat. The following command displays the contents of the mount unit file generated for /dev/sdb1.

systemctl cat run-media-$USER-backups.mount
# /run/systemd/generator/run-media-jordan-backups.mount
# Automatically generated by systemd-fstab-generator

[Unit]
SourcePath=/etc/fstab
Documentation=man:fstab(5) man:systemd-fstab-generator(8)
Before=local-fs.target

[Mount]
Where=/run/media/jordan/backups
What=/dev/disk/by-uuid/13177899-cb85-45b7-99b6-b76e2fc41f44
Type=btrfs
Options=defaults,nofail,noauto,noatime,autodefrag,compress=zstd,commit=120,subvol=my-backups

A systemd.automount(5) can be generated automatically for an entry in fstab(5) by adding the x-systemd.automount mount option. You can pair this option with noauto if you wish to prevent the volume from being mounted automatically at boot. The x-systemd.idle-timeout mount option for automount units is handy for specifying how many seconds before an idle drive should be unmounted from the filesystem.

systemd-mount

Mount units can be generated on the fly by mounting volumes with systemd-mount(1). The systemd-mount command to mount /dev/sdb1 with the desired Btrfs options appears suspiciously like the corresponding mount command.

sudo systemd-mount -o noatime,autodefrag,compress=zstd,commit=120,subvol=my-backups /dev/sdb1 /run/media/$USER/backups
Started unit run-media-jordan-backups.mount for mount point: /run/media/jordan/backups

It’s possible to eschew the mount point and let systemd decide where to mount the volume. By default, this will mount the volume underneath the directory /run/media/system/<label> where <label> is a placeholder for the filesystem label or other identifier. Mount /dev/sdb1 to the default systemd location as follows.

sudo systemd-mount -o noatime,autodefrag,compress=zstd,commit=120,subvol=my-backups /dev/sdb1
Started unit run-media-system-backups.mount for mount point: /run/media/system/backups

Use the -A flag to generate a corresponding systemd automount unit when mounting a volume.

Likewise, use systemd.mount(5) to unmount the volume by providing either the device or the path to the mount point. This command unmounts the device /dev/sdb1 mounted with either or both of the previous two commands.

sudo systemd-umount /dev/sdb1
Stopped unit run-media-system-backups.mount for mount point: /run/media/system/backups
Manual

Practically speaking, it shouldn’t be necessary to create mount units outright. It’s still completely possible. The steps to do so our outlined below.

  1. Create a mount unit to mount the volume.

    /etc/systemd/system/run-media-jordan-backups.mount
    [Unit]
    Description=Additional drive
    
    [Mount]
    What=/dev/sdb1
    Where=/run/media/jordan/backups
    Type=btrfs
    Options=defaults,nofail,noauto,noatime,autodefrag,compress=zstd,commit=120,subvol=my-backups
    
    [Install]
    WantedBy=multi-user.target

    The name of the mount unit must reflect the path of the mount point.

  2. Enable the mount unit with systemctl.

    sudo systemctl enable run-media-$USER-backups.mount

A corresponding automount unit for the mount unit defined above would be as follows.

/etc/systemd/system/run-media-jordan-backups.automount
Description=Automount drive

[Automount]
Where=/run/media/jordan/backups

[Install]
WantedBy=multi-user.target

Usesrpace Mounting

Mounting filesystems without root privileges is less straightforward. While accommodations can be made for mount and systemd offers such functionality, the best tool to use is udisks2 which ships with most mainstream distributions. Each of these is discussed below.

mount

Given that fstab contains an entry with the user or users mount options, that entry can be mounted by the user without root privileges. This still requires support from someone with superuser access on the system, which is impractical for those users who just want to be able to mount a flash drive. This method doesn’t allow the user to mount the filesystem with any special mount options on the command-line. Mount options may only be specified within fstab.

The fstab entry below allows a user to mount /dev/sdb1 to /run/media/$USER/backups.

/etc/fstab
/dev/sdb1 /run/media/jordan/backups btrfs defaults,user,nofail,noauto,noatime,autodefrag,compress=zstd,commit=120,subvol=my-backups 0 0

Now, a user can mount the volume with the device path or the mount point as done here.

mount /run/media/$USER/backups

Attempting to provide both the device and mount point to the mount command as a user will result in an error. Here mount doesn’t like the fact that I gave it the device and the mount point.

mount /dev/sdb1 /run/media/$USER/backups
mount: only root can do that

A user can also unmount the entry they have mounted when it is set with the user option.

umount /run/media/$USER/backups

When the users option is provided, it allows any user to unmount the drive regardless of which user mounted it. This differs from the user option which only allows the user that mounted the volume to unmount it.

systemd

While systemd provides user-level services, including mounting, its abilities are limited to that of the mount command. And to that end, its practically usesless for userspace mounting. After trying all sorts of workarounds, the mount command just isn’t called correctly to allow non-root users the ability to mount filesystems. A corresponding fstab entry with the user or users mount option has no effect. This is because systemd hard-codes the mount command with both the device and the mount point. This was shown to end with an error when run as a normal user previously.

The only sensible way to make this possible is by using a {systemd-service} unit rather than a systemd mount unit. A correctly formed mount command will succeed when executed by the user. Given the entry for /run/media/jordan/backups has the user or users mount option set in fstab, a user service file to mount it would look like the following.

~/.config/systemd/user/mount-run-media-jordan-backups.service
[Unit]
Description=Mount my backups

[Service]
ExecStart=/bin/mount /run/media/jordan/backups
ExecStop=/bin/umount /run/media/jordan/backups
RemainAfterExit=yes

[Install]
WantedBy=default.target

User units are placed in different directories than system units. The ~/.config/systemd/user/ directory is a standard directory for user units. No root privileges are required to create units here.

To mount the volume, start the service.

systemctl --user start mount-run-media-$USER-backups.service

Unmounting the volume is just a matter of stopping the service. Do this like so.

systemctl --user stop mount-run-media-$USER-backups.service

If you want to mount automatically when logging in, use the enable subcommand instead of start.

systemctl --user enable mount-run-media-$USER-backups.service

To take this a step, further, it’s possible to create an instantiable systemd unit. This is a fancy way of saying that variable information can be provided in the file name after the @ symbol and before the units extension. This allows creating a single unit file to accommodate a variety of situations. It effectively introduces a variable which can be used to customize the unit.

The previous unit can be made into a generic, instantiable unit which allows mounting a variety of volumes. Thanks goes to byly’s answer on the Unix & Linux Stack Exchange for introducing me to this nifty approach. To follow conventions, the unit will mount the volume under /run/media/$USER. The mount point will be encoded in the name of the service, i.e. sandwiched between the @ and .service suffix. This user service unit, dubbed mount@, looks like this.

~/.config/systemd/user/mount@.service
[Unit]
Description=Mount volumes for a user which have the `user` or `users` mount options defined

[Service]
ExecStart=/bin/mount /run/media/%u/%I
ExecStop=/bin/umount /run/media/%u/%I
RemainAfterExit=yes

[Install]
WantedBy=default.target

This unit uses wildcards, letters prefixed with %. Wildcards are substituted with the appropriate information when the unit is enabled. %u stands for the username of the user using the unit. %I represents the instantiable component provided in the unit’s name.

With superuser access, the file can placed in the directory /etc/systemd/user/ instead of ~/.config/systemd/user/ to provide this user service to all users. Of course, you’ll probably want to use a path which doesn’t include the username, /run/media for instance, if you want to avoid creating an entry for each individual user in fstab.

To use the instantiable unit, the directory for the mount point must exist in /run/media/$USER. Additionally, an entry in fstab that mounts to that mount point must set the user or users mount option. Given those requirements, use the instantiable service as demonstrated here. To mount /run/media/run/$USER/backups, start the service with the name mount@backups.

systemctl --user start mount@backups.service

Unmount it by stopping the service of the same name.

systemctl --user stop mount@backups.service

Now it’s time to move on to a more practical tool for mounting volumes from userspace.

udisks2

There’s a tool for easily mounting volumes in userspace. It’s udisks2 and it streamlines userspace mounting and changing up those default mount options. If you’re accustomed to a desktop environment on Linux, you’ve likely benefitted from udisks2. That’s because it’s what graphical applications such as file managers use to mount drives on your behalf.

Mounting and unmounting are done with the udisksctl command. To mount a volume, use the mount subcommand. Unlike the mount program, only the block device is specified. The mount point is determined by udisks2. Depending on how udisks2 was compiled, the volume will be mounted in a subdirectory of either be /run/media/ or /media/. Use the -b flag before the block device. Mount options should be provided as a comma-separated list following the --options flag.

Here, I mount /dev/sdb1 with specific Btrfs mount options.

udisksctl mount -b /dev/sdb1 --options noatime,autodefrag,compress=zstd,commit=120,subvol=my-backups
Error mounting /dev/sdb1: GDBus.Error:org.freedesktop.UDisks2.Error.OptionNotPermitted: Mount option `autodefrag' is not allowed

Drat. udisks2 doesn’t allow the options I want. In version 2.9.0 of udisks2, a newer version than ships with Ubuntu 18.04, it’s possible to configure the allowed and default mount options as described in the following sections. A newer version of udisks2 can be installed on Ubuntu 18.04 by following the instructions in the post Install udisks2 From Source. It turns out the only allowed mount option here is noatime, so the simpler command below will still mount the volume.

udisksctl mount -b /dev/sdb1 --options noatime
Mounted /dev/sdb1 at /run/media/jordan/backups

Unmount the volume using the unmount subcommand followed by the -b flag and the block device.

The subcommand is the word unmount not umount.

udisksctl unmount -b /dev/sdb1
Unmounted /dev/sdb1.
Changing the Default and Allowed Mount Options

The udisks2 exposes the ability to change the default mount options since version 2.9.0. Unfortunately, Ubuntu 18.04 doesn’t ship with a new enough version. To install a version with these capabilities, follow the instructions in the post Install udisks2 From Source.

If you installed from source into the default destination under /usr/local, then the configuration file and udev rules will be under /usr/local instead of /usr. Adjust the file paths used in the following examples accordingly.

The configuration of mount options udisks2 is done through a global configuration file or udev rules. Options can be tweaked for specific filesystems, device classes, and individual devices.

Global Config File

The easiest way to change the default mount options for all devices is through the global configuration file which lives at /etc/udisks2/mount_options.conf. The file uses a simple INI format. The section [defaults] contains settings for the default and allowed mount options. These settings are further divided among default and allowed mount options for all filesystems and for each particular type of filesystem. The default and allowed options for all filesystems are set with the defaults and allow keys respectively. The filesystem-specific versions of these keys come from prefixing _defaults and _allow with the filesystem type used by mount(8), such as vfat, ntfs, ext4, and btrfs. Thus, the default mount options for btrfs use the key btrfs_defaults and the allowed options use the key btrfs_allow. The sample configuration here demonstrates how to modify the default and allowed options used for Btrfs. The other settings are simply the defaults used by udisks2.

/etc/udisks2/mount_options.conf
[defaults]
allow=exec,noexec,nodev,nosuid,atime,noatime,nodiratime,relatime,strictatime,lazytime,ro,rw,sync,dirsync,noload,acl,nosymfollow

vfat_defaults=uid=$UID,gid=$GID,shortname=mixed,utf8=1,showexec,flush
vfat_allow=uid=$UID,gid=$GID,flush,utf8,shortname,umask,dmask,fmask,codepage,iocharset,usefree,showexec

# common options for both the native kernel driver and exfat-fuse
exfat_defaults=uid=$UID,gid=$GID,iocharset=utf8,errors=remount-ro
exfat_allow=uid=$UID,gid=$GID,dmask,errors,fmask,iocharset,namecase,umask

ntfs_defaults=uid=$UID,gid=$GID,windows_names
ntfs_allow=uid=$UID,gid=$GID,umask,dmask,fmask,locale,norecover,ignore_case,windows_names,compression,nocompression,big_writes

iso9660_defaults=uid=$UID,gid=$GID,iocharset=utf8,mode=0400,dmode=0500
iso9660_allow=uid=$UID,gid=$GID,norock,nojoliet,iocharset,mode,dmode

udf_defaults=uid=$UID,gid=$GID,iocharset=utf8
udf_allow=uid=$UID,gid=$GID,iocharset,utf8,umask,mode,dmode,unhide,undelete

hfsplus_defaults=uid=$UID,gid=$GID,nls=utf8
hfsplus_allow=uid=$UID,gid=$GID,creator,type,umask,session,part,decompose,nodecompose,force,nls

btrfs_defaults=autodefrag,compress=zstd
btrfs_allow=autodefrag,compress,compress-force,datacow,nodatacow,datasum,nodatasum,degraded,device,discard,nodiscard,subvol,subvolid,space_cache

f2fs_allow=discard,nodiscard,compress_algorithm,compress_log_size,compress_extension,alloc_mode

xfs_allow=discard,nodiscard,inode32,largeio,wsync

reiserfs_allow=hashed_relocation,no_unhashed_relocation,noborder,notail

Generally, you should start with the default settings stated in the documentation for udisks2’s udisks2 Mount Options. You’ll also need to make sure that any default options are specified in the corresponding allowed set. The Btrfs notably allows the autodefrag option in addition to the default udisks2 settings and defaults to using it and zstd compression.

The configuration file also provides functionality to specify defaults for particular devices. To do so, a device section named after the block device is followed by the general and filesystem-specific default keys discussed previously. Here, the defaults for the vfat filesystem are modified for two devices. One device is specified by its UUID and another the other by its label.

/etc/udisks2/mount_options.conf
[/dev/disk/by-uuid/13177899-cb85-45b7-99b6-b76e2fc41f44]
btrfs_defaults=autodefrag,compress=zstd

[/dev/disk/by-label/Black\\x20WD\\x20EasyStore\\x20External\\x20HDD\\x20-\\x20My\\x20Backups]
btrfs_defaults=autodefrag,compress=zstd

For security reasons, prefer udev rules for setting device-specific mount options. It’s easy to falsify the device symlinks used to define the sections.

udev Rules

udev(7) is the subsystem for handling device events on Linux. It is a robust method for triggering certain actions when devices are detected. udev rules can be used with udisks2 to specify the allowed or default mount options for specific devices. This can be for an individual device, a class of devices or some other subset of devices.

A system’s udev rules reside in rules files in standard directories, such as /etc/udev/rules.d. To create a new rule, create a new file in this directory. udisks2 recommends using the prefix 99- to ensure that the rule runs last.

udev rules pretty much boil down to matching on a device on certain criteria. To work with udisks2, there is a required format including a specific header for block devices and a closing LABEL. Modifying the mount options is done through a few variables used in the same way as the keys in the configuration file. The variables are named differently than the keys, but follow the same naming convention. Defaults are set with the variable UDISKS_MOUNT_OPTIONS_DEFAULTS and allowed options with UDISKS_MOUNT_OPTIONS_ALLOW. Filesystem-specific variables place the filesystem type in all caps in between the UDISKS_MOUNT_OPTIONS portion at the beginning and the _ALLOW or _DEFAULTS part at the end. Btrfs defaults can be changed by setting the variable UDISKS_MOUNT_OPTIONS_BTRFS_DEFAULTS. When setting filesystem-specific options, you should match the rule on the filesystem type provided by the variable ID_FS_TYPE. There’s more to it that that, but this isn’t supposed to be a udev tutorial so I’ll show a couple of examples.

The udev rule here applies specific Btrfs default mount options to all USB devices. These are the same defaults set above in the global configuration file. This also mounts USB devices as read-write.

/etc/udev/rules.d/99-udisks2-btrfs-usb.rules
# Skip if not a block device or if requested by other rules
#
SUBSYSTEM!="block", GOTO="udisks_mount_options_end"
ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="udisks_mount_options_end"
ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="?*", GOTO="udisks_mount_options_end"

# Mount all USB devices read-only
SUBSYSTEMS="usb", ENV{ID_FS_USAGE}=="filesystem", \
    ENV{UDISKS_MOUNT_OPTIONS_DEFAULTS}="rw", \
    ENV{ID_FS_TYPE}=="btrfs", \
    ENV{UDISKS_MOUNT_OPTIONS_BTRFS_DEFAULTS}="autodefrag,compress=zstd", \
    ENV{UDISKS_MOUNT_OPTIONS_BTRFS_ALLOW}="autodefrag,compress,compress-force,datacow,nodatacow,datasum,nodatasum,degraded,device,discard,nodiscard,subvol,subvolid,space_cache"

LABEL="udisks_mount_options_end"

To enable a new rule, either reboot your system or reload the udev daemon as demonstrated by the command here.

udevadm control --reload-rules

The following rule matches on an exact USB device and applies the same default Btrfs options.

/etc/udev/rules.d/99-udisks2-btrfs-backups-usb.rules
SUBSYSTEM!="block", GOTO="udisks_mount_options_end"
ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="udisks_mount_options_end"
ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="?*", GOTO="udisks_mount_options_end"

ENV{ID_VENDOR}=="WD", ENV{ID_MODEL}=="easystore_25FC", \
    ENV{ID_SERIAL_SHORT}=="000000000000000000000001", \
    ENV{UDISKS_MOUNT_OPTIONS_DEFAULTS}="rw", \
    ENV{UDISKS_MOUNT_OPTIONS_BTRFS_DEFAULTS}="autodefrag,compress=zstd",subvol=my-backups, \
    ENV{UDISKS_MOUNT_OPTIONS_BTRFS_ALLOW}="autodefrag,compress,compress-force,datacow,nodatacow,datasum,nodatasum,degraded,device,discard,nodiscard,subvol,subvolid,space_cache"

LABEL="udisks_mount_options_end"

To determine the id attributes for your hardware, query the information with udevadm. Here I filter the output of such a query for /dev/sdb1 to just show the ID_VENDOR, ID_MODEL, and ID_SERIAL_SHORT attributes.

udevadm info --query=all --name=/dev/sdb \
  | awk -F'=' '/ID_VENDOR=/ || /ID_MODEL=/ || /ID_SERIAL_SHORT=/ {print $2}'
WD
easystore_25FC
000000000000000000000001

For more examples and information, refer to the udisks2 documentation.

GIO

GIO is a filesystem layer abstraction GNOME and GTK. GTK and GNOME applications use GIO to interact with filesystems. GIO also bundles a command-line tool which can be used to mount and unmount filesystems. It can’t be used to control mount options directly. However, since it uses udisks2 to mount physical media, default mount options configured for udisks2 carry over. GIO has the added convenience of being able to unlock and mount an encrypted volume in a single command. It can also use encryption keys saved in a user’s keyring to unlock encrypted volumes without requiring a password every time. Follow the steps below to mount and unmount the /dev/sdb1 volume.

  1. Mount the volume by passing the device to GIO’s mount subcommand via the -d flag.

    gio mount -d /dev/sdb1
    Mounted /dev/sdb1 at /run/media/jordan/backups
  2. Unmount the volume with the mount command, the -u flag, and the mount point.

    gio mount -u /run/media/jordan/backups

Conclusion

If you’ve made it this far, you now understand way more about mounting filesystems in Linux then you probably ever wanted too. You should now know the different ways to control mounting a filesystem whether that’s as a normal user or as the superuser. If you’re using Btrfs, you should now be able to specify those pesky mount options properly now, too. Interested in mounting encrypted volumes or automatically mounting devices? Keep an eye on this space for upcoming posts on these topics.