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

Re: [Xen-devel] [PATCH 16/25] argo: implement the notify op



>>> On 01.12.18 at 02:32, <christopher.w.clark@xxxxxxxxx> wrote:
> +static uint32_t
> +argo_ringbuf_payload_space(struct domain *d, struct argo_ring_info 
> *ring_info)
> +{
> +    argo_ring_t ring;
> +    int32_t ret;
> +
> +    ASSERT(spin_is_locked(&ring_info->lock));
> +
> +    ring.len = ring_info->len;
> +    if ( !ring.len )
> +        return 0;
> +
> +    ring.tx_ptr = ring_info->tx_ptr;
> +
> +    if ( argo_ringbuf_get_rx_ptr(ring_info, &ring.rx_ptr) )
> +        return 0;
> +
> +    argo_dprintk("argo_ringbuf_payload_space: tx_ptr=%d rx_ptr=%d\n",
> +                 ring.tx_ptr, ring.rx_ptr);
> +
> +    if ( ring.rx_ptr == ring.tx_ptr )
> +        return ring.len - sizeof(struct argo_ring_message_header);
> +
> +    ret = ring.rx_ptr - ring.tx_ptr;
> +    if ( ret < 0 )
> +        ret += ring.len;

Seeing these two if()-s - how is an empty ring distinguished from
a completely full one? I'm getting the impression that
ring.rx_ptr == ring.tx_ptr in both cases.

> +    ret -= sizeof(struct argo_ring_message_header);
> +    ret -= ARGO_ROUNDUP(1);

Wouldn't you instead better round ret to a suitable multiple of
whatever granularity you try to arrange for here? Otherwise
what is this extra subtraction supposed to do?

> @@ -627,6 +679,43 @@ argo_pending_remove_all(struct argo_ring_info *ring_info)
>      }
>  }
>  
> +static void
> +argo_pending_notify(struct hlist_head *to_notify)
> +{
> +    struct hlist_node *node, *next;
> +    struct argo_pending_ent *pending_ent;
> +
> +    ASSERT(rw_is_locked(&argo_lock));
> +
> +    hlist_for_each_entry_safe(pending_ent, node, next, to_notify, node)
> +    {
> +        hlist_del(&pending_ent->node);
> +        argo_signal_domid(pending_ent->id);
> +        xfree(pending_ent);
> +    }
> +}
> +
> +static void
> +argo_pending_find(const struct domain *d, struct argo_ring_info *ring_info,
> +                  uint32_t payload_space, struct hlist_head *to_notify)
> +{
> +    struct hlist_node *node, *next;
> +    struct argo_pending_ent *ent;
> +
> +    ASSERT(rw_is_locked(&d->argo->lock));
> +
> +    spin_lock(&ring_info->lock);
> +    hlist_for_each_entry_safe(ent, node, next, &ring_info->pending, node)
> +    {
> +        if ( payload_space >= ent->len )
> +        {
> +            hlist_del(&ent->node);
> +            hlist_add_head(&ent->node, to_notify);
> +        }
> +    }

So if there's space available to fit e.g. just the first pending entry,
you'd continue the loop and also signal all others, provided their
lengths aren't too big? What good does producing such a burst of
notifications do, when only one of the interested parties is
actually going to be able to put something on the ring?

> @@ -705,6 +812,107 @@ argo_ring_remove_info(struct domain *d, struct 
> argo_ring_info *ring_info)
>      xfree(ring_info);
>  }
>  
> +/*ring data*/

Now this comment is malformed in any event.

