summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsmh <smh@FreeBSD.org>2014-05-04 14:05:14 +0000
committersmh <smh@FreeBSD.org>2014-05-04 14:05:14 +0000
commitfd5ca872534cfb4949b6199db73196121e33e293 (patch)
tree69541f3c4777c0bb8d2ec34d823e972df362d3fc
parent86a85509b8f3be04a1991c4213e5634c18adff3e (diff)
downloadFreeBSD-src-fd5ca872534cfb4949b6199db73196121e33e293.zip
FreeBSD-src-fd5ca872534cfb4949b6199db73196121e33e293.tar.gz
Use a zio flag to prevent recursion of vdev_queue_io_done which can
cause stack overflow for IO's which return ZIO_PIPELINE_CONTINUE from the zio_vdev_io_start stage and hence don't suspend and complete in a different thread. This prevents double fault panic on slow machines running ZFS on GELI volumes which return EOPNOTSUPP directly to BIO_DELETE requests. MFC after: 1 month X-MFC-With: r265152
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h1
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c11
2 files changed, 12 insertions, 0 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h
index 2cce781..84187a8 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h
@@ -196,6 +196,7 @@ enum zio_flag {
ZIO_FLAG_NOPWRITE = 1 << 25,
ZIO_FLAG_REEXECUTED = 1 << 26,
ZIO_FLAG_DELEGATED = 1 << 27,
+ ZIO_FLAG_QUEUE_IO_DONE = 1 << 28,
};
#define ZIO_FLAG_MUSTSUCCEED 0
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c
index 5747aa4..60fd4c3 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c
@@ -796,14 +796,25 @@ vdev_queue_io_done(zio_t *zio)
vq->vq_io_complete_ts = gethrtime();
+ if (zio->io_flags & ZIO_FLAG_QUEUE_IO_DONE) {
+ /*
+ * Executing from a previous vdev_queue_io_done so
+ * to avoid recursion we just unlock and return.
+ */
+ mutex_exit(&vq->vq_lock);
+ return;
+ }
+
while ((nio = vdev_queue_io_to_issue(vq)) != NULL) {
mutex_exit(&vq->vq_lock);
+ nio->io_flags |= ZIO_FLAG_QUEUE_IO_DONE;
if (nio->io_done == vdev_queue_agg_io_done) {
zio_nowait(nio);
} else {
zio_vdev_io_reissue(nio);
zio_execute(nio);
}
+ nio->io_flags &= ~ZIO_FLAG_QUEUE_IO_DONE;
mutex_enter(&vq->vq_lock);
}
OpenPOWER on IntegriCloud