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

[Xen-changelog] [xen master] sched: DOMCTL_*vcpuaffinity works with hard and soft affinity



commit 6e4ecc6d5884b816ed6eb1949561fdfb85acd179
Author:     Dario Faggioli <dario.faggioli@xxxxxxxxxx>
AuthorDate: Mon Jun 16 12:13:25 2014 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Mon Jun 16 12:13:25 2014 +0200

    sched: DOMCTL_*vcpuaffinity works with hard and soft affinity
    
    by adding a flag for the caller to specify which one he cares about.
    
    At the same time, enable the caller to get back the "effective affinity"
    of the vCPU. That is the intersection between cpupool's cpus, the (new)
    hard affinity and, for soft affinity, the (new) soft affinity. In fact,
    despite what has been successfully set with the DOMCTL_setvcpuaffinity
    hypercall, the Xen scheduler will never run a vCPU outside of its hard
    affinity or of its domain's cpupool.
    
    This happens by adding another cpumap to the interface and making both
    the cpumaps IN/OUT parameters (for DOMCTL_setvcpuaffinity, they're of
    course out-only for DOMCTL_getvcpuaffinity).
    
    Signed-off-by: Dario Faggioli <dario.faggioli@xxxxxxxxxx>
    Reviewed-by: George Dunlap <george.dunlap@xxxxxxxxxxxxx>
    Acked-by: Jan Beulich <jbeulich@xxxxxxxx>
    Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
---
 tools/libxc/xc_domain.c     |   12 +++--
 xen/arch/x86/traps.c        |    4 +-
 xen/common/domctl.c         |  107 +++++++++++++++++++++++++++++++++++++++----
 xen/common/schedule.c       |   35 ++++++++++----
 xen/common/wait.c           |    6 +-
 xen/include/public/domctl.h |   29 +++++++++++-
 xen/include/xen/sched.h     |    3 +-
 7 files changed, 162 insertions(+), 34 deletions(-)

diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index 9c8653e..26edbaf 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -225,13 +225,14 @@ int xc_vcpu_setaffinity(xc_interface *xch,
 
     domctl.cmd = XEN_DOMCTL_setvcpuaffinity;
     domctl.domain = (domid_t)domid;
-    domctl.u.vcpuaffinity.vcpu    = vcpu;
+    domctl.u.vcpuaffinity.vcpu = vcpu;
+    domctl.u.vcpuaffinity.flags = XEN_VCPUAFFINITY_HARD;
 
     memcpy(local, cpumap, cpusize);
 
-    set_xen_guest_handle(domctl.u.vcpuaffinity.cpumap.bitmap, local);
+    set_xen_guest_handle(domctl.u.vcpuaffinity.cpumap_hard.bitmap, local);
 
-    domctl.u.vcpuaffinity.cpumap.nr_bits = cpusize * 8;
+    domctl.u.vcpuaffinity.cpumap_hard.nr_bits = cpusize * 8;
 
     ret = do_domctl(xch, &domctl);
 
@@ -269,9 +270,10 @@ int xc_vcpu_getaffinity(xc_interface *xch,
     domctl.cmd = XEN_DOMCTL_getvcpuaffinity;
     domctl.domain = (domid_t)domid;
     domctl.u.vcpuaffinity.vcpu = vcpu;
+    domctl.u.vcpuaffinity.flags = XEN_VCPUAFFINITY_HARD;
 
-    set_xen_guest_handle(domctl.u.vcpuaffinity.cpumap.bitmap, local);
-    domctl.u.vcpuaffinity.cpumap.nr_bits = cpusize * 8;
+    set_xen_guest_handle(domctl.u.vcpuaffinity.cpumap_hard.bitmap, local);
+    domctl.u.vcpuaffinity.cpumap_hard.nr_bits = cpusize * 8;
 
     ret = do_domctl(xch, &domctl);
 
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index cc1c87c..5897928 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -3183,7 +3183,7 @@ static void nmi_mce_softirq(void)
          * Make sure to wakeup the vcpu on the
          * specified processor.
          */
-        vcpu_set_affinity(st->vcpu, cpumask_of(st->processor));
+        vcpu_set_hard_affinity(st->vcpu, cpumask_of(st->processor));
 
         /* Affinity is restored in the iret hypercall. */
     }
@@ -3212,7 +3212,7 @@ void async_exception_cleanup(struct vcpu *curr)
     if ( !cpumask_empty(curr->cpu_hard_affinity_tmp) &&
          !cpumask_equal(curr->cpu_hard_affinity_tmp, curr->cpu_hard_affinity) )
     {
-        vcpu_set_affinity(curr, curr->cpu_hard_affinity_tmp);
+        vcpu_set_hard_affinity(curr, curr->cpu_hard_affinity_tmp);
         cpumask_clear(curr->cpu_hard_affinity_tmp);
     }
 
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index b5c5c6c..000993f 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -287,6 +287,16 @@ void domctl_lock_release(void)
     spin_unlock(&current->domain->hypercall_deadlock_mutex);
 }
 
