From 6c2856726fbae681649930d9620d9087080e58fc Mon Sep 17 00:00:00 2001 From: Jorgen Lundman Date: Mon, 17 Dec 2012 10:33:57 +0900 Subject: Fix using zvol as slog device 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 Closes #1131 --- include/sys/vdev.h | 1 - include/sys/zvol.h | 1 + module/zfs/vdev.c | 20 +++++++------------- module/zfs/zvol.c | 23 +++++++++++++++++++++++ 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/include/sys/vdev.h b/include/sys/vdev.h index 50dbe695c..005578398 100644 --- a/include/sys/vdev.h +++ b/include/sys/vdev.h @@ -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); diff --git a/include/sys/zvol.h b/include/sys/zvol.h index 815b186e0..185d64523 100644 --- a/include/sys/zvol.h +++ b/include/sys/zvol.h @@ -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 *); diff --git a/module/zfs/vdev.c b/module/zfs/vdev.c index e0d82e673..e374f6d78 100644 --- a/module/zfs/vdev.c +++ b/module/zfs/vdev.c @@ -42,6 +42,7 @@ #include #include #include +#include /* * 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); } diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index 5d4802560..7a448f194 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -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. */ -- cgit v1.2.3