aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/zpool/zpool_main.c23
-rw-r--r--module/zfs/spa.c18
-rwxr-xr-xtests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_hostid_changed_cachefile_unclean_export.ksh20
3 files changed, 49 insertions, 12 deletions
diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c
index d64fdfa5b..5507f9d3f 100644
--- a/cmd/zpool/zpool_main.c
+++ b/cmd/zpool/zpool_main.c
@@ -3122,12 +3122,21 @@ zfs_force_import_required(nvlist_t *config)
nvlist_t *nvinfo;
state = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE);
- (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
+ nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
+
+ /*
+ * The hostid on LOAD_INFO comes from the MOS label via
+ * spa_tryimport(). If its not there then we're likely talking to an
+ * older kernel, so use the top one, which will be from the label
+ * discovered in zpool_find_import(), or if a cachefile is in use, the
+ * local hostid.
+ */
+ if (nvlist_lookup_uint64(nvinfo, ZPOOL_CONFIG_HOSTID, &hostid) != 0)
+ 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);
@@ -3198,7 +3207,10 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
time_t timestamp = 0;
uint64_t hostid = 0;
- if (nvlist_exists(config, ZPOOL_CONFIG_HOSTNAME))
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_HOSTNAME))
+ hostname = fnvlist_lookup_string(nvinfo,
+ ZPOOL_CONFIG_HOSTNAME);
+ else if (nvlist_exists(config, ZPOOL_CONFIG_HOSTNAME))
hostname = fnvlist_lookup_string(config,
ZPOOL_CONFIG_HOSTNAME);
@@ -3206,7 +3218,10 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
timestamp = fnvlist_lookup_uint64(config,
ZPOOL_CONFIG_TIMESTAMP);
- if (nvlist_exists(config, ZPOOL_CONFIG_HOSTID))
+ if (nvlist_exists(nvinfo, ZPOOL_CONFIG_HOSTID))
+ hostid = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_HOSTID);
+ else if (nvlist_exists(config, ZPOOL_CONFIG_HOSTID))
hostid = fnvlist_lookup_uint64(config,
ZPOOL_CONFIG_HOSTID);
diff --git a/module/zfs/spa.c b/module/zfs/spa.c
index 413150fd2..0b69568e2 100644
--- a/module/zfs/spa.c
+++ b/module/zfs/spa.c
@@ -3934,6 +3934,24 @@ spa_ld_trusted_config(spa_t *spa, spa_import_type_t type,
spa_config_exit(spa, SCL_ALL, FTAG);
/*
+ * If 'zpool import' used a cached config, then the on-disk hostid and
+ * hostname may be different to the cached config in ways that should
+ * prevent import. Userspace can't discover this without a scan, but
+ * we know, so we add these values to LOAD_INFO so the caller can know
+ * the difference.
+ *
+ * Note that we have to do this before the config is regenerated,
+ * because the new config will have the hostid and hostname for this
+ * host, in readiness for import.
+ */
+ if (nvlist_exists(mos_config, ZPOOL_CONFIG_HOSTID))
+ fnvlist_add_uint64(spa->spa_load_info, ZPOOL_CONFIG_HOSTID,
+ fnvlist_lookup_uint64(mos_config, ZPOOL_CONFIG_HOSTID));
+ if (nvlist_exists(mos_config, ZPOOL_CONFIG_HOSTNAME))
+ fnvlist_add_string(spa->spa_load_info, ZPOOL_CONFIG_HOSTNAME,
+ fnvlist_lookup_string(mos_config, ZPOOL_CONFIG_HOSTNAME));
+
+ /*
* We will use spa_config if we decide to reload the spa or if spa_load
* fails and we rewind. We must thus regenerate the config using the
* MOS information with the updated paths. ZPOOL_LOAD_POLICY is used to
diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_hostid_changed_cachefile_unclean_export.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_hostid_changed_cachefile_unclean_export.ksh
index 8362d915f..dcb1ac1ab 100755
--- a/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_hostid_changed_cachefile_unclean_export.ksh
+++ b/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_hostid_changed_cachefile_unclean_export.ksh
@@ -20,8 +20,8 @@
#
# DESCRIPTION:
-# A pool that wasn't cleanly exported should be importable from a cachefile
-# without force even if the local hostid doesn't match the on-disk hostid.
+# A pool that wasn't cleanly exported should not be importable from a cachefile
+# without force if the local hostid doesn't match the on-disk hostid.
#
# STRATEGY:
# 1. Set a hostid.
@@ -32,8 +32,9 @@
# 4.2. Export the pool.
# 4.3. Restore the device state from the copy.
# 5. Change the hostid.
-# 6. Verify that importing the pool from the cachefile succeeds
-# without force.
+# 6. Verify that importing the pool from the cachefile fails.
+# 7. Verify that importing the pool from the cachefile with force
+# succeeds.
#
verify_runnable "global"
@@ -64,8 +65,11 @@ log_must rm -f $VDEV0.bak
# 5. Change the hostid.
log_must zgenhostid -f $HOSTID2
-# 6. Verify that importing the pool from the cachefile succeeds without force.
-log_must zpool import -c $CPATHBKP $TESTPOOL1
+# 6. Verify that importing the pool from the cachefile fails.
+log_mustnot zpool import -c $CPATHBKP $TESTPOOL1
-log_pass "zpool import can import pool from cachefile if not cleanly " \
- "exported when hostid changes."
+# 7. Verify that importing the pool from the cachefile with force succeeds.
+log_must zpool import -f -c $CPATHBKP $TESTPOOL1
+
+log_pass "zpool import from cachefile requires force if not cleanly " \
+ "exported and hostid changes."