From: Karel Zak Date: Tue, 25 Nov 2025 11:56:07 +0000 (+0100) Subject: libmount: read from udev, add --disable-libmount-udev-support X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8bdc2546d38979ca65fa9bfd1bbd6e7b985c69db;p=thirdparty%2Futil-linux.git libmount: read from udev, add --disable-libmount-udev-support 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 --- diff --git a/configure.ac b/configure.ac index cf415f5ed..93ad3a38b 100644 --- a/configure.ac +++ b/configure.ac @@ -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 ]) + ] + ) +]) +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)]), diff --git a/libmount/meson.build b/libmount/meson.build index 28feadf48..558f30468 100644 --- a/libmount/meson.build +++ b/libmount/meson.build @@ -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, diff --git a/libmount/src/Makemodule.am b/libmount/src/Makemodule.am index 28dbc5811..bbd83b8bc 100644 --- a/libmount/src/Makemodule.am +++ b/libmount/src/Makemodule.am @@ -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) \ diff --git a/libmount/src/cache.c b/libmount/src/cache.c index ebba427e4..4d2a20f23 100644 --- a/libmount/src/cache.c +++ b/libmount/src/cache.c @@ -30,10 +30,16 @@ #include #include +/* sd-device is a replacement for libudev */ +#ifdef USE_LIBMOUNT_UDEV_SUPPORT +# include +#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. */ diff --git a/libmount/src/version.c b/libmount/src/version.c index 19326d280..5ec0d490c 100644 --- a/libmount/src/version.c +++ b/libmount/src/version.c @@ -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 diff --git a/meson.build b/meson.build index cac8bb578..2f4e66fef 100644 --- a/meson.build +++ b/meson.build @@ -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')) diff --git a/meson_options.txt b/meson_options.txt index 1ec904668..c03de17ff 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -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')