summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libzfs/libzfs_import.c74
-rw-r--r--lib/libzfs/libzfs_pool.c55
-rw-r--r--lib/libzfs/libzfs_status.c27
-rw-r--r--lib/libzfs/libzfs_util.c9
-rw-r--r--lib/libzpool/Makefile.am1
5 files changed, 161 insertions, 5 deletions
diff --git a/lib/libzfs/libzfs_import.c b/lib/libzfs/libzfs_import.c
index 02264433e..f371d925b 100644
--- a/lib/libzfs/libzfs_import.c
+++ b/lib/libzfs/libzfs_import.c
@@ -2166,6 +2166,80 @@ zpool_search_import(libzfs_handle_t *hdl, importargs_t *import)
return (zpool_find_import_impl(hdl, import));
}
+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 *name = NULL, *sepp = NULL;
+ char sep = '\0';
+ int count = 0;
+ char *targetdup = strdup(target);
+
+ *configp = NULL;
+
+ if ((sepp = strpbrk(targetdup, "/@")) != NULL) {
+ sep = *sepp;
+ *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;
+ name = nvpair_name(elem);
+ }
+ }
+ }
+ }
+
+ if (count == 0) {
+ (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "no pools found"));
+ free(targetdup);
+ return (ENOENT);
+ }
+
+ if (count > 1) {
+ (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "%d pools found, use pool GUID\n"), count);
+ free(targetdup);
+ return (EINVAL);
+ }
+
+ *configp = match;
+ free(targetdup);
+
+ return (0);
+}
+
boolean_t
find_guid(nvlist_t *nv, uint64_t guid)
{
diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c
index 746e6a8cc..58d91c8f4 100644
--- a/lib/libzfs/libzfs_pool.c
+++ b/lib/libzfs/libzfs_pool.c
@@ -676,7 +676,14 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
goto error;
}
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);
@@ -1779,6 +1786,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
@@ -1824,6 +1832,47 @@ 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. "
+ "Set a unique system hostid with "
+ "the genhostid(1) command.\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;
@@ -2206,7 +2255,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;
@@ -2274,7 +2323,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/lib/libzfs/libzfs_status.c b/lib/libzfs/libzfs_status.c
index d5470f412..05a9afce8 100644
--- a/lib/libzfs/libzfs_status.c
+++ b/lib/libzfs/libzfs_status.c
@@ -64,6 +64,8 @@ static char *zfs_msgid_table[] = {
"ZFS-8000-9P",
"ZFS-8000-A5",
"ZFS-8000-EY",
+ "ZFS-8000-EY",
+ "ZFS-8000-EY",
"ZFS-8000-HC",
"ZFS-8000-JQ",
"ZFS-8000-K4",
@@ -216,6 +218,26 @@ check_status(nvlist_t *config, boolean_t isimport, zpool_errata_t *erratap)
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);
@@ -344,8 +366,9 @@ check_status(nvlist_t *config, boolean_t isimport, zpool_errata_t *erratap)
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/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c
index 30255d643..bc51a76a8 100644
--- a/lib/libzfs/libzfs_util.c
+++ b/lib/libzfs/libzfs_util.c
@@ -261,6 +261,9 @@ libzfs_error_description(libzfs_handle_t *hdl)
return (dgettext(TEXT_DOMAIN, "invalid diff data"));
case EZFS_POOLREADONLY:
return (dgettext(TEXT_DOMAIN, "pool is read-only"));
+ case EZFS_ACTIVE_POOL:
+ return (dgettext(TEXT_DOMAIN, "pool is imported on a "
+ "different host"));
case EZFS_UNKNOWN:
return (dgettext(TEXT_DOMAIN, "unknown error"));
default:
@@ -423,6 +426,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);
@@ -511,6 +517,9 @@ zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
"block size out of range or does not match"));
zfs_verror(hdl, EZFS_BADPROP, fmt, ap);
break;
+ case EREMOTEIO:
+ zfs_verror(hdl, EZFS_ACTIVE_POOL, fmt, ap);
+ break;
default:
zfs_error_aux(hdl, strerror(error));
diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am
index 1e95f8064..a8c72c98d 100644
--- a/lib/libzpool/Makefile.am
+++ b/lib/libzpool/Makefile.am
@@ -71,6 +71,7 @@ KERNEL_C = \
lzjb.c \
lz4.c \
metaslab.c \
+ mmp.c \
multilist.c \
pathname.c \
range_tree.c \