+static inline
+int vcpuaffinity_params_invalid(const xen_domctl_vcpuaffinity_t *vcpuaff)
+{
+    return vcpuaff->flags == 0 ||
+           ((vcpuaff->flags & XEN_VCPUAFFINITY_HARD) &&
+            guest_handle_is_null(vcpuaff->cpumap_hard.bitmap)) ||
+           ((vcpuaff->flags & XEN_VCPUAFFINITY_SOFT) &&
+            guest_handle_is_null(vcpuaff->cpumap_soft.bitmap));
+}
+
 long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
 {
     long ret = 0;
@@ -601,31 +611,108 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) 
u_domctl)
     case XEN_DOMCTL_getvcpuaffinity:
     {
         struct vcpu *v;
+        xen_domctl_vcpuaffinity_t *vcpuaff = &op->u.vcpuaffinity;
 
         ret = -EINVAL;
-        if ( op->u.vcpuaffinity.vcpu >= d->max_vcpus )
+        if ( vcpuaff->vcpu >= d->max_vcpus )
             break;
 
         ret = -ESRCH;
-        if ( (v = d->vcpu[op->u.vcpuaffinity.vcpu]) == NULL )
+        if ( (v = d->vcpu[vcpuaff->vcpu]) == NULL )
+            break;
+
+        ret = -EINVAL;
+        if ( vcpuaffinity_params_invalid(vcpuaff) )
             break;
 
         if ( op->cmd == XEN_DOMCTL_setvcpuaffinity )
         {
-            cpumask_var_t new_affinity;
+            cpumask_var_t new_affinity, old_affinity;
+            cpumask_t *online = cpupool_online_cpumask(v->domain->cpupool);;
+
+            /*
+             * We want to be able to restore hard affinity if we are trying
+             * setting both and changing soft affinity (which happens later,
+             * when hard affinity has been succesfully chaged already) fails.
+             */
+            if ( !alloc_cpumask_var(&old_affinity) )
+            {
+                ret = -ENOMEM;
+                break;
+            }
+            cpumask_copy(old_affinity, v->cpu_hard_affinity);
+
+            if ( !alloc_cpumask_var(&new_affinity) )
+            {
+                free_cpumask_var(old_affinity);
+                ret = -ENOMEM;
+                break;
+            }
 
-            ret = xenctl_bitmap_to_cpumask(
-                &new_affinity, &op->u.vcpuaffinity.cpumap);
-            if ( !ret )
+            /*
+             * We both set a new affinity and report back to the caller what
+             * the scheduler will be effectively using.
+             */
+            if ( vcpuaff->flags & XEN_VCPUAFFINITY_HARD )
+            {
+                ret = xenctl_bitmap_to_bitmap(cpumask_bits(new_affinity),
+                                              &vcpuaff->cpumap_hard,
+                                              nr_cpu_ids);
+                if ( !ret )
+                    ret = vcpu_set_hard_affinity(v, new_affinity);
+                if ( ret )
+                    goto setvcpuaffinity_out;
+
+                /*
+                 * For hard affinity, what we return is the intersection of
+                 * cpupool's online mask and the new hard affinity.
+                 */
+                cpumask_and(new_affinity, online, v->cpu_hard_affinity);
+                ret = cpumask_to_xenctl_bitmap(&vcpuaff->cpumap_hard,
+                                               new_affinity);
+            }
+            if ( vcpuaff->flags & XEN_VCPUAFFINITY_SOFT )
             {
-                ret = vcpu_set_affinity(v, new_affinity);
-                free_cpumask_var(new_affinity);
+                ret = xenctl_bitmap_to_bitmap(cpumask_bits(new_affinity),
+                                              &vcpuaff->cpumap_soft,
+                                              nr_cpu_ids);
+                if ( !ret)
+                    ret = vcpu_set_soft_affinity(v, new_affinity);
+                if ( ret )
+                {
+                    /*
+                     * Since we're returning error, the caller expects nothing
+                     * happened, so we rollback the changes to hard affinity
+                     * (if any).
+                     */
+                    if ( vcpuaff->flags & XEN_VCPUAFFINITY_HARD )
+                        vcpu_set_hard_affinity(v, old_affinity);
+                    goto setvcpuaffinity_out;
+                }
+
+                /*
+                 * For soft affinity, we return the intersection between the
+                 * new soft affinity, the cpupool's online map and the (new)
+                 * hard affinity.
+                 */
+                cpumask_and(new_affinity, new_affinity, online);
+                cpumask_and(new_affinity, new_affinity, v->cpu_hard_affinity);
+                ret = cpumask_to_xenctl_bitmap(&vcpuaff->cpumap_soft,
+                                               new_affinity);
             }
+
+ setvcpuaffinity_out:
+            free_cpumask_var(new_affinity);
+            free_cpumask_var(old_affinity);
         }
         else
         {
-            ret = cpumask_to_xenctl_bitmap(
-                &op->u.vcpuaffinity.cpumap, v->cpu_hard_affinity);
+            if ( vcpuaff->flags & XEN_VCPUAFFINITY_HARD )
+                ret = cpumask_to_xenctl_bitmap(&vcpuaff->cpumap_hard,
+                                               v->cpu_hard_affinity);
+            if ( vcpuaff->flags & XEN_VCPUAFFINITY_SOFT )
+                ret = cpumask_to_xenctl_bitmap(&vcpuaff->cpumap_soft,
+                                               v->cpu_soft_affinity);
         }
     }
     break;
