From 2a2c8ac0fd357ca33293f64932cca377e1f3956c Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sat, 25 Jun 2022 16:06:08 -0400 Subject: [PATCH] Avoid extra memory copies during mirror scrub. When several mirror scrub reads complete successfully, we do not need to copy data from each of them into the parent ZIO buffer, the first one is enough. This also moves the memory copy out of the ZIO locks, that I expected to cause contention, though on my system they almost didn't, had incorrect lock order and was partially not needed. When scrubbing 4-way mirror with 1.5TB of 128KB ZVOL blocks, this reduces CPU time spent in memcpy() by 75% and total CPU time by 31%. Signed-off-by: Alexander Motin Sponsored-By: iXsystems, Inc. --- module/zfs/vdev_mirror.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/module/zfs/vdev_mirror.c b/module/zfs/vdev_mirror.c index e7df0f0019fe..d1e606d8fcc3 100644 --- a/module/zfs/vdev_mirror.c +++ b/module/zfs/vdev_mirror.c @@ -120,6 +120,7 @@ typedef struct mirror_map { boolean_t mm_resilvering; boolean_t mm_rebuilding; boolean_t mm_root; + boolean_t mm_got_data; mirror_child_t mm_child[]; } mirror_map_t; @@ -451,17 +452,17 @@ vdev_mirror_scrub_done(zio_t *zio) mirror_child_t *mc = zio->io_private; if (zio->io_error == 0) { - zio_t *pio; - zio_link_t *zl = NULL; - - mutex_enter(&zio->io_lock); - while ((pio = zio_walk_parents(zio, &zl)) != NULL) { - mutex_enter(&pio->io_lock); - ASSERT3U(zio->io_size, >=, pio->io_size); + zio_t *pio = zio_unique_parent(zio); + mirror_map_t *mm = pio->io_vsd; + mutex_enter(&pio->io_lock); + if (!mm->mm_got_data) { + mm->mm_got_data = B_TRUE; + mutex_exit(&pio->io_lock); + ASSERT3U(zio->io_size, ==, pio->io_size); abd_copy(pio->io_abd, zio->io_abd, pio->io_size); + } else { mutex_exit(&pio->io_lock); } - mutex_exit(&zio->io_lock); } abd_free(zio->io_abd);