From 9dd6f7c28eaa7d001a526d51c74bbf89d5402b8c Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 17 Sep 2020 10:44:53 +0100 Subject: util/iov: add iov_discard_undo() The iov_discard_front/back() operations are useful for parsing iovecs but they modify the array elements. If the original array is needed after parsing finishes there is currently no way to restore it. Although g_memdup() can be used before performing destructive iov_discard_front/back() operations, this is inefficient. Introduce iov_discard_undo() to restore the array to the state prior to an iov_discard_front/back() operation. Signed-off-by: Stefan Hajnoczi Reviewed-by: Li Qiang Message-Id: <20200917094455.822379-2-stefanha@redhat.com> --- util/iov.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) (limited to 'util') diff --git a/util/iov.c b/util/iov.c index ae61d696aa..f3a9e92a37 100644 --- a/util/iov.c +++ b/util/iov.c @@ -636,14 +636,33 @@ void qemu_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src, void *buf) } } -size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt, - size_t bytes) +void iov_discard_undo(IOVDiscardUndo *undo) +{ + /* Restore original iovec if it was modified */ + if (undo->modified_iov) { + *undo->modified_iov = undo->orig; + } +} + +size_t iov_discard_front_undoable(struct iovec **iov, + unsigned int *iov_cnt, + size_t bytes, + IOVDiscardUndo *undo) { size_t total = 0; struct iovec *cur; + if (undo) { + undo->modified_iov = NULL; + } + for (cur = *iov; *iov_cnt > 0; cur++) { if (cur->iov_len > bytes) { + if (undo) { + undo->modified_iov = cur; + undo->orig = *cur; + } + cur->iov_base += bytes; cur->iov_len -= bytes; total += bytes; @@ -659,12 +678,24 @@ size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt, return total; } -size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt, - size_t bytes) +size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt, + size_t bytes) +{ + return iov_discard_front_undoable(iov, iov_cnt, bytes, NULL); +} + +size_t iov_discard_back_undoable(struct iovec *iov, + unsigned int *iov_cnt, + size_t bytes, + IOVDiscardUndo *undo) { size_t total = 0; struct iovec *cur; + if (undo) { + undo->modified_iov = NULL; + } + if (*iov_cnt == 0) { return 0; } @@ -673,6 +704,11 @@ size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt, while (*iov_cnt > 0) { if (cur->iov_len > bytes) { + if (undo) { + undo->modified_iov = cur; + undo->orig = *cur; + } + cur->iov_len -= bytes; total += bytes; break; @@ -687,6 +723,12 @@ size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt, return total; } +size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt, + size_t bytes) +{ + return iov_discard_back_undoable(iov, iov_cnt, bytes, NULL); +} + void qemu_iovec_discard_back(QEMUIOVector *qiov, size_t bytes) { size_t total; -- cgit v1.2.3