From: David Vrabel <david.vrabel@citrix.com>
Hypercall buffer arrays are used when a hypercall takes a variable
length array of buffers.
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
---
 tools/libxc/xc_hcall_buf.c |   73 ++++++++++++++++++++++++++++++++++++++++++++
 tools/libxc/xenctrl.h      |   27 ++++++++++++++++
 2 files changed, 100 insertions(+), 0 deletions(-)
diff --git a/tools/libxc/xc_hcall_buf.c b/tools/libxc/xc_hcall_buf.c
index ced9abd..3e01f3f 100644
--- a/tools/libxc/xc_hcall_buf.c
+++ b/tools/libxc/xc_hcall_buf.c
@@ -228,6 +228,79 @@ void xc__hypercall_bounce_post(xc_interface *xch,
xc_hypercall_buffer_t *b)
     xc__hypercall_buffer_free(xch, b);
 }
 
+struct xc_hypercall_buffer_array {
+    unsigned max_bufs;
+    xc_hypercall_buffer_t *bufs;
+};
+
+xc_hypercall_buffer_array_t *xc_hypercall_buffer_array_create(xc_interface
*xch,
+                                                              unsigned n)
+{
+    xc_hypercall_buffer_array_t *array;
+    xc_hypercall_buffer_t *bufs = NULL;
+
+    array = malloc(sizeof(*array));
+    if ( array == NULL )
+        goto error;
+
+    bufs = calloc(n, sizeof(*bufs));
+    if ( bufs == NULL )
+        goto error;
+
+    array->max_bufs = n;
+    array->bufs     = bufs;
+
+    return array;
+
+error:
+    free(bufs);
+    free(array);
+    return NULL;
+}
+
+void *xc__hypercall_buffer_array_alloc(xc_interface *xch,
+                                       xc_hypercall_buffer_array_t *array,
+                                       unsigned index,
+                                       xc_hypercall_buffer_t *hbuf,
+                                       size_t size)
+{
+    void *buf;
+
+    if ( index >= array->max_bufs || array->bufs[index].hbuf )
+        abort();
+
+    buf = xc__hypercall_buffer_alloc(xch, hbuf, size);
+    if ( buf )
+        array->bufs[index] = *hbuf;
+    return buf;
+}
+
+void *xc__hypercall_buffer_array_get(xc_interface *xch,
+                                     xc_hypercall_buffer_array_t *array,
+                                     unsigned index,
+                                     xc_hypercall_buffer_t *hbuf)
+{
+    if ( index >= array->max_bufs || array->bufs[index].hbuf == NULL )
+        abort();
+
+    *hbuf = array->bufs[index];
+    return array->bufs[index].hbuf;
+}
+
+void xc_hypercall_buffer_array_destroy(xc_interface *xc,
+                                       xc_hypercall_buffer_array_t *array)
+{
+    unsigned i;
+
+    if ( array == NULL )
+        return;
+
+    for (i = 0; i < array->max_bufs; i++ )
+        xc__hypercall_buffer_free(xc, &array->bufs[i]);
+    free(array->bufs);
+    free(array);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index 32122fd..c3b2c28 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -317,6 +317,33 @@ void xc__hypercall_buffer_free_pages(xc_interface *xch,
xc_hypercall_buffer_t *b
 #define xc_hypercall_buffer_free_pages(_xch, _name, _nr)
xc__hypercall_buffer_free_pages(_xch, HYPERCALL_BUFFER(_name), _nr)
 
 /*
+ * Array of hypercall buffers.
+ *
+ * Create an array with xc_hypercall_buffer_array_create() and
+ * populate it by declaring one hypercall buffer in a loop and
+ * allocating the buffer with xc_hypercall_buffer_array_alloc().
+ *
+ * To access a previously allocated buffers, declare a new hypercall
+ * buffer and call xc_hypercall_buffer_array_get().
+ *
+ * Destroy the array with xc_hypercall_buffer_array_destroy() to free
+ * the array and all its alocated hypercall buffers.
+ */
+struct xc_hypercall_buffer_array;
+typedef struct xc_hypercall_buffer_array xc_hypercall_buffer_array_t;
+
+xc_hypercall_buffer_array_t *xc_hypercall_buffer_array_create(xc_interface
*xch, unsigned n);
+void *xc__hypercall_buffer_array_alloc(xc_interface *xch,
xc_hypercall_buffer_array_t *array,
+                                       unsigned index, xc_hypercall_buffer_t
*hbuf, size_t size);
+#define xc_hypercall_buffer_array_alloc(_xch, _array, _index, _name, _size) \
+    xc__hypercall_buffer_array_alloc(_xch, _array, _index,
HYPERCALL_BUFFER(_name), _size)
+void *xc__hypercall_buffer_array_get(xc_interface *xch,
xc_hypercall_buffer_array_t *array,
+                                     unsigned index, xc_hypercall_buffer_t
*hbuf);
+#define xc_hypercall_buffer_array_get(_xch, _array, _index, _name, _size) \
+    xc__hypercall_buffer_array_get(_xch, _array, _index,
HYPERCALL_BUFFER(_name))
+void xc_hypercall_buffer_array_destroy(xc_interface *xc,
xc_hypercall_buffer_array_t *array);
+
+/*
  * CPUMAP handling
  */
 typedef uint8_t *xc_cpumap_t;
-- 
1.7.2.5
David Vrabel writes ("[Xen-devel] [PATCH 7/8] libxc: add hypercall buffer
arrays"):> From: David Vrabel <david.vrabel@citrix.com>
> 
> Hypercall buffer arrays are used when a hypercall takes a variable
> length array of buffers.
Ian Campbell did the hypercall buffers and is the relevant authority,
so CC''ing him.
Ian.
On Thu, 2013-02-21 at 17:48 +0000, David Vrabel wrote:> From: David Vrabel <david.vrabel@citrix.com> > > Hypercall buffer arrays are used when a hypercall takes a variable > length array of buffers.This looks good to me, I took a quick peek at the 4/4 patch in the kexec tools series which uses it as well. Acked-by: Ian Campbell <ian.campbell@citrix.com>> > Signed-off-by: David Vrabel <david.vrabel@citrix.com> > --- > tools/libxc/xc_hcall_buf.c | 73 ++++++++++++++++++++++++++++++++++++++++++++ > tools/libxc/xenctrl.h | 27 ++++++++++++++++ > 2 files changed, 100 insertions(+), 0 deletions(-) > > diff --git a/tools/libxc/xc_hcall_buf.c b/tools/libxc/xc_hcall_buf.c > index ced9abd..3e01f3f 100644 > --- a/tools/libxc/xc_hcall_buf.c > +++ b/tools/libxc/xc_hcall_buf.c > @@ -228,6 +228,79 @@ void xc__hypercall_bounce_post(xc_interface *xch, xc_hypercall_buffer_t *b) > xc__hypercall_buffer_free(xch, b); > } > > +struct xc_hypercall_buffer_array { > + unsigned max_bufs; > + xc_hypercall_buffer_t *bufs; > +}; > + > +xc_hypercall_buffer_array_t *xc_hypercall_buffer_array_create(xc_interface *xch, > + unsigned n) > +{ > + xc_hypercall_buffer_array_t *array; > + xc_hypercall_buffer_t *bufs = NULL; > + > + array = malloc(sizeof(*array)); > + if ( array == NULL ) > + goto error; > + > + bufs = calloc(n, sizeof(*bufs)); > + if ( bufs == NULL ) > + goto error; > + > + array->max_bufs = n; > + array->bufs = bufs; > + > + return array; > + > +error: > + free(bufs); > + free(array); > + return NULL; > +} > + > +void *xc__hypercall_buffer_array_alloc(xc_interface *xch, > + xc_hypercall_buffer_array_t *array, > + unsigned index, > + xc_hypercall_buffer_t *hbuf, > + size_t size) > +{ > + void *buf; > + > + if ( index >= array->max_bufs || array->bufs[index].hbuf ) > + abort(); > + > + buf = xc__hypercall_buffer_alloc(xch, hbuf, size); > + if ( buf ) > + array->bufs[index] = *hbuf; > + return buf; > +} > + > +void *xc__hypercall_buffer_array_get(xc_interface *xch, > + xc_hypercall_buffer_array_t *array, > + unsigned index, > + xc_hypercall_buffer_t *hbuf) > +{ > + if ( index >= array->max_bufs || array->bufs[index].hbuf == NULL ) > + abort(); > + > + *hbuf = array->bufs[index]; > + return array->bufs[index].hbuf; > +} > + > +void xc_hypercall_buffer_array_destroy(xc_interface *xc, > + xc_hypercall_buffer_array_t *array) > +{ > + unsigned i; > + > + if ( array == NULL ) > + return; > + > + for (i = 0; i < array->max_bufs; i++ ) > + xc__hypercall_buffer_free(xc, &array->bufs[i]); > + free(array->bufs); > + free(array); > +} > + > /* > * Local variables: > * mode: C > diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h > index 32122fd..c3b2c28 100644 > --- a/tools/libxc/xenctrl.h > +++ b/tools/libxc/xenctrl.h > @@ -317,6 +317,33 @@ void xc__hypercall_buffer_free_pages(xc_interface *xch, xc_hypercall_buffer_t *b > #define xc_hypercall_buffer_free_pages(_xch, _name, _nr) xc__hypercall_buffer_free_pages(_xch, HYPERCALL_BUFFER(_name), _nr) > > /* > + * Array of hypercall buffers. > + * > + * Create an array with xc_hypercall_buffer_array_create() and > + * populate it by declaring one hypercall buffer in a loop and > + * allocating the buffer with xc_hypercall_buffer_array_alloc(). > + * > + * To access a previously allocated buffers, declare a new hypercall > + * buffer and call xc_hypercall_buffer_array_get(). > + * > + * Destroy the array with xc_hypercall_buffer_array_destroy() to free > + * the array and all its alocated hypercall buffers. > + */ > +struct xc_hypercall_buffer_array; > +typedef struct xc_hypercall_buffer_array xc_hypercall_buffer_array_t; > + > +xc_hypercall_buffer_array_t *xc_hypercall_buffer_array_create(xc_interface *xch, unsigned n); > +void *xc__hypercall_buffer_array_alloc(xc_interface *xch, xc_hypercall_buffer_array_t *array, > + unsigned index, xc_hypercall_buffer_t *hbuf, size_t size); > +#define xc_hypercall_buffer_array_alloc(_xch, _array, _index, _name, _size) \ > + xc__hypercall_buffer_array_alloc(_xch, _array, _index, HYPERCALL_BUFFER(_name), _size) > +void *xc__hypercall_buffer_array_get(xc_interface *xch, xc_hypercall_buffer_array_t *array, > + unsigned index, xc_hypercall_buffer_t *hbuf); > +#define xc_hypercall_buffer_array_get(_xch, _array, _index, _name, _size) \ > + xc__hypercall_buffer_array_get(_xch, _array, _index, HYPERCALL_BUFFER(_name)) > +void xc_hypercall_buffer_array_destroy(xc_interface *xc, xc_hypercall_buffer_array_t *array); > + > +/* > * CPUMAP handling > */ > typedef uint8_t *xc_cpumap_t;