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

Re: [Xen-devel] [PATCH] x86/mm: Improve ring management for memory events. Do not lose guest events



Hi, 

This looks fine to me; this time I'd like Olaf to review and test it
before I commit it. :)

A few comments inline below -- mostly nits about style. 

At 13:28 -0500 on 11 Jan (1326288504), Andres Lagar-Cavilla wrote:
> Signed-off-by: Adin Scannell <adin@xxxxxxxxxxx>
> Signed-off-by: Andres Lagar-Cavilla <andres@xxxxxxxxxxxxxxxx>

Housekeeping: please keep Olaf's Signed-off-by: line to cover the parts
of this patch that he's certifying. 

> diff -r d3342b370b6f -r a85e7d46401b xen/arch/x86/hvm/hvm.c
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -4188,25 +4188,31 @@ static int hvm_memory_event_traps(long p
>                                    unsigned long value, unsigned long old, 
>                                    bool_t gla_valid, unsigned long gla) 
>  {
> +    int rc;
>      struct vcpu* v = current;
>      struct domain *d = v->domain;
>      mem_event_request_t req;
> -    int rc;
>  

Please try to avoid this kind of unrelated shuffling (and I saw some
whitespace changes later on as well).  It's not a big deal, but it makes
reviewing a bit easier and avoids unnecessarily clashing with other
patches. 

> diff -r d3342b370b6f -r a85e7d46401b xen/arch/x86/mm/mem_event.c
> --- a/xen/arch/x86/mm/mem_event.c
> +++ b/xen/arch/x86/mm/mem_event.c

> +
> +/*
> + * mem_event_wake_requesters() will wakeup vcpus waiting for room in the

DYM mem_event_wake_blocked() ?

> + * ring. These vCPUs were paused on their way out after placing an event,
> + * but need to be resumed where the ring is capable of processing at least
> + * one event from them.
> + */
> +static void mem_event_wake_blocked(struct domain *d, struct mem_event_domain 
> *med)
> +{
> +    struct vcpu *v;
> +    int online = d->max_vcpus;
> +    int avail_req = mem_event_ring_available(med);
> +
> +    if( avail_req <= 0 || med->blocked == 0 )

s/if(/if (/

> +        return;
> +
> +    /*
> +     * We ensure that we only have vCPUs online if there are enough free 
> slots
> +     * for their memory events to be processed.  This will ensure that no
> +     * memory events are lost (due to the fact that certain types of events
> +     * cannot be replayed, we need to ensure that there is space in the ring
> +     * for when they are hit). 
> +     * See comment below in mem_event_put_request().
> +     */
> +    for_each_vcpu ( d, v )
> +        if ( test_bit(med->pause_flag, &v->pause_flags) )
> +            online--;
> +
> +    ASSERT(online == (d->max_vcpus - med->blocked));

Maybe better to do the cheap calculation as the default and the more
expensive one for the ASSERT?

> +    /* We remember which vcpu last woke up to avoid scanning always linearly
> +     * from zero and starving higher-numbered vcpus under high load */
> +    if ( d->vcpu )
> +    {
> +        int i, j, k;
> +
> +        for (i = med->last_vcpu_wake_up + 1, j = 0; j < d->max_vcpus; i++, 
> j++)
> +        {
> +            k = i % d->max_vcpus;
> +            v = d->vcpu[k];
> +            if ( !v )
> +                continue;
> +
> +            if ( !(med->blocked) || online >= avail_req )
> +               break;
> +
> +            if ( test_and_clear_bit(med->pause_flag, &v->pause_flags) )
> +            {
> +                vcpu_unpause(v);
> +                online++;
> +                med->blocked--;
> +                med->last_vcpu_wake_up = k;
> +            }
> +        }
> +    }
> +}
> +
> +/*
> + * In the event that a vCPU attempted to place an event in the ring and
> + * was unable to do so, it is queued on a wait queue.  These are woken as
> + * needed, and take precedence over the blocked vCPUs.
> + */
> +static void mem_event_wake_queued(struct domain *d, struct mem_event_domain 
> *med)
> +{
> +    int avail_req = mem_event_ring_available(med);
> +
> +    if ( avail_req > 0 )
> +        wake_up_nr(&med->wq, avail_req);
> +}
> +
> +/*
> + * mem_event_wake_waiters() will wakeup all vcpus waiting for the ring to

DYM mem_event_wake() ?

> + * become available.  If we have queued vCPUs, they get top priority. We
> + * are guaranteed that they will go through code paths that will eventually
> + * call mem_event_wake() again, ensuring that any blocked vCPUs will get
> + * unpaused once all the queued vCPUs have made it through.
> + */
> +void mem_event_wake(struct domain *d, struct mem_event_domain *med)
> +{
> +    if (!list_empty(&med->wq.list))
> +        mem_event_wake_queued(d, med);
> +    else
> +        mem_event_wake_blocked(d, med);
> +}
> +
> +static int mem_event_disable(struct domain *d, struct mem_event_domain *med)
> +{
> +    if( med->ring_page )

s/if(/if (/g  :)

> +    {
> +        struct vcpu *v;
> +
> +        mem_event_ring_lock(med);
> +
> +        if (!list_empty(&med->wq.list))

if ( ... ) 

> +        {
> +            mem_event_ring_unlock(med);
> +            return -EBUSY;
> +        }
> +
> +        unmap_domain_page(med->ring_page);
> +        med->ring_page = NULL;
> +
> +        unmap_domain_page(med->shared_page);
> +        med->shared_page = NULL;
> +
> +        /* Wake up everybody */
> +        wake_up_all(&med->wq);
> +
> +        /* Unblock all vCPUs */ 
> +        for_each_vcpu ( d, v )
> +        {
> +            if ( test_and_clear_bit(med->pause_flag, &v->pause_flags) )
> +            {
> +                vcpu_unpause(v);
> +                med->blocked--;
> +            }
> +        }
> +
> +        mem_event_ring_unlock(med);
> +    }
>  
>      return 0;
>  }
>  
> -void mem_event_put_request(struct domain *d, struct mem_event_domain *med, 
> mem_event_request_t *req)
> +static inline void mem_event_release_slot(struct domain *d,
> +                                          struct mem_event_domain *med)
> +{
> +    /* Update the accounting */
> +    if ( current->domain == d )
> +        med->target_producers--;
> +    else
> +        med->foreign_producers--;
> +
> +    /* Kick any waiters */
> +    mem_event_wake(d, med);
> +}
> +
> +/*
> + * mem_event_mark_and_pause() tags vcpu and put it to sleep.
> + * The vcpu will resume execution in mem_event_wake_waiters().
> + */
> +void mem_event_mark_and_pause(struct vcpu *v, struct mem_event_domain *med)
> +{
> +    if ( !test_and_set_bit(med->pause_flag, &v->pause_flags) )
> +    {
> +        vcpu_pause_nosync(v);
> +        med->blocked++;
> +    }
> +}
> +
> +/*
> + * This must be preceeded by a call to claim_slot(), and is guaranteed to

preceded

Cheers,

Tim.

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

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