[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 |