diff --git a/xen/common/schedule.c b/xen/common/schedule.c
index e57cd91..e9eb0bc 100644
--- a/xen/common/schedule.c
+++ b/xen/common/schedule.c
@@ -650,22 +650,14 @@ int cpu_disable_scheduler(unsigned int cpu)
     return ret;
 }
 
-int vcpu_set_affinity(struct vcpu *v, const cpumask_t *affinity)
+static int vcpu_set_affinity(
+    struct vcpu *v, const cpumask_t *affinity, cpumask_t *which)
 {
-    cpumask_t online_affinity;
-    cpumask_t *online;
     spinlock_t *lock;
 
-    if ( v->domain->is_pinned )
-        return -EINVAL;
-    online = VCPU2ONLINE(v);
-    cpumask_and(&online_affinity, affinity, online);
-    if ( cpumask_empty(&online_affinity) )
-        return -EINVAL;
-
     lock = vcpu_schedule_lock_irq(v);
 
-    cpumask_copy(v->cpu_hard_affinity, affinity);
+    cpumask_copy(which, affinity);
 
     /* Always ask the scheduler to re-evaluate placement
      * when changing the affinity */
@@ -684,6 +676,27 @@ int vcpu_set_affinity(struct vcpu *v, const cpumask_t 
*affinity)
     return 0;
 }
 
