ia64/xen-unstable

changeset 11567:8860eba3dcad

[XEN] Fix domctl for changing VCPU affinity.

Now works for any VCPU, including the caller's VCPU.

By not synchronously pausing the affected VCPU we avoid
any risk of deadlock.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Thu Sep 21 19:34:00 2006 +0100 (2006-09-21)
parents 449dcaff2551
children 8c29bf7ede67
files xen/common/domctl.c xen/common/sched_credit.c xen/common/sched_sedf.c xen/common/schedule.c xen/include/xen/sched-if.h xen/include/xen/sched.h
line diff
     1.1 --- a/xen/common/domctl.c	Thu Sep 21 18:29:48 2006 +0100
     1.2 +++ b/xen/common/domctl.c	Thu Sep 21 19:34:00 2006 +0100
     1.3 @@ -356,37 +356,20 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
     1.4          struct vcpu *v;
     1.5          cpumask_t new_affinity;
     1.6  
     1.7 +        ret = -ESRCH;
     1.8          if ( d == NULL )
     1.9 -        {
    1.10 -            ret = -ESRCH;            
    1.11              break;
    1.12 -        }
    1.13 -        
    1.14 -        if ( (op->u.vcpuaffinity.vcpu >= MAX_VIRT_CPUS) ||
    1.15 -             !d->vcpu[op->u.vcpuaffinity.vcpu] )
    1.16 -        {
    1.17 -            ret = -EINVAL;
    1.18 -            put_domain(d);
    1.19 -            break;
    1.20 -        }
    1.21  
    1.22 -        v = d->vcpu[op->u.vcpuaffinity.vcpu];
    1.23 -        if ( v == NULL )
    1.24 -        {
    1.25 -            ret = -ESRCH;
    1.26 -            put_domain(d);
    1.27 -            break;
    1.28 -        }
    1.29 +        ret = -EINVAL;
    1.30 +        if ( op->u.vcpuaffinity.vcpu >= MAX_VIRT_CPUS )
    1.31 +            goto vcpuaffinity_out;
    1.32 +
    1.33 +        ret = -ESRCH;
    1.34 +        if ( (v = d->vcpu[op->u.vcpuaffinity.vcpu]) == NULL )
    1.35 +            goto vcpuaffinity_out;
    1.36  
    1.37          if ( op->cmd == XEN_DOMCTL_setvcpuaffinity )
    1.38          {
    1.39 -            if ( v == current )
    1.40 -            {
    1.41 -                ret = -EINVAL;
    1.42 -                put_domain(d);
    1.43 -                break;
    1.44 -            }
    1.45 -
    1.46              xenctl_cpumap_to_cpumask(
    1.47                  &new_affinity, &op->u.vcpuaffinity.cpumap);
    1.48              ret = vcpu_set_affinity(v, &new_affinity);
    1.49 @@ -395,8 +378,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
    1.50          {
    1.51              cpumask_to_xenctl_cpumap(
    1.52                  &op->u.vcpuaffinity.cpumap, &v->cpu_affinity);
    1.53 +            ret = 0;
    1.54          }
    1.55  
    1.56 +    vcpuaffinity_out:
    1.57          put_domain(d);
    1.58      }
    1.59      break;
     2.1 --- a/xen/common/sched_credit.c	Thu Sep 21 18:29:48 2006 +0100
     2.2 +++ b/xen/common/sched_credit.c	Thu Sep 21 19:34:00 2006 +0100
     2.3 @@ -572,47 +572,6 @@ csched_vcpu_wake(struct vcpu *vc)
     2.4  }
     2.5  
     2.6  static int
     2.7 -csched_vcpu_set_affinity(struct vcpu *vc, cpumask_t *affinity)
     2.8 -{
     2.9 -    unsigned long flags;
    2.10 -    int lcpu;
    2.11 -
    2.12 -    if ( vc == current )
    2.13 -    {
    2.14 -        /* No locking needed but also can't move on the spot... */
    2.15 -        if ( !cpu_isset(vc->processor, *affinity) )
    2.16 -            return -EBUSY;
    2.17 -
    2.18 -        vc->cpu_affinity = *affinity;
    2.19 -    }
    2.20 -    else
    2.21 -    {
    2.22 -        /* Pause, modify, and unpause. */
    2.23 -        vcpu_pause(vc);
    2.24 -
    2.25 -        vc->cpu_affinity = *affinity;
    2.26 -        if ( !cpu_isset(vc->processor, vc->cpu_affinity) )
    2.27 -        {
    2.28 -            /*
    2.29 -             * We must grab the scheduler lock for the CPU currently owning
    2.30 -             * this VCPU before changing its ownership.
    2.31 -             */
    2.32 -            vcpu_schedule_lock_irqsave(vc, flags);
    2.33 -            lcpu = vc->processor;
    2.34 -
    2.35 -            vc->processor = first_cpu(vc->cpu_affinity);
    2.36 -
    2.37 -            spin_unlock_irqrestore(&per_cpu(schedule_data, lcpu).schedule_lock,
    2.38 -                                   flags);
    2.39 -        }
    2.40 -
    2.41 -        vcpu_unpause(vc);
    2.42 -    }
    2.43 -
    2.44 -    return 0;
    2.45 -}
    2.46 -
    2.47 -static int
    2.48  csched_dom_cntl(
    2.49      struct domain *d,
    2.50      struct xen_domctl_scheduler_op *op)
    2.51 @@ -1227,8 +1186,6 @@ struct scheduler sched_credit_def = {
    2.52      .sleep          = csched_vcpu_sleep,
    2.53      .wake           = csched_vcpu_wake,
    2.54  
    2.55 -    .set_affinity   = csched_vcpu_set_affinity,
    2.56 -
    2.57      .adjust         = csched_dom_cntl,
    2.58  
    2.59      .tick           = csched_tick,
     3.1 --- a/xen/common/sched_sedf.c	Thu Sep 21 18:29:48 2006 +0100
     3.2 +++ b/xen/common/sched_sedf.c	Thu Sep 21 19:34:00 2006 +0100
     3.3 @@ -1175,20 +1175,6 @@ void sedf_wake(struct vcpu *d)
     3.4  }
     3.5  
     3.6  
     3.7 -static int sedf_set_affinity(struct vcpu *v, cpumask_t *affinity)
     3.8 -{
     3.9 -    if ( v == current )
    3.10 -        return cpu_isset(v->processor, *affinity) ? 0 : -EBUSY;
    3.11 -
    3.12 -    vcpu_pause(v);
    3.13 -    v->cpu_affinity = *affinity;
    3.14 -    v->processor = first_cpu(v->cpu_affinity);
    3.15 -    vcpu_unpause(v);
    3.16 -
    3.17 -    return 0;
    3.18 -}
    3.19 -
    3.20 -
    3.21  /* Print a lot of useful information about a domains in the system */
    3.22  static void sedf_dump_domain(struct vcpu *d)
    3.23  {
    3.24 @@ -1449,7 +1435,6 @@ struct scheduler sched_sedf_def = {
    3.25      .sleep          = sedf_sleep,
    3.26      .wake           = sedf_wake,
    3.27      .adjust         = sedf_adjust,
    3.28 -    .set_affinity   = sedf_set_affinity
    3.29  };
    3.30  
    3.31  /*
     4.1 --- a/xen/common/schedule.c	Thu Sep 21 18:29:48 2006 +0100
     4.2 +++ b/xen/common/schedule.c	Thu Sep 21 19:34:00 2006 +0100
     4.3 @@ -181,15 +181,56 @@ void vcpu_wake(struct vcpu *v)
     4.4      TRACE_2D(TRC_SCHED_WAKE, v->domain->domain_id, v->vcpu_id);
     4.5  }
     4.6  
     4.7 +static void vcpu_migrate(struct vcpu *v)
     4.8 +{
     4.9 +    cpumask_t online_affinity;
    4.10 +    unsigned long flags;
    4.11 +    int old_cpu;
    4.12 +
    4.13 +    vcpu_schedule_lock_irqsave(v, flags);
    4.14 +
    4.15 +    if ( test_bit(_VCPUF_running, &v->vcpu_flags) ||
    4.16 +         !test_and_clear_bit(_VCPUF_migrating, &v->vcpu_flags) )
    4.17 +    {
    4.18 +        vcpu_schedule_unlock_irqrestore(v, flags);
    4.19 +        return;
    4.20 +    }
    4.21 +
    4.22 +    /* Switch to new CPU, then unlock old CPU. */
    4.23 +    old_cpu = v->processor;
    4.24 +    cpus_and(online_affinity, v->cpu_affinity, cpu_online_map);
    4.25 +    v->processor = first_cpu(online_affinity);
    4.26 +    spin_unlock_irqrestore(
    4.27 +        &per_cpu(schedule_data, old_cpu).schedule_lock, flags);
    4.28 +
    4.29 +    /* Wake on new CPU. */
    4.30 +    vcpu_wake(v);
    4.31 +}
    4.32 +
    4.33  int vcpu_set_affinity(struct vcpu *v, cpumask_t *affinity)
    4.34  {
    4.35      cpumask_t online_affinity;
    4.36 +    unsigned long flags;
    4.37  
    4.38      cpus_and(online_affinity, *affinity, cpu_online_map);
    4.39      if ( cpus_empty(online_affinity) )
    4.40          return -EINVAL;
    4.41  
    4.42 -    return SCHED_OP(set_affinity, v, affinity);
    4.43 +    vcpu_schedule_lock_irqsave(v, flags);
    4.44 +
    4.45 +    v->cpu_affinity = *affinity;
    4.46 +    if ( !cpu_isset(v->processor, v->cpu_affinity) )
    4.47 +        set_bit(_VCPUF_migrating, &v->vcpu_flags);
    4.48 +
    4.49 +    vcpu_schedule_unlock_irqrestore(v, flags);
    4.50 +
    4.51 +    if ( test_bit(_VCPUF_migrating, &v->vcpu_flags) )
    4.52 +    {
    4.53 +        vcpu_sleep_nosync(v);
    4.54 +        vcpu_migrate(v);
    4.55 +    }
    4.56 +
    4.57 +    return 0;
    4.58  }
    4.59  
    4.60  /* Block the currently-executing domain until a pertinent event occurs. */
    4.61 @@ -555,6 +596,13 @@ static void __enter_scheduler(void)
    4.62      context_switch(prev, next);
    4.63  }
    4.64  
    4.65 +void context_saved(struct vcpu *prev)
    4.66 +{
    4.67 +    clear_bit(_VCPUF_running, &prev->vcpu_flags);
    4.68 +
    4.69 +    if ( unlikely(test_bit(_VCPUF_migrating, &prev->vcpu_flags)) )
    4.70 +        vcpu_migrate(prev);
    4.71 +}
    4.72  
    4.73  /****************************************************************************
    4.74   * Timers: the scheduler utilises a number of timers
     5.1 --- a/xen/include/xen/sched-if.h	Thu Sep 21 18:29:48 2006 +0100
     5.2 +++ b/xen/include/xen/sched-if.h	Thu Sep 21 19:34:00 2006 +0100
     5.3 @@ -69,8 +69,6 @@ struct scheduler {
     5.4      void         (*sleep)          (struct vcpu *);
     5.5      void         (*wake)           (struct vcpu *);
     5.6  
     5.7 -    int          (*set_affinity)   (struct vcpu *, cpumask_t *);
     5.8 -
     5.9      struct task_slice (*do_schedule) (s_time_t);
    5.10  
    5.11      int          (*adjust)         (struct domain *,
     6.1 --- a/xen/include/xen/sched.h	Thu Sep 21 18:29:48 2006 +0100
     6.2 +++ b/xen/include/xen/sched.h	Thu Sep 21 19:34:00 2006 +0100
     6.3 @@ -312,7 +312,7 @@ extern void context_switch(
     6.4   * saved to memory. Alternatively, if implementing lazy context switching,
     6.5   * ensure that invoking sync_vcpu_execstate() will switch and commit @prev.
     6.6   */
     6.7 -#define context_saved(prev) (clear_bit(_VCPUF_running, &(prev)->vcpu_flags))
     6.8 +extern void context_saved(struct vcpu *prev);
     6.9  
    6.10  /* Called by the scheduler to continue running the current VCPU. */
    6.11  extern void continue_running(
    6.12 @@ -386,9 +386,12 @@ extern struct domain *domain_list;
    6.13   /* VCPU is paused by the hypervisor? */
    6.14  #define _VCPUF_paused          11
    6.15  #define VCPUF_paused           (1UL<<_VCPUF_paused)
    6.16 -/* VCPU is blocked awaiting an event to be consumed by Xen. */
    6.17 + /* VCPU is blocked awaiting an event to be consumed by Xen. */
    6.18  #define _VCPUF_blocked_in_xen  12
    6.19  #define VCPUF_blocked_in_xen   (1UL<<_VCPUF_blocked_in_xen)
    6.20 + /* VCPU affinity has changed: migrating to a new CPU. */
    6.21 +#define _VCPUF_migrating       13
    6.22 +#define VCPUF_migrating        (1UL<<_VCPUF_migrating)
    6.23  
    6.24  /*
    6.25   * Per-domain flags (domain_flags).
    6.26 @@ -418,9 +421,15 @@ extern struct domain *domain_list;
    6.27  static inline int vcpu_runnable(struct vcpu *v)
    6.28  {
    6.29      return ( !(v->vcpu_flags &
    6.30 -               (VCPUF_blocked|VCPUF_down|VCPUF_paused|VCPUF_blocked_in_xen)) &&
    6.31 +               ( VCPUF_blocked |
    6.32 +                 VCPUF_down |
    6.33 +                 VCPUF_paused |
    6.34 +                 VCPUF_blocked_in_xen |
    6.35 +                 VCPUF_migrating )) &&
    6.36               !(v->domain->domain_flags &
    6.37 -               (DOMF_shutdown|DOMF_ctrl_pause|DOMF_paused)) );
    6.38 +               ( DOMF_shutdown |
    6.39 +                 DOMF_ctrl_pause |
    6.40 +                 DOMF_paused )));
    6.41  }
    6.42  
    6.43  void vcpu_pause(struct vcpu *v);