|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 1 of 2] tools/ocaml: libxc bindings: Fix stub_xc_readconsolering()
There are two problems with this function:
* The caml_{enter,leave}_blocking_section() calls mean that two threads can
compete for use of the static ring[] buffer.
* It fails to retrieve the entire buffer if the hypervisor has used 32K or
more of its console ring.
Unfortunately, fixing the code in a sensible is rather difficult. The Ocaml
caller expects to get the entire console ring in a single buffer. There are
no mechanisms to ask Xen for the size of the console ring (which is fixed
after boot). Even if there was a way to get the size of the console ring, the
XEN_SYSCTL_readconsole hypercall itself races with printk(), leading to
possibly discontinuities if the ring is full. The requirement for a NULL
terminating string means that a full console ring will appear to fail when use
the correct power of two, forcing us to double up again. Furthermore, libxc
will bounce the allocated buffer, as will caml_copy_string().
On the other hand, this is very definitely for debugging and testing, so lets
do the best we can to get the entire buffer, and accept the inefficiencies.
Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
diff -r 63594ce1708f -r 1daa30509f1c tools/ocaml/libs/xc/xenctrl_stubs.c
--- a/tools/ocaml/libs/xc/xenctrl_stubs.c
+++ b/tools/ocaml/libs/xc/xenctrl_stubs.c
@@ -523,27 +523,55 @@ CAMLprim value stub_xc_evtchn_reset(valu
CAMLreturn(Val_unit);
}
-
-#define RING_SIZE 32768
-static char ring[RING_SIZE];
-
+/* Maximum size of console ring we are prepared to read, 16MB */
+#define MAX_CONSOLE_RING_SIZE (1U << 24)
CAMLprim value stub_xc_readconsolering(value xch)
{
- unsigned int size = RING_SIZE - 1;
- char *ring_ptr = ring;
- int retval;
+ /* 32K starting size (adj for loop doubling at start) */
+ unsigned int ring_size = 1U << 14;
+ unsigned int nr_chars = ring_size;
+ char * ring = NULL;
+ int r;
CAMLparam1(xch);
+ CAMLlocal1(conring);
- caml_enter_blocking_section();
- retval = xc_readconsolering(_H(xch), ring_ptr, &size, 0, 0, NULL);
- caml_leave_blocking_section();
+ do
+ {
+ ring_size *= 2;
+ if ( ring_size > MAX_CONSOLE_RING_SIZE )
+ {
+ caml_failwith("Console ring too large");
+ CAMLreturn(Val_unit);
+ }
+ nr_chars = ring_size;
- if (retval)
- failwith_xc(_H(xch));
+ free(ring);
+ if ( ! ( ring = malloc(ring_size) ) )
+ {
+ caml_failwith("Out of memory");
+ CAMLreturn(Val_unit);
+ }
- ring[size] = '\0';
- CAMLreturn(caml_copy_string(ring));
+ caml_enter_blocking_section();
+ r = xc_readconsolering(_H(xch), ring, &nr_chars, 0, 0, NULL);
+ caml_leave_blocking_section();
+
+ if ( r )
+ {
+ failwith_xc(_H(xch));
+ free(ring);
+ CAMLreturn(Val_unit);
+ }
+
+ /* If nr_chars == ring_size, we have not read the entire ring.
+ * Try again with a larger buffer. */
+ } while ( nr_chars >= ring_size );
+
+ ring[nr_chars] = '\0';
+ conring = caml_copy_string(ring);
+ free(ring);
+ CAMLreturn(conring);
}
CAMLprim value stub_xc_send_debug_keys(value xch, value keys)
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |