You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
pool is imported on host '<unknown>' (hostid=0). #18823
We are running a shared jbob zfs cluster. Our dev/test environement is running under VMware using shared disks (thick provisioning, independant, multi-writer). This has been working fine in the past and today we use it to validate an upgrade from 2.3.4 to 2.4.3. 'multihost' is enabled and we have unique /etc/hostid.
Under 2.4.3 the pool cannot be moved from one node to the other anymore (note: pacemaker/corosync have been disabled and we are testing everything manually). Pool is properly exported on one node and we get the following error while importing on the other node:
cannot import 'p02': pool is imported on host '<unknown>' (hostid=0).
Export the pool on the other system, then run 'zpool import'.
Disabling multihost/mmp makes it possible to move the pool from one node to the other. Re-enabling multihost brings the issue back when trying to move the pool to another node.
Also, import systematically triggers an activity check, which ends with (note: the pool 'p02' was properly exported before this):
NOTICE: pool 'p02' activity check required, 34 seconds remaining
WARNING: pool 'p02' activity detected, aborted import during claim
This pool is made of a pair of mirrors (2x2 disks) and contains a 'hole' vdev due to a previous mirror removal test. Could this be part of the issue ?
I was able to reproduce this and bisect it. @pzwahlen's narrowing to the log
removal is exactly right: the trigger is the hole that zpool remove leaves
in the vdev config.
Reproduction
This is on a plain QEMU VM with file vdevs and a single node, simulating the
second host by changing the hostid between export and import, so none of your
VMware or shared-disk setup is needed to hit it.
zpool create -f p mirror d1 d2 mirror d3 d4
zpool set multihost=on p
zpool add p log mirror d5 d6
zpool remove p mirror-2 # leaves type: 'hole' in the config
zpool export p
zgenhostid -f feedface # pretend we are the other node
zpool import -d . p
cannot import 'p': pool is imported on host '<unknown>' (hostid=0).
A control run that never adds or removes a log imports cleanly through the same
export/hostid-change/import sequence, which is what points at the hole rather
than at multihost itself.
Bisect
Each step below was built with --enable-debug and I checked that the loaded
module's srcversion matched the freshly built one, so none of these are stale
module results.
zfs-2.3.4 GOOD
zfs-2.4.0 GOOD
zfs-2.4.1 BAD
zfs-2.4.2 BAD
master BAD
git bisect run over the 85 commits in zfs-2.4.0..zfs-2.4.1 lands on
c710f879236a94bb10a051b1e88648ad0475b76e mmp: claim sequence id before final import
and I re-tested its parent 96ffe5100 explicitly to confirm it is GOOD.
Worth noting for anyone else hitting this: 2.4.0 is unaffected, so the exposure
starts at 2.4.1.
Mechanism
In mmp_claim_uberblock_sync() the new activity check walks the vdev tree
accumulating req_writes, then requires that many good writes:
if (cvd->vdev_islog||cvd->vdev_isspare||cvd->vdev_isl2cache)
continue;
if (cvd->vdev_top==cvd) {
...
*req_writes+=MIN(MAX(cvd->vdev_children, 1), 2);
}
A hole is a top-level vdev and is none of log/spare/l2cache, so it survives that
filter and adds 1 to req_writes. It is not writeable, so the function returns
at the vdev_writeable() check before issuing any write and good_writes never
accounts for it. good_writes can then never reach req_writes, the check
concludes the pool is active elsewhere, and the import fails with hostid 0
because the hole has no label to read a hostid from.
That also explains why it only shows up after a log device is removed, and why a
pool that never had one is fine.
Candidate fix
Skipping holes alongside the other vdev types resolves it here. vdev_label.c
already guards vdev_ishole in the equivalent places (lines 769 and 820), so
this matches existing practice:
if (cvd->vdev_islog||cvd->vdev_isspare||cvd->vdev_isl2cache||cvd->vdev_ishole)
continue;
With that applied to master the same reproduction imports cleanly, with the hole
still present in the config.
The mmp test group still passes with it applied, 17/17 on Ubuntu 24.04 /
kernel 6.8, including mmp_active_import, mmp_concurrent_import and mmp_exported_import, so the activity check itself still behaves for the cases
it is meant to catch.
I have not tried to judge whether skipping holes is the right shape of fix
compared with, say, deriving req_writes from writeable leaves. Happy to open a
PR if that is useful, or leave it with you.
Activity
pzwahlen commentedon Jul 19, 2026
I am able to replicate this issue:
mkhllr commentedon Jul 20, 2026
I was able to reproduce this and bisect it. @pzwahlen's narrowing to the log
removal is exactly right: the trigger is the hole that
zpool removeleavesin the vdev config.
Reproduction
This is on a plain QEMU VM with file vdevs and a single node, simulating the
second host by changing the hostid between export and import, so none of your
VMware or shared-disk setup is needed to hit it.
A control run that never adds or removes a log imports cleanly through the same
export/hostid-change/import sequence, which is what points at the hole rather
than at multihost itself.
Bisect
Each step below was built with
--enable-debugand I checked that the loadedmodule's srcversion matched the freshly built one, so none of these are stale
module results.
git bisect runover the 85 commits inzfs-2.4.0..zfs-2.4.1lands onand I re-tested its parent
96ffe5100explicitly to confirm it is GOOD.Worth noting for anyone else hitting this: 2.4.0 is unaffected, so the exposure
starts at 2.4.1.
Mechanism
In
mmp_claim_uberblock_sync()the new activity check walks the vdev treeaccumulating
req_writes, then requires that many good writes:A hole is a top-level vdev and is none of log/spare/l2cache, so it survives that
filter and adds 1 to
req_writes. It is not writeable, so the function returnsat the
vdev_writeable()check before issuing any write andgood_writesneveraccounts for it.
good_writescan then never reachreq_writes, the checkconcludes the pool is active elsewhere, and the import fails with hostid 0
because the hole has no label to read a hostid from.
That also explains why it only shows up after a log device is removed, and why a
pool that never had one is fine.
Candidate fix
Skipping holes alongside the other vdev types resolves it here.
vdev_label.calready guards
vdev_isholein the equivalent places (lines 769 and 820), sothis matches existing practice:
With that applied to master the same reproduction imports cleanly, with the hole
still present in the config.
The
mmptest group still passes with it applied, 17/17 on Ubuntu 24.04 /kernel 6.8, including
mmp_active_import,mmp_concurrent_importandmmp_exported_import, so the activity check itself still behaves for the casesit is meant to catch.
I have not tried to judge whether skipping holes is the right shape of fix
compared with, say, deriving
req_writesfrom writeable leaves. Happy to open aPR if that is useful, or leave it with you.
mmp: skip non-writeable vdevs during activity check
mmp: skip non-writeable vdevs during activity check
mmp: skip non-writeable vdevs during activity check
mmp: skip non-writeable vdevs during activity check
mmp: skip non-writeable vdevs during activity check
mmp: skip non-writeable vdevs during activity check
mmp: skip non-writeable vdevs during activity check
NAS-142538 / 25.10.7 / None / Update ZFS 2.3 to zfs-2.3.9 (by ixhamza) (
mmp: skip non-writeable vdevs during activity check
OpenZFS 2.4.4: a degraded multihost pool can be imported again