diff options
author | Brian Behlendorf <[email protected]> | 2019-09-10 13:42:30 -0700 |
---|---|---|
committer | GitHub <[email protected]> | 2019-09-10 13:42:30 -0700 |
commit | 25f06d677a81a65ca98fa3d725ab5031a4864104 (patch) | |
tree | 0ca39f861a6cbbc8aa858dc8857c8d327c33c889 /include/sys | |
parent | 562e1c0327be13bce43d81479bb113a1175569d4 (diff) |
Fix /etc/hostid on root pool deadlock
Accidentally introduced by dc04a8c which now takes the SCL_VDEV lock
as a reader in zfs_blkptr_verify(). A deadlock can occur if the
/etc/hostid file resides on a dataset in the same pool. This is
because reading the /etc/hostid file may occur while the caller is
holding the SCL_VDEV lock as a writer. For example, to perform a
`zpool attach` as shown in the abbreviated stack below.
To resolve the issue we cache the system's hostid when initializing
the spa_t, or when modifying the multihost property. The cached
value is then relied upon for subsequent accesses.
Call Trace:
spa_config_enter+0x1e8/0x350 [zfs]
zfs_blkptr_verify+0x33c/0x4f0 [zfs] <--- trying read lock
zio_read+0x6c/0x140 [zfs]
...
vfs_read+0xfc/0x1e0
kernel_read+0x50/0x90
...
spa_get_hostid+0x1c/0x38 [zfs]
spa_config_generate+0x1a0/0x610 [zfs]
vdev_label_init+0xa0/0xc80 [zfs]
vdev_create+0x98/0xe0 [zfs]
spa_vdev_attach+0x14c/0xb40 [zfs] <--- grabbed write lock
Reviewed-by: loli10K <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Closes #9256
Closes #9285
Diffstat (limited to 'include/sys')
-rw-r--r-- | include/sys/spa.h | 2 | ||||
-rw-r--r-- | include/sys/spa_impl.h | 1 |
2 files changed, 2 insertions, 1 deletions
diff --git a/include/sys/spa.h b/include/sys/spa.h index 494326843..8323662f6 100644 --- a/include/sys/spa.h +++ b/include/sys/spa.h @@ -1136,7 +1136,7 @@ extern void spa_set_missing_tvds(spa_t *spa, uint64_t missing); extern boolean_t spa_top_vdevs_spacemap_addressable(spa_t *spa); extern uint64_t spa_total_metaslabs(spa_t *spa); extern boolean_t spa_multihost(spa_t *spa); -extern unsigned long spa_get_hostid(void); +extern uint32_t spa_get_hostid(spa_t *spa); extern void spa_activate_allocation_classes(spa_t *, dmu_tx_t *); extern boolean_t spa_livelist_delete_check(spa_t *spa); diff --git a/include/sys/spa_impl.h b/include/sys/spa_impl.h index 503600c8c..71b07405c 100644 --- a/include/sys/spa_impl.h +++ b/include/sys/spa_impl.h @@ -411,6 +411,7 @@ struct spa { mmp_thread_t spa_mmp; /* multihost mmp thread */ list_t spa_leaf_list; /* list of leaf vdevs */ uint64_t spa_leaf_list_gen; /* track leaf_list changes */ + uint32_t spa_hostid; /* cached system hostid */ /* * spa_refcount & spa_config_lock must be the last elements |