Differential D16416 Diff 46059 head/emulators/xen-kernel47/files/0004-gnttab-correct-maptrack-table-accesses.patch
Changeset View
Changeset View
Standalone View
Standalone View
head/emulators/xen-kernel47/files/0004-gnttab-correct-maptrack-table-accesses.patch
Property | Old Value | New Value |
---|---|---|
fbsd:nokeywords | null | yes \ No newline at end of property |
svn:eol-style | null | native \ No newline at end of property |
svn:mime-type | null | text/plain \ No newline at end of property |
From bb765f7863e5d19eebcfb29c117e2909bce241e7 Mon Sep 17 00:00:00 2001 | |||||
From: Jan Beulich <jbeulich@suse.com> | |||||
Date: Thu, 15 Jun 2017 12:05:29 +0100 | |||||
Subject: [PATCH 4/4] gnttab: correct maptrack table accesses | |||||
In order to observe a consistent (limit,pointer-table) pair, the reader | |||||
needs to either hold the maptrack lock (in line with documentation) or | |||||
both sides need to order their accesses suitably (the writer side | |||||
barrier was removed by commit dff515dfea ["gnttab: use per-VCPU | |||||
maptrack free lists"], and a read side barrier has never been there). | |||||
Make the writer publish a new table page before limit (for bounds | |||||
checks to work), and new list head last (for racing maptrack_entry() | |||||
invocations to work). At the same time add read barriers to lockless | |||||
readers. | |||||
Additionally get_maptrack_handle() must not assume ->maptrack_head to | |||||
not change behind its back: Another handle may be put (updating only | |||||
->maptrack_tail) and then got or stolen (updating ->maptrack_head). | |||||
This is part of XSA-218. | |||||
Signed-off-by: Jan Beulich <jbeulich@suse.com> | |||||
Reviewed-by: George Dunlap <george.dunlap@citrix.com> | |||||
--- | |||||
xen/common/grant_table.c | 13 +++++++++---- | |||||
1 file changed, 9 insertions(+), 4 deletions(-) | |||||
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c | |||||
index 81a1a8b..c4d73af 100644 | |||||
--- a/xen/common/grant_table.c | |||||
+++ b/xen/common/grant_table.c | |||||
@@ -395,7 +395,7 @@ get_maptrack_handle( | |||||
struct grant_table *lgt) | |||||
{ | |||||
struct vcpu *curr = current; | |||||
- int i; | |||||
+ unsigned int i, head; | |||||
grant_handle_t handle; | |||||
struct grant_mapping *new_mt; | |||||
@@ -451,17 +451,20 @@ get_maptrack_handle( | |||||
new_mt[i].ref = handle + i + 1; | |||||
new_mt[i].vcpu = curr->vcpu_id; | |||||
} | |||||
- new_mt[i - 1].ref = curr->maptrack_head; | |||||
/* Set tail directly if this is the first page for this VCPU. */ | |||||
if ( curr->maptrack_tail == MAPTRACK_TAIL ) | |||||
curr->maptrack_tail = handle + MAPTRACK_PER_PAGE - 1; | |||||
- write_atomic(&curr->maptrack_head, handle + 1); | |||||
- | |||||
lgt->maptrack[nr_maptrack_frames(lgt)] = new_mt; | |||||
+ smp_wmb(); | |||||
lgt->maptrack_limit += MAPTRACK_PER_PAGE; | |||||
+ do { | |||||
+ new_mt[i - 1].ref = read_atomic(&curr->maptrack_head); | |||||
+ head = cmpxchg(&curr->maptrack_head, new_mt[i - 1].ref, handle + 1); | |||||
+ } while ( head != new_mt[i - 1].ref ); | |||||
+ | |||||
spin_unlock(&lgt->maptrack_lock); | |||||
return handle; | |||||
@@ -727,6 +730,7 @@ static unsigned int mapkind( | |||||
for ( handle = 0; !(kind & MAPKIND_WRITE) && | |||||
handle < lgt->maptrack_limit; handle++ ) | |||||
{ | |||||
+ smp_rmb(); | |||||
map = &maptrack_entry(lgt, handle); | |||||
if ( !(map->flags & (GNTMAP_device_map|GNTMAP_host_map)) || | |||||
map->domid != rd->domain_id ) | |||||
@@ -1094,6 +1098,7 @@ __gnttab_unmap_common( | |||||
return; | |||||
} | |||||
+ smp_rmb(); | |||||
map = &maptrack_entry(lgt, op->handle); | |||||
grant_read_lock(lgt); | |||||
-- | |||||
2.1.4 | |||||