From 4db2f59a718c18202a7ce1d559be18bfa1087747 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 8 Mar 2006 14:17:28 -0500 Subject: [PATCH] Add device-mapper support to the blkid library On systems where is multi-path storage device is problem with duplicated filesystems. The solution is select "the best" device. This is possible by device-mapper library. Short quotation from RH bugzilla: With my patch, all dm devices remains in libblkid cache. Only the top level dm devices are given high priority and more appropriate node names (i.e. /dev/mapper/*) are used. For example, if we have linear mapped dm device "ov1" over dm device "disk1p3" which is multipath mapped to /dev/sdd3 and /dev/sdh3: # dmsetup.static ls --tree ov1 (253:5) <-- /dev/mapper/ov1 or /dev/dm-5 `-disk1p3 (253:4) <-- /dev/mapper/disk1p3 or /dev/dm-4 `-disk1 (253:0) |- (8:112) <-- /dev/sdh `- (8:48) <-- /dev/sdd Original version of blkid will show: # ./orig/blkid -t LABEL=mpdisk1p3 -l /dev/sdd3: LABEL="mpdisk1p3" ... TYPE="ext3" With my patch, blkid will show: # ./deptree/blkid -t LABEL=mpdisk1p3 -l /dev/mapper/ov1: LABEL="mpdisk1p3" ... TYPE="ext3" In blkid cache, all devices are listed: # ./orig/blkid -t LABEL=mpdisk1p3 /dev/sdd3: LABEL="mpdisk1p3" ... TYPE="ext3" /dev/sdh3: LABEL="mpdisk1p3" ... TYPE="ext3" /dev/dm-4: LABEL="mpdisk1p3" ... TYPE="ext3" /dev/dm-5: LABEL="mpdisk1p3" ... TYPE="ext3" # ./deptree/blkid -t LABEL=mpdisk1p3 /dev/mapper/ov1: LABEL="mpdisk1p3" ... TYPE="ext3" /dev/sdd3: LABEL="mpdisk1p3" ... TYPE="ext3" /dev/sdh3: LABEL="mpdisk1p3" ... TYPE="ext3" /dev/dm-4: LABEL="mpdisk1p3" ... TYPE="ext3" For more details see discussion on: https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=156324 Addresses Red Hat Bug: #156324 Signed-off-by: Karel Zak Signed-off-by: Peter Jones Signed-off-by: "Theodore Ts'o" --- MCONFIG.in | 7 +- configure | 38 +++++++++- configure.in | 28 +++++++ lib/blkid/Makefile.in | 2 +- lib/blkid/blkid.pc.in | 4 +- lib/blkid/blkidP.h | 1 + lib/blkid/devname.c | 166 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 240 insertions(+), 6 deletions(-) diff --git a/MCONFIG.in b/MCONFIG.in index 991aaa0d..5463dac5 100644 --- a/MCONFIG.in +++ b/MCONFIG.in @@ -66,13 +66,16 @@ MKINSTALLDIRS = @MKINSTALLDIRS@ # # Library definitions # +DEVMAPPER_LIBS = @DEVMAPPER_LIBS@ +STATIC_DEVMAPPER_LIBS = @STATIC_DEVMAPPER_LIBS@ + LIB = $(top_builddir)/lib LIBSS = $(LIB)/libss@LIB_EXT@ LIBCOM_ERR = $(LIB)/libcom_err@LIB_EXT@ LIBE2P = $(LIB)/libe2p@LIB_EXT@ LIBEXT2FS = $(LIB)/libext2fs@LIB_EXT@ LIBUUID = $(LIB)/libuuid@LIB_EXT@ @SOCKET_LIB@ -LIBBLKID = $(LIB)/libblkid@LIB_EXT@ +LIBBLKID = $(LIB)/libblkid@LIB_EXT@ $(DEVMAPPER_LIBS) LIBINTL = @LIBINTL@ DEPLIBUUID = $(LIB)/libuuid@LIB_EXT@ @@ -81,7 +84,7 @@ STATIC_LIBCOM_ERR = $(LIB)/libcom_err@STATIC_LIB_EXT@ STATIC_LIBE2P = $(LIB)/libe2p@STATIC_LIB_EXT@ STATIC_LIBEXT2FS = $(LIB)/libext2fs@STATIC_LIB_EXT@ STATIC_LIBUUID = $(LIB)/libuuid@STATIC_LIB_EXT@ @SOCKET_LIB@ -STATIC_LIBBLKID = $(LIB)/libblkid@STATIC_LIB_EXT@ +STATIC_LIBBLKID = $(LIB)/libblkid@STATIC_LIB_EXT@ $(STATIC_DEVMAPPER_LIBS) DEPSTATIC_LIBUUID = $(LIB)/libuuid@STATIC_LIB_EXT@ PROFILED_LIBSS = $(LIB)/libss@PROFILED_LIB_EXT@ diff --git a/configure b/configure index e9d719b5..26517459 100755 --- a/configure +++ b/configure @@ -309,7 +309,7 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS E2FSPROGS_YEAR E2FSPROGS_MONTH E2FSPROGS_DAY E2FSPROGS_VERSION build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT LD CPP EGREP LINUX_INCLUDE MAINTAINER_CMT HTREE_CMT ELF_CMT BSDLIB_CMT PROFILE_CMT CHECKER_CMT LIB_EXT STATIC_LIB_EXT PROFILED_LIB_EXT SWAPFS_CMT DEBUGFS_CMT IMAGER_CMT RESIZER_CMT E2FSCK_TYPE FSCK_PROG FSCK_MAN E2INITRD_PROG E2INITRD_MAN GETTEXT_PACKAGE PACKAGE VERSION SET_MAKE INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA MKINSTALLDIRS USE_NLS MSGFMT GMSGFMT XGETTEXT MSGMERGE RANLIB ac_ct_RANLIB ALLOCA GLIBC21 HAVE_POSIX_PRINTF HAVE_ASPRINTF HAVE_SNPRINTF HAVE_WPRINTF LIBICONV LTLIBICONV INTLBISON BUILD_INCLUDED_LIBINTL USE_INCLUDED_LIBINTL CATOBJEXT DATADIRNAME INSTOBJEXT GENCAT INTLOBJS INTL_LIBTOOL_SUFFIX_PREFIX INTLLIBS LIBINTL LTLIBINTL POSUB BINARY_TYPE LN LN_S MV CP RM CHMOD AWK SED PERL LDCONFIG AR ac_ct_AR STRIP ac_ct_STRIP BUILD_CC SIZEOF_SHORT SIZEOF_INT SIZEOF_LONG SIZEOF_LONG_LONG SOCKET_LIB DLOPEN_LIB LINUX_CMT CYGWIN_CMT UNIX_CMT root_prefix root_bindir root_sbindir root_libdir root_sysconfdir LDFLAG_STATIC SS_DIR ET_DIR DO_TEST_SUITE INTL_FLAGS BUILD_CFLAGS BUILD_LDFLAGS LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS E2FSPROGS_YEAR E2FSPROGS_MONTH E2FSPROGS_DAY E2FSPROGS_VERSION build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT LD CPP EGREP LINUX_INCLUDE MAINTAINER_CMT HTREE_CMT ELF_CMT BSDLIB_CMT PROFILE_CMT CHECKER_CMT LIB_EXT STATIC_LIB_EXT PROFILED_LIB_EXT SWAPFS_CMT DEBUGFS_CMT IMAGER_CMT RESIZER_CMT E2FSCK_TYPE FSCK_PROG FSCK_MAN E2INITRD_PROG E2INITRD_MAN DEVMAPPER_REQ DEVMAPPER_PC_LIBS DEVMAPPER_LIBS STATIC_DEVMAPPER_LIBS GETTEXT_PACKAGE PACKAGE VERSION SET_MAKE INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA MKINSTALLDIRS USE_NLS MSGFMT GMSGFMT XGETTEXT MSGMERGE RANLIB ac_ct_RANLIB ALLOCA GLIBC21 HAVE_POSIX_PRINTF HAVE_ASPRINTF HAVE_SNPRINTF HAVE_WPRINTF LIBICONV LTLIBICONV INTLBISON BUILD_INCLUDED_LIBINTL USE_INCLUDED_LIBINTL CATOBJEXT DATADIRNAME INSTOBJEXT GENCAT INTLOBJS INTL_LIBTOOL_SUFFIX_PREFIX INTLLIBS LIBINTL LTLIBINTL POSUB BINARY_TYPE LN LN_S MV CP RM CHMOD AWK SED PERL LDCONFIG AR ac_ct_AR STRIP ac_ct_STRIP BUILD_CC SIZEOF_SHORT SIZEOF_INT SIZEOF_LONG SIZEOF_LONG_LONG SOCKET_LIB DLOPEN_LIB LINUX_CMT CYGWIN_CMT UNIX_CMT root_prefix root_bindir root_sbindir root_libdir root_sysconfdir LDFLAG_STATIC SS_DIR ET_DIR DO_TEST_SUITE INTL_FLAGS BUILD_CFLAGS BUILD_LDFLAGS LIBOBJS LTLIBOBJS' ac_subst_files='MCONFIG MAKEFILE_ELF MAKEFILE_BSDLIB MAKEFILE_PROFILE MAKEFILE_CHECKER MAKEFILE_LIBRARY' # Initialize some variables set by options. @@ -861,6 +861,7 @@ Optional Features: --enable-dynamic-e2fsck build e2fsck dynamically --enable-fsck build fsck wrapper program --enable-e2initrd-helper build e2initrd-helper program + --enable-blkid-devmapper build with device-mapper support --disable-nls do not use Native Language Support --disable-rpath do not hardcode runtime library paths @@ -3450,6 +3451,37 @@ echo "Building e2initrd helper by default" fi; +# Check whether --enable-blkid-devmapper or --disable-blkid-devmapper was given. +if test "${enable_blkid_devmapper+set}" = set; then + enableval="$enable_blkid_devmapper" + if test "$enableval" = "no" +then + echo "Disabling device-mapper support" + DEVMAPPER_REQ='' + DEVMAPPER_LIBS='' + STATIC_DEVMAPPER_LIBS='' +else + cat >>confdefs.h <<\_ACEOF +#define HAVE_DEVMAPPER 1 +_ACEOF + + echo "Enabling device-mapper support" + + DEVMAPPER_REQ='libselinux libsepol' + DEVMAPPER_PC_LIBS='-ldevmapper' + DEVMAPPER_LIBS='-ldevmapper -lselinux -lsepol' + STATIC_DEVMAPPER_LIBS='/usr/lib/libdevmapper.a /usr/lib/libselinux.a /usr/lib/libsepol.a' + +fi + +else + echo "Disabling device-mapper support by default" + +fi; + + + + MAKEFILE_LIBRARY=$srcdir/lib/Makefile.library GETTEXT_PACKAGE=e2fsprogs @@ -14969,6 +15001,10 @@ s,@FSCK_PROG@,$FSCK_PROG,;t t s,@FSCK_MAN@,$FSCK_MAN,;t t s,@E2INITRD_PROG@,$E2INITRD_PROG,;t t s,@E2INITRD_MAN@,$E2INITRD_MAN,;t t +s,@DEVMAPPER_REQ@,$DEVMAPPER_REQ,;t t +s,@DEVMAPPER_PC_LIBS@,$DEVMAPPER_PC_LIBS,;t t +s,@DEVMAPPER_LIBS@,$DEVMAPPER_LIBS,;t t +s,@STATIC_DEVMAPPER_LIBS@,$STATIC_DEVMAPPER_LIBS,;t t s,@GETTEXT_PACKAGE@,$GETTEXT_PACKAGE,;t t s,@PACKAGE@,$PACKAGE,;t t s,@VERSION@,$VERSION,;t t diff --git a/configure.in b/configure.in index 44166b39..744301c9 100644 --- a/configure.in +++ b/configure.in @@ -480,6 +480,34 @@ echo "Building e2initrd helper by default" ) AC_SUBST(E2INITRD_PROG) AC_SUBST(E2INITRD_MAN) +dnl handle --enable-blkid-devmapper +dnl +AC_ARG_ENABLE([blkid-devmapper], +[ --enable-blkid-devmapper build with device-mapper support], +[if test "$enableval" = "no" +then + echo "Disabling device-mapper support" + DEVMAPPER_REQ='' + DEVMAPPER_LIBS='' + STATIC_DEVMAPPER_LIBS='' +else + AC_DEFINE(HAVE_DEVMAPPER) + echo "Enabling device-mapper support" + + DEVMAPPER_REQ='libselinux libsepol' + DEVMAPPER_PC_LIBS='-ldevmapper' + DEVMAPPER_LIBS='-ldevmapper -lselinux -lsepol' + STATIC_DEVMAPPER_LIBS='/usr/lib/libdevmapper.a /usr/lib/libselinux.a /usr/lib/libsepol.a' + +fi] +, +echo "Disabling device-mapper support by default" +) +AC_SUBST(DEVMAPPER_REQ) +AC_SUBST(DEVMAPPER_PC_LIBS) +AC_SUBST(DEVMAPPER_LIBS) +AC_SUBST(STATIC_DEVMAPPER_LIBS) +dnl dnl dnl MAKEFILE_LIBRARY=$srcdir/lib/Makefile.library diff --git a/lib/blkid/Makefile.in b/lib/blkid/Makefile.in index 2dd92609..046f182e 100644 --- a/lib/blkid/Makefile.in +++ b/lib/blkid/Makefile.in @@ -37,7 +37,7 @@ ELF_SO_VERSION = 1 ELF_IMAGE = libblkid ELF_MYDIR = blkid ELF_INSTALL_DIR = $(root_libdir) -ELF_OTHER_LIBS = -L../.. -luuid +ELF_OTHER_LIBS = -L../.. -luuid $(DEVMAPPER_LIBS) BSDLIB_VERSION = 2.0 BSDLIB_IMAGE = libblkid diff --git a/lib/blkid/blkid.pc.in b/lib/blkid/blkid.pc.in index fda7f921..510aa840 100644 --- a/lib/blkid/blkid.pc.in +++ b/lib/blkid/blkid.pc.in @@ -6,6 +6,6 @@ includedir=@includedir@ Name: blkid Description: Block device id library Version: @E2FSPROGS_VERSION@ -Requires: uuid +Requires: uuid @DEVMAPPER_REQ@ Cflags: -I${includedir} -Libs: -L${libdir} -lblkid +Libs: -L${libdir} -lblkid @DEVMAPPER_PC_LIBS@ diff --git a/lib/blkid/blkidP.h b/lib/blkid/blkidP.h index e6d8e276..dfe0eca0 100644 --- a/lib/blkid/blkidP.h +++ b/lib/blkid/blkidP.h @@ -118,6 +118,7 @@ extern const char *blkid_devdirs[]; /* * Priority settings for different types of devices */ +#define BLKID_PRI_DM 40 #define BLKID_PRI_EVMS 30 #define BLKID_PRI_LVM 20 #define BLKID_PRI_MD 10 diff --git a/lib/blkid/devname.c b/lib/blkid/devname.c index 3b1ad89b..0a13c477 100644 --- a/lib/blkid/devname.c +++ b/lib/blkid/devname.c @@ -11,6 +11,8 @@ * %End-Header% */ +#define _GNU_SOURCE 1 + #include #include #if HAVE_UNISTD_H @@ -35,6 +37,10 @@ #include "blkidP.h" +#ifdef HAVE_DEVMAPPER +#include +#endif + /* * Find a dev struct in the cache by device name, if available. * @@ -75,6 +81,10 @@ blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags) return dev; } +#ifdef HAVE_DEVMAPPER +static int dm_device_is_leaf(const dev_t dev); +#endif + /* * Probe a single block device to add to the device cache. */ @@ -90,6 +100,10 @@ static void probe_one(blkid_cache cache, const char *ptname, list_for_each(p, &cache->bic_devs) { blkid_dev tmp = list_entry(p, struct blkid_struct_dev, bid_devs); +#ifdef HAVE_DEVMAPPER + if (!dm_device_is_leaf(devno)) + continue; +#endif if (tmp->bid_devno == devno) { if (only_if_new) return; @@ -137,6 +151,155 @@ set_pri: return; } +#ifdef HAVE_DEVMAPPER +/* + * device-mapper support + */ +static int dm_device_has_dep(const dev_t dev, const char *name) +{ + struct dm_task *task; + struct dm_deps *deps; + struct dm_info info; + int i; + + task = dm_task_create(DM_DEVICE_DEPS); + if (!task) + return 0; + + dm_task_set_name(task, name); + dm_task_run(task); + dm_task_get_info(task, &info); + + if (!info.exists) { + dm_task_destroy(task); + return 0; + } + + deps = dm_task_get_deps(task); + if (!deps || deps->count == 0) { + dm_task_destroy(task); + return 0; + } + + for (i = 0; i < deps->count; i++) { + dev_t dep_dev = deps->device[i]; + + if (dev == dep_dev) { + dm_task_destroy(task); + return 1; + } + } + + dm_task_destroy(task); + return 0; +} + +static int dm_device_is_leaf(const dev_t dev) +{ + struct dm_task *task; + struct dm_names *names; + unsigned int next = 0; + int n, ret = 1; + + task = dm_task_create(DM_DEVICE_LIST); + if (!task) + return 1; + + dm_task_run(task); + names = dm_task_get_names(task); + if (!names || !names->dev) { + dm_task_destroy(task); + return 1; + } + + n = 0; + do { + names = (void *)names + next; + + if (dm_device_has_dep(dev, names->name)) + ret = 0; + + next = names->next; + } while (next); + + dm_task_destroy(task); + + return ret; +} + +static dev_t dm_get_devno(const char *name) +{ + struct dm_task *task; + struct dm_info info; + dev_t ret = 0; + + task = dm_task_create(DM_DEVICE_INFO); + if (!task) + return ret; + + dm_task_set_name(task, name); + dm_task_run(task); + dm_task_get_info(task, &info); + + if (!info.exists) { + dm_task_destroy(task); + return ret; + } + + ret = makedev(info.major, info.minor); + + dm_task_destroy(task); + + return ret; +} + +static void dm_probe_all(blkid_cache cache, int only_if_new) +{ + struct dm_task *task; + struct dm_names *names; + unsigned int next = 0; + int n; + + task = dm_task_create(DM_DEVICE_LIST); + if (!task) + return; + + dm_task_run(task); + names = dm_task_get_names(task); + if (!names || !names->dev) { + dm_task_destroy(task); + return; + } + + n = 0; + do { + int rc; + char *device = NULL; + dev_t dev = 0; + + names = (void *)names + next; + + rc = asprintf(&device, "/dev/mapper/%s", names->name); + if (rc < 0) + goto try_next; + + dev = dm_get_devno(names->name); + if (dev == 0) + goto try_next; + + if (!dm_device_is_leaf(dev)) + goto try_next; + + probe_one(cache, device, dev, BLKID_PRI_DM, only_if_new); + +try_next: + next = names->next; + } while (next); + + dm_task_destroy(task); +} +#endif /* HAVE_DEVMAPPER */ + #define PROC_PARTITIONS "/proc/partitions" #define VG_DIR "/proc/lvm/VGs" @@ -290,6 +453,9 @@ static int probe_all(blkid_cache cache, int only_if_new) return 0; blkid_read_cache(cache); +#ifdef HAVE_DEVMAPPER + dm_probe_all(cache, only_if_new); +#endif evms_probe_all(cache, only_if_new); #ifdef VG_DIR lvm_probe_all(cache, only_if_new);