diff mbox series

[1/2] util/iov: introduce qemu_iovec_init_extended

Message ID 20190528084544.183558-2-vsementsov@virtuozzo.com
State New
Headers show
Series block/io: refactor padding | expand

Commit Message

Vladimir Sementsov-Ogievskiy May 28, 2019, 8:45 a.m. UTC
Introduce new initialization API, to create requests with padding. Will
be used in the following patch.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
 include/qemu/iov.h |  5 +++
 util/iov.c         | 89 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 94 insertions(+)

Comments

Stefan Hajnoczi May 31, 2019, 8:33 a.m. UTC | #1
On Tue, May 28, 2019 at 11:45:43AM +0300, Vladimir Sementsov-Ogievskiy wrote:
> diff --git a/util/iov.c b/util/iov.c
> index 74e6ca8ed7..6bfd609998 100644
> --- a/util/iov.c
> +++ b/util/iov.c
> @@ -353,6 +353,95 @@ void qemu_iovec_concat(QEMUIOVector *dst,
>      qemu_iovec_concat_iov(dst, src->iov, src->niov, soffset, sbytes);
>  }
>  
> +/*
> + * qiov_find_iov
> + *
> + * Return iov, where byte at @offset (in @qiov) is.
> + * Update @offset to be offset inside that iov to the smae byte.

s/smae/same/

> + */
> +static struct iovec *qiov_find_iov(QEMUIOVector *qiov, size_t *offset)
> +{
> +    struct iovec *iov = qiov->iov;
> +
> +    assert(*offset < qiov->size);
> +
> +    while (*offset >= iov->iov_len) {
> +        *offset -= iov->iov_len;
> +        iov++;
> +    }
> +
> +    return iov;
> +}
> +
> +/*
> + * qiov_slice
> + *
> + * Fund subarray of iovec's, containing requested range. @head would

s/Fund/Find/

> + * be offset in first iov (retruned by the function), @tail would be

s/retruned/returned/

> + * count of extra bytes in last iov (returned iov + @niov - 1).
> + */
> +static struct iovec *qiov_slice(QEMUIOVector *qiov,
> +                                size_t offset, size_t len,
> +                                size_t *head, size_t *tail, int *niov)
> +{
> +    struct iovec *iov = qiov_find_iov(qiov, &offset), *end_iov;
> +    size_t end_offset;
> +
> +    assert(offset + len <= qiov->size);

offset has already been modified by qiov_find_iov() in iov's
initializer so this comparison is meaningless.  Fix:

  struct iovec *iov;
  struct iovec *end_iov;
  size_t end_offset;

  assert(offset + len <= qiov->size);

  iov = qiov_find_iov(qiov, &offset);

Perhaps qiov_find_iov() shouldn't reuse the offset argument for two
different things (the offset from the beginning of qiov and the offset
from the beginning of the returned iovec).  This would eliminate this
class of bugs.

> +
> +    end_offset = iov->iov_len;
> +    end_iov = iov + 1;
> +
> +    while (end_offset - offset < len) {
> +        end_offset += end_iov->iov_len;
> +        end_iov++;
> +    }

Hmm...this looks like qiov_find_iov().  Can this function be implemented
in less code using two calls to qiov_find_iov() to find the first and
last iovecs?
diff mbox series

Patch

diff --git a/include/qemu/iov.h b/include/qemu/iov.h
index 48b45987b7..1c5be66102 100644
--- a/include/qemu/iov.h
+++ b/include/qemu/iov.h
@@ -199,6 +199,11 @@  static inline void *qemu_iovec_buf(QEMUIOVector *qiov)
 
 void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint);
 void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov);
+void qemu_iovec_init_extended(
+        QEMUIOVector *qiov,
+        void *left, size_t left_len,
+        QEMUIOVector *middle, size_t middle_offset, size_t middle_len,
+        void *right, size_t right_len);
 void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len);
 void qemu_iovec_concat(QEMUIOVector *dst,
                        QEMUIOVector *src, size_t soffset, size_t sbytes);
diff --git a/util/iov.c b/util/iov.c
index 74e6ca8ed7..6bfd609998 100644
--- a/util/iov.c
+++ b/util/iov.c
@@ -353,6 +353,95 @@  void qemu_iovec_concat(QEMUIOVector *dst,
     qemu_iovec_concat_iov(dst, src->iov, src->niov, soffset, sbytes);
 }
 
+/*
+ * qiov_find_iov
+ *
+ * Return iov, where byte at @offset (in @qiov) is.
+ * Update @offset to be offset inside that iov to the smae byte.
+ */
+static struct iovec *qiov_find_iov(QEMUIOVector *qiov, size_t *offset)
+{
+    struct iovec *iov = qiov->iov;
+
+    assert(*offset < qiov->size);
+
+    while (*offset >= iov->iov_len) {
+        *offset -= iov->iov_len;
+        iov++;
+    }
+
+    return iov;
+}
+
+/*
+ * qiov_slice
+ *
+ * Fund subarray of iovec's, containing requested range. @head would
+ * be offset in first iov (retruned by the function), @tail would be
+ * count of extra bytes in last iov (returned iov + @niov - 1).
+ */
+static struct iovec *qiov_slice(QEMUIOVector *qiov,
+                                size_t offset, size_t len,
+                                size_t *head, size_t *tail, int *niov)
+{
+    struct iovec *iov = qiov_find_iov(qiov, &offset), *end_iov;
+    size_t end_offset;
+
+    assert(offset + len <= qiov->size);
+
+    end_offset = iov->iov_len;
+    end_iov = iov + 1;
+
+    while (end_offset - offset < len) {
+        end_offset += end_iov->iov_len;
+        end_iov++;
+    }
+
+    *niov = end_iov - iov;
+    *head = offset;
+    *tail = (end_offset - offset) - len;
+
+    return iov;
+}
+
+/*
+ * Compile new iovec, combining @head_buf buffer, sub-qiov of @mid_qiov,
+ * and @tail_buf buffer into new qiov.
+ */
+void qemu_iovec_init_extended(
+        QEMUIOVector *qiov,
+        void *head_buf, size_t head_len,
+        QEMUIOVector *mid_qiov, size_t mid_offset, size_t mid_len,
+        void *tail_buf, size_t tail_len)
+{
+    size_t mid_head, mid_tail;
+    int niov;
+    struct iovec *p, *mid_iov = qiov_slice(mid_qiov, mid_offset, mid_len,
+                                           &mid_head, &mid_tail, &niov);
+
+    assert(niov);
+    qiov->niov = qiov->nalloc = niov + !!head_len + !!tail_len;
+    qiov->size = head_len + mid_len + tail_len;
+
+    p = qiov->iov = g_new(struct iovec, qiov->niov);
+    if (head_len) {
+        p->iov_base = head_buf;
+        p->iov_len = head_len;
+        p++;
+    }
+
+    memcpy(p, mid_iov, niov * sizeof(*p));
+    p[0].iov_base = (uint8_t *)p[0].iov_base + mid_head;
+    p[0].iov_len -= mid_head;
+    p[niov - 1].iov_len -= mid_tail;
+    p += niov;
+
+    if (tail_len) {
+        p->iov_base = tail_buf;
+        p->iov_len = tail_len;
+    }
+}
+
 /*
  * Check if the contents of the iovecs are all zero
  */