]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
fstrim: resolve non-device sources to real block devices
authorKarel Zak <kzak@redhat.com>
Thu, 28 May 2026 12:01:53 +0000 (14:01 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 1 Jun 2026 11:35:33 +0000 (13:35 +0200)
When fstrim reads fstab entries (--fstab, --listed-in), bind mount
entries use directory paths as sources (e.g. /data/ssd/ldap) rather
than device names. Source de-duplication compares path strings, so
these never match the real device paths (e.g. /dev/mapper/foo),
causing the same filesystem to be trimmed multiple times.

Use statmount(STATMOUNT_SB_SOURCE) to resolve directory source paths
to their real block device before de-duplication. Fall back to the
original source when statmount() is unavailable.

Addresses: https://github.com/util-linux/util-linux/issues/857
Signed-off-by: Karel Zak <kzak@redhat.com>
sys-utils/fstrim.c

index 208e9008e747b676c929a4e9bc9f6f091427b68e..cd96f77ab94f84ae6e7e649cd66ac293bcea1f91 100644 (file)
@@ -47,6 +47,7 @@
 #include "sysfs.h"
 #include "optutils.h"
 #include "statfs_magic.h"
+#include "mountutils.h"
 
 #include <libmount.h>
 
@@ -368,6 +369,26 @@ static int fstrim_all_from_file(struct fstrim_control *ctl, const char *filename
                        continue;       /* overlaying mount */
                }
 
+               /* resolve non-device source (e.g. bind mount directory
+                * path) to real block device via statmount();
+                * requires mountfd support (mountutils.h) */
+#ifdef STATMOUNT_SB_SOURCE
+               if (is_directory(src, 1)) {
+                       char *orig = xstrdup(src);
+
+                       mnt_fs_set_source(fs, NULL);
+                       src = NULL;
+                       if (mnt_fs_fetch_statmount(fs,
+                                       STATMOUNT_SB_SOURCE) == 0)
+                               src = mnt_fs_get_srcpath(fs);
+                       if (!src || *src != '/') {
+                               mnt_fs_set_source(fs, orig);
+                               src = mnt_fs_get_srcpath(fs);
+                       }
+                       free(orig);
+               }
+#endif
+
                if (!is_directory(tgt, 1) ||
                    !has_discard(src, &wholedisk)) {
                        mnt_table_remove_fs(tab, fs);