From 398bc1b6d18ba3a8c4a95985abaac021b23463d6 Mon Sep 17 00:00:00 2001
Message-Id: <398bc1b6d18ba3a8c4a95985abaac021b23463d6.1357726992.git.minovotn@redhat.com>
In-Reply-To: <4f8efce613a639a3c1e3022c521d6c70b7154de8.1357726992.git.minovotn@redhat.com>
References: <4f8efce613a639a3c1e3022c521d6c70b7154de8.1357726992.git.minovotn@redhat.com>
From: Stefan Hajnoczi <stefanha@redhat.com>
Date: Wed, 2 Jan 2013 15:02:33 +0100
Subject: [PATCH 10/16] iov: add qemu_iovec_concat_iov()

RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: <1357138959-1918-11-git-send-email-stefanha@redhat.com>
Patchwork-id: 45523
O-Subject: [RHEL6.4 qemu-kvm PATCH v5 10/16] iov: add qemu_iovec_concat_iov()
Bugzilla: 877836
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>

The qemu_iovec_concat() function copies a subset of a QEMUIOVector.  The
new qemu_iovec_concat_iov() function does the same for a iov/cnt pair.

Upstream defined qemu_iovec_concat() in terms of qemu_iovec_concat_iov()
but the RHEL codebase has an older version of qemu_iovec_concat() which
uses qemu_iovec_copy() and is therefore not easy to share.

Conflicts:
    iov.c -> cutils.c

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 cutils.c      | 30 ++++++++++++++++++++++++++++++
 qemu-common.h |  3 +++
 2 files changed, 33 insertions(+)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
 cutils.c      | 30 ++++++++++++++++++++++++++++++
 qemu-common.h |  3 +++
 2 files changed, 33 insertions(+)

diff --git a/cutils.c b/cutils.c
index 7941325..9fb79fd 100644
--- a/cutils.c
+++ b/cutils.c
@@ -213,6 +213,36 @@ void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size)
     qemu_iovec_copy(dst, src, 0, size);
 }
 
+/*
+ * Concatenates (partial) iovecs from src_iov to the end of dst.
+ * It starts copying after skipping `soffset' bytes at the
+ * beginning of src and adds individual vectors from src to
+ * dst copies up to `sbytes' bytes total, or up to the end
+ * of src_iov if it comes first.  This way, it is okay to specify
+ * very large value for `sbytes' to indicate "up to the end
+ * of src".
+ * Only vector pointers are processed, not the actual data buffers.
+ */
+void qemu_iovec_concat_iov(QEMUIOVector *dst,
+                           struct iovec *src_iov, unsigned int src_cnt,
+                           size_t soffset, size_t sbytes)
+{
+    int i;
+    size_t done;
+    assert(dst->nalloc != -1);
+    for (i = 0, done = 0; done < sbytes && i < src_cnt; i++) {
+        if (soffset < src_iov[i].iov_len) {
+            size_t len = MIN(src_iov[i].iov_len - soffset, sbytes - done);
+            qemu_iovec_add(dst, src_iov[i].iov_base + soffset, len);
+            done += len;
+            soffset = 0;
+        } else {
+            soffset -= src_iov[i].iov_len;
+        }
+    }
+    assert(soffset == 0); /* offset beyond end of src */
+}
+
 void qemu_iovec_destroy(QEMUIOVector *qiov)
 {
     assert(qiov->nalloc != -1);
diff --git a/qemu-common.h b/qemu-common.h
index 03cd2b0..1f26638 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -276,6 +276,9 @@ void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len);
 void qemu_iovec_copy(QEMUIOVector *dst, QEMUIOVector *src, uint64_t skip,
     size_t size);
 void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size);
+void qemu_iovec_concat_iov(QEMUIOVector *dst,
+                           struct iovec *src_iov, unsigned int src_cnt,
+                           size_t soffset, size_t sbytes);
 void qemu_iovec_destroy(QEMUIOVector *qiov);
 void qemu_iovec_reset(QEMUIOVector *qiov);
 void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf);
-- 
1.7.11.7

