[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 4 of 5] tools/ocaml: libxc bindings: Fix stub_xc_readconsolering()



On Wed, 2013-02-20 at 18:05 +0000, Andrew Cooper wrote:
> 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.
> 
> Rewrite the function using the new xc_consoleringsize() and
> xc_readconsolering_buffer() functions to efficiently grab the entire console
> ring.
> 
> Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> 
> diff -r 6b8c513cff4f -r a73d0c5a5b24 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,61 @@ 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)

A bit arbitrary, why not just let it handle whatever the hypervisor
throws at it. If there is to be a limit it probably belongs on the
hypervisor side, but in the meantime someone who passes consring=1G can
keep all the pieces ;-)

>  CAMLprim value stub_xc_readconsolering(value xch)
>  {
> -     unsigned int size = RING_SIZE - 1;
> -     char *ring_ptr = ring;
> -     int retval;
> +     uint64_t conring_size;
> +     DECLARE_HYPERCALL_BUFFER(char, ring);
> +     unsigned int nr_chars;
> +     int r;
>  
>       CAMLparam1(xch);
> +     CAMLlocal1(conring);
> +
> +     r = xc_consoleringsize(_H(xch), &conring_size);

static int consoleringsize and only call this once the first time?

> +
> +     if ( r )
> +     {
> +             failwith_xc(_H(xch));
> +             CAMLreturn(Val_unit);
> +     }
> +
> +     /* Round conring_size up to the next page, for NULL terminator and
> +        slop from a race with printk() in the hypervisor. */
> +     conring_size = (conring_size + XC_PAGE_SIZE) & XC_PAGE_MASK;
> +     nr_chars = conring_size-1;
> +
> +     if ( conring_size > MAX_CONSOLE_RING_SIZE )
> +     {
> +             caml_failwith("Console ring too large");
> +             CAMLreturn(Val_unit);
> +     }
> +
> +     ring = xc_hypercall_buffer_alloc(_H(xch), ring, conring_size);
> +
> +     if ( ! ring )
> +     {
> +             failwith_xc(_H(xch));
> +             CAMLreturn(Val_unit);
> +     }
>  
>       caml_enter_blocking_section();
> -     retval = xc_readconsolering(_H(xch), ring_ptr, &size, 0, 0, NULL);
> +     r = xc_readconsolering_buffer(_H(xch), HYPERCALL_BUFFER(ring),
> +                                   &nr_chars, 0, 0, NULL);
>       caml_leave_blocking_section();
>  
> -     if (retval)
> +     if ( r )
> +     {
>               failwith_xc(_H(xch));

Doesn't this (due to caml_raise...) end up exiting synchronously via a
longjmp back to the runtime? i.e. it leaks the buffer which is only
free'd after.

It's a good idea to cc xen-api@ with ocaml changes, for this sort of
reason...


> +             xc_hypercall_buffer_free(_H(xch), ring);
> +             CAMLreturn(Val_unit);

I think CAMLnoreturn here.

> +     }
>  
> -     ring[size] = '\0';
> -     CAMLreturn(caml_copy_string(ring));
> +     ring[nr_chars] = '\0';
> +     conring = caml_copy_string(ring);
> +     xc_hypercall_buffer_free(_H(xch), 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.