summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs/zfs/vdev.c
diff options
context:
space:
mode:
authorEric Taylor <Eric.Taylor@Sun.COM>2008-10-20 08:51:30 -0600
committerEric Taylor <Eric.Taylor@Sun.COM>2008-10-20 08:51:30 -0600
commit4d04273f2ee96d881d072f95c50570e17dc3a635 (patch)
tree6a11e2bbfe141eb12a6ffa3387b306b9b27e4bcb /usr/src/uts/common/fs/zfs/vdev.c
parent5b17e9bd2e8746f9025fdb928568a44b58c45dbf (diff)
downloadillumos-gate-4d04273f2ee96d881d072f95c50570e17dc3a635.tar.gz
6752810 deadlock when trying to online missing boot drive
Diffstat (limited to 'usr/src/uts/common/fs/zfs/vdev.c')
-rw-r--r--usr/src/uts/common/fs/zfs/vdev.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/usr/src/uts/common/fs/zfs/vdev.c b/usr/src/uts/common/fs/zfs/vdev.c
index 2b0ad52561..240f955ea2 100644
--- a/usr/src/uts/common/fs/zfs/vdev.c
+++ b/usr/src/uts/common/fs/zfs/vdev.c
@@ -1642,7 +1642,7 @@ vdev_fault(spa_t *spa, uint64_t guid)
vdev_set_state(vd, B_FALSE, VDEV_STATE_FAULTED, VDEV_AUX_ERR_EXCEEDED);
/*
- * If marking the vdev as faulted cause the top-level vdev to become
+ * If marking the vdev as faulted causes the top-level vdev to become
* unavailable, then back off and simply mark the vdev as degraded
* instead.
*/
@@ -1708,6 +1708,27 @@ vdev_online(spa_t *spa, uint64_t guid, uint64_t flags, vdev_state_t *newstate)
{
vdev_t *vd;
+ if (spa_is_root(spa)) {
+ /*
+ * if we're trying to online a device that's part of
+ * the root pool, trigger an attach (if any) with only
+ * the SCL_STATE lock held in order to avoid a deadlock
+ * where modload tries to read from the disk
+ */
+ spa_config_enter(spa, SCL_STATE, FTAG, RW_WRITER);
+ if ((vd = spa_lookup_by_guid(spa, guid, B_TRUE)) == NULL) {
+ spa_config_exit(spa, SCL_STATE, FTAG);
+ return (ENODEV);
+ }
+ if (!vd->vdev_ops->vdev_op_leaf) {
+ spa_config_exit(spa, SCL_STATE, FTAG);
+ return (ENOTSUP);
+ }
+ vdev_close(vd);
+ vdev_open(vd);
+ spa_config_exit(spa, SCL_STATE, FTAG);
+ }
+
spa_vdev_state_enter(spa);
if ((vd = spa_lookup_by_guid(spa, guid, B_TRUE)) == NULL)