Fix using zvol as slog device
authorJorgen Lundman <lundman@lundman.net>
Mon, 17 Dec 2012 01:33:57 +0000 (10:33 +0900)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 18 Dec 2012 19:02:28 +0000 (11:02 -0800)
During the original ZoL port the vdev_uses_zvols() function was
disabled until it could be properly implemented.  This prevented
a zpool from use a zvol for its slog device.

This patch implements that missing functionality by adding a
zvol_is_zvol() function to zvol.c.  Given the full path to a
device it will lookup the device and verify its major number
against the registered zvol major number for the system.  If
they match we know the device is a zvol.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #1131

include/sys/vdev.h
include/sys/zvol.h
module/zfs/vdev.c
module/zfs/zvol.c

index 50dbe69..0055783 100644 (file)
@@ -48,7 +48,6 @@ extern int zfs_nocacheflush;
 
 extern int vdev_open(vdev_t *);
 extern void vdev_open_children(vdev_t *);
-extern boolean_t vdev_uses_zvols(vdev_t *);
 extern int vdev_validate(vdev_t *, boolean_t);
 extern void vdev_close(vdev_t *);
 extern int vdev_create(vdev_t *, uint64_t txg, boolean_t isreplace);
index 815b186..185d645 100644 (file)
@@ -36,6 +36,7 @@
 extern int zvol_check_volsize(uint64_t volsize, uint64_t blocksize);
 extern int zvol_check_volblocksize(uint64_t volblocksize);
 extern int zvol_get_stats(objset_t *os, nvlist_t *nv);
+extern boolean_t zvol_is_zvol(const char *);
 extern void zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
 extern int zvol_create_minor(const char *);
 extern int zvol_create_minors(const char *);
index e0d82e6..e374f6d 100644 (file)
@@ -42,6 +42,7 @@
 #include <sys/arc.h>
 #include <sys/zil.h>
 #include <sys/dsl_scan.h>
+#include <sys/zvol.h>
 
 /*
  * Virtual device management.
@@ -1074,27 +1075,20 @@ vdev_open_child(void *arg)
        vd->vdev_open_thread = NULL;
 }
 
-boolean_t
+static boolean_t
 vdev_uses_zvols(vdev_t *vd)
 {
-/*
- * Stacking zpools on top of zvols is unsupported until we implement a method
- * for determining if an arbitrary block device is a zvol without using the
- * path.  Solaris would check the 'zvol' path component but this does not
- * exist in the Linux port, so we really should do something like stat the
- * file and check the major number.  This is complicated by the fact that
- * we need to do this portably in user or kernel space.
- */
-#if 0
        int c;
 
-       if (vd->vdev_path && strncmp(vd->vdev_path, ZVOL_DIR,
-           strlen(ZVOL_DIR)) == 0)
+#ifdef _KERNEL
+       if (zvol_is_zvol(vd->vdev_path))
                return (B_TRUE);
+#endif
+
        for (c = 0; c < vd->vdev_children; c++)
                if (vdev_uses_zvols(vd->vdev_child[c]))
                        return (B_TRUE);
-#endif
+
        return (B_FALSE);
 }
 
index 5d48025..7a448f1 100644 (file)
@@ -141,6 +141,29 @@ zvol_find_by_name(const char *name)
        return NULL;
 }
 
+
+/*
+ * Given a path, return TRUE if path is a ZVOL.
+ */
+boolean_t
+zvol_is_zvol(const char *device)
+{
+       struct block_device *bdev;
+       unsigned int major;
+
+       bdev = lookup_bdev(device);
+       if (IS_ERR(bdev))
+               return (B_FALSE);
+
+       major = MAJOR(bdev->bd_dev);
+       bdput(bdev);
+
+       if (major == zvol_major)
+            return (B_TRUE);
+
+       return (B_FALSE);
+}
+
 /*
  * ZFS_IOC_CREATE callback handles dmu zvol and zap object creation.
  */