aboutsummaryrefslogtreecommitdiff
path: root/cddl/contrib/opensolaris
diff options
context:
space:
mode:
authorAndriy Gapon <avg@FreeBSD.org>2019-11-18 09:38:35 +0000
committerAndriy Gapon <avg@FreeBSD.org>2019-11-18 09:38:35 +0000
commita8c08e008a28197ebf061be1096cea97212d27dd (patch)
tree3fb2b064f957421d66d5ccab95bfcf1e754df03e /cddl/contrib/opensolaris
parentf327c2ba2fb6ab6915a19c02db291fcdeb43840d (diff)
parent2185a970072a56aa5573b33e848b900ef2067006 (diff)
downloadsrc-a8c08e008a28197ebf061be1096cea97212d27dd.tar.gz
src-a8c08e008a28197ebf061be1096cea97212d27dd.zip
MFV r354378,r354379,r354386: 10499 Multi-modifier protection (MMP)
10499 Multi-modifier protection (MMP) illumos/illumos-gate@e0f1c0afa46cc84d4b1e40124032a9a87310386e https://github.com/illumos/illumos-gate/commit/e0f1c0afa46cc84d4b1e40124032a9a87310386e https://www.illumos.org/issues/10499 Port the following ZFS commits from ZoL to illumos. 379ca9cf2 Multi-modifier protection (MMP) bbffb59ef Fix multihost stale cache file import 0d398b256 Do not initiate MMP writes while pool is suspended 10701 Correct lock ASSERTs in vdev_label_read/write illumos/illumos-gate@58447f688d5e308373ab16a3b129bc0ba0fbc154 https://github.com/illumos/illumos-gate/commit/58447f688d5e308373ab16a3b129bc0ba0fbc154 https://www.illumos.org/issues/10701 Port of ZoL commit: 0091d66f4e Correct lock ASSERTs in vdev_label_read/write At a minimum, this fixes a blown assert during an MMP test run when running on a DEBUG build. 11770 additional mmp fixes illumos/illumos-gate@4348eb901228d2f8fa50bb132a34248e8662074e https://github.com/illumos/illumos-gate/commit/4348eb901228d2f8fa50bb132a34248e8662074e https://www.illumos.org/issues/11770 Port a few additional MMP fixes from ZoL that came in after our initial MMP port. 4ca457b065 ZTS: Fix mmp_interval failure ca95f70dff zpool import progress kstat (only minimal changes from above can be pulled in right now) 060f0226e6 MMP interval and fail_intervals in uberblock Note from the committer (me). I do not have any use for this feature and I have not tested it. I only did smoke testing with multihost=off. Please be aware. I merged the code only to make future merges easier. Portions contributed by: Jerry Jelinek <jerry.jelinek@joyent.com> Portions contributed by: Tim Chase <tim@chase2k.com> Portions contributed by: sanjeevbagewadi <sanjeev.bagewadi@gmail.com> Portions contributed by: John L. Hammond <john.hammond@intel.com> Portions contributed by: Giuseppe Di Natale <dinatale2@llnl.gov> Portions contributed by: Prakash Surya <surya1@llnl.gov> Portions contributed by: Brian Behlendorf <behlendorf1@llnl.gov> Author: Olaf Faaland <faaland1@llnl.gov> MFC after: 4 weeks
Notes
Notes: svn path=/head/; revision=354804
Diffstat (limited to 'cddl/contrib/opensolaris')
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb.c192
-rw-r--r--cddl/contrib/opensolaris/cmd/zhack/zhack.c59
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool.876
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool_main.c171
-rw-r--r--cddl/contrib/opensolaris/cmd/ztest/ztest.c157
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h11
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c2
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h2
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c77
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c54
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c80
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c29
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/kernel.c5
-rw-r--r--cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h3
14 files changed, 687 insertions, 231 deletions
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb.c b/cddl/contrib/opensolaris/cmd/zdb/zdb.c
index 2ff94970f26c..a775595bda60 100644
--- a/cddl/contrib/opensolaris/cmd/zdb/zdb.c
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb.c
@@ -24,6 +24,7 @@
* Copyright (c) 2011, 2017 by Delphix. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2017 Nexenta Systems, Inc.
+ * Copyright (c) 2017, 2018 Lawrence Livermore National Security, LLC.
* Copyright 2017 RackTop Systems.
*/
@@ -2436,6 +2437,26 @@ dump_uberblock(uberblock_t *ub, const char *header, const char *footer)
(void) printf("\tguid_sum = %llu\n", (u_longlong_t)ub->ub_guid_sum);
(void) printf("\ttimestamp = %llu UTC = %s",
(u_longlong_t)ub->ub_timestamp, asctime(localtime(&timestamp)));
+
+ (void) printf("\tmmp_magic = %016llx\n",
+ (u_longlong_t)ub->ub_mmp_magic);
+ if (MMP_VALID(ub)) {
+ (void) printf("\tmmp_delay = %0llu\n",
+ (u_longlong_t)ub->ub_mmp_delay);
+ if (MMP_SEQ_VALID(ub))
+ (void) printf("\tmmp_seq = %u\n",
+ (unsigned int) MMP_SEQ(ub));
+ if (MMP_FAIL_INT_VALID(ub))
+ (void) printf("\tmmp_fail = %u\n",
+ (unsigned int) MMP_FAIL_INT(ub));
+ if (MMP_INTERVAL_VALID(ub))
+ (void) printf("\tmmp_write = %u\n",
+ (unsigned int) MMP_INTERVAL(ub));
+ /* After MMP_* to make summarize_uberblock_mmp cleaner */
+ (void) printf("\tmmp_valid = %x\n",
+ (unsigned int) ub->ub_mmp_config & 0xFF);
+ }
+
if (dump_opt['u'] >= 3) {
char blkbuf[BP_SPRINTF_LEN];
snprintf_blkptr(blkbuf, sizeof (blkbuf), &ub->ub_rootbp);
@@ -2534,6 +2555,12 @@ dump_label_uberblocks(vdev_label_t *lbl, uint64_t ashift)
if (uberblock_verify(ub))
continue;
+
+ if ((dump_opt['u'] < 4) &&
+ (ub->ub_mmp_magic == MMP_MAGIC) && ub->ub_mmp_delay &&
+ (i >= VDEV_UBERBLOCK_COUNT(&vd) - MMP_BLOCKS_PER_LABEL))
+ continue;
+
(void) snprintf(header, ZDB_MAX_UB_HEADER_SIZE,
"Uberblock[%d]\n", i);
dump_uberblock(ub, header, "");
@@ -4173,6 +4200,22 @@ verify_device_removal_feature_counts(spa_t *spa)
return (ret);
}
+static void
+zdb_set_skip_mmp(char *target)
+{
+ spa_t *spa;
+
+ /*
+ * Disable the activity check to allow examination of
+ * active pools.
+ */
+ mutex_enter(&spa_namespace_lock);
+ if ((spa = spa_lookup(target)) != NULL) {
+ spa->spa_import_flags |= ZFS_IMPORT_SKIP_MMP;
+ }
+ mutex_exit(&spa_namespace_lock);
+}
+
#define BOGUS_SUFFIX "_CHECKPOINTED_UNIVERSE"
/*
* Import the checkpointed state of the pool specified by the target
@@ -4207,6 +4250,7 @@ import_checkpointed_state(char *target, nvlist_t *cfg, char **new_path)
}
if (cfg == NULL) {
+ zdb_set_skip_mmp(poolname);
error = spa_get_stats(poolname, &cfg, NULL, 0);
if (error != 0) {
fatal("Tried to read config of pool \"%s\" but "
@@ -4219,7 +4263,8 @@ import_checkpointed_state(char *target, nvlist_t *cfg, char **new_path)
fnvlist_add_string(cfg, ZPOOL_CONFIG_POOL_NAME, bogus_name);
error = spa_import(bogus_name, cfg, NULL,
- ZFS_IMPORT_MISSING_LOG | ZFS_IMPORT_CHECKPOINT);
+ ZFS_IMPORT_MISSING_LOG | ZFS_IMPORT_CHECKPOINT |
+ ZFS_IMPORT_SKIP_MMP);
if (error != 0) {
fatal("Tried to import pool \"%s\" but spa_import() failed "
"with error %d\n", bogus_name, error);
@@ -5222,90 +5267,6 @@ zdb_embedded_block(char *thing)
free(buf);
}
-static boolean_t
-pool_match(nvlist_t *cfg, char *tgt)
-{
- uint64_t v, guid = strtoull(tgt, NULL, 0);
- char *s;
-
- if (guid != 0) {
- if (nvlist_lookup_uint64(cfg, ZPOOL_CONFIG_POOL_GUID, &v) == 0)
- return (v == guid);
- } else {
- if (nvlist_lookup_string(cfg, ZPOOL_CONFIG_POOL_NAME, &s) == 0)
- return (strcmp(s, tgt) == 0);
- }
- return (B_FALSE);
-}
-
-static char *
-find_zpool(char **target, nvlist_t **configp, int dirc, char **dirv)
-{
- nvlist_t *pools;
- nvlist_t *match = NULL;
- char *name = NULL;
- char *sepp = NULL;
- char sep = '\0';
- int count = 0;
- importargs_t args;
-
- bzero(&args, sizeof (args));
- args.paths = dirc;
- args.path = dirv;
- args.can_be_active = B_TRUE;
-
- if ((sepp = strpbrk(*target, "/@")) != NULL) {
- sep = *sepp;
- *sepp = '\0';
- }
-
- pools = zpool_search_import(g_zfs, &args);
-
- if (pools != NULL) {
- nvpair_t *elem = NULL;
- while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
- verify(nvpair_value_nvlist(elem, configp) == 0);
- if (pool_match(*configp, *target)) {
- count++;
- if (match != NULL) {
- /* print previously found config */
- if (name != NULL) {
- (void) printf("%s\n", name);
- dump_nvlist(match, 8);
- name = NULL;
- }
- (void) printf("%s\n",
- nvpair_name(elem));
- dump_nvlist(*configp, 8);
- } else {
- match = *configp;
- name = nvpair_name(elem);
- }
- }
- }
- }
- if (count > 1)
- (void) fatal("\tMatched %d pools - use pool GUID "
- "instead of pool name or \n"
- "\tpool name part of a dataset name to select pool", count);
-
- if (sepp)
- *sepp = sep;
- /*
- * If pool GUID was specified for pool id, replace it with pool name
- */
- if (name && (strstr(*target, name) != *target)) {
- int sz = 1 + strlen(name) + ((sepp) ? strlen(sepp) : 0);
-
- *target = umem_alloc(sz, UMEM_NOFAIL);
- (void) snprintf(*target, sz, "%s%s", name, sepp ? sepp : "");
- }
-
- *configp = name ? match : NULL;
-
- return (name);
-}
-
int
main(int argc, char **argv)
{
@@ -5318,7 +5279,7 @@ main(int argc, char **argv)
int error = 0;
char **searchdirs = NULL;
int nsearch = 0;
- char *target;
+ char *target, *target_pool;
nvlist_t *policy = NULL;
uint64_t max_txg = UINT64_MAX;
int flags = ZFS_IMPORT_MISSING_LOG;
@@ -5526,22 +5487,48 @@ main(int argc, char **argv)
error = 0;
target = argv[0];
+ if (strpbrk(target, "/@") != NULL) {
+ size_t targetlen;
+
+ target_pool = strdup(target);
+ *strpbrk(target_pool, "/@") = '\0';
+
+ target_is_spa = B_FALSE;
+ targetlen = strlen(target);
+ if (targetlen && target[targetlen - 1] == '/')
+ target[targetlen - 1] = '\0';
+ } else {
+ target_pool = target;
+ }
+
if (dump_opt['e']) {
- char *name = find_zpool(&target, &cfg, nsearch, searchdirs);
+ importargs_t args = { 0 };
- error = ENOENT;
- if (name) {
- if (dump_opt['C'] > 1) {
- (void) printf("\nConfiguration for import:\n");
- dump_nvlist(cfg, 8);
- }
+ args.paths = nsearch;
+ args.path = searchdirs;
+ args.can_be_active = B_TRUE;
+
+ error = zpool_tryimport(g_zfs, target_pool, &cfg, &args);
+
+ if (error == 0) {
if (nvlist_add_nvlist(cfg,
ZPOOL_LOAD_POLICY, policy) != 0) {
fatal("can't open '%s': %s",
target, strerror(ENOMEM));
}
- error = spa_import(name, cfg, NULL, flags);
+
+ if (dump_opt['C'] > 1) {
+ (void) printf("\nConfiguration for import:\n");
+ dump_nvlist(cfg, 8);
+ }
+
+ /*
+ * Disable the activity check to allow examination of
+ * active pools.
+ */
+ error = spa_import(target_pool, cfg, NULL,
+ flags | ZFS_IMPORT_SKIP_MMP);
}
}
@@ -5556,21 +5543,6 @@ main(int argc, char **argv)
}
- if (strpbrk(target, "/@") != NULL) {
- size_t targetlen;
-
- target_is_spa = B_FALSE;
- /*
- * Remove any trailing slash. Later code would get confused
- * by it, but we want to allow it so that "pool/" can
- * indicate that we want to dump the topmost filesystem,
- * rather than the whole pool.
- */
- targetlen = strlen(target);
- if (targetlen != 0 && target[targetlen - 1] == '/')
- target[targetlen - 1] = '\0';
- }
-
if (error == 0) {
if (dump_opt['k'] && (target_is_spa || dump_opt['R'])) {
ASSERT(checkpoint_pool != NULL);
@@ -5584,6 +5556,7 @@ main(int argc, char **argv)
}
} else if (target_is_spa || dump_opt['R']) {
+ zdb_set_skip_mmp(target);
error = spa_open_rewind(target, &spa, FTAG, policy,
NULL);
if (error) {
@@ -5606,6 +5579,7 @@ main(int argc, char **argv)
}
}
} else {
+ zdb_set_skip_mmp(target);
error = open_objset(target, DMU_OST_ANY, FTAG, &os);
}
}
diff --git a/cddl/contrib/opensolaris/cmd/zhack/zhack.c b/cddl/contrib/opensolaris/cmd/zhack/zhack.c
index 98bd1c16e576..20a0c60e6a18 100644
--- a/cddl/contrib/opensolaris/cmd/zhack/zhack.c
+++ b/cddl/contrib/opensolaris/cmd/zhack/zhack.c
@@ -121,16 +121,11 @@ space_delta_cb(dmu_object_type_t bonustype, void *data,
* Target is the dataset whose pool we want to open.
*/
static void
-import_pool(const char *target, boolean_t readonly)
+zhack_import(char *target, boolean_t readonly)
{
nvlist_t *config;
- nvlist_t *pools;
- int error;
- char *sepp;
- spa_t *spa;
- nvpair_t *elem;
nvlist_t *props;
- const char *name;
+ int error;
kernel_init(readonly ? FREAD : (FREAD | FWRITE));
g_zfs = libzfs_init();
@@ -139,68 +134,40 @@ import_pool(const char *target, boolean_t readonly)
dmu_objset_register_type(DMU_OST_ZFS, space_delta_cb);
g_readonly = readonly;
-
- /*
- * If we only want readonly access, it's OK if we find
- * a potentially-active (ie, imported into the kernel) pool from the
- * default cachefile.
- */
- if (readonly && spa_open(target, &spa, FTAG) == 0) {
- spa_close(spa, FTAG);
- return;
- }
-
g_importargs.unique = B_TRUE;
g_importargs.can_be_active = readonly;
g_pool = strdup(target);
- if ((sepp = strpbrk(g_pool, "/@")) != NULL)
- *sepp = '\0';
- g_importargs.poolname = g_pool;
- pools = zpool_search_import(g_zfs, &g_importargs);
-
- if (nvlist_empty(pools)) {
- if (!g_importargs.can_be_active) {
- g_importargs.can_be_active = B_TRUE;
- if (zpool_search_import(g_zfs, &g_importargs) != NULL ||
- spa_open(target, &spa, FTAG) == 0) {
- fatal(spa, FTAG, "cannot import '%s': pool is "
- "active; run " "\"zpool export %s\" "
- "first\n", g_pool, g_pool);
- }
- }
- fatal(NULL, FTAG, "cannot import '%s': no such pool "
- "available\n", g_pool);
- }
-
- elem = nvlist_next_nvpair(pools, NULL);
- name = nvpair_name(elem);
- verify(nvpair_value_nvlist(elem, &config) == 0);
+ error = zpool_tryimport(g_zfs, target, &config, &g_importargs);
+ if (error)
+ fatal(NULL, FTAG, "cannot import '%s': %s", target,
+ libzfs_error_description(g_zfs));
props = NULL;
if (readonly) {
- verify(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0);
- verify(nvlist_add_uint64(props,
+ VERIFY(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0);
+ VERIFY(nvlist_add_uint64(props,
zpool_prop_to_name(ZPOOL_PROP_READONLY), 1) == 0);
}
zfeature_checks_disable = B_TRUE;
- error = spa_import(name, config, props, ZFS_IMPORT_NORMAL);
+ error = spa_import(target, config, props,
+ (readonly ? ZFS_IMPORT_SKIP_MMP : ZFS_IMPORT_NORMAL));
zfeature_checks_disable = B_FALSE;
if (error == EEXIST)
error = 0;
if (error)
- fatal(NULL, FTAG, "can't import '%s': %s", name,
+ fatal(NULL, FTAG, "can't import '%s': %s", target,
strerror(error));
}
static void
-zhack_spa_open(const char *target, boolean_t readonly, void *tag, spa_t **spa)
+zhack_spa_open(char *target, boolean_t readonly, void *tag, spa_t **spa)
{
int err;
- import_pool(target, readonly);
+ zhack_import(target, readonly);
zfeature_checks_disable = B_TRUE;
err = spa_open(target, spa, tag);
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool.8 b/cddl/contrib/opensolaris/cmd/zpool/zpool.8
index f4c375cbb16e..f550b6ec83ed 100644
--- a/cddl/contrib/opensolaris/cmd/zpool/zpool.8
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool.8
@@ -481,6 +481,11 @@ If a pool has a shared spare that is currently being used, the pool can not be
exported since other pools may use this shared spare, which may lead to
potential data corruption.
.Pp
+Shared spares add some risk.
+If the pools are imported on different hosts, and both pools suffer a device
+failure at the same time, both could attempt to use the spare at the same time.
+This may not be detected, resulting in data corruption.
+.Pp
An in-progress spare replacement can be cancelled by detaching the hot spare.
If the original faulted device is detached, then the hot spare assumes its
place in the configuration, and is removed from the spare list of all active
@@ -806,7 +811,7 @@ to the enabled state.
See
.Xr zpool-features 7
for details on feature states.
-.It Sy listsnaps Ns = Ns Cm on No | Cm off
+.It Sy listsnapshots Ns = Ns Cm on No | Cm off
Controls whether information about snapshots associated with this pool is
output when
.Qq Nm zfs Cm list
@@ -814,6 +819,31 @@ is run without the
.Fl t
option. The default value is
.Cm off .
+This property can also be referred to by its shortened name,
+.Sy listsnaps .
+.It Sy multihost Ns = Ns Sy on No | Sy off
+Controls whether a pool activity check should be performed during
+.Nm zpool Cm import .
+When a pool is determined to be active it cannot be imported, even with the
+.Fl f
+option.
+This property is intended to be used in failover configurations
+where multiple hosts have access to a pool on shared storage.
+.sp
+Multihost provides protection on import only.
+It does not protect against an
+individual device being used in multiple pools, regardless of the type of vdev.
+See the discussion under
+.Sy zpool create.
+.sp
+When this property is on, periodic writes to storage occur to show the pool is
+in use.
+See
+.Sy vfs.zfs.multihost_interval
+sysctl.
+In order to enable this property each host must set a unique hostid.
+The default value is
+.Sy off .
.It Sy version Ns = Ns Ar version
The current on-disk version of the pool. This can be increased, but never
decreased. The preferred method of updating pools is with the
@@ -958,8 +988,22 @@ discarded transactions is irretrievably lost.
Used in combination with the
.Fl F
flag. Check whether discarding transactions would make the pool openable, but
+<<<<<<<
do not actually discard any transactions.
.El
+|||||||
+If no arguments are specified, all device errors within the pool are cleared.
+If one or more devices is specified, only those errors associated with the
+specified device or devices are cleared.
+=======
+If no arguments are specified, all device errors within the pool are cleared.
+If one or more devices is specified, only those errors associated with the
+specified device or devices are cleared.
+If multihost is enabled, and the pool has been suspended, this will not
+resume I/O.
+While the pool was suspended, it may have been imported on
+another host, and resuming I/O could result in pool damage.
+>>>>>>>
.It Xo
.Nm
.Cm create
@@ -984,7 +1028,37 @@ specification is described in the
.Qq Sx Virtual Devices
section.
.Pp
+<<<<<<<
+The command verifies that each device specified is accessible and not currently
+|||||||
The command verifies that each device specified is accessible and not currently
+in use by another subsystem.
+There are some uses, such as being currently mounted, or specified as the
+dedicated dump device, that prevents a device from ever being used by ZFS.
+Other uses, such as having a preexisting UFS file system, can be overridden with
+=======
+The command attempts to verify that each device specified is accessible and not
+currently in use by another subsystem.
+However this check is not robust enough
+to detect simultaneous attempts to use a new device in different pools, even if
+.Sy multihost
+is
+.Sy enabled.
+The
+administrator must ensure that simultaneous invocations of any combination of
+.Sy zpool replace ,
+.Sy zpool create ,
+.Sy zpool add ,
+or
+.Sy zpool labelclear ,
+do not refer to the same device.
+Using the same device in two pools will
+result in pool corruption.
+.sp
+There are some uses, such as being currently mounted, or specified as the
+dedicated dump device, that prevents a device from ever being used by ZFS.
+Other uses, such as having a preexisting UFS file system, can be overridden with
+>>>>>>>
in use by another subsystem. There are some uses, such as being currently
mounted, or specified as the dedicated dump device, that prevents a device from
ever being used by
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
index d3f179c5cb16..d07d18247e96 100644
--- a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
@@ -53,6 +53,7 @@
#include <zfs_prop.h>
#include <sys/fs/zfs.h>
#include <sys/stat.h>
+#include <sys/debug.h>
#include <libzfs.h>
@@ -1635,6 +1636,10 @@ print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
(void) printf(gettext("split into new pool"));
break;
+ case VDEV_AUX_ACTIVE:
+ (void) printf(gettext("currently in use"));
+ break;
+
case VDEV_AUX_CHILDREN_OFFLINE:
(void) printf(gettext("all children offline"));
break;
@@ -1769,6 +1774,10 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
(void) printf(gettext("too many errors"));
break;
+ case VDEV_AUX_ACTIVE:
+ (void) printf(gettext("currently in use"));
+ break;
+
case VDEV_AUX_CHILDREN_OFFLINE:
(void) printf(gettext("all children offline"));
break;
@@ -1866,8 +1875,10 @@ show_import(nvlist_t *config)
vdev_stat_t *vs;
char *name;
uint64_t guid;
+ uint64_t hostid = 0;
char *msgid;
- nvlist_t *nvroot;
+ char *hostname = "unknown";
+ nvlist_t *nvroot, *nvinfo;
int reason;
const char *health;
uint_t vsc;
@@ -1954,6 +1965,17 @@ show_import(nvlist_t *config)
zpool_print_unsup_feat(config);
break;
+ case ZPOOL_STATUS_HOSTID_ACTIVE:
+ (void) printf(gettext(" status: The pool is currently "
+ "imported by another system.\n"));
+ break;
+
+ case ZPOOL_STATUS_HOSTID_REQUIRED:
+ (void) printf(gettext(" status: The pool has the "
+ "multihost property on. It cannot\n\tbe safely imported "
+ "when the system hostid is not set.\n"));
+ break;
+
case ZPOOL_STATUS_HOSTID_MISMATCH:
(void) printf(gettext(" status: The pool was last accessed by "
"another system.\n"));
@@ -2040,6 +2062,27 @@ show_import(nvlist_t *config)
"imported. Attach the missing\n\tdevices and try "
"again.\n"));
break;
+ case ZPOOL_STATUS_HOSTID_ACTIVE:
+ VERIFY0(nvlist_lookup_nvlist(config,
+ ZPOOL_CONFIG_LOAD_INFO, &nvinfo));
+
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTNAME))
+ hostname = fnvlist_lookup_string(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTNAME);
+
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTID))
+ hostid = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTID);
+
+ (void) printf(gettext(" action: The pool must be "
+ "exported from %s (hostid=%lx)\n\tbefore it "
+ "can be safely imported.\n"), hostname,
+ (unsigned long) hostid);
+ break;
+ case ZPOOL_STATUS_HOSTID_REQUIRED:
+ (void) printf(gettext(" action: Check the SMF "
+ "svc:/system/hostid service.\n"));
+ break;
default:
(void) printf(gettext(" action: The pool cannot be "
"imported due to damaged devices or data.\n"));
@@ -2087,6 +2130,31 @@ show_import(nvlist_t *config)
}
}
+static boolean_t
+zfs_force_import_required(nvlist_t *config)
+{
+ uint64_t state;
+ uint64_t hostid = 0;
+ nvlist_t *nvinfo;
+
+ state = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE);
+ (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
+
+ if (state != POOL_STATE_EXPORTED && hostid != get_system_hostid())
+ return (B_TRUE);
+
+ nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_STATE)) {
+ mmp_state_t mmp_state = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_STATE);
+
+ if (mmp_state != MMP_STATE_INACTIVE)
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
/*
* Perform the import for the given configuration. This passes the heavy
* lifting off to zpool_import_props(), and then mounts the datasets contained
@@ -2098,53 +2166,73 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
{
zpool_handle_t *zhp;
char *name;
- uint64_t state;
uint64_t version;
- verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
- &name) == 0);
+ name = fnvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME);
+ version = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION);
- verify(nvlist_lookup_uint64(config,
- ZPOOL_CONFIG_POOL_STATE, &state) == 0);
- verify(nvlist_lookup_uint64(config,
- ZPOOL_CONFIG_VERSION, &version) == 0);
if (!SPA_VERSION_IS_SUPPORTED(version)) {
(void) fprintf(stderr, gettext("cannot import '%s': pool "
"is formatted using an unsupported ZFS version\n"), name);
return (1);
- } else if (state != POOL_STATE_EXPORTED &&
+ } else if (zfs_force_import_required(config) &&
!(flags & ZFS_IMPORT_ANY_HOST)) {
- uint64_t hostid;
-
- if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
- &hostid) == 0) {
- if ((unsigned long)hostid != gethostid()) {
- char *hostname;
- uint64_t timestamp;
- time_t t;
-
- verify(nvlist_lookup_string(config,
- ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
- verify(nvlist_lookup_uint64(config,
- ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
- t = timestamp;
- (void) fprintf(stderr, gettext("cannot import "
- "'%s': pool may be in use from other "
- "system, it was last accessed by %s "
- "(hostid: 0x%lx) on %s"), name, hostname,
- (unsigned long)hostid,
- asctime(localtime(&t)));
- (void) fprintf(stderr, gettext("use '-f' to "
- "import anyway\n"));
- return (1);
- }
+ mmp_state_t mmp_state = MMP_STATE_INACTIVE;
+ nvlist_t *nvinfo;
+
+ nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_STATE))
+ mmp_state = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_STATE);
+
+ if (mmp_state == MMP_STATE_ACTIVE) {
+ char *hostname = "<unknown>";
+ uint64_t hostid = 0;
+
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTNAME))
+ hostname = fnvlist_lookup_string(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTNAME);
+
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTID))
+ hostid = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTID);
+
+ (void) fprintf(stderr, gettext("cannot import '%s': "
+ "pool is imported on %s (hostid: "
+ "0x%lx)\nExport the pool on the other system, "
+ "then run 'zpool import'.\n"),
+ name, hostname, (unsigned long) hostid);
+ } else if (mmp_state == MMP_STATE_NO_HOSTID) {
+ (void) fprintf(stderr, gettext("Cannot import '%s': "
+ "pool has the multihost property on and the\n"
+ "system's hostid is not set.\n"), name);
} else {
+ char *hostname = "<unknown>";
+ uint64_t timestamp = 0;
+ uint64_t hostid = 0;
+
+ if (nvlist_exists(config, ZPOOL_CONFIG_HOSTNAME))
+ hostname = fnvlist_lookup_string(config,
+ ZPOOL_CONFIG_HOSTNAME);
+
+ if (nvlist_exists(config, ZPOOL_CONFIG_TIMESTAMP))
+ timestamp = fnvlist_lookup_uint64(config,
+ ZPOOL_CONFIG_TIMESTAMP);
+
+ if (nvlist_exists(config, ZPOOL_CONFIG_HOSTID))
+ hostid = fnvlist_lookup_uint64(config,
+ ZPOOL_CONFIG_HOSTID);
+
(void) fprintf(stderr, gettext("cannot import '%s': "
- "pool may be in use from other system\n"), name);
- (void) fprintf(stderr, gettext("use '-f' to import "
- "anyway\n"));
- return (1);
+ "pool was previously in use from another system.\n"
+ "Last accessed by %s (hostid=%lx) at %s"
+ "The pool can be imported, use 'zpool import -f' "
+ "to import the pool.\n"), name, hostname,
+ (unsigned long)hostid, ctime((time_t *)&timestamp));
+
}
+
+ return (1);
}
if (zpool_import_props(g_zfs, config, newname, props, flags) != 0)
@@ -5108,6 +5196,15 @@ status_callback(zpool_handle_t *zhp, void *data)
"to be recovered.\n"));
break;
+ case ZPOOL_STATUS_IO_FAILURE_MMP:
+ (void) printf(gettext("status: The pool is suspended because "
+ "multihost writes failed or were delayed;\n\tanother "
+ "system could import the pool undetected.\n"));
+ (void) printf(gettext("action: Make sure the pool's devices "
+ "are connected, then reboot your system and\n\timport the "
+ "pool.\n"));
+ break;
+
case ZPOOL_STATUS_IO_FAILURE_WAIT:
case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
(void) printf(gettext("status: One or more devices are "
diff --git a/cddl/contrib/opensolaris/cmd/ztest/ztest.c b/cddl/contrib/opensolaris/cmd/ztest/ztest.c
index 25fc77f75b9a..130f590595cc 100644
--- a/cddl/contrib/opensolaris/cmd/ztest/ztest.c
+++ b/cddl/contrib/opensolaris/cmd/ztest/ztest.c
@@ -128,6 +128,7 @@
#include <errno.h>
#include <sys/fs/zfs.h>
#include <libnvpair.h>
+#include <libzfs.h>
#include <libcmdutils.h>
static int ztest_fd_data = -1;
@@ -166,6 +167,7 @@ typedef struct ztest_shared_opts {
uint64_t zo_time;
uint64_t zo_maxloops;
uint64_t zo_metaslab_force_ganging;
+ int zo_mmp_test;
} ztest_shared_opts_t;
static const ztest_shared_opts_t ztest_opts_defaults = {
@@ -184,6 +186,7 @@ static const ztest_shared_opts_t ztest_opts_defaults = {
.zo_passtime = 60, /* 60 seconds */
.zo_killrate = 70, /* 70% kill rate */
.zo_verbose = 0,
+ .zo_mmp_test = 0,
.zo_init = 1,
.zo_time = 300, /* 5 minutes */
.zo_maxloops = 50, /* max loops during spa_freeze() */
@@ -343,6 +346,7 @@ ztest_func_t ztest_spa_create_destroy;
ztest_func_t ztest_fault_inject;
ztest_func_t ztest_ddt_repair;
ztest_func_t ztest_dmu_snapshot_hold;
+ztest_func_t ztest_mmp_enable_disable;
ztest_func_t ztest_scrub;
ztest_func_t ztest_dsl_dataset_promote_busy;
ztest_func_t ztest_vdev_attach_detach;
@@ -388,6 +392,7 @@ ztest_info_t ztest_info[] = {
{ ztest_fault_inject, 1, &zopt_incessant },
{ ztest_ddt_repair, 1, &zopt_sometimes },
{ ztest_dmu_snapshot_hold, 1, &zopt_sometimes },
+ { ztest_mmp_enable_disable, 1, &zopt_sometimes },
{ ztest_reguid, 1, &zopt_rarely },
{ ztest_scrub, 1, &zopt_often },
{ ztest_spa_upgrade, 1, &zopt_rarely },
@@ -601,6 +606,7 @@ usage(boolean_t requested)
"\t[-k kill_percentage (default: %llu%%)]\n"
"\t[-p pool_name (default: %s)]\n"
"\t[-f dir (default: %s)] file directory for vdev files\n"
+ "\t[-M] Multi-host simulate pool imported on remote host\n"
"\t[-V] verbose (use multiple times for ever more blather)\n"
"\t[-E] use existing pool instead of creating new one\n"
"\t[-T time (default: %llu sec)] total run time\n"
@@ -644,7 +650,7 @@ process_options(int argc, char **argv)
bcopy(&ztest_opts_defaults, zo, sizeof (*zo));
while ((opt = getopt(argc, argv,
- "v:s:a:m:r:R:d:t:g:i:k:p:f:VET:P:hF:B:o:")) != EOF) {
+ "v:s:a:m:r:R:d:t:g:i:k:p:f:MVET:P:hF:B:o:")) != EOF) {
value = 0;
switch (opt) {
case 'v':
@@ -713,6 +719,9 @@ process_options(int argc, char **argv)
sizeof (zo->zo_dir));
}
break;
+ case 'M':
+ zo->zo_mmp_test = 1;
+ break;
case 'V':
zo->zo_verbose++;
break;
@@ -2480,6 +2489,9 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
spa_t *spa;
nvlist_t *nvroot;
+ if (zo->zo_mmp_test)
+ return;
+
/*
* Attempt to create using a bad file.
*/
@@ -2511,6 +2523,56 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
rw_exit(&ztest_name_lock);
}
+/*
+ * Start and then stop the MMP threads to ensure the startup and shutdown code
+ * works properly. Actual protection and property-related code tested via ZTS.
+ */
+/* ARGSUSED */
+void
+ztest_mmp_enable_disable(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_shared_opts_t *zo = &ztest_opts;
+ spa_t *spa = ztest_spa;
+
+ if (zo->zo_mmp_test)
+ return;
+
+ /*
+ * Since enabling MMP involves setting a property, it could not be done
+ * while the pool is suspended.
+ */
+ if (spa_suspended(spa))
+ return;
+
+ spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
+ mutex_enter(&spa->spa_props_lock);
+
+ zfs_multihost_fail_intervals = 0;
+
+ if (!spa_multihost(spa)) {
+ spa->spa_multihost = B_TRUE;
+ mmp_thread_start(spa);
+ }
+
+ mutex_exit(&spa->spa_props_lock);
+ spa_config_exit(spa, SCL_CONFIG, FTAG);
+
+ txg_wait_synced(spa_get_dsl(spa), 0);
+ mmp_signal_all_threads();
+ txg_wait_synced(spa_get_dsl(spa), 0);
+
+ spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
+ mutex_enter(&spa->spa_props_lock);
+
+ if (spa_multihost(spa)) {
+ mmp_thread_stop(spa);
+ spa->spa_multihost = B_FALSE;
+ }
+
+ mutex_exit(&spa->spa_props_lock);
+ spa_config_exit(spa, SCL_CONFIG, FTAG);
+}
+
/* ARGSUSED */
void
ztest_spa_upgrade(ztest_ds_t *zd, uint64_t id)
@@ -2521,6 +2583,9 @@ ztest_spa_upgrade(ztest_ds_t *zd, uint64_t id)
nvlist_t *nvroot, *props;
char *name;
+ if (ztest_opts.zo_mmp_test)
+ return;
+
mutex_enter(&ztest_vdev_lock);
name = kmem_asprintf("%s_upgrade", ztest_opts.zo_pool);
@@ -2689,6 +2754,9 @@ ztest_vdev_add_remove(ztest_ds_t *zd, uint64_t id)
nvlist_t *nvroot;
int error;
+ if (ztest_opts.zo_mmp_test)
+ return;
+
mutex_enter(&ztest_vdev_lock);
leaves = MAX(zs->zs_mirrors + zs->zs_splits, 1) * ztest_opts.zo_raidz;
@@ -2771,6 +2839,9 @@ ztest_vdev_aux_add_remove(ztest_ds_t *zd, uint64_t id)
uint64_t guid = 0;
int error;
+ if (ztest_opts.zo_mmp_test)
+ return;
+
if (ztest_random(2) == 0) {
sav = &spa->spa_spares;
aux = ZPOOL_CONFIG_SPARES;
@@ -2866,6 +2937,9 @@ ztest_split_pool(ztest_ds_t *zd, uint64_t id)
uint_t c, children, schildren = 0, lastlogid = 0;
int error = 0;
+ if (ztest_opts.zo_mmp_test)
+ return;
+
mutex_enter(&ztest_vdev_lock);
/* ensure we have a useable config; mirrors of raidz aren't supported */
@@ -2972,6 +3046,9 @@ ztest_vdev_attach_detach(ztest_ds_t *zd, uint64_t id)
int oldvd_is_log;
int error, expected_error;
+ if (ztest_opts.zo_mmp_test)
+ return;
+
mutex_enter(&ztest_vdev_lock);
leaves = MAX(zs->zs_mirrors, 1) * ztest_opts.zo_raidz;
@@ -5564,6 +5641,9 @@ ztest_reguid(ztest_ds_t *zd, uint64_t id)
uint64_t orig, load;
int error;
+ if (ztest_opts.zo_mmp_test)
+ return;
+
orig = spa_guid(spa);
load = spa_load_guid(spa);
@@ -6249,7 +6329,7 @@ ztest_run(ztest_shared_t *zs)
* Verify that we can export the pool and reimport it under a
* different name.
*/
- if (ztest_random(2) == 0) {
+ if ((ztest_random(2) == 0) && !ztest_opts.zo_mmp_test) {
char name[ZFS_MAX_DATASET_NAME_LEN];
(void) snprintf(name, sizeof (name), "%s_import",
ztest_opts.zo_pool);
@@ -6398,6 +6478,56 @@ make_random_props()
}
/*
+ * Import a storage pool with the given name.
+ */
+static void
+ztest_import(ztest_shared_t *zs)
+{
+ libzfs_handle_t *hdl;
+ importargs_t args = { 0 };
+ spa_t *spa;
+ nvlist_t *cfg = NULL;
+ int nsearch = 1;
+ char *searchdirs[nsearch];
+ char *name = ztest_opts.zo_pool;
+ int flags = ZFS_IMPORT_MISSING_LOG;
+ int error;
+
+ mutex_init(&ztest_vdev_lock, NULL, MUTEX_DEFAULT, NULL);
+ rw_init(&ztest_name_lock, NULL, USYNC_THREAD, NULL);
+
+ kernel_init(FREAD | FWRITE);
+ hdl = libzfs_init();
+
+ searchdirs[0] = ztest_opts.zo_dir;
+ args.paths = nsearch;
+ args.path = searchdirs;
+ args.can_be_active = B_FALSE;
+
+ error = zpool_tryimport(hdl, name, &cfg, &args);
+ if (error)
+ (void) fatal(0, "No pools found\n");
+
+ VERIFY0(spa_import(name, cfg, NULL, flags));
+ VERIFY0(spa_open(name, &spa, FTAG));
+ zs->zs_metaslab_sz =
+ 1ULL << spa->spa_root_vdev->vdev_child[0]->vdev_ms_shift;
+ spa_close(spa, FTAG);
+
+ libzfs_fini(hdl);
+ kernel_fini();
+
+ if (!ztest_opts.zo_mmp_test) {
+ ztest_run_zdb(ztest_opts.zo_pool);
+ ztest_freeze();
+ ztest_run_zdb(ztest_opts.zo_pool);
+ }
+
+ rw_destroy(&ztest_name_lock);
+ mutex_destroy(&ztest_vdev_lock);
+}
+
+/*
* Create a storage pool with the given name and initial vdev size.
* Then test spa_freeze() functionality.
*/
@@ -6441,11 +6571,11 @@ ztest_init(ztest_shared_t *zs)
kernel_fini();
- ztest_run_zdb(ztest_opts.zo_pool);
-
- ztest_freeze();
-
- ztest_run_zdb(ztest_opts.zo_pool);
+ if (!ztest_opts.zo_mmp_test) {
+ ztest_run_zdb(ztest_opts.zo_pool);
+ ztest_freeze();
+ ztest_run_zdb(ztest_opts.zo_pool);
+ }
rw_destroy(&ztest_name_lock);
mutex_destroy(&ztest_vdev_lock);
@@ -6610,13 +6740,19 @@ ztest_run_init(void)
{
ztest_shared_t *zs = ztest_shared;
- ASSERT(ztest_opts.zo_init != 0);
-
/*
* Blow away any existing copy of zpool.cache
*/
(void) remove(spa_config_path);
+ if (ztest_opts.zo_init == 0) {
+ if (ztest_opts.zo_verbose >= 1)
+ (void) printf("Importing pool %s\n",
+ ztest_opts.zo_pool);
+ ztest_import(zs);
+ return;
+ }
+
/*
* Create and initialize our storage pool.
*/
@@ -6823,7 +6959,8 @@ main(int argc, char **argv)
(void) printf("\n");
}
- ztest_run_zdb(ztest_opts.zo_pool);
+ if (!ztest_opts.zo_mmp_test)
+ ztest_run_zdb(ztest_opts.zo_pool);
}
if (ztest_opts.zo_verbose >= 1) {
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
index aeae6e3822a3..9e022cf896a0 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
@@ -23,7 +23,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 Pawel Jakub Dawidek. All rights reserved.
* Copyright (c) 2011, 2017 by Delphix. All rights reserved.
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
* Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
@@ -131,6 +131,7 @@ typedef enum zfs_error {
EZFS_DIFFDATA, /* bad zfs diff data */
EZFS_POOLREADONLY, /* pool is in read-only mode */
EZFS_SCRUB_PAUSED, /* scrub currently paused */
+ EZFS_ACTIVE_POOL, /* pool is imported on a different system */
EZFS_NO_PENDING, /* cannot cancel, no operation is pending */
EZFS_CHECKPOINT_EXISTS, /* checkpoint exists */
EZFS_DISCARDING_CHECKPOINT, /* currently discarding a checkpoint */
@@ -315,6 +316,8 @@ typedef enum {
/*
* The following correspond to faults as defined in the (fault.fs.zfs.*)
* event namespace. Each is associated with a corresponding message ID.
+ * This must be kept in sync with the zfs_msgid_table in
+ * lib/libzfs/libzfs_status.c.
*/
ZPOOL_STATUS_CORRUPT_CACHE, /* corrupt /kernel/drv/zpool.cache */
ZPOOL_STATUS_MISSING_DEV_R, /* missing device with replicas */
@@ -327,8 +330,11 @@ typedef enum {
ZPOOL_STATUS_FAILING_DEV, /* device experiencing errors */
ZPOOL_STATUS_VERSION_NEWER, /* newer on-disk version */
ZPOOL_STATUS_HOSTID_MISMATCH, /* last accessed by another system */
+ ZPOOL_STATUS_HOSTID_ACTIVE, /* currently active on another system */
+ ZPOOL_STATUS_HOSTID_REQUIRED, /* multihost=on and hostid=0 */
ZPOOL_STATUS_IO_FAILURE_WAIT, /* failed I/O, failmode 'wait' */
ZPOOL_STATUS_IO_FAILURE_CONTINUE, /* failed I/O, failmode 'continue' */
+ ZPOOL_STATUS_IO_FAILURE_MMP, /* failed MMP, failmode not 'panic' */
ZPOOL_STATUS_BAD_LOG, /* cannot read log chain(s) */
/*
@@ -407,6 +413,8 @@ typedef struct importargs {
} importargs_t;
extern nvlist_t *zpool_search_import(libzfs_handle_t *, importargs_t *);
+extern int zpool_tryimport(libzfs_handle_t *hdl, char *target,
+ nvlist_t **configp, importargs_t *args);
/* legacy pool search routines */
extern nvlist_t *zpool_find_import(libzfs_handle_t *, int, char **);
@@ -745,6 +753,7 @@ extern boolean_t zfs_dataset_exists(libzfs_handle_t *, const char *,
zfs_type_t);
extern int zfs_spa_version(zfs_handle_t *, int *);
extern boolean_t zfs_bookmark_exists(const char *path);
+extern ulong_t get_system_hostid(void);
/*
* Mount support functions.
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
index b6a17c2c85c1..cdf20b8543fd 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
@@ -440,6 +440,8 @@ make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc)
zhp->zfs_head_type = ZFS_TYPE_VOLUME;
else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
+ else if (zhp->zfs_dmustats.dds_type == DMU_OST_OTHER)
+ return (-1);
else
abort();
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
index 0f66ac0aeadb..a0338afadb8f 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
@@ -137,7 +137,7 @@ typedef enum {
SHARED_SMB = 0x4
} zfs_share_type_t;
-#define CONFIG_BUF_MINSIZE 65536
+#define CONFIG_BUF_MINSIZE 262144
int zfs_error(libzfs_handle_t *, int, const char *);
int zfs_error_fmt(libzfs_handle_t *, int, const char *, ...);
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
index 664f6b42df9e..a982e545a0b8 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_import.c
@@ -1599,16 +1599,87 @@ name_or_guid_exists(zpool_handle_t *zhp, void *data)
nvlist_t *
zpool_search_import(libzfs_handle_t *hdl, importargs_t *import)
{
+ nvlist_t *pools = NULL;
+
verify(import->poolname == NULL || import->guid == 0);
if (import->unique)
import->exists = zpool_iter(hdl, name_or_guid_exists, import);
if (import->cachefile != NULL)
- return (zpool_find_import_cached(hdl, import->cachefile,
- import->poolname, import->guid));
+ pools = zpool_find_import_cached(hdl, import->cachefile,
+ import->poolname, import->guid);
+ else
+ pools = zpool_find_import_impl(hdl, import);
+
+ return (pools);
+}
+
+static boolean_t
+pool_match(nvlist_t *cfg, char *tgt)
+{
+ uint64_t v, guid = strtoull(tgt, NULL, 0);
+ char *s;
+
+ if (guid != 0) {
+ if (nvlist_lookup_uint64(cfg, ZPOOL_CONFIG_POOL_GUID, &v) == 0)
+ return (v == guid);
+ } else {
+ if (nvlist_lookup_string(cfg, ZPOOL_CONFIG_POOL_NAME, &s) == 0)
+ return (strcmp(s, tgt) == 0);
+ }
+ return (B_FALSE);
+}
+
+int
+zpool_tryimport(libzfs_handle_t *hdl, char *target, nvlist_t **configp,
+ importargs_t *args)
+{
+ nvlist_t *pools;
+ nvlist_t *match = NULL;
+ nvlist_t *config = NULL;
+ char *sepp = NULL;
+ int count = 0;
+ char *targetdup = strdup(target);
+
+ *configp = NULL;
- return (zpool_find_import_impl(hdl, import));
+ if ((sepp = strpbrk(targetdup, "/@")) != NULL) {
+ *sepp = '\0';
+ }
+
+ pools = zpool_search_import(hdl, args);
+
+ if (pools != NULL) {
+ nvpair_t *elem = NULL;
+ while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
+ VERIFY0(nvpair_value_nvlist(elem, &config));
+ if (pool_match(config, targetdup)) {
+ count++;
+ if (match != NULL) {
+ /* multiple matches found */
+ continue;
+ } else {
+ match = config;
+ }
+ }
+ }
+ }
+
+ if (count == 0) {
+ free(targetdup);
+ return (ENOENT);
+ }
+
+ if (count > 1) {
+ free(targetdup);
+ return (EINVAL);
+ }
+
+ *configp = match;
+ free(targetdup);
+
+ return (0);
}
boolean_t
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
index 153fda241188..3800001992b6 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
@@ -665,6 +665,15 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
}
break;
+ case ZPOOL_PROP_MULTIHOST:
+ if (get_system_hostid() == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "requires a non-zero system hostid"));
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ break;
+
default:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"property '%s'(%d) not defined"), propname, prop);
@@ -1802,6 +1811,7 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
if (error) {
char desc[1024];
+ char aux[256];
/*
* Dry-run failed, but we print out what success
@@ -1847,6 +1857,46 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
(void) zfs_error(hdl, EZFS_BADVERSION, desc);
break;
+ case EREMOTEIO:
+ if (nv != NULL && nvlist_lookup_nvlist(nv,
+ ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0) {
+ char *hostname = "<unknown>";
+ uint64_t hostid = 0;
+ mmp_state_t mmp_state;
+
+ mmp_state = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_STATE);
+
+ if (nvlist_exists(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTNAME))
+ hostname = fnvlist_lookup_string(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTNAME);
+
+ if (nvlist_exists(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTID))
+ hostid = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTID);
+
+ if (mmp_state == MMP_STATE_ACTIVE) {
+ (void) snprintf(aux, sizeof (aux),
+ dgettext(TEXT_DOMAIN, "pool is imp"
+ "orted on host '%s' (hostid=%lx).\n"
+ "Export the pool on the other "
+ "system, then run 'zpool import'."),
+ hostname, (unsigned long) hostid);
+ } else if (mmp_state == MMP_STATE_NO_HOSTID) {
+ (void) snprintf(aux, sizeof (aux),
+ dgettext(TEXT_DOMAIN, "pool has "
+ "the multihost property on and "
+ "the\nsystem's hostid is not "
+ "set.\n"));
+ }
+
+ (void) zfs_error_aux(hdl, aux);
+ }
+ (void) zfs_error(hdl, EZFS_ACTIVE_POOL, desc);
+ break;
+
case EINVAL:
(void) zfs_error(hdl, EZFS_INVALCONFIG, desc);
break;
@@ -2392,7 +2442,7 @@ zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
}
static int
-vdev_online(nvlist_t *nv)
+vdev_is_online(nvlist_t *nv)
{
uint64_t ival;
@@ -2460,7 +2510,7 @@ vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size,
return (EZFS_INVALCONFIG);
}
- if (vdev_online(nv)) {
+ if (vdev_is_online(nv)) {
if ((ret = vdev_get_one_physpath(nv, physpath,
phypath_size, rsz)) != 0)
return (ret);
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c
index 8bcd126e0b08..d32662022cf5 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c
@@ -53,20 +53,36 @@
* of this table, and hence have no associated message ID.
*/
static char *zfs_msgid_table[] = {
- "ZFS-8000-14",
- "ZFS-8000-2Q",
- "ZFS-8000-3C",
- "ZFS-8000-4J",
- "ZFS-8000-5E",
- "ZFS-8000-6X",
- "ZFS-8000-72",
- "ZFS-8000-8A",
- "ZFS-8000-9P",
- "ZFS-8000-A5",
- "ZFS-8000-EY",
- "ZFS-8000-HC",
- "ZFS-8000-JQ",
- "ZFS-8000-K4",
+ "ZFS-8000-14", /* ZPOOL_STATUS_CORRUPT_CACHE */
+ "ZFS-8000-2Q", /* ZPOOL_STATUS_MISSING_DEV_R */
+ "ZFS-8000-3C", /* ZPOOL_STATUS_MISSING_DEV_NR */
+ "ZFS-8000-4J", /* ZPOOL_STATUS_CORRUPT_LABEL_R */
+ "ZFS-8000-5E", /* ZPOOL_STATUS_CORRUPT_LABEL_NR */
+ "ZFS-8000-6X", /* ZPOOL_STATUS_BAD_GUID_SUM */
+ "ZFS-8000-72", /* ZPOOL_STATUS_CORRUPT_POOL */
+ "ZFS-8000-8A", /* ZPOOL_STATUS_CORRUPT_DATA */
+ "ZFS-8000-9P", /* ZPOOL_STATUS_FAILING_DEV */
+ "ZFS-8000-A5", /* ZPOOL_STATUS_VERSION_NEWER */
+ "ZFS-8000-EY", /* ZPOOL_STATUS_HOSTID_MISMATCH */
+ "ZFS-8000-EY", /* ZPOOL_STATUS_HOSTID_ACTIVE */
+ "ZFS-8000-EY", /* ZPOOL_STATUS_HOSTID_REQUIRED */
+ "ZFS-8000-HC", /* ZPOOL_STATUS_IO_FAILURE_WAIT */
+ "ZFS-8000-JQ", /* ZPOOL_STATUS_IO_FAILURE_CONTINUE */
+ "ZFS-8000-MM", /* ZPOOL_STATUS_IO_FAILURE_MMP */
+ "ZFS-8000-K4", /* ZPOOL_STATUS_BAD_LOG */
+ /*
+ * The following results have no message ID.
+ * ZPOOL_STATUS_UNSUP_FEAT_READ
+ * ZPOOL_STATUS_UNSUP_FEAT_WRITE
+ * ZPOOL_STATUS_FAULTED_DEV_R
+ * ZPOOL_STATUS_FAULTED_DEV_NR
+ * ZPOOL_STATUS_VERSION_OLDER
+ * ZPOOL_STATUS_FEAT_DISABLED
+ * ZPOOL_STATUS_RESILVERING
+ * ZPOOL_STATUS_OFFLINE_DEV
+ * ZPOOL_STATUS_REMOVED_DEV
+ * ZPOOL_STATUS_OK
+ */
};
#define NMSGID (sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
@@ -204,6 +220,7 @@ check_status(nvlist_t *config, boolean_t isimport)
uint64_t stateval;
uint64_t suspended;
uint64_t hostid = 0;
+ unsigned long system_hostid = get_system_hostid();
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
&version) == 0);
@@ -224,10 +241,30 @@ check_status(nvlist_t *config, boolean_t isimport)
return (ZPOOL_STATUS_RESILVERING);
/*
+ * The multihost property is set and the pool may be active.
+ */
+ if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+ vs->vs_aux == VDEV_AUX_ACTIVE) {
+ mmp_state_t mmp_state;
+ nvlist_t *nvinfo;
+
+ nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
+ mmp_state = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_STATE);
+
+ if (mmp_state == MMP_STATE_ACTIVE)
+ return (ZPOOL_STATUS_HOSTID_ACTIVE);
+ else if (mmp_state == MMP_STATE_NO_HOSTID)
+ return (ZPOOL_STATUS_HOSTID_REQUIRED);
+ else
+ return (ZPOOL_STATUS_HOSTID_MISMATCH);
+ }
+
+ /*
* Pool last accessed by another system.
*/
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
- if (hostid != 0 && (unsigned long)hostid != gethostid() &&
+ if (hostid != 0 && (unsigned long)hostid != system_hostid &&
stateval == POOL_STATE_ACTIVE)
return (ZPOOL_STATUS_HOSTID_MISMATCH);
@@ -260,10 +297,16 @@ check_status(nvlist_t *config, boolean_t isimport)
return (ZPOOL_STATUS_BAD_GUID_SUM);
/*
- * Check whether the pool has suspended due to failed I/O.
+ * Check whether the pool has suspended.
*/
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SUSPENDED,
&suspended) == 0) {
+ uint64_t reason;
+
+ if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SUSPENDED_REASON,
+ &reason) == 0 && reason == ZIO_SUSPEND_MMP)
+ return (ZPOOL_STATUS_IO_FAILURE_MMP);
+
if (suspended == ZIO_FAILURE_MODE_CONTINUE)
return (ZPOOL_STATUS_IO_FAILURE_CONTINUE);
return (ZPOOL_STATUS_IO_FAILURE_WAIT);
@@ -358,8 +401,9 @@ check_status(nvlist_t *config, boolean_t isimport)
if (isimport) {
feat = fnvlist_lookup_nvlist(config,
ZPOOL_CONFIG_LOAD_INFO);
- feat = fnvlist_lookup_nvlist(feat,
- ZPOOL_CONFIG_ENABLED_FEAT);
+ if (nvlist_exists(feat, ZPOOL_CONFIG_ENABLED_FEAT))
+ feat = fnvlist_lookup_nvlist(feat,
+ ZPOOL_CONFIG_ENABLED_FEAT);
} else {
feat = fnvlist_lookup_nvlist(config,
ZPOOL_CONFIG_FEATURE_STATS);
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
index faf00486751c..8ba496abae33 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
* Copyright (c) 2011, 2017 by Delphix. All rights reserved.
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
* Copyright (c) 2017 Datto Inc.
@@ -56,6 +56,7 @@
#include "libzfs_impl.h"
#include "zfs_prop.h"
+#include "zfs_comutil.h"
#include "zfeature_common.h"
@@ -254,6 +255,9 @@ libzfs_error_description(libzfs_handle_t *hdl)
return (dgettext(TEXT_DOMAIN, "device removal in progress"));
case EZFS_VDEV_TOO_BIG:
return (dgettext(TEXT_DOMAIN, "device exceeds supported size"));
+ case EZFS_ACTIVE_POOL:
+ return (dgettext(TEXT_DOMAIN, "pool is imported on a "
+ "different host"));
case EZFS_TOOMANY:
return (dgettext(TEXT_DOMAIN, "argument list too long"));
case EZFS_INITIALIZING:
@@ -424,6 +428,9 @@ zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
"pool I/O is currently suspended"));
zfs_verror(hdl, EZFS_POOLUNAVAIL, fmt, ap);
break;
+ case EREMOTEIO:
+ zfs_verror(hdl, EZFS_ACTIVE_POOL, fmt, ap);
+ break;
default:
zfs_error_aux(hdl, strerror(error));
zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
@@ -512,6 +519,9 @@ zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
case ESRCH:
zfs_verror(hdl, EZFS_NO_PENDING, fmt, ap);
break;
+ case EREMOTEIO:
+ zfs_verror(hdl, EZFS_ACTIVE_POOL, fmt, ap);
+ break;
case ZFS_ERR_CHECKPOINT_EXISTS:
zfs_verror(hdl, EZFS_CHECKPOINT_EXISTS, fmt, ap);
break;
@@ -1592,3 +1602,20 @@ zprop_iter(zprop_func func, void *cb, boolean_t show_all, boolean_t ordered,
{
return (zprop_iter_common(func, cb, show_all, ordered, type));
}
+
+ulong_t
+get_system_hostid(void)
+{
+ char *env;
+
+ /*
+ * Allow the hostid to be subverted for testing.
+ */
+ env = getenv("ZFS_HOSTID");
+ if (env) {
+ ulong_t hostid = strtoull(env, NULL, 16);
+ return (hostid & 0xFFFFFFFF);
+ }
+
+ return (gethostid());
+}
diff --git a/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c b/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
index 4af6eb033e32..9b54e419705b 100644
--- a/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
+++ b/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
@@ -41,6 +41,7 @@
#include <sys/zmod.h>
#include <sys/utsname.h>
#include <sys/systeminfo.h>
+#include <libzfs.h>
/*
* Emulation of kernel services in userland.
@@ -989,8 +990,8 @@ kernel_init(int mode)
dprintf("physmem = %llu pages (%.2f GB)\n", physmem,
(double)physmem * sysconf(_SC_PAGE_SIZE) / (1ULL << 30));
- (void) snprintf(hw_serial, sizeof (hw_serial), "%lu",
- (mode & FWRITE) ? (unsigned long)gethostid() : 0);
+ (void) snprintf(hw_serial, sizeof (hw_serial), "%ld",
+ (mode & FWRITE) ? get_system_hostid() : 0);
VERIFY((random_fd = open("/dev/random", O_RDONLY)) != -1);
VERIFY((urandom_fd = open("/dev/urandom", O_RDONLY)) != -1);
diff --git a/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h b/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h
index 30d50dd8a25b..652458ea309c 100644
--- a/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h
+++ b/cddl/contrib/opensolaris/lib/libzpool/common/sys/zfs_context.h
@@ -332,8 +332,11 @@ extern void cv_destroy(kcondvar_t *cv);
extern void cv_wait(kcondvar_t *cv, kmutex_t *mp);
extern int cv_wait_sig(kcondvar_t *cv, kmutex_t *mp);
extern clock_t cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime);
+#define cv_timedwait_sig(cvp, mp, t) cv_timedwait(cvp, mp, t)
extern clock_t cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim,
hrtime_t res, int flag);
+#define cv_timedwait_sig_hires(cvp, mp, t, r, f) \
+ cv_timedwait_hires(cvp, mp, t, r, f)
extern void cv_signal(kcondvar_t *cv);
extern void cv_broadcast(kcondvar_t *cv);