aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--module/zfs/vdev_queue.c22
1 files changed, 12 insertions, 10 deletions
diff --git a/module/zfs/vdev_queue.c b/module/zfs/vdev_queue.c
index e74df76b7..86b20f134 100644
--- a/module/zfs/vdev_queue.c
+++ b/module/zfs/vdev_queue.c
@@ -709,6 +709,18 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio)
do {
dio = nio;
nio = AVL_NEXT(t, dio);
+ zio_add_child(dio, aio);
+ vdev_queue_io_remove(vq, dio);
+ } while (dio != last);
+
+ /*
+ * We need to drop the vdev queue's lock during zio_execute() to
+ * avoid a deadlock that we could encounter due to lock order
+ * reversal between vq_lock and io_lock in zio_change_priority().
+ * Use the dropped lock to do memory copy without congestion.
+ */
+ mutex_exit(&vq->vq_lock);
+ while ((dio = zio_walk_parents(aio, &zl)) != NULL) {
ASSERT3U(dio->io_type, ==, aio->io_type);
if (dio->io_flags & ZIO_FLAG_NODATA) {
@@ -720,16 +732,6 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio)
dio->io_offset - aio->io_offset, 0, dio->io_size);
}
- zio_add_child(dio, aio);
- vdev_queue_io_remove(vq, dio);
- } while (dio != last);
-
- /*
- * We need to drop the vdev queue's lock to avoid a deadlock that we
- * could encounter since this I/O will complete immediately.
- */
- mutex_exit(&vq->vq_lock);
- while ((dio = zio_walk_parents(aio, &zl)) != NULL) {
zio_vdev_io_bypass(dio);
zio_execute(dio);
}