]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: read from udev, add --disable-libmount-udev-support
authorKarel Zak <kzak@redhat.com>
Tue, 25 Nov 2025 11:56:07 +0000 (12:56 +0100)
committerKarel Zak <kzak@redhat.com>
Tue, 9 Dec 2025 10:27:30 +0000 (11:27 +0100)
The library traditionally uses libblkid to obtain device properties
(such as FS-type if not specified). This can be a relatively costly
operation to scan the device and requires read access to the device.

All relevant libblkid information is usually cached by the udev DB.
This commit adds the possibility to reuse the information from udev,
with a fallback to libblkid if udev is not available.

The commit also adds

 $ ./configure --disable-libmount-udev-support
 $ meson setup build -Dbuild-libmount-udev-support=disabled

to completely disable this feature and avoid libmount's dependence
on libsystemd.

Signed-off-by: Karel Zak <kzak@redhat.com>
configure.ac
libmount/meson.build
libmount/src/Makemodule.am
libmount/src/cache.c
libmount/src/version.c
meson.build
meson_options.txt

index cf415f5ed463ff2f4154c20c0dd1456dacb95706..93ad3a38b12d4e227ee719cafcd62e7e7c3c8c8b 100644 (file)
@@ -1390,6 +1390,10 @@ AC_ARG_ENABLE([libmount-mountfd-support],
   AS_HELP_STRING([--disable-libmount-mountfd-support], [do not use new mount API based on FDs]),
   [], [enable_libmount_mountfd_support=check]
 )
+AC_ARG_ENABLE([libmount-udev-support],
+  AS_HELP_STRING([--disable-libmount-udev-support], [do not read from udev in libmount]),
+  [], [enable_libmount_udev_support=check]
+)
 UL_BUILD_INIT([libmount_mountfd_support])
 UL_REQUIRES_BUILD([libmount_mountfd_support], [libmount])
 UL_REQUIRES_LINUX([libmount_mountfd_support])
@@ -2701,6 +2705,20 @@ AS_IF([test "x$with_systemd" != xno], [
 ])
 AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$have_systemd" = xyes])
 
