diff options
author | Matt Macy <mmacy@FreeBSD.org> | 2020-09-04 21:31:58 +0000 |
---|---|---|
committer | Matt Macy <mmacy@FreeBSD.org> | 2020-09-04 21:31:58 +0000 |
commit | 431004027d028e7e689b171c442e6f1c384205c6 (patch) | |
tree | 6cf42660d552d2264586ffc9e69020ae6a604f1f /module/os/freebsd | |
parent | 93ddd0259dd285fbac5cc5086a039a22f1b046a1 (diff) | |
download | src-431004027d028e7e689b171c442e6f1c384205c6.tar.gz src-431004027d028e7e689b171c442e6f1c384205c6.zip |
Update vendor openzfs to fd20a8vendor/openzfs/2.0-rc1-gfd20a8
Notes
Notes:
svn path=/vendor-sys/openzfs/dist/; revision=365340
svn path=/vendor-sys/openzfs/2.0-rc1-gfd20a8/; revision=365341; tag=vendor/openzfs/2.0-rc1-gfd20a8
Diffstat (limited to 'module/os/freebsd')
-rw-r--r-- | module/os/freebsd/spl/spl_kstat.c | 278 | ||||
-rw-r--r-- | module/os/freebsd/spl/spl_zone.c | 6 | ||||
-rw-r--r-- | module/os/freebsd/zfs/spa_stats.c | 114 | ||||
-rw-r--r-- | module/os/freebsd/zfs/zfs_vfsops.c | 193 | ||||
-rw-r--r-- | module/os/freebsd/zfs/zvol_os.c | 22 |
5 files changed, 244 insertions, 369 deletions
diff --git a/module/os/freebsd/spl/spl_kstat.c b/module/os/freebsd/spl/spl_kstat.c index 756667045b17..df2da2d602b6 100644 --- a/module/os/freebsd/spl/spl_kstat.c +++ b/module/os/freebsd/spl/spl_kstat.c @@ -22,6 +22,10 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * Links to Illumos.org for more information on kstat function: + * [1] https://illumos.org/man/1M/kstat + * [2] https://illumos.org/man/9f/kstat_create */ #include <sys/cdefs.h> @@ -34,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/sysctl.h> #include <sys/kstat.h> +#include <sys/sbuf.h> static MALLOC_DEFINE(M_KSTAT, "kstat_data", "Kernel statistics"); @@ -61,6 +66,156 @@ kstat_default_update(kstat_t *ksp, int rw) return (0); } +static int +kstat_resize_raw(kstat_t *ksp) +{ + if (ksp->ks_raw_bufsize == KSTAT_RAW_MAX) + return (ENOMEM); + + free(ksp->ks_raw_buf, M_TEMP); + ksp->ks_raw_bufsize = MIN(ksp->ks_raw_bufsize * 2, KSTAT_RAW_MAX); + ksp->ks_raw_buf = malloc(ksp->ks_raw_bufsize, M_TEMP, M_WAITOK); + + return (0); +} + +static void * +kstat_raw_default_addr(kstat_t *ksp, loff_t n) +{ + if (n == 0) + return (ksp->ks_data); + return (NULL); +} + +static int +kstat_sysctl(SYSCTL_HANDLER_ARGS) +{ + kstat_t *ksp = arg1; + kstat_named_t *ksent; + uint64_t val; + + ksent = ksp->ks_data; + /* Select the correct element */ + ksent += arg2; + /* Update the aggsums before reading */ + (void) ksp->ks_update(ksp, KSTAT_READ); + val = ksent->value.ui64; + + return (sysctl_handle_64(oidp, &val, 0, req)); +} + +static int +kstat_sysctl_string(SYSCTL_HANDLER_ARGS) +{ + kstat_t *ksp = arg1; + kstat_named_t *ksent = ksp->ks_data; + char *val; + uint32_t len = 0; + + /* Select the correct element */ + ksent += arg2; + /* Update the aggsums before reading */ + (void) ksp->ks_update(ksp, KSTAT_READ); + val = KSTAT_NAMED_STR_PTR(ksent); + len = KSTAT_NAMED_STR_BUFLEN(ksent); + val[len-1] = '\0'; + + return (sysctl_handle_string(oidp, val, len, req)); +} + +static int +kstat_sysctl_io(SYSCTL_HANDLER_ARGS) +{ + struct sbuf *sb; + kstat_t *ksp = arg1; + kstat_io_t *kip = ksp->ks_data; + int rc; + + sb = sbuf_new_auto(); + if (sb == NULL) + return (ENOMEM); + /* Update the aggsums before reading */ + (void) ksp->ks_update(ksp, KSTAT_READ); + + /* though wlentime & friends are signed, they will never be negative */ + sbuf_printf(sb, + "%-8llu %-8llu %-8u %-8u %-8llu %-8llu " + "%-8llu %-8llu %-8llu %-8llu %-8u %-8u\n", + kip->nread, kip->nwritten, + kip->reads, kip->writes, + kip->wtime, kip->wlentime, kip->wlastupdate, + kip->rtime, kip->rlentime, kip->rlastupdate, + kip->wcnt, kip->rcnt); + rc = sbuf_finish(sb); + if (rc == 0) + rc = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb)); + sbuf_delete(sb); + return (rc); +} + +static int +kstat_sysctl_raw(SYSCTL_HANDLER_ARGS) +{ + struct sbuf *sb; + void *data; + kstat_t *ksp = arg1; + void *(*addr_op)(kstat_t *ksp, loff_t index); + int n, rc = 0; + + sb = sbuf_new_auto(); + if (sb == NULL) + return (ENOMEM); + + if (ksp->ks_raw_ops.addr) + addr_op = ksp->ks_raw_ops.addr; + else + addr_op = kstat_raw_default_addr; + + mutex_enter(ksp->ks_lock); + + /* Update the aggsums before reading */ + (void) ksp->ks_update(ksp, KSTAT_READ); + + ksp->ks_raw_bufsize = PAGE_SIZE; + ksp->ks_raw_buf = malloc(PAGE_SIZE, M_TEMP, M_WAITOK); + + n = 0; +restart_headers: + if (ksp->ks_raw_ops.headers) { + rc = ksp->ks_raw_ops.headers( + ksp->ks_raw_buf, ksp->ks_raw_bufsize); + if (rc == ENOMEM && !kstat_resize_raw(ksp)) + goto restart_headers; + if (rc == 0) + sbuf_printf(sb, "%s", ksp->ks_raw_buf); + } + + while ((data = addr_op(ksp, n)) != NULL) { +restart: + if (ksp->ks_raw_ops.data) { + rc = ksp->ks_raw_ops.data(ksp->ks_raw_buf, + ksp->ks_raw_bufsize, data); + if (rc == ENOMEM && !kstat_resize_raw(ksp)) + goto restart; + if (rc == 0) + sbuf_printf(sb, "%s", ksp->ks_raw_buf); + + } else { + ASSERT(ksp->ks_ndata == 1); + sbuf_hexdump(sb, ksp->ks_data, + ksp->ks_data_size, NULL, 0); + } + n++; + } + free(ksp->ks_raw_buf, M_TEMP); + mutex_exit(ksp->ks_lock); + rc = sbuf_finish(sb); + if (rc == 0) + rc = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb)); + sbuf_delete(sb); + return (rc); +} + kstat_t * __kstat_create(const char *module, int instance, const char *name, const char *class, uchar_t ks_type, uint_t ks_ndata, uchar_t flags) @@ -88,6 +243,9 @@ __kstat_create(const char *module, int instance, const char *name, ksp->ks_flags = flags; ksp->ks_update = kstat_default_update; + mutex_init(&ksp->ks_private_lock, NULL, MUTEX_DEFAULT, NULL); + ksp->ks_lock = &ksp->ks_private_lock; + switch (ksp->ks_type) { case KSTAT_TYPE_RAW: ksp->ks_ndata = 1; @@ -146,75 +304,38 @@ __kstat_create(const char *module, int instance, const char *name, free(ksp, M_KSTAT); return (NULL); } - root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, SYSCTL_CHILDREN(root), - OID_AUTO, name, CTLFLAG_RW, 0, ""); - if (root == NULL) { - printf("%s: Cannot create kstat.%s.%s.%s tree!\n", __func__, - module, class, name); - sysctl_ctx_free(&ksp->ks_sysctl_ctx); - free(ksp, M_KSTAT); - return (NULL); + if (ksp->ks_type == KSTAT_TYPE_NAMED) { + root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, + SYSCTL_CHILDREN(root), + OID_AUTO, name, CTLFLAG_RW, 0, ""); + if (root == NULL) { + printf("%s: Cannot create kstat.%s.%s.%s tree!\n", + __func__, module, class, name); + sysctl_ctx_free(&ksp->ks_sysctl_ctx); + free(ksp, M_KSTAT); + return (NULL); + } + } ksp->ks_sysctl_root = root; return (ksp); } -static int -kstat_sysctl(SYSCTL_HANDLER_ARGS) -{ - kstat_t *ksp = arg1; - kstat_named_t *ksent = ksp->ks_data; - uint64_t val; - - /* Select the correct element */ - ksent += arg2; - /* Update the aggsums before reading */ - (void) ksp->ks_update(ksp, KSTAT_READ); - val = ksent->value.ui64; - - return (sysctl_handle_64(oidp, &val, 0, req)); -} - -static int -kstat_sysctl_string(SYSCTL_HANDLER_ARGS) -{ - kstat_t *ksp = arg1; - kstat_named_t *ksent = ksp->ks_data; - char *val; - uint32_t len = 0; - - /* Select the correct element */ - ksent += arg2; - /* Update the aggsums before reading */ - (void) ksp->ks_update(ksp, KSTAT_READ); - val = KSTAT_NAMED_STR_PTR(ksent); - len = KSTAT_NAMED_STR_BUFLEN(ksent); - val[len-1] = '\0'; - - return (sysctl_handle_string(oidp, val, len, req)); -} - -void -kstat_install(kstat_t *ksp) +static void +kstat_install_named(kstat_t *ksp) { kstat_named_t *ksent; char *namelast; int typelast; ksent = ksp->ks_data; - if (ksp->ks_ndata == UINT32_MAX) { -#ifdef INVARIANTS - printf("can't handle raw ops yet!!!\n"); -#endif - return; - } - if (ksent == NULL) { - printf("%s ksp->ks_data == NULL!!!!\n", __func__); - return; - } + + VERIFY((ksp->ks_flags & KSTAT_FLAG_VIRTUAL) || ksent != NULL); + typelast = 0; namelast = NULL; + for (int i = 0; i < ksp->ks_ndata; i++, ksent++) { if (ksent->data_type != 0) { typelast = ksent->data_type; @@ -278,6 +399,51 @@ kstat_install(kstat_t *ksp) } } + +} + +void +kstat_install(kstat_t *ksp) +{ + struct sysctl_oid *root; + + if (ksp->ks_ndata == UINT32_MAX) + VERIFY(ksp->ks_type == KSTAT_TYPE_RAW); + + switch (ksp->ks_type) { + case KSTAT_TYPE_NAMED: + return (kstat_install_named(ksp)); + break; + case KSTAT_TYPE_RAW: + if (ksp->ks_raw_ops.data) { + root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, + SYSCTL_CHILDREN(ksp->ks_sysctl_root), + OID_AUTO, ksp->ks_name, + CTLTYPE_STRING | CTLFLAG_RD, ksp, 0, + kstat_sysctl_raw, "A", ksp->ks_name); + } else { + root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, + SYSCTL_CHILDREN(ksp->ks_sysctl_root), + OID_AUTO, ksp->ks_name, + CTLTYPE_OPAQUE | CTLFLAG_RD, ksp, 0, + kstat_sysctl_raw, "", ksp->ks_name); + } + VERIFY(root != NULL); + break; + case KSTAT_TYPE_IO: + root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, + SYSCTL_CHILDREN(ksp->ks_sysctl_root), + OID_AUTO, ksp->ks_name, + CTLTYPE_STRING | CTLFLAG_RD, ksp, 0, + kstat_sysctl_io, "A", ksp->ks_name); + break; + case KSTAT_TYPE_TIMER: + case KSTAT_TYPE_INTR: + default: + panic("unsupported kstat type %d\n", ksp->ks_type); + } + ksp->ks_sysctl_root = root; + } void @@ -285,6 +451,8 @@ kstat_delete(kstat_t *ksp) { sysctl_ctx_free(&ksp->ks_sysctl_ctx); + ksp->ks_lock = NULL; + mutex_destroy(&ksp->ks_private_lock); free(ksp, M_KSTAT); } diff --git a/module/os/freebsd/spl/spl_zone.c b/module/os/freebsd/spl/spl_zone.c index 0b3b04d2a73e..bd3f019b2fa6 100644 --- a/module/os/freebsd/spl/spl_zone.c +++ b/module/os/freebsd/spl/spl_zone.c @@ -242,12 +242,6 @@ zone_get_hostid(void *ptr) return ((uint32_t)curthread->td_ucred->cr_prison->pr_hostid); } -boolean_t -in_globalzone(struct proc *p) -{ - return (!jailed(FIRST_THREAD_IN_PROC((p))->td_ucred)); -} - static void zone_sysinit(void *arg __unused) { diff --git a/module/os/freebsd/zfs/spa_stats.c b/module/os/freebsd/zfs/spa_stats.c index 45c880ada24d..e69de29bb2d1 100644 --- a/module/os/freebsd/zfs/spa_stats.c +++ b/module/os/freebsd/zfs/spa_stats.c @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2020 iXsystems, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/zfs_context.h> -#include <sys/spa_impl.h> -#include <sys/vdev_impl.h> -#include <sys/spa.h> -#include <zfs_comutil.h> - -void -spa_stats_init(spa_t *spa) -{ - -} - -void -spa_stats_destroy(spa_t *spa) -{ - -} - -void -spa_iostats_trim_add(spa_t *spa, trim_type_t type, - uint64_t extents_written, uint64_t bytes_written, - uint64_t extents_skipped, uint64_t bytes_skipped, - uint64_t extents_failed, uint64_t bytes_failed) -{ -} - -void -spa_read_history_add(spa_t *spa, const zbookmark_phys_t *zb, uint32_t aflags) -{ -} - -void -spa_txg_history_add(spa_t *spa, uint64_t txg, hrtime_t birth_time) -{ - -} -/* - * Set txg state completion time and increment current state. - */ -int -spa_txg_history_set(spa_t *spa, uint64_t txg, txg_state_t completed_state, - hrtime_t completed_time) -{ - return (0); -} - -txg_stat_t * -spa_txg_history_init_io(spa_t *spa, uint64_t txg, dsl_pool_t *dp) -{ - return (NULL); -} - -void -spa_txg_history_fini_io(spa_t *spa, txg_stat_t *ts) -{ - -} - -void -spa_tx_assign_add_nsecs(spa_t *spa, uint64_t nsecs) -{ - -} - -void -spa_mmp_history_add(spa_t *spa, uint64_t txg, uint64_t timestamp, - uint64_t mmp_delay, vdev_t *vd, int label, uint64_t mmp_node_id, - int error) -{ - -} - -int -spa_mmp_history_set(spa_t *spa, uint64_t mmp_node_id, int io_error, - hrtime_t duration) -{ - return (0); -} - -int -spa_mmp_history_set_skip(spa_t *spa, uint64_t mmp_node_id) -{ - return (0); -} diff --git a/module/os/freebsd/zfs/zfs_vfsops.c b/module/os/freebsd/zfs/zfs_vfsops.c index f94ea44335c6..b6cf0c92b70b 100644 --- a/module/os/freebsd/zfs/zfs_vfsops.c +++ b/module/os/freebsd/zfs/zfs_vfsops.c @@ -1267,193 +1267,6 @@ zfs_unregister_callbacks(zfsvfs_t *zfsvfs) dsl_prop_unregister_all(dmu_objset_ds(os), zfsvfs); } -#ifdef SECLABEL -/* - * Convert a decimal digit string to a uint64_t integer. - */ -static int -str_to_uint64(char *str, uint64_t *objnum) -{ - uint64_t num = 0; - - while (*str) { - if (*str < '0' || *str > '9') - return (SET_ERROR(EINVAL)); - - num = num*10 + *str++ - '0'; - } - - *objnum = num; - return (0); -} - -/* - * The boot path passed from the boot loader is in the form of - * "rootpool-name/root-filesystem-object-number'. Convert this - * string to a dataset name: "rootpool-name/root-filesystem-name". - */ -static int -zfs_parse_bootfs(char *bpath, char *outpath) -{ - char *slashp; - uint64_t objnum; - int error; - - if (*bpath == 0 || *bpath == '/') - return (SET_ERROR(EINVAL)); - - (void) strcpy(outpath, bpath); - - slashp = strchr(bpath, '/'); - - /* if no '/', just return the pool name */ - if (slashp == NULL) { - return (0); - } - - /* if not a number, just return the root dataset name */ - if (str_to_uint64(slashp+1, &objnum)) { - return (0); - } - - *slashp = '\0'; - error = dsl_dsobj_to_dsname(bpath, objnum, outpath); - *slashp = '/'; - - return (error); -} - -/* - * Check that the hex label string is appropriate for the dataset being - * mounted into the global_zone proper. - * - * Return an error if the hex label string is not default or - * admin_low/admin_high. For admin_low labels, the corresponding - * dataset must be readonly. - */ -int -zfs_check_global_label(const char *dsname, const char *hexsl) -{ - if (strcasecmp(hexsl, ZFS_MLSLABEL_DEFAULT) == 0) - return (0); - if (strcasecmp(hexsl, ADMIN_HIGH) == 0) - return (0); - if (strcasecmp(hexsl, ADMIN_LOW) == 0) { - /* must be readonly */ - uint64_t rdonly; - - if (dsl_prop_get_integer(dsname, - zfs_prop_to_name(ZFS_PROP_READONLY), &rdonly, NULL)) - return (SET_ERROR(EACCES)); - return (rdonly ? 0 : EACCES); - } - return (SET_ERROR(EACCES)); -} - -/* - * Determine whether the mount is allowed according to MAC check. - * by comparing (where appropriate) label of the dataset against - * the label of the zone being mounted into. If the dataset has - * no label, create one. - * - * Returns 0 if access allowed, error otherwise (e.g. EACCES) - */ -static int -zfs_mount_label_policy(vfs_t *vfsp, char *osname) -{ - int error, retv; - zone_t *mntzone = NULL; - ts_label_t *mnt_tsl; - bslabel_t *mnt_sl; - bslabel_t ds_sl; - char ds_hexsl[MAXNAMELEN]; - - retv = EACCES; /* assume the worst */ - - /* - * Start by getting the dataset label if it exists. - */ - error = dsl_prop_get(osname, zfs_prop_to_name(ZFS_PROP_MLSLABEL), - 1, sizeof (ds_hexsl), &ds_hexsl, NULL); - if (error) - return (SET_ERROR(EACCES)); - - /* - * If labeling is NOT enabled, then disallow the mount of datasets - * which have a non-default label already. No other label checks - * are needed. - */ - if (!is_system_labeled()) { - if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) == 0) - return (0); - return (SET_ERROR(EACCES)); - } - - /* - * Get the label of the mountpoint. If mounting into the global - * zone (i.e. mountpoint is not within an active zone and the - * zoned property is off), the label must be default or - * admin_low/admin_high only; no other checks are needed. - */ - mntzone = zone_find_by_any_path(vfsp->vfs_mntpt, B_FALSE); - if (mntzone->zone_id == GLOBAL_ZONEID) { - uint64_t zoned; - - zone_rele(mntzone); - - if (dsl_prop_get_integer(osname, - zfs_prop_to_name(ZFS_PROP_ZONED), &zoned, NULL)) - return (SET_ERROR(EACCES)); - if (!zoned) - return (zfs_check_global_label(osname, ds_hexsl)); - else - /* - * This is the case of a zone dataset being mounted - * initially, before the zone has been fully created; - * allow this mount into global zone. - */ - return (0); - } - - mnt_tsl = mntzone->zone_slabel; - ASSERT(mnt_tsl != NULL); - label_hold(mnt_tsl); - mnt_sl = label2bslabel(mnt_tsl); - - if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) == 0) { - /* - * The dataset doesn't have a real label, so fabricate one. - */ - char *str = NULL; - - if (l_to_str_internal(mnt_sl, &str) == 0 && - dsl_prop_set_string(osname, - zfs_prop_to_name(ZFS_PROP_MLSLABEL), - ZPROP_SRC_LOCAL, str) == 0) - retv = 0; - if (str != NULL) - kmem_free(str, strlen(str) + 1); - } else if (hexstr_to_label(ds_hexsl, &ds_sl) == 0) { - /* - * Now compare labels to complete the MAC check. If the - * labels are equal then allow access. If the mountpoint - * label dominates the dataset label, allow readonly access. - * Otherwise, access is denied. - */ - if (blequal(mnt_sl, &ds_sl)) - retv = 0; - else if (bldominates(mnt_sl, &ds_sl)) { - vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); - retv = 0; - } - } - - label_rele(mnt_tsl); - zone_rele(mntzone); - return (retv); -} -#endif /* SECLABEL */ - static int getpoolname(const char *osname, char *poolname) { @@ -1544,12 +1357,6 @@ zfs_mount(vfs_t *vfsp) goto out; } -#ifdef SECLABEL - error = zfs_mount_label_policy(vfsp, osname); - if (error) - goto out; -#endif - vfsp->vfs_flag |= MNT_NFS4ACLS; /* diff --git a/module/os/freebsd/zfs/zvol_os.c b/module/os/freebsd/zfs/zvol_os.c index 113733a5c11a..ecef075f9e15 100644 --- a/module/os/freebsd/zfs/zvol_os.c +++ b/module/os/freebsd/zfs/zvol_os.c @@ -210,6 +210,7 @@ zvol_geom_open(struct g_provider *pp, int flag, int count) zvol_state_t *zv; int err = 0; boolean_t drop_suspend = B_TRUE; + boolean_t drop_namespace = B_FALSE; if (!zpool_on_zvol && tsd_get(zfs_geom_probe_vdev_key) != NULL) { /* @@ -223,13 +224,28 @@ zvol_geom_open(struct g_provider *pp, int flag, int count) return (SET_ERROR(EOPNOTSUPP)); } +retry: rw_enter(&zvol_state_lock, ZVOL_RW_READER); zv = pp->private; if (zv == NULL) { + if (drop_namespace) + mutex_exit(&spa_namespace_lock); rw_exit(&zvol_state_lock); return (SET_ERROR(ENXIO)); } + if (zv->zv_open_count == 0 && !mutex_owned(&spa_namespace_lock)) { + /* + * We need to guarantee that the namespace lock is held + * to avoid spurious failures in zvol_first_open + */ + drop_namespace = B_TRUE; + if (!mutex_tryenter(&spa_namespace_lock)) { + rw_exit(&zvol_state_lock); + mutex_enter(&spa_namespace_lock); + goto retry; + } + } mutex_enter(&zv->zv_state_lock); ASSERT(zv->zv_zso->zso_volmode == ZFS_VOLMODE_GEOM); @@ -291,6 +307,8 @@ zvol_geom_open(struct g_provider *pp, int flag, int count) #endif zv->zv_open_count += count; + if (drop_namespace) + mutex_exit(&spa_namespace_lock); mutex_exit(&zv->zv_state_lock); if (drop_suspend) rw_exit(&zv->zv_suspend_lock); @@ -300,6 +318,8 @@ out_open_count: if (zv->zv_open_count == 0) zvol_last_close(zv); out_mutex: + if (drop_namespace) + mutex_exit(&spa_namespace_lock); mutex_exit(&zv->zv_state_lock); if (drop_suspend) rw_exit(&zv->zv_suspend_lock); @@ -606,7 +626,7 @@ zvol_geom_bio_strategy(struct bio *bp) addr = bp->bio_data; resid = bp->bio_length; - if (resid > 0 && (off < 0 || off >= volsize)) { + if (resid > 0 && off >= volsize) { error = SET_ERROR(EIO); goto resume; } |