> +static int
> +argo_fill_ring_data(struct domain *src_d,

const?

> +static long
> +argo_notify(struct domain *d,
> +            XEN_GUEST_HANDLE_PARAM(argo_ring_data_t) ring_data_hnd)
> +{
> +    argo_ring_data_t ring_data;
> +    int ret = 0;
> +
> +    read_lock(&argo_lock);
> +
> +    if ( !d->argo )
> +    {
> +        read_unlock(&argo_lock);
> +        argo_dprintk("!d->argo, ENODEV\n");
> +        return -ENODEV;
> +    }
> +
> +    argo_notify_check_pending(d);
> +
> +    do {
> +        if ( !guest_handle_is_null(ring_data_hnd) )
> +        {
> +            /* Quick sanity check on ring_data_hnd */
> +            ret = copy_field_from_guest_errno(&ring_data, ring_data_hnd, 
> magic);
> +            if ( ret )
> +                break;
> +
> +            if ( ring_data.magic != ARGO_RING_DATA_MAGIC )
> +            {
> +                argo_dprintk(
> +                    "ring.magic(%"PRIx64") != ARGO_RING_MAGIC(%llx), 
> EINVAL\n",
> +                    ring_data.magic, ARGO_RING_MAGIC);
> +                ret = -EINVAL;
> +                break;
> +            }
> +
> +            ret = copy_from_guest_errno(&ring_data, ring_data_hnd, 1);
> +            if ( ret )
> +                break;
> +
> +            {
> +                /*
> +                 * This is a guest pointer passed as a field in a struct
> +                 * so XEN_GUEST_HANDLE is used.
> +                 */
> +                XEN_GUEST_HANDLE(argo_ring_data_ent_t) ring_data_ent_hnd;
> +                ring_data_ent_hnd = guest_handle_for_field(ring_data_hnd,
> +                                                           
> argo_ring_data_ent_t,
> +                                                           data[0]);
> +                ret = argo_fill_ring_data_array(d, ring_data.nent,
> +                                                ring_data_ent_hnd);
> +            }

Stray braces and bogus indentation: The declaration can move up
and then you don't need the braces and the extra level of indentation.

> @@ -103,6 +104,40 @@ typedef struct argo_ring
>   */
>  #define ARGO_ROUNDUP(a) (((a) + 0xf) & ~(typeof(a))0xf)
>  
> +/*
> + * Notify flags
> + */
> +/* Ring is empty */
> +#define ARGO_RING_DATA_F_EMPTY       (1U << 0)
> +/* Ring exists */
> +#define ARGO_RING_DATA_F_EXISTS      (1U << 1)
> +/* Pending interrupt exists. Do not rely on this field - for profiling only 
> */
> +#define ARGO_RING_DATA_F_PENDING     (1U << 2)
> +/* Sufficient space to queue space_required bytes exists */
> +#define ARGO_RING_DATA_F_SUFFICIENT  (1U << 3)
> +
> +typedef struct argo_ring_data_ent
> +{
> +    argo_addr_t ring;
> +    uint16_t flags;
> +    uint16_t pad;
> +    uint32_t space_required;
> +    uint32_t max_message_size;
> +} argo_ring_data_ent_t;
> +
> +typedef struct argo_ring_data
> +{
> +    uint64_t magic;

What is this good for?

> @@ -179,6 +214,33 @@ struct argo_ring_message_header
>   */
>  #define ARGO_MESSAGE_OP_sendv               5
>  
> +/*
> + * ARGO_MESSAGE_OP_notify
> + *
> + * Asks Xen for information about other rings in the system.
> + *
> + * ent->ring is the argo_addr_t of the ring you want information on.
> + * Uses the same ring matching rules as ARGO_MESSAGE_OP_sendv.
> + *
> + * ent->space_required : if this field is not null then Xen will check
> + * that there is space in the destination ring for this many bytes of  
> payload.
> + * If sufficient space is available, it will set ARGO_RING_DATA_F_SUFFICIENT
> + * and CANCEL any pending notification for that ent->ring; otherwise it
> + * will schedule a notification event and the flag will not be set.
> + *
> + * These flags are set by Xen when notify replies:
> + * ARGO_RING_DATA_F_EMPTY       ring is empty
> + * ARGO_RING_DATA_F_PENDING     notify event is pending - * don't rely on 
> this *
> + * ARGO_RING_DATA_F_SUFFICIENT  sufficient space for space_required is there
> + * ARGO_RING_DATA_F_EXISTS      ring exists
> + *
> + * arg1: XEN_GUEST_HANDLE(argo_ring_data_t) ring_data (may be NULL)
> + * arg2: NULL
> + * arg3: 0 (ZERO)
> + * arg4: 0 (ZERO)

Another observation I probably should have made earlier: You
don't check that the NULL/ZERO specified argument are indeed
so. Just like for padding fields, please do.

Jan


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

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