Skip to content

Commit

Permalink
Move write aggregation memory copy out of vq_lock
Browse files Browse the repository at this point in the history
Memory copy is too heavy operation to do under the congested lock.
Moving it out reduces congestion by many times to almost invisible.
Since the original zio removed from the queue, and the child zio is
not executed yet, I don't see why would the copy need protection.
My guess it just remained like this from the time when lock was not
dropped here, which was added later to fix lock ordering issue.

Multi-threaded sequential write tests with both HDD and SSD pools
with ZVOL block sizes of 4KB, 16KB, 64KB and 128KB all show major
reduction of lock congestion, saving from 15% to 35% of CPU time
and increasing throughput from 10% to 40%.

Reviewed-by: Richard Yao <ryao@gentoo.org>
Reviewed-by: Matt Ahrens <mahrens@delphix.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by:  Alexander Motin <mav@FreeBSD.org>
Closes #8890
  • Loading branch information
amotin authored and tonyhutter committed Aug 13, 2019
1 parent 5379280 commit 90343ff
Showing 1 changed file with 12 additions and 10 deletions.
22 changes: 12 additions & 10 deletions module/zfs/vdev_queue.c
Expand Up @@ -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) {
Expand All @@ -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);
}
Expand Down

0 comments on commit 90343ff

Please sign in to comment.