summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Wilson <alex.wilson@joyent.com>2015-08-28 18:03:26 -0700
committerRobert Mustacchi <rm@joyent.com>2015-09-01 17:28:54 -0700
commit0ad555ad6a787635be8c8a424168dc59cfbce6c7 (patch)
tree5cdd4cf2e87316026bc1b56cb8f13aec9ceb451a
parent2becb8cdf9cd77e1a76224f216be15d6ae3b9ec9 (diff)
downloadillumos-joyent-0ad555ad6a787635be8c8a424168dc59cfbce6c7.tar.gz
6174 /dev/zvol does not show pool directories
Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Jason King <jason.brian.king@gmail.com> Approved by: Dan McDonald <danmcd@omniti.com>
-rw-r--r--usr/src/uts/common/fs/dev/sdev_vfsops.c17
-rw-r--r--usr/src/uts/common/fs/dev/sdev_zvolops.c91
-rw-r--r--usr/src/uts/common/sys/fs/sdev_impl.h4
3 files changed, 91 insertions, 21 deletions
diff --git a/usr/src/uts/common/fs/dev/sdev_vfsops.c b/usr/src/uts/common/fs/dev/sdev_vfsops.c
index ea9cb6374a..00e981ce9c 100644
--- a/usr/src/uts/common/fs/dev/sdev_vfsops.c
+++ b/usr/src/uts/common/fs/dev/sdev_vfsops.c
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc. All rights reserved.
*/
/*
@@ -56,6 +57,7 @@
#include <sys/fs/dv_node.h>
#include <sys/sunndi.h>
#include <sys/mntent.h>
+#include <sys/disp.h>
/*
* /dev vfs operations.
@@ -66,6 +68,7 @@
*/
struct sdev_data *sdev_origins; /* mount info for origins under /dev */
kmutex_t sdev_lock; /* used for mount/unmount/rename synchronization */
+taskq_t *sdev_taskq = NULL;
/*
* static
@@ -254,6 +257,20 @@ sdev_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
mutex_enter(&sdev_lock);
/*
+ * Check that the taskq has been created. We can't do this in our
+ * _init or devinit because they run too early for ddi_taskq_create.
+ */
+ if (sdev_taskq == NULL) {
+ sdev_taskq = taskq_create("sdev", 1, minclsyspri, 1, 1, 0);
+ if (sdev_taskq == NULL) {
+ error = ENOMEM;
+ mutex_exit(&sdev_lock);
+ VN_RELE(avp);
+ goto cleanup;
+ }
+ }
+
+ /*
* handling installation
*/
if (uap->flags & MS_REMOUNT) {
diff --git a/usr/src/uts/common/fs/dev/sdev_zvolops.c b/usr/src/uts/common/fs/dev/sdev_zvolops.c
index e4c3acf787..54061b48cf 100644
--- a/usr/src/uts/common/fs/dev/sdev_zvolops.c
+++ b/usr/src/uts/common/fs/dev/sdev_zvolops.c
@@ -41,14 +41,18 @@
#include <sys/vfs_opreg.h>
struct vnodeops *devzvol_vnodeops;
+static major_t devzvol_major;
+static taskq_ent_t devzvol_zclist_task;
+
+static kmutex_t devzvol_mtx;
+/* Below are protected by devzvol_mtx */
+static boolean_t devzvol_isopen;
+static boolean_t devzvol_zclist_task_running = B_FALSE;
static uint64_t devzvol_gen = 0;
static uint64_t devzvol_zclist;
static size_t devzvol_zclist_size;
static ldi_ident_t devzvol_li;
static ldi_handle_t devzvol_lh;
-static kmutex_t devzvol_mtx;
-static boolean_t devzvol_isopen;
-static major_t devzvol_major;
/*
* we need to use ddi_mod* since fs/dev gets loaded early on in
@@ -310,19 +314,20 @@ devzvol_validate(struct sdev_node *dv)
}
/*
- * creates directories as needed in response to a readdir
+ * Taskq callback to update the devzvol_zclist.
+ *
+ * We need to defer this to the taskq to avoid it running with a user
+ * context that might be associated with some non-global zone, and thus
+ * not being able to list all of the pools on the entire system.
*/
-void
-devzvol_create_pool_dirs(struct vnode *dvp)
+/*ARGSUSED*/
+static void
+devzvol_update_zclist_cb(void *arg)
{
zfs_cmd_t *zc;
- nvlist_t *nv = NULL;
- nvpair_t *elem = NULL;
- size_t size;
- int pools = 0;
- int rc;
+ int rc;
+ size_t size;
- sdcmn_err13(("devzvol_create_pool_dirs"));
zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
mutex_enter(&devzvol_mtx);
zc->zc_cookie = devzvol_gen;
@@ -337,22 +342,67 @@ devzvol_create_pool_dirs(struct vnode *dvp)
kmem_free((void *)(uintptr_t)devzvol_zclist,
devzvol_zclist_size);
devzvol_zclist = zc->zc_nvlist_dst;
+ /* Keep the alloc'd size, not the nvlist size. */
devzvol_zclist_size = size;
break;
- case EEXIST:
+ default:
/*
- * no change in the configuration; still need
- * to do lookups in case we did a lookup in
- * zvol/rdsk but not zvol/dsk (or vice versa)
+ * Either there was no change in pool configuration
+ * since we last asked (rc == EEXIST) or we got a
+ * catastrophic error.
+ *
+ * Give up memory and exit.
*/
kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst,
size);
break;
- default:
- kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst,
- size);
- goto out;
}
+
+ VERIFY(devzvol_zclist_task_running == B_TRUE);
+ devzvol_zclist_task_running = B_FALSE;
+ mutex_exit(&devzvol_mtx);
+
+ kmem_free(zc, sizeof (zfs_cmd_t));
+}
+
+static void
+devzvol_update_zclist(void)
+{
+ mutex_enter(&devzvol_mtx);
+ if (devzvol_zclist_task_running == B_TRUE) {
+ mutex_exit(&devzvol_mtx);
+ goto wait;
+ }
+
+ devzvol_zclist_task_running = B_TRUE;
+
+ taskq_dispatch_ent(sdev_taskq, devzvol_update_zclist_cb, NULL, 0,
+ &devzvol_zclist_task);
+
+ mutex_exit(&devzvol_mtx);
+
+wait:
+ taskq_wait(sdev_taskq);
+}
+
+/*
+ * Creates sub-directories for each zpool as needed in response to a
+ * readdir on one of the /dev/zvol/{dsk,rdsk} directories.
+ */
+void
+devzvol_create_pool_dirs(struct vnode *dvp)
+{
+ nvlist_t *nv = NULL;
+ nvpair_t *elem = NULL;
+ int pools = 0;
+ int rc;
+
+ sdcmn_err13(("devzvol_create_pool_dirs"));
+
+ devzvol_update_zclist();
+
+ mutex_enter(&devzvol_mtx);
+
rc = nvlist_unpack((char *)(uintptr_t)devzvol_zclist,
devzvol_zclist_size, &nv, 0);
if (rc) {
@@ -385,7 +435,6 @@ devzvol_create_pool_dirs(struct vnode *dvp)
}
out:
mutex_exit(&devzvol_mtx);
- kmem_free(zc, sizeof (zfs_cmd_t));
}
/*ARGSUSED3*/
diff --git a/usr/src/uts/common/sys/fs/sdev_impl.h b/usr/src/uts/common/sys/fs/sdev_impl.h
index 19a147d88a..7ea6b88ec2 100644
--- a/usr/src/uts/common/sys/fs/sdev_impl.h
+++ b/usr/src/uts/common/sys/fs/sdev_impl.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Joyent, Inc. All rights reserved.
*/
#ifndef _SYS_SDEV_IMPL_H
@@ -35,6 +36,7 @@ extern "C" {
#include <sys/vfs_opreg.h>
#include <sys/list.h>
#include <sys/nvpair.h>
+#include <sys/sunddi.h>
/*
* sdev_nodes are the file-system specific part of the
@@ -541,6 +543,8 @@ extern int sdev_nc_disable;
extern int sdev_nc_disable_reset;
extern int sdev_nc_verbose;
+extern taskq_t *sdev_taskq;
+
/*
* misc. defines
*/