+libmount_udev_support=no
+AS_IF([test "x$enable_libmount_udev_support" != xno && test "x$build_libmount" = xyes], [
+  AS_CASE([$enable_libmount_udev_support:$have_systemd],
+    [yes:no],
+      [AC_MSG_ERROR([libmount udev support expected but libsystemd not found])],
+    [*:yes], [
+      AC_CHECK_DECLS([sd_device_new_from_devname], [
+        AC_DEFINE([USE_LIBMOUNT_UDEV_SUPPORT], [1], [Define if use udev support in libmount])
+        libmount_udev_support=yes],
+        [], [#include <systemd/sd-device.h>])
+      ]
+   )
+])
+AM_CONDITIONAL([USE_LIBMOUNT_UDEV_SUPPORT], [test "x$libmount_udev_support" = xyes])
 
 AC_ARG_WITH([systemdsystemunitdir],
   AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [directory for systemd unit files (requires systemd support)]),
index 28feadf48451cf0723823003ec2b4b5b2a37b42a..558f30468aa25215ed2de3065aa3856516dcd3c7 100644 (file)
@@ -98,6 +98,11 @@ lib__mount_deps = [
   cryptsetup_dlopen ? lib_dl : lib_cryptsetup,
   realtime_libs
 ]
+
+if conf.get('USE_LIBMOUNT_UDEV_SUPPORT').to_string() == '1'
+  lib__mount_deps += [lib_systemd]
+endif
+
 lib_mount = library(
   'mount',
   link_whole : lib__mount,
index 28dbc5811304cbdffb8b942681e7b8ecd4fcf35b..bbd83b8bcd438404b805ca237998f2f16641b04a 100644 (file)
@@ -69,6 +69,10 @@ libmount_la_LIBADD += $(CRYPTSETUP_LIBS)
 endif
 endif
 
+if USE_LIBMOUNT_UDEV_SUPPORT
+libmount_la_LIBADD += $(SYSTEMD_LIBS)
+endif
+
 libmount_la_CFLAGS = \
        $(AM_CFLAGS) \
        $(SOLIB_CFLAGS) \
index ebba427e43b54037f9fe253c8b149fdc41fc3adc..4d2a20f235f0ebe5162dff59476b147a3af04b32 100644 (file)
 #include <fcntl.h>
 #include <blkid.h>
 
+/* sd-device is a replacement for libudev */
+#ifdef USE_LIBMOUNT_UDEV_SUPPORT
+# include <systemd/sd-device.h>
+#endif
+
 #include "canonicalize.h"
 #include "mountP.h"
 #include "loopdev.h"
 #include "strutils.h"
+#include "mangle.h"
 
 /*
  * Canonicalized (resolved) paths & tags cache
@@ -76,16 +82,17 @@ struct libmnt_cache {
 struct libmnt_cachetag {
        const char *mnt_name;   /* tag name used by libmount */
        const char *blk_name;   /* tag name used by libblkid */
+       const char *udev_name;  /* tag name used by udev db */
 };
 
 static const struct libmnt_cachetag mnttags[] =
 {
-       /* mount        blkid */
-       { "LABEL",      "LABEL" },
-       { "UUID",       "UUID" },
-       { "TYPE",       "TYPE" },
-       { "PARTUUID",   "PART_ENTRY_UUID" },
-       { "PARTLABEL",  "PART_ENTRY_NAME" },
+       /* mount        blkid                   udev */
+       { "LABEL",      "LABEL",                "ID_FS_LABEL_ENC" },
+       { "UUID",       "UUID",                 "ID_FS_UUID_ENC" },
+       { "TYPE",       "TYPE",                 "ID_FS_TYPE" },
+       { "PARTUUID",   "PART_ENTRY_UUID",      "ID_PART_ENTRY_UUID" },
+       { "PARTLABEL",  "PART_ENTRY_NAME",      "ID_PART_ENTRY_NAME" },
 
        { NULL, NULL }
 };
@@ -357,7 +364,10 @@ static bool is_device_cached(struct libmnt_cache *cache, const char *devname)
        return 0;
 }
 
-/* read data from libblkid into local cache */
+/*
+ * read data from libblkid into local cache
+ * returns: <0 on error; 0 success; 1 nothing
+*/
 static int read_from_blkid(struct libmnt_cache *cache, const char *devname)
 {
        blkid_probe pr;
@@ -373,7 +383,7 @@ static int read_from_blkid(struct libmnt_cache *cache, const char *devname)
 
        pr =  blkid_new_probe_from_filename(devname);
        if (!pr)
-               return -1;
+               return -EINVAL;
 
        blkid_probe_enable_superblocks(pr, 1);
        blkid_probe_set_superblocks_flags(pr,
@@ -412,12 +422,68 @@ done:
        return rc ? rc : ntags ? 0 : 1;
 }
 
+#ifdef USE_LIBMOUNT_UDEV_SUPPORT
+/*
+ * read data from udev into local cache
+ * returns: <0 on error; 0 success; 1 nothing
+ */
+static int read_from_udev(struct libmnt_cache *cache, const char *devname)
+{
+       sd_device *sd = NULL;
+       const struct libmnt_cachetag *t;
+       size_t ntags = 0;
+       char *tagval = NULL, *cacheval = NULL;
+       int rc;
+
+       assert(cache);
+       assert(devname);
+
+       rc = sd_device_new_from_devname(&sd, devname);
+       if (rc < 0)
+               return rc;
+
+       DBG(CACHE, ul_debugobj(cache, "%s: reading from udev", devname));
+
+       for (t = mnttags; t && t->mnt_name; t++) {
+               const char *data;
+
+               if (cache_find_tag_value(cache, devname, t->mnt_name))
+                       continue;
+               if (sd_device_get_property_value(sd, t->udev_name, &data) < 0)
+                       continue;
+
+               tagval = strdup(data); /* temporary for unhexmangle() */
+               cacheval = strdup(devname);
+
+               if (tagval && cacheval) {
+                       unhexmangle_string(tagval);
+                       rc = cache_add_tag(cache, t->mnt_name,
+                                       tagval, cacheval, MNT_CACHE_TAGREAD);
+               } else
+                       rc = -ENOMEM;
+               if (rc)
+                       break;
+               ntags++;
+               cacheval = NULL; /* stored into cache */
+               free(tagval), tagval = NULL;
+       }
+
+       DBG(CACHE, ul_debugobj(cache, "\tread %zd tags [rc=%d]", ntags, rc));
+       sd_device_unref(sd);
+       free(cacheval);
+       free(tagval);
+
+       return rc ? rc : ntags ? 0 : 1;
+}
+#endif /* USE_LIBMOUNT_UDEV_SUPPORT */
+
+
 /**
  * mnt_cache_read_tags
  * @cache: pointer to struct libmnt_cache instance
  * @devname: path device
  *
- * Reads @devname LABEL and UUID to the @cache.
+ * Reads @devname information into the @cache.
  *
  * Returns: 0 if at least one tag was added, 1 if no tag was added or
  *          negative number in case of error.
@@ -432,6 +498,10 @@ int mnt_cache_read_tags(struct libmnt_cache *cache, const char *devname)
        if (is_device_cached(cache, devname))
                return 0;
 
+#ifdef USE_LIBMOUNT_UDEV_SUPPORT
+       if (read_from_udev(cache, devname) == 0)
+               return 0;
+#endif
        return read_from_blkid(cache, devname);
 }
 
@@ -532,6 +602,9 @@ static char *fstype_from_blkid(const char *devname, int *ambi)
  * @ambi: returns TRUE if probing result is ambivalent (optional argument)
  * @cache: cache for results or NULL
  *
+ * Note: If the cache is not specified, it reads the file system type from the
+ * device, and in this case, there is no optimization like udev db, etc. *
+ *
  * Returns: filesystem type or NULL in case of error. The result has to be
  * deallocated by free() if @cache is NULL.
  */
index 19326d280cb2ec2406e917ec3f77c950278cc31a..5ec0d490cdee94c534294e4c5dc07ffb3ac618d8 100644 (file)
@@ -52,6 +52,9 @@ static const char *lib_features[] = {
 #ifdef HAVE_STRUCT_FANOTIFY_EVENT_INFO_HEADER
        "fanotify",
 #endif
+#ifdef USE_LIBMOUNT_UDEV_SUPPORT
+       "udev",
+#endif
 #if !defined(NDEBUG)
        "assert",       /* libc assert.h stuff */
 #endif
index cac8bb57869d856dcdca3039e81badc8ea805c6c..2f4e66feff03bab5a88ecd92d93de2486ef8fe61 100644 (file)
@@ -396,6 +396,12 @@ have = cc.has_function(
   dependencies : lib_systemd)
 conf.set('HAVE_DECL_SD_SESSION_GET_USERNAME', have ? 1 : false)
 
+have = cc.has_function(
+  'sd_device_new_from_devname',
+  dependencies : lib_systemd)
+conf.set('USE_LIBMOUNT_UDEV_SUPPORT',
+  not get_option('build-libmount-udev-support').disabled() and have ? 1 : false)
+
 lib_udev = dependency(
   'libudev',
   required : get_option('systemd'))
index 1ec904668be8bd420b99d653daec560d538159c3..c03de17ff9cdde5ed7ad840d0cf379ab12c76482 100644 (file)
@@ -303,6 +303,11 @@ option('fs-search-path',
 option('fs-search-path-extra',
        type : 'string',
        description : 'additional search path for fs helpers')
+
+option('build-libmount-udev-support',
+       type : 'feature',
+       description : 'support reading from udev in libmount')
+
 option('vendordir',
        type: 'string',
        description : 'directory for distribution provided econf files')