Andrew Cooper, on Tue 10 Nov 2015 10:46:44 +0000, wrote:
> ml_interface_{read,write}() would miscalculate the quantity of
> data/space in the ring if it crossed the ring boundary, and incorrectly
> return a short read/write.
> 
> This causes a protocol stall, as either side of the ring ends up waiting
> for what they believe to be the other side needing to take the next
> action.
> 
> Correct the calculations to cope with crossing the ring boundary.
> 
> In addition, correct the error detection.  It is a hard error if the
> producer index gets more than a ring size ahead of the consumer, or if
> the consumer ever overtakes the producer.
> 
> Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com>

Reviewed-by: Samuel Thibault <samuel.thiba...@ens-lyon.org>

> ---
> CC: Ian Campbell <ian.campb...@citrix.com>
> CC: Ian Jackson <ian.jack...@eu.citrix.com>
> CC: Wei Liu <wei.l...@citrix.com>
> CC: David Scott <d...@recoil.org>
> CC: Samuel Thibault <samuel.thiba...@ens-lyon.org>
> 
> v2:
>  * Correct error handling adjustments
>  * More fixes to space calculations
>  * Fix whitespace errors
>  * No longer RFC - passed XenServer sanity testing
> ---
>  tools/ocaml/libs/xb/xs_ring_stubs.c | 64 
> +++++++++++++++++++++++++------------
>  1 file changed, 44 insertions(+), 20 deletions(-)
> 
> diff --git a/tools/ocaml/libs/xb/xs_ring_stubs.c 
> b/tools/ocaml/libs/xb/xs_ring_stubs.c
> index fd561a2..4737870 100644
> --- a/tools/ocaml/libs/xb/xs_ring_stubs.c
> +++ b/tools/ocaml/libs/xb/xs_ring_stubs.c
> @@ -50,7 +50,7 @@ CAMLprim value ml_interface_read(value ml_interface,
>  
>       struct xenstore_domain_interface *intf = interface->addr;
>       XENSTORE_RING_IDX cons, prod; /* offsets only */
> -     int to_read;
> +     int total_data, data;
>       uint32_t connection;
>  
>       cons = *(volatile uint32_t*)&intf->req_cons;
> @@ -65,19 +65,28 @@ CAMLprim value ml_interface_read(value ml_interface,
>       if ((prod - cons) > XENSTORE_RING_SIZE)
>               caml_failwith("bad connection");
>  
> -     if (prod == cons) {
> +     /* Check for any pending data at all. */
> +     total_data = prod - cons;
> +     if (total_data == 0) {
> +             /* No pending data at all. */
>               result = 0;
>               goto exit;
>       }
> -     cons = MASK_XENSTORE_IDX(cons);
> -     prod = MASK_XENSTORE_IDX(prod);
> -     if (prod > cons)
> -             to_read = prod - cons;
> -     else
> -             to_read = XENSTORE_RING_SIZE - cons;
> -     if (to_read < len)
> -             len = to_read;
> -     memcpy(buffer, intf->req + cons, len);
> +     else if (total_data < len)
> +             /* Some data - make a partial read. */
> +             len = total_data;
> +
> +     /* Check whether data crosses the end of the ring. */
> +     data = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
> +     if (len < data)
> +             /* Data within the remaining part of the ring. */
> +             memcpy(buffer, intf->req + MASK_XENSTORE_IDX(cons), len);
> +     else {
> +             /* Data crosses the ring boundary. Read both halves. */
> +             memcpy(buffer, intf->req + MASK_XENSTORE_IDX(cons), data);
> +             memcpy(buffer + data, intf->req, len - data);
> +     }
> +
>       xen_mb();
>       intf->req_cons += len;
>       result = len;
> @@ -100,7 +109,7 @@ CAMLprim value ml_interface_write(value ml_interface,
>  
>       struct xenstore_domain_interface *intf = interface->addr;
>       XENSTORE_RING_IDX cons, prod;
> -     int can_write;
> +     int total_space, space;
>       uint32_t connection;
>  
>       cons = *(volatile uint32_t*)&intf->rsp_cons;
> @@ -111,17 +120,32 @@ CAMLprim value ml_interface_write(value ml_interface,
>               caml_raise_constant(*caml_named_value("Xb.Reconnect"));
>  
>       xen_mb();
> -     if ( (prod - cons) >= XENSTORE_RING_SIZE ) {
> +
> +     if ((prod - cons) > XENSTORE_RING_SIZE)
> +             caml_failwith("bad connection");
> +
> +     /* Check for space to write the full message. */
> +     total_space = XENSTORE_RING_SIZE - (prod - cons);
> +     if (total_space == 0) {
> +             /* No space at all - exit having done nothing. */
>               result = 0;
>               goto exit;
>       }
> -     if (MASK_XENSTORE_IDX(prod) >= MASK_XENSTORE_IDX(cons))
> -             can_write = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
> -     else 
> -             can_write = MASK_XENSTORE_IDX(cons) - MASK_XENSTORE_IDX(prod);
> -     if (can_write < len)
> -             len = can_write;
> -     memcpy(intf->rsp + MASK_XENSTORE_IDX(prod), buffer, len);
> +     else if (total_space < len)
> +             /* Some space - make a partial write. */
> +             len = total_space;
> +
> +     /* Check for space until the ring wraps. */
> +     space = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
> +     if (len < space)
> +             /* Message fits inside the remaining part of the ring. */
> +             memcpy(intf->rsp + MASK_XENSTORE_IDX(prod), buffer, len);
> +     else {
> +             /* Message wraps around the end of the ring. Write both halves. 
> */
> +             memcpy(intf->rsp + MASK_XENSTORE_IDX(prod), buffer, space);
> +             memcpy(intf->rsp, buffer + space, len - space);
> +     }
> +
>       xen_mb();
>       intf->rsp_prod += len;
>       result = len;
> -- 
> 2.1.4
> 

-- 
Samuel
As usual, this being a 1.3.x release, I haven't even compiled this
kernel yet.  So if it works, you should be doubly impressed.
(Linus Torvalds, announcing kernel 1.3.3 on the linux-kernel mailing list.)

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

Reply via email to