+int vcpu_set_hard_affinity(struct vcpu *v, const cpumask_t *affinity)
+{
+    cpumask_t online_affinity;
+    cpumask_t *online;
+
+    if ( v->domain->is_pinned )
+        return -EINVAL;
+
+    online = VCPU2ONLINE(v);
+    cpumask_and(&online_affinity, affinity, online);
+    if ( cpumask_empty(&online_affinity) )
+        return -EINVAL;
+
+    return vcpu_set_affinity(v, affinity, v->cpu_hard_affinity);
+}
+
+int vcpu_set_soft_affinity(struct vcpu *v, const cpumask_t *affinity)
+{
+    return vcpu_set_affinity(v, affinity, v->cpu_soft_affinity);
+}
+
 /* Block the currently-executing domain until a pertinent event occurs. */
 void vcpu_block(void)
 {
diff --git a/xen/common/wait.c b/xen/common/wait.c
index 3f6ff41..1f6b597 100644
--- a/xen/common/wait.c
+++ b/xen/common/wait.c
@@ -135,7 +135,7 @@ static void __prepare_to_wait(struct waitqueue_vcpu *wqv)
     /* Save current VCPU affinity; force wakeup on *this* CPU only. */
     wqv->wakeup_cpu = smp_processor_id();
     cpumask_copy(&wqv->saved_affinity, curr->cpu_hard_affinity);
-    if ( vcpu_set_affinity(curr, cpumask_of(wqv->wakeup_cpu)) )
+    if ( vcpu_set_hard_affinity(curr, cpumask_of(wqv->wakeup_cpu)) )
     {
         gdprintk(XENLOG_ERR, "Unable to set vcpu affinity\n");
         domain_crash_synchronous();
@@ -166,7 +166,7 @@ static void __prepare_to_wait(struct waitqueue_vcpu *wqv)
 static void __finish_wait(struct waitqueue_vcpu *wqv)
 {
     wqv->esp = NULL;
-    (void)vcpu_set_affinity(current, &wqv->saved_affinity);
+    (void)vcpu_set_hard_affinity(current, &wqv->saved_affinity);
 }
 
 void check_wakeup_from_wait(void)
@@ -184,7 +184,7 @@ void check_wakeup_from_wait(void)
         /* Re-set VCPU affinity and re-enter the scheduler. */
         struct vcpu *curr = current;
         cpumask_copy(&wqv->saved_affinity, curr->cpu_hard_affinity);
-        if ( vcpu_set_affinity(curr, cpumask_of(wqv->wakeup_cpu)) )
+        if ( vcpu_set_hard_affinity(curr, cpumask_of(wqv->wakeup_cpu)) )
         {
             gdprintk(XENLOG_ERR, "Unable to set vcpu affinity\n");
             domain_crash_synchronous();
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 2967133..5b11bbf 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -300,8 +300,33 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_nodeaffinity_t);
 /* XEN_DOMCTL_setvcpuaffinity */
 /* XEN_DOMCTL_getvcpuaffinity */
 struct xen_domctl_vcpuaffinity {
-    uint32_t  vcpu;              /* IN */
-    struct xenctl_bitmap cpumap; /* IN/OUT */
+    /* IN variables. */
+    uint32_t  vcpu;
+ /* Set/get the hard affinity for vcpu */
+#define _XEN_VCPUAFFINITY_HARD  0
+#define XEN_VCPUAFFINITY_HARD   (1U<<_XEN_VCPUAFFINITY_HARD)
+ /* Set/get the soft affinity for vcpu */
+#define _XEN_VCPUAFFINITY_SOFT  1
+#define XEN_VCPUAFFINITY_SOFT   (1U<<_XEN_VCPUAFFINITY_SOFT)
+    uint32_t flags;
+    /*
+     * IN/OUT variables.
+     *
+     * Both are IN/OUT for XEN_DOMCTL_setvcpuaffinity, in which case they
+     * contain effective hard or/and soft affinity. That is, upon successful
+     * return, cpumap_soft, contains the intersection of the soft affinity,
+     * hard affinity and the cpupool's online CPUs for the domain (if
+     * XEN_VCPUAFFINITY_SOFT was set in flags). cpumap_hard contains the
+     * intersection between hard affinity and the cpupool's online CPUs (if
+     * XEN_VCPUAFFINITY_HARD was set in flags).
+     *
+     * Both are OUT-only for XEN_DOMCTL_getvcpuaffinity, in which case they
+     * contain the plain hard and/or soft affinity masks that were set during
+     * previous successful calls to XEN_DOMCTL_setvcpuaffinity (or the
+     * default values), without intersecting or altering them in any way.
+     */
+    struct xenctl_bitmap cpumap_hard;
+    struct xenctl_bitmap cpumap_soft;
 };
 typedef struct xen_domctl_vcpuaffinity xen_domctl_vcpuaffinity_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_vcpuaffinity_t);
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 445b659..f920e1a 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -781,7 +781,8 @@ void scheduler_free(struct scheduler *sched);
 int schedule_cpu_switch(unsigned int cpu, struct cpupool *c);
 void vcpu_force_reschedule(struct vcpu *v);
 int cpu_disable_scheduler(unsigned int cpu);
-int vcpu_set_affinity(struct vcpu *v, const cpumask_t *affinity);
+int vcpu_set_hard_affinity(struct vcpu *v, const cpumask_t *affinity);
+int vcpu_set_soft_affinity(struct vcpu *v, const cpumask_t *affinity);
 void restore_vcpu_affinity(struct domain *d);
 
 void vcpu_runstate_get(struct vcpu *v, struct vcpu_runstate_info *runstate);
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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