diff options
Diffstat (limited to 'lib/libzfs/libzfs_pool.c')
-rw-r--r-- | lib/libzfs/libzfs_pool.c | 183 |
1 files changed, 87 insertions, 96 deletions
diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index 6727a77e7..9d0702b56 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -41,9 +41,6 @@ #include <sys/vtoc.h> #include <sys/zfs_ioctl.h> #include <dlfcn.h> -#if HAVE_LIBDEVMAPPER -#include <libdevmapper.h> -#endif #include "zfs_namecheck.h" #include "zfs_prop.h" @@ -3432,6 +3429,43 @@ zfs_strip_partition(char *path) return (tmp); } +/* + * Same as zfs_strip_partition, but allows "/dev/" to be in the pathname + * + * path: /dev/sda1 + * returns: /dev/sda + * + * Returned string must be freed. + */ +char * +zfs_strip_partition_path(char *path) +{ + char *newpath = strdup(path); + char *sd_offset; + char *new_sd; + + if (!newpath) + return (NULL); + + /* Point to "sda1" part of "/dev/sda1" */ + sd_offset = strrchr(newpath, '/') + 1; + + /* Get our new name "sda" */ + new_sd = zfs_strip_partition(sd_offset); + if (!new_sd) { + free(newpath); + return (NULL); + } + + /* Paste the "sda" where "sda1" was */ + strlcpy(sd_offset, new_sd, strlen(sd_offset) + 1); + + /* Free temporary "sda" */ + free(new_sd); + + return (newpath); +} + #define PATH_BUF_LEN 64 /* @@ -4318,112 +4352,69 @@ zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) return (0); } -#if HAVE_LIBDEVMAPPER -static void libdevmapper_dummy_log(int level, const char *file, int line, - int dm_errno_or_class, const char *f, ...) {} - -/* Disable libdevmapper error logging */ -static void disable_libdevmapper_errors(void) { - dm_log_with_errno_init(libdevmapper_dummy_log); -} -/* Enable libdevmapper error logging */ -static void enable_libdevmapper_errors(void) { - dm_log_with_errno_init(NULL); -} -#endif - /* * Allocate and return the underlying device name for a device mapper device. * If a device mapper device maps to multiple devices, return the first device. * - * For example, dm_name = "/dev/dm-0" could return "/dev/sda" - * - * dm_name should include the "/dev[/mapper]" prefix. + * For example, dm_name = "/dev/dm-0" could return "/dev/sda". Symlinks to a + * DM device (like /dev/disk/by-vdev/A0) are also allowed. * * Returns device name, or NULL on error or no match. If dm_name is not a DM * device then return NULL. * * NOTE: The returned name string must be *freed*. */ -static char * dm_get_underlying_path(char *dm_name) +char * +dm_get_underlying_path(char *dm_name) { - char *name = NULL; -#if HAVE_LIBDEVMAPPER - char *tmp; - struct dm_task *dmt = NULL; - struct dm_tree *dt = NULL; - struct dm_tree_node *root, *child; - void *handle = NULL; - struct dm_info info; - const struct dm_info *child_info; + DIR *dp = NULL; + struct dirent *ep; + char *realp; + char *tmp = NULL; + char *path = NULL; + char *dev_str; + int size; - /* - * Disable libdevmapper errors. It's entirely possible user is not - * running devmapper, or that dm_name is not a devmapper device. - * That's totally ok, we will just harmlessly and silently return NULL. - */ - disable_libdevmapper_errors(); + if (dm_name == NULL) + return (NULL); + + /* dm name may be a symlink (like /dev/disk/by-vdev/A0) */ + realp = realpath(dm_name, NULL); + if (realp == NULL) + return (NULL); /* - * libdevmapper tutorial - * - * libdevmapper is basically a fancy wrapper for its ioctls. You - * create a "task", fill in the needed info to the task (fill in the - * ioctl fields), then run the task (call the ioctl). - * - * First we need the major/minor number for our DM device. + * If they preface 'dev' with a path (like "/dev") then strip it off. + * We just want the 'dm-N' part. */ - if (!(dmt = dm_task_create(DM_DEVICE_INFO))) - goto end; - - /* Lookup the name in libdevmapper */ - if (!dm_task_set_name(dmt, dm_name)) { - enable_libdevmapper_errors(); - goto end; - } - - if (!dm_task_run(dmt)) - goto end; - - /* Get DM device's major/minor */ - if (!dm_task_get_info(dmt, &info)) - goto end; - - /* We have major/minor number. Lookup the dm device's children */ - if (!(dt = dm_tree_create())) - goto end; - - /* We add the device into the tree and its children get populated */ - if (!dm_tree_add_dev(dt, info.major, info.minor)) - goto end; - - if (!(root = dm_tree_find_node(dt, 0, 0))) - goto end; - - if (!(child = dm_tree_next_child(&handle, root, 1))) - goto end; + tmp = strrchr(realp, '/'); + if (tmp != NULL) + dev_str = tmp + 1; /* +1 since we want the chr after '/' */ + else + dev_str = tmp; - /* Get child's major/minor numbers */ - if (!(child_info = dm_tree_node_get_info(child))) + size = asprintf(&tmp, "/sys/block/%s/slaves/", dev_str); + if (size == -1 || !tmp) goto end; - if ((asprintf(&tmp, "/dev/block/%d:%d", child_info->major, - child_info->minor) == -1) || tmp == NULL) + dp = opendir(tmp); + if (dp == NULL) goto end; - /* Further translate /dev/block/ name into the normal name */ - name = realpath(tmp, NULL); - free(tmp); + /* Return first sd* entry in /sys/block/dm-N/slaves/ */ + while ((ep = readdir(dp))) { + if (ep->d_type != DT_DIR) { /* skip "." and ".." dirs */ + size = asprintf(&path, "/dev/%s", ep->d_name); + break; + } + } end: - if (dmt) - dm_task_destroy(dmt); - if (dt) - dm_tree_free(dt); - enable_libdevmapper_errors(); -#endif /* HAVE_LIBDEVMAPPER */ - - return (name); + if (dp != NULL) + closedir(dp); + free(tmp); + free(realp); + return (path); } /* @@ -4436,7 +4427,7 @@ zfs_dev_is_dm(char *dev_name) char *tmp; tmp = dm_get_underlying_path(dev_name); - if (!tmp) + if (tmp == NULL) return (0); free(tmp); @@ -4489,17 +4480,17 @@ zfs_get_underlying_path(char *dev_name) char *name = NULL; char *tmp; - if (!dev_name) + if (dev_name == NULL) return (NULL); tmp = dm_get_underlying_path(dev_name); /* dev_name not a DM device, so just un-symlinkize it */ - if (!tmp) + if (tmp == NULL) tmp = realpath(dev_name, NULL); - if (tmp) { - name = zfs_strip_partition(tmp); + if (tmp != NULL) { + name = zfs_strip_partition_path(tmp); free(tmp); } @@ -4532,12 +4523,12 @@ zfs_get_enclosure_sysfs_path(char *dev_name) size_t size; int tmpsize; - if (!dev_name) + if (dev_name == NULL) return (NULL); /* If they preface 'dev' with a path (like "/dev") then strip it off */ tmp1 = strrchr(dev_name, '/'); - if (tmp1) + if (tmp1 != NULL) dev_name = tmp1 + 1; /* +1 since we want the chr after '/' */ tmpsize = asprintf(&tmp1, "/sys/block/%s/device", dev_name); @@ -4558,7 +4549,7 @@ zfs_get_enclosure_sysfs_path(char *dev_name) */ while ((ep = readdir(dp))) { /* Ignore everything that's not our enclosure_device link */ - if (!strstr(ep->d_name, "enclosure_device")) + if (strstr(ep->d_name, "enclosure_device") == NULL) continue; if (asprintf(&tmp2, "%s/%s", tmp1, ep->d_name) == -1 || @@ -4605,7 +4596,7 @@ end: free(tmp2); free(tmp1); - if (dp) + if (dp != NULL) closedir(dp); return (path); |