|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Re-order calls to put_gfn() around wait queue invocations
# HG changeset patch
# User Andres Lagar-Cavilla <andres@xxxxxxxxxxxxxxxx>
# Date 1328890027 0
# Node ID e0ddac877f420e51314a97fc9f9f7befb44dc5a1
# Parent 28edc2b31a9bc50bae915129dfbd315a73260a09
Re-order calls to put_gfn() around wait queue invocations
Since we use wait queues to handle potential ring congestion cases,
code paths that try to generate a mem event while holding a gfn lock
would go to sleep in non-preemptible mode.
Most such code paths can be fixed by simply postponing event generation until
locks are released.
Signed-off-by: Adin Scannell <adin@xxxxxxxxxxx>
Signed-off-by: Andres Lagar-Cavilla <andres@xxxxxxxxxxxxxxxx>
Acked-by: Tim Deegan <tim@xxxxxxx>
Committed-by: Tim Deegan <tim@xxxxxxx>
---
diff -r 28edc2b31a9b -r e0ddac877f42 xen/arch/x86/hvm/emulate.c
--- a/xen/arch/x86/hvm/emulate.c Fri Feb 10 16:07:07 2012 +0000
+++ b/xen/arch/x86/hvm/emulate.c Fri Feb 10 16:07:07 2012 +0000
@@ -67,8 +67,8 @@
ram_mfn = get_gfn_unshare(curr->domain, ram_gfn, &p2mt);
if ( p2m_is_paging(p2mt) )
{
+ put_gfn(curr->domain, ram_gfn);
p2m_mem_paging_populate(curr->domain, ram_gfn);
- put_gfn(curr->domain, ram_gfn);
return X86EMUL_RETRY;
}
if ( p2m_is_shared(p2mt) )
diff -r 28edc2b31a9b -r e0ddac877f42 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c Fri Feb 10 16:07:07 2012 +0000
+++ b/xen/arch/x86/hvm/hvm.c Fri Feb 10 16:07:07 2012 +0000
@@ -64,6 +64,7 @@
#include <public/version.h>
#include <public/memory.h>
#include <asm/mem_event.h>
+#include <asm/mem_access.h>
#include <public/mem_event.h>
bool_t __read_mostly hvm_enabled;
@@ -363,8 +364,8 @@
}
if ( p2m_is_paging(p2mt) )
{
+ put_gfn(d, gmfn);
p2m_mem_paging_populate(d, gmfn);
- put_gfn(d, gmfn);
return -ENOENT;
}
if ( p2m_is_shared(p2mt) )
@@ -1195,7 +1196,8 @@
mfn_t mfn;
struct vcpu *v = current;
struct p2m_domain *p2m;
- int rc, fall_through = 0;
+ int rc, fall_through = 0, paged = 0;
+ mem_event_request_t *req_ptr = NULL;
/* On Nested Virtualization, walk the guest page table.
* If this succeeds, all is fine.
@@ -1270,7 +1272,7 @@
if ( violation )
{
if ( p2m_mem_access_check(gpa, gla_valid, gla, access_r,
- access_w, access_x) )
+ access_w, access_x, &req_ptr) )
{
fall_through = 1;
} else {
@@ -1297,7 +1299,7 @@
#ifdef __x86_64__
/* Check if the page has been paged out */
if ( p2m_is_paged(p2mt) || (p2mt == p2m_ram_paging_out) )
- p2m_mem_paging_populate(v->domain, gfn);
+ paged = 1;
/* Mem sharing: unshare the page and try again */
if ( access_w && (p2mt == p2m_ram_shared) )
@@ -1343,6 +1345,13 @@
out_put_gfn:
put_gfn(p2m->domain, gfn);
+ if ( paged )
+ p2m_mem_paging_populate(v->domain, gfn);
+ if ( req_ptr )
+ {
+ mem_access_send_req(v->domain, req_ptr);
+ xfree(req_ptr);
+ }
return rc;
}
@@ -1849,8 +1858,8 @@
}
if ( p2m_is_paging(p2mt) )
{
+ put_gfn(d, gfn);
p2m_mem_paging_populate(d, gfn);
- put_gfn(d, gfn);
return NULL;
}
@@ -2325,8 +2334,8 @@
if ( p2m_is_paging(p2mt) )
{
+ put_gfn(curr->domain, gfn);
p2m_mem_paging_populate(curr->domain, gfn);
- put_gfn(curr->domain, gfn);
return HVMCOPY_gfn_paged_out;
}
if ( p2m_is_shared(p2mt) )
@@ -3923,8 +3932,8 @@
mfn_t mfn = get_gfn_unshare(d, pfn, &t);
if ( p2m_is_paging(t) )
{
+ put_gfn(d, pfn);
p2m_mem_paging_populate(d, pfn);
- put_gfn(d, pfn);
rc = -EINVAL;
goto param_fail3;
}
@@ -4040,8 +4049,8 @@
mfn = get_gfn_unshare(d, pfn, &t);
if ( p2m_is_paging(t) )
{
+ put_gfn(d, pfn);
p2m_mem_paging_populate(d, pfn);
- put_gfn(d, pfn);
rc = -EINVAL;
goto param_fail4;
}
diff -r 28edc2b31a9b -r e0ddac877f42 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Fri Feb 10 16:07:07 2012 +0000
+++ b/xen/arch/x86/mm.c Fri Feb 10 16:07:07 2012 +0000
@@ -3536,8 +3536,8 @@
if ( p2m_is_paged(p2mt) )
{
+ put_gfn(pt_owner, gmfn);
p2m_mem_paging_populate(pg_owner, gmfn);
- put_gfn(pt_owner, gmfn);
rc = -ENOENT;
break;
}
@@ -3568,8 +3568,8 @@
if ( p2m_is_paged(l1e_p2mt) )
{
+ put_gfn(pg_owner, l1egfn);
p2m_mem_paging_populate(pg_owner, l1e_get_pfn(l1e));
- put_gfn(pg_owner, l1egfn);
rc = -ENOENT;
break;
}
@@ -3617,8 +3617,8 @@
if ( p2m_is_paged(l2e_p2mt) )
{
+ put_gfn(pg_owner, l2egfn);
p2m_mem_paging_populate(pg_owner, l2egfn);
- put_gfn(pg_owner, l2egfn);
rc = -ENOENT;
break;
}
@@ -3652,8 +3652,8 @@
if ( p2m_is_paged(l3e_p2mt) )
{
+ put_gfn(pg_owner, l3egfn);
p2m_mem_paging_populate(pg_owner, l3egfn);
- put_gfn(pg_owner, l3egfn);
rc = -ENOENT;
break;
}
@@ -3687,8 +3687,8 @@
if ( p2m_is_paged(l4e_p2mt) )
{
+ put_gfn(pg_owner, l4egfn);
p2m_mem_paging_populate(pg_owner, l4egfn);
- put_gfn(pg_owner, l4egfn);
rc = -ENOENT;
break;
}
diff -r 28edc2b31a9b -r e0ddac877f42 xen/arch/x86/mm/guest_walk.c
--- a/xen/arch/x86/mm/guest_walk.c Fri Feb 10 16:07:07 2012 +0000
+++ b/xen/arch/x86/mm/guest_walk.c Fri Feb 10 16:07:07 2012 +0000
@@ -102,8 +102,8 @@
if ( p2m_is_paging(*p2mt) )
{
ASSERT(!p2m_is_nestedp2m(p2m));
+ __put_gfn(p2m, gfn_x(gfn));
p2m_mem_paging_populate(p2m->domain, gfn_x(gfn));
- __put_gfn(p2m, gfn_x(gfn));
*rc = _PAGE_PAGED;
return NULL;
}
diff -r 28edc2b31a9b -r e0ddac877f42 xen/arch/x86/mm/hap/guest_walk.c
--- a/xen/arch/x86/mm/hap/guest_walk.c Fri Feb 10 16:07:07 2012 +0000
+++ b/xen/arch/x86/mm/hap/guest_walk.c Fri Feb 10 16:07:07 2012 +0000
@@ -64,10 +64,9 @@
if ( p2m_is_paging(p2mt) )
{
ASSERT(!p2m_is_nestedp2m(p2m));
- p2m_mem_paging_populate(p2m->domain, cr3 >> PAGE_SHIFT);
-
pfec[0] = PFEC_page_paged;
__put_gfn(p2m, top_gfn);
+ p2m_mem_paging_populate(p2m->domain, cr3 >> PAGE_SHIFT);
return INVALID_GFN;
}
if ( p2m_is_shared(p2mt) )
@@ -101,10 +100,9 @@
if ( p2m_is_paging(p2mt) )
{
ASSERT(!p2m_is_nestedp2m(p2m));
- p2m_mem_paging_populate(p2m->domain, gfn_x(gfn));
-
pfec[0] = PFEC_page_paged;
__put_gfn(p2m, gfn_x(gfn));
+ p2m_mem_paging_populate(p2m->domain, gfn_x(gfn));
return INVALID_GFN;
}
if ( p2m_is_shared(p2mt) )
diff -r 28edc2b31a9b -r e0ddac877f42 xen/arch/x86/mm/mem_access.c
--- a/xen/arch/x86/mm/mem_access.c Fri Feb 10 16:07:07 2012 +0000
+++ b/xen/arch/x86/mm/mem_access.c Fri Feb 10 16:07:07 2012 +0000
@@ -47,6 +47,16 @@
return rc;
}
+int mem_access_send_req(struct domain *d, mem_event_request_t *req)
+{
+ int rc = mem_event_claim_slot(d, &d->mem_event->access);
+ if ( rc < 0 )
+ return rc;
+
+ mem_event_put_request(d, &d->mem_event->access, req);
+
+ return 0;
+}
/*
* Local variables:
diff -r 28edc2b31a9b -r e0ddac877f42 xen/arch/x86/mm/mem_event.c
--- a/xen/arch/x86/mm/mem_event.c Fri Feb 10 16:07:07 2012 +0000
+++ b/xen/arch/x86/mm/mem_event.c Fri Feb 10 16:07:07 2012 +0000
@@ -423,6 +423,11 @@
return rc;
}
+bool_t mem_event_check_ring(struct mem_event_domain *med)
+{
+ return (med->ring_page != NULL);
+}
+
/*
* Determines whether or not the current vCPU belongs to the target domain,
* and calls the appropriate wait function. If it is a guest vCPU, then we
diff -r 28edc2b31a9b -r e0ddac877f42 xen/arch/x86/mm/p2m.c
--- a/xen/arch/x86/mm/p2m.c Fri Feb 10 16:07:07 2012 +0000
+++ b/xen/arch/x86/mm/p2m.c Fri Feb 10 16:07:07 2012 +0000
@@ -1130,17 +1130,18 @@
}
bool_t p2m_mem_access_check(unsigned long gpa, bool_t gla_valid, unsigned long
gla,
- bool_t access_r, bool_t access_w, bool_t access_x)
+ bool_t access_r, bool_t access_w, bool_t access_x,
+ mem_event_request_t **req_ptr)
{
struct vcpu *v = current;
- mem_event_request_t req;
unsigned long gfn = gpa >> PAGE_SHIFT;
struct domain *d = v->domain;
struct p2m_domain* p2m = p2m_get_hostp2m(d);
mfn_t mfn;
p2m_type_t p2mt;
p2m_access_t p2ma;
-
+ mem_event_request_t *req;
+
/* First, handle rx2rw conversion automatically */
gfn_lock(p2m, gfn, 0);
mfn = p2m->get_entry(p2m, gfn, &p2mt, &p2ma, p2m_query, NULL);
@@ -1159,7 +1160,7 @@
gfn_unlock(p2m, gfn, 0);
/* Otherwise, check if there is a memory event listener, and send the
message along */
- if ( mem_event_claim_slot(d, &d->mem_event->access) == -ENOSYS )
+ if ( !mem_event_check_ring(&d->mem_event->access) || !req_ptr )
{
/* No listener */
if ( p2m->access_required )
@@ -1183,29 +1184,34 @@
}
}
- memset(&req, 0, sizeof(req));
- req.type = MEM_EVENT_TYPE_ACCESS;
- req.reason = MEM_EVENT_REASON_VIOLATION;
+ *req_ptr = NULL;
+ req = xmalloc(mem_event_request_t);
+ if ( req )
+ {
+ *req_ptr = req;
+ memset(req, 0, sizeof(req));
+ req->type = MEM_EVENT_TYPE_ACCESS;
+ req->reason = MEM_EVENT_REASON_VIOLATION;
+
+ /* Pause the current VCPU */
+ if ( p2ma != p2m_access_n2rwx )
+ req->flags |= MEM_EVENT_FLAG_VCPU_PAUSED;
+
+ /* Send request to mem event */
+ req->gfn = gfn;
+ req->offset = gpa & ((1 << PAGE_SHIFT) - 1);
+ req->gla_valid = gla_valid;
+ req->gla = gla;
+ req->access_r = access_r;
+ req->access_w = access_w;
+ req->access_x = access_x;
+
+ req->vcpu_id = v->vcpu_id;
+ }
/* Pause the current VCPU */
if ( p2ma != p2m_access_n2rwx )
- {
vcpu_pause_nosync(v);
- req.flags |= MEM_EVENT_FLAG_VCPU_PAUSED;
- }
-
- /* Send request to mem event */
- req.gfn = gfn;
- req.offset = gpa & ((1 << PAGE_SHIFT) - 1);
- req.gla_valid = gla_valid;
- req.gla = gla;
- req.access_r = access_r;
- req.access_w = access_w;
- req.access_x = access_x;
-
- req.vcpu_id = v->vcpu_id;
-
- mem_event_put_request(d, &d->mem_event->access, &req);
/* VCPU may be paused, return whether we promoted automatically */
return (p2ma == p2m_access_n2rwx);
diff -r 28edc2b31a9b -r e0ddac877f42 xen/common/grant_table.c
--- a/xen/common/grant_table.c Fri Feb 10 16:07:07 2012 +0000
+++ b/xen/common/grant_table.c Fri Feb 10 16:07:07 2012 +0000
@@ -164,8 +164,8 @@
*frame = mfn_x(mfn);
if ( p2m_is_paging(p2mt) )
{
+ put_gfn(rd, gfn);
p2m_mem_paging_populate(rd, gfn);
- put_gfn(rd, gfn);
rc = GNTST_eagain;
}
} else {
diff -r 28edc2b31a9b -r e0ddac877f42 xen/common/memory.c
--- a/xen/common/memory.c Fri Feb 10 16:07:07 2012 +0000
+++ b/xen/common/memory.c Fri Feb 10 16:07:07 2012 +0000
@@ -166,8 +166,8 @@
if ( unlikely(p2m_is_paging(p2mt)) )
{
guest_physmap_remove_page(d, gmfn, mfn, 0);
+ put_gfn(d, gmfn);
p2m_mem_paging_drop_page(d, gmfn, p2mt);
- put_gfn(d, gmfn);
return 1;
}
#else
diff -r 28edc2b31a9b -r e0ddac877f42 xen/include/asm-x86/mem_access.h
--- a/xen/include/asm-x86/mem_access.h Fri Feb 10 16:07:07 2012 +0000
+++ b/xen/include/asm-x86/mem_access.h Fri Feb 10 16:07:07 2012 +0000
@@ -23,6 +23,7 @@
int mem_access_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec,
XEN_GUEST_HANDLE(void) u_domctl);
+int mem_access_send_req(struct domain *d, mem_event_request_t *req);
/*
diff -r 28edc2b31a9b -r e0ddac877f42 xen/include/asm-x86/mem_event.h
--- a/xen/include/asm-x86/mem_event.h Fri Feb 10 16:07:07 2012 +0000
+++ b/xen/include/asm-x86/mem_event.h Fri Feb 10 16:07:07 2012 +0000
@@ -24,6 +24,9 @@
#ifndef __MEM_EVENT_H__
#define __MEM_EVENT_H__
+/* Returns whether a ring has been set up */
+bool_t mem_event_check_ring(struct mem_event_domain *med);
+
/* Returns 0 on success, -ENOSYS if there is no ring, -EBUSY if there is no
* available space. For success or -EBUSY, the vCPU may be left blocked
* temporarily to ensure that the ring does not lose future events. In
diff -r 28edc2b31a9b -r e0ddac877f42 xen/include/asm-x86/p2m.h
--- a/xen/include/asm-x86/p2m.h Fri Feb 10 16:07:07 2012 +0000
+++ b/xen/include/asm-x86/p2m.h Fri Feb 10 16:07:07 2012 +0000
@@ -494,9 +494,12 @@
#ifdef __x86_64__
/* Send mem event based on the access (gla is -1ull if not available). Handles
* the rw2rx conversion. Boolean return value indicates if access rights have
- * been promoted with no underlying vcpu pause. */
+ * been promoted with no underlying vcpu pause. If the req_ptr has been
populated,
+ * then the caller must put the event in the ring (once having released
get_gfn*
+ * locks -- caller must also xfree the request. */
bool_t p2m_mem_access_check(unsigned long gpa, bool_t gla_valid, unsigned long
gla,
- bool_t access_r, bool_t access_w, bool_t access_x);
+ bool_t access_r, bool_t access_w, bool_t access_x,
+ mem_event_request_t **req_ptr);
/* Resumes the running of the VCPU, restarting the last instruction */
void p2m_mem_access_resume(struct domain *d);
@@ -513,7 +516,8 @@
#else
static inline bool_t p2m_mem_access_check(unsigned long gpa, bool_t gla_valid,
unsigned long gla, bool_t access_r,
- bool_t access_w, bool_t access_x)
+ bool_t access_w, bool_t access_x,
+ mem_event_request_t **req_ptr)
{ return 1; }
static inline int p2m_set_mem_access(struct domain *d,
unsigned long start_pfn,
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |