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

Re: [Xen-devel] [PATCH v3 10/15] argo: implement the notify op



On Thu, Jan 10, 2019 at 4:22 AM Roger Pau Monné <royger@xxxxxxxxxxx> wrote:
>
>  On Mon, Jan 7, 2019 at 8:44 AM Christopher Clark
> <christopher.w.clark@xxxxxxxxx> wrote:
> >
> > Queries for data about space availability in registered rings and
> > causes notification to be sent when space has become available.
> >
> > The hypercall op populates a supplied data structure with information about
> > ring state, and if insufficent space is currently available in a given ring,
>
> insufficient

ack, fixed

> > the hypervisor will record the domain's expressed interest and notify it
> > when it observes that space has become available.
> >
> > Checks for free space occur when this notify op is invoked, so it may be
> > intentionally invoked with no data structure to populate
> > (ie. a NULL argument) to trigger such a check and consequent notifications.
> >
> > Limit the maximum number of notify requests in a single operation to a
> > simple fixed limit of 256.

> >
> > +static struct argo_ring_info *
> > +ring_find_info(const struct domain *d, const struct argo_ring_id *id);
> > +
> > +static struct argo_ring_info *
> > +ring_find_info_by_match(const struct domain *d, uint32_t port,
> > +                        domid_t partner_id);
>
> Can you place the static functions such that you don't need prototypes for 
> them?

Ack, yes. These have now been pulled to the top of the file and the
prototypes removed.

> > +
> >  /*
> >   * This hash function is used to distribute rings within the per-domain
> >   * hash tables (d->argo->ring_hash and d->argo_send_hash). The hash table
> > @@ -265,6 +275,17 @@ signal_domain(struct domain *d)
> >  }
> >
> >  static void
> > +signal_domid(domid_t domain_id)
> > +{
> > +    struct domain *d = get_domain_by_id(domain_id);
>
> Newline.

ack

>
> > +    if ( !d )
> > +        return;
> > +
> > +    signal_domain(d);
> > +    put_domain(d);
> > +}
> > +
> > +static void
> >  ring_unmap(struct argo_ring_info *ring_info)
> >  {
> >      unsigned int i;
> > @@ -473,6 +494,62 @@ get_sanitized_ring(xen_argo_ring_t *ring, struct 
> > argo_ring_info *ring_info)
> >      return 0;
> >  }
> >
> > +static uint32_t
> > +ringbuf_payload_space(struct domain *d, struct argo_ring_info *ring_info)
> > +{
> > +    xen_argo_ring_t ring;
> > +    uint32_t len;
> > +    int32_t ret;
>
> You use a signed type to internally store the return value, but the
> return type from the function itself is unsigned. Is it guaranteed
> that ret < INT32_MAX always?

It is, yes, so I've added a explanatory comment:

    /*
     * In a sanitized ring, we can rely on:
     *              (rx_ptr < ring_info->len)           &&
     *              (tx_ptr < ring_info->len)           &&
     *      (ring_info->len <= XEN_ARGO_MAX_RING_SIZE)
     *
     * and since: XEN_ARGO_MAX_RING_SIZE < INT32_MAX
     * therefore right here: ret < INT32_MAX
     * and we are safe to return it as a unsigned value from this function.
     * The subtractions below cannot increase its value.
     */

>
> > +
> > +    ASSERT(spin_is_locked(&ring_info->lock));
> > +
> > +    len = ring_info->len;
> > +    if ( !len )
> > +        return 0;
> > +
> > +    ret = get_sanitized_ring(&ring, ring_info);
> > +    if ( ret )
> > +        return 0;
> > +
> > +    argo_dprintk("sanitized ringbuf_payload_space: tx_ptr=%d rx_ptr=%d\n",
> > +                 ring.tx_ptr, ring.rx_ptr);
> > +
> > +    /*
> > +     * rx_ptr == tx_ptr means that the ring has been emptied, so return
> > +     * the maximum payload size that can be accepted -- see message size
> > +     * checking logic in the entry to ringbuf_insert which ensures that
> > +     * there is always one message slot (of size ROUNDUP_MESSAGE(1)) left
> > +     * available, preventing a ring from being entirely filled. This 
> > ensures
> > +     * that matching ring indexes always indicate an empty ring and not a
> > +     * full one.
> > +     * The subtraction here will not underflow due to minimum size 
> > constraints
> > +     * enforced on ring size elsewhere.
> > +     */
> > +    if ( ring.rx_ptr == ring.tx_ptr )
> > +        return len - sizeof(struct xen_argo_ring_message_header)
> > +                   - ROUNDUP_MESSAGE(1);
>
> Why not do something like:
>
> ret = ring.rx_ptr - ring.tx_ptr;
> if ( ret <= 0)
>     ret += len;
>
> Instead of this early return?
>
> The only difference when the ring is full is that len should be used
> instead of the ptr difference.

That's much nicer -- thanks. Done.

> >
> >  static int
> > +fill_ring_data(const struct domain *currd,
> > +               XEN_GUEST_HANDLE(xen_argo_ring_data_ent_t) data_ent_hnd)
> > +{
> > +    xen_argo_ring_data_ent_t ent;
> > +    struct domain *dst_d;
> > +    struct argo_ring_info *ring_info;
> > +    int ret;
> > +
> > +    ASSERT(rw_is_locked(&argo_lock));
> > +
> > +    ret = __copy_from_guest(&ent, data_ent_hnd, 1) ? -EFAULT : 0;
> > +    if ( ret )
> > +        goto out;
>
> if ( __copy_from_guest(&ent, data_ent_hnd, 1) )
>     return -EFAULT;
>
> And you can get rid of the out label.

ack, done.

>
> > +
> > +    argo_dprintk("fill_ring_data: ent.ring.domain=%u,ent.ring.port=%x\n",
> > +                 ent.ring.domain_id, ent.ring.port);
> > +
> > +    ent.flags = 0;
>
> Please memset ent to 0 or initialize it to { }, or else you are
> leaking hypervisor stack data to the guest in the padding field.

ok - I've added the initializer, thanks.
Was it really leaking stack data though because the struct should have
been fully populated, including the padding field, with the
__copy_from_guest above?


> > +static void
> > +notify_check_pending(struct domain *currd)
> > +{
> > +    unsigned int i;
> > +    HLIST_HEAD(to_notify);
> > +
> > +    ASSERT(rw_is_locked(&argo_lock));
> > +
> > +    read_lock(&currd->argo->lock);
> > +
> > +    for ( i = 0; i < ARGO_HTABLE_SIZE; i++ )
> > +    {
> > +        struct hlist_node *node, *next;
> > +        struct argo_ring_info *ring_info;
> > +
> > +        hlist_for_each_entry_safe(ring_info, node, next,
> > +                                  &currd->argo->ring_hash[i], node)
> > +        {
> > +            notify_ring(currd, ring_info, &to_notify);
> > +        }
>
> No need for the braces.

Fixed - thanks.

Christopher

_______________________________________________
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®.