aboutsummaryrefslogtreecommitdiffstats
path: root/lib/libzfs/libzfs_pool.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libzfs/libzfs_pool.c')
-rw-r--r--lib/libzfs/libzfs_pool.c183
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);