From f142f57c04dd0c5fe36eb4e930a0acbfc123878c Mon Sep 17 00:00:00 2001 From: Pawel Jakub Dawidek Date: Thu, 10 Dec 2009 18:38:40 +0000 Subject: [PATCH] MFC r200124,r200126, r200124: Avoid using additional variable for storing an error if we are not going to do anything with it. r200126: Fix deadlock when ZVOLs are present and we are replacing dead component or calling scrub when pool is in a degraded state. It will try to taste ZVOLs, which will lead to deadlock, as ZVOL will try to acquire the same locks as replace/scrub is holding already. We can't simply skip provider based on their GEOM class, because ZVOL can have providers build on top of it and we need to skip those as well. We do it by asking for ZFS::iszvol attribute. Any ZVOL-based provider will give us positive answer and we have to skip those providers. This way we remove possibility to create ZFS pools on top of ZVOLs, but it is not very useful anyway. I believe deadlock is still possible in some very complex situations like when we have MD provider on top of UFS file on top of ZVOL. When we try to replace dead component in the pool mentioned ZVOL is based on, there might be a deadlock when ZFS will try to taste MD provider. There is no easy way to detect that, but it isn't very common. r200125,r200158: Fix order of looking for providers. Before r200125 the order of looking for providers was wrong. It was: 1. Find provider by name. 2. Find provider by guid. 3. Find provider by name and guid. Where it should have been: 1. Find provider by name and guid. 2. Find provider by guid. 3. Find provider by name. --- .../opensolaris/uts/common/fs/zfs/vdev_geom.c | 14 +++++++++----- .../contrib/opensolaris/uts/common/fs/zfs/zvol.c | 5 ++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c index f0f9c6fa693..4c41f90253e 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c @@ -293,11 +293,16 @@ vdev_geom_read_guid(struct g_consumer *cp) uint64_t psize; off_t offset, size; uint64_t guid; - int error, l, len; + int error, l, len, iszvol; g_topology_assert_not(); pp = cp->provider; + ZFS_LOG(1, "Reading guid from %s...", pp->name); + if (g_getattr("ZFS::iszvol", cp, &iszvol) == 0 && iszvol) { + ZFS_LOG(1, "Skipping ZVOL-based provider %s.", pp->name); + return (0); + } psize = pp->mediasize; psize = P2ALIGN(psize, (uint64_t)sizeof(vdev_label_t)); @@ -316,8 +321,7 @@ vdev_geom_read_guid(struct g_consumer *cp) if ((offset % pp->sectorsize) != 0) continue; - error = vdev_geom_io(cp, BIO_READ, label, offset, size); - if (error != 0) + if (vdev_geom_io(cp, BIO_READ, label, offset, size) != 0) continue; buf = label->vl_vdev_phys.vp_nvlist; @@ -502,7 +506,7 @@ vdev_geom_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift) if ((owned = mtx_owned(&Giant))) mtx_unlock(&Giant); - cp = vdev_geom_open_by_path(vd, 0); + cp = vdev_geom_open_by_path(vd, 1); if (cp == NULL) { /* * The device at vd->vdev_path doesn't have the expected guid. @@ -512,7 +516,7 @@ vdev_geom_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift) cp = vdev_geom_open_by_guid(vd); } if (cp == NULL) - cp = vdev_geom_open_by_path(vd, 1); + cp = vdev_geom_open_by_path(vd, 0); if (cp == NULL) { ZFS_LOG(1, "Provider %s not found.", vd->vdev_path); vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c index e9b00cbbb68..b07a8c11da4 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c @@ -335,8 +335,11 @@ zvol_start(struct bio *bp) wakeup_one(&zv->zv_queue); mtx_unlock(&zv->zv_queue_mtx); break; - case BIO_DELETE: case BIO_GETATTR: + if (g_handleattr_int(bp, "ZFS::iszvol", 1)) + break; + /* FALLTHROUGH */ + case BIO_DELETE: default: g_io_deliver(bp, EOPNOTSUPP); break;