]> xenbits.xensource.com Git - xen.git/commitdiff
x86/mem_event: prevent underflow of vcpu pause counts
authorAndrew Cooper <andrew.cooper3@citrix.com>
Mon, 28 Jul 2014 13:16:19 +0000 (15:16 +0200)
committerJan Beulich <jbeulich@suse.com>
Mon, 28 Jul 2014 13:16:19 +0000 (15:16 +0200)
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Tested-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
Reviewed-by: Andres Lagar-Cavilla <andres@lagarcavilla.org>
Tested-by: Aravindh Puthiyaparambil <aravindp@cisco.com>
master commit: 868d9b99b39c53dc1f6ae9bfd7b148c206fd7240
master date: 2014-07-23 18:08:04 +0200

xen/arch/x86/hvm/hvm.c
xen/arch/x86/mm/mem_event.c
xen/arch/x86/mm/mem_sharing.c
xen/arch/x86/mm/p2m.c
xen/include/asm-x86/mem_event.h
xen/include/xen/sched.h

index 8959a5419179c81c1ec738d087d6f852bda95cd2..153b89afef24ed5acbfc9fd3b9bbfef86b35ee3e 100644 (file)
@@ -4532,7 +4532,7 @@ static int hvm_memory_event_traps(long p, uint32_t reason,
     if ( (p & HVMPME_MODE_MASK) == HVMPME_mode_sync ) 
     {
         req.flags |= MEM_EVENT_FLAG_VCPU_PAUSED;    
-        vcpu_pause_nosync(v);   
+        mem_event_vcpu_pause(v);
     }
 
     req.gfn = value;
index d728889e108bf9648dc96c6e97018d5d7d6e843d..1123c9f55d0ff4ffad7dcc7058e56efb49d81ba7 100644 (file)
@@ -672,6 +672,38 @@ int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
     return rc;
 }
 
+void mem_event_vcpu_pause(struct vcpu *v)
+{
+    ASSERT(v == current);
+
+    atomic_inc(&v->mem_event_pause_count);
+    vcpu_pause_nosync(v);
+}
+
+void mem_event_vcpu_unpause(struct vcpu *v)
+{
+    int old, new, prev = v->mem_event_pause_count.counter;
+
+    /* All unpause requests as a result of toolstack responses.  Prevent
+     * underflow of the vcpu pause count. */
+    do
+    {
+        old = prev;
+        new = old - 1;
+
+        if ( new < 0 )
+        {
+            printk(XENLOG_G_WARNING
+                   "d%d:v%d mem_event: Too many unpause attempts\n",
+                   v->domain->domain_id, v->vcpu_id);
+            return;
+        }
+
+        prev = cmpxchg(&v->mem_event_pause_count.counter, old, new);
+    } while ( prev != old );
+
+    vcpu_unpause(v);
+}
 
 /*
  * Local variables:
index f04034d9114d7b7b6e84697ee0b45e5b5ed63f0c..d1a9130ef05b07f2637da44eeee4001e25555a9f 100644 (file)
@@ -567,7 +567,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned long gfn,
     if ( v->domain == d )
     {
         req.flags = MEM_EVENT_FLAG_VCPU_PAUSED;
-        vcpu_pause_nosync(v);
+        mem_event_vcpu_pause(v);
     }
 
     req.p2mt = p2m_ram_shared;
@@ -608,7 +608,7 @@ int mem_sharing_sharing_resume(struct domain *d)
 
         /* Unpause domain/vcpu */
         if ( rsp.flags & MEM_EVENT_FLAG_VCPU_PAUSED )
-            vcpu_unpause(v);
+            mem_event_vcpu_unpause(v);
     }
 
     return 0;
index 1619a793b8428ea15d9f06cdc32906fbd2af2236..1146f818939379f5b06f8b3a80fcc11977ec7cc0 100644 (file)
@@ -1077,7 +1077,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned long gfn)
     /* Pause domain if request came from guest and gfn has paging type */
     if ( p2m_is_paging(p2mt) && v->domain == d )
     {
-        vcpu_pause_nosync(v);
+        mem_event_vcpu_pause(v);
         req.flags |= MEM_EVENT_FLAG_VCPU_PAUSED;
     }
     /* No need to inform pager if the gfn is not in the page-out path */
@@ -1240,7 +1240,7 @@ void p2m_mem_paging_resume(struct domain *d)
         }
         /* Unpause domain */
         if ( rsp.flags & MEM_EVENT_FLAG_VCPU_PAUSED )
-            vcpu_unpause(v);
+            mem_event_vcpu_unpause(v);
     }
 }
 
@@ -1324,7 +1324,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla,
 
     /* Pause the current VCPU */
     if ( p2ma != p2m_access_n2rwx )
-        vcpu_pause_nosync(v);
+        mem_event_vcpu_pause(v);
 
     /* VCPU may be paused, return whether we promoted automatically */
     return (p2ma == p2m_access_n2rwx);
@@ -1350,7 +1350,7 @@ void p2m_mem_access_resume(struct domain *d)
 
         /* Unpause domain */
         if ( rsp.flags & MEM_EVENT_FLAG_VCPU_PAUSED )
-            vcpu_unpause(v);
+            mem_event_vcpu_unpause(v);
     }
 }
 
index 23d71c1d8e8a966bc2e270a7e420dc00ad86f4ca..f5890bde173066f0ca66b6ee9f9718185a846d68 100644 (file)
@@ -67,6 +67,9 @@ int do_mem_event_op(int op, uint32_t domain, void *arg);
 int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
                      XEN_GUEST_HANDLE(void) u_domctl);
 
+void mem_event_vcpu_pause(struct vcpu *v);
+void mem_event_vcpu_unpause(struct vcpu *v);
+
 #endif /* __MEM_EVENT_H__ */
 
 
index d04e96b9617a5d6163f9b9abf944b0d608bb7a72..e9af8e2abfe12f7deed1bae174344dd47fa45f13 100644 (file)
@@ -157,6 +157,9 @@ struct vcpu
     unsigned long    pause_flags;
     atomic_t         pause_count;
 
+    /* VCPU paused for mem_event replies. */
+    atomic_t         mem_event_pause_count;
+
     /* IRQ-safe virq_lock protects against delivering VIRQ to stale evtchn. */
     u16              virq_to_evtchn[NR_VIRQS];
     spinlock_t       virq_lock;