From e50b5217e7a85f1466edf88d5f3ea5aed0c2fd22 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Wed, 13 Jan 2021 10:00:12 -0700 Subject: libzutil: optimize zpool_read_label with AIO Read all labels in parallel instead of sequentially. Originally committed as https://cgit.freebsd.org/src/commit/?id=b49e9abcf44cafaf5cfad7029c9a6adbb28346e8 Obtained from: FreeBSD Sponsored by: Spectra Logic, Axcient Reviewed-by: Jorgen Lundman Reviewed-by: Brian Behlendorf Reviewed-by: Alek Pinchuk Signed-off-by: Alan Somers Closes #11467 --- lib/libzutil/zutil_import.c | 53 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 10 deletions(-) (limited to 'lib/libzutil/zutil_import.c') diff --git a/lib/libzutil/zutil_import.c b/lib/libzutil/zutil_import.c index bf914d37c..823f093f4 100644 --- a/lib/libzutil/zutil_import.c +++ b/lib/libzutil/zutil_import.c @@ -46,6 +46,7 @@ * using our derived config, and record the results. */ +#include #include #include #include @@ -887,11 +888,12 @@ int zpool_read_label(int fd, nvlist_t **config, int *num_labels) { struct stat64 statbuf; - int l, count = 0; - vdev_phys_t *label; + struct aiocb aiocbs[VDEV_LABELS]; + struct aiocb *aiocbps[VDEV_LABELS]; + vdev_phys_t *labels; nvlist_t *expected_config = NULL; uint64_t expected_guid = 0, size; - int error; + int error, l, count = 0; *config = NULL; @@ -899,20 +901,51 @@ zpool_read_label(int fd, nvlist_t **config, int *num_labels) return (0); size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t); - error = posix_memalign((void **)&label, PAGESIZE, sizeof (*label)); + error = posix_memalign((void **)&labels, PAGESIZE, + VDEV_LABELS * sizeof (*labels)); if (error) return (-1); + memset(aiocbs, 0, sizeof (aiocbs)); for (l = 0; l < VDEV_LABELS; l++) { - uint64_t state, guid, txg; off_t offset = label_offset(size, l) + VDEV_SKIP_SIZE; - if (pread64(fd, label, sizeof (vdev_phys_t), - offset) != sizeof (vdev_phys_t)) + aiocbs[l].aio_fildes = fd; + aiocbs[l].aio_offset = offset; + aiocbs[l].aio_buf = &labels[l]; + aiocbs[l].aio_nbytes = sizeof (vdev_phys_t); + aiocbs[l].aio_lio_opcode = LIO_READ; + aiocbps[l] = &aiocbs[l]; + } + + if (lio_listio(LIO_WAIT, aiocbps, VDEV_LABELS, NULL) != 0) { + int saved_errno = errno; + + if (errno == EAGAIN || errno == EINTR || errno == EIO) { + /* + * A portion of the requests may have been submitted. + * Clean them up. + */ + for (l = 0; l < VDEV_LABELS; l++) { + errno = 0; + int r = aio_error(&aiocbs[l]); + if (r != EINVAL) + (void) aio_return(&aiocbs[l]); + } + } + free(labels); + errno = saved_errno; + return (-1); + } + + for (l = 0; l < VDEV_LABELS; l++) { + uint64_t state, guid, txg; + + if (aio_return(&aiocbs[l]) != sizeof (vdev_phys_t)) continue; - if (nvlist_unpack(label->vp_nvlist, - sizeof (label->vp_nvlist), config, 0) != 0) + if (nvlist_unpack(labels[l].vp_nvlist, + sizeof (labels[l].vp_nvlist), config, 0) != 0) continue; if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_GUID, @@ -949,7 +982,7 @@ zpool_read_label(int fd, nvlist_t **config, int *num_labels) if (num_labels != NULL) *num_labels = count; - free(label); + free(labels); *config = expected_config; return (0); -- cgit v1.2.3