diff options
author | smh <smh@FreeBSD.org> | 2014-05-04 14:05:14 +0000 |
---|---|---|
committer | smh <smh@FreeBSD.org> | 2014-05-04 14:05:14 +0000 |
commit | fd5ca872534cfb4949b6199db73196121e33e293 (patch) | |
tree | 69541f3c4777c0bb8d2ec34d823e972df362d3fc | |
parent | 86a85509b8f3be04a1991c4213e5634c18adff3e (diff) | |
download | FreeBSD-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.h | 1 | ||||
-rw-r--r-- | sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c | 11 |
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); } |