aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/grant_table.c
diff options
context:
space:
mode:
authorTim Deegan <tim@xen.org>2012-03-15 11:12:44 +0000
committerTim Deegan <tim@xen.org>2012-03-15 11:12:44 +0000
commit0806e3965914990286b62c120e95f09e4962152c (patch)
tree2c7da2078ca2aec05371fffde8c56d11ddbefdb6 /xen/common/grant_table.c
parent9ccfacd4706c785434848b9b31701945eceefe0f (diff)
downloadxen-0806e3965914990286b62c120e95f09e4962152c.tar.gz
xen-0806e3965914990286b62c120e95f09e4962152c.tar.bz2
xen-0806e3965914990286b62c120e95f09e4962152c.zip
Memory sharing: better handling of ENOMEM while unsharing
If unsharing fails with ENOMEM, we were: - leaving the list of gfns backed by the shared page in an inconsistent state - cycling forever on the hap page fault handler. - Attempting to produce a mem event (which could sleep on a wait queue) while holding locks. - Not checking, for all callers, that unshare could have indeed failed. Fix bugs above, and sanitize callers to place a ring event in an unlocked context, or without requiring to go to sleep on a wait queue. A note on the rationale for unshare error handling: 1. Unshare can only fail with ENOMEM. Any other error conditions BUG_ON() 2. We notify a potential dom0 helper through a mem_event ring. But we allow the notification to not go to sleep. If the event ring is full of ENOMEM warnings, then the helper will already have been kicked enough. 3. We cannot "just" go to sleep until the unshare is resolved, because we might be buried deep into locks (e.g. something -> copy_to_user -> __hvm_copy) 4. So, we make sure we: 4.1. return an error 4.2. do not corrupt memory shared with other guests 4.3. do not corrupt memory private to the current guest 4.4. do not corrupt the hypervisor memory sharing meta data 4.5. let the guest deal with the error, if propagation will reach that far Signed-off-by: Andres Lagar-Cavilla <andres@lagarcavilla.org> Acked-by: Tim Deegan <tim@xen.org> Committed-by: Tim Deegan <tim@xen.org>
Diffstat (limited to 'xen/common/grant_table.c')
-rw-r--r--xen/common/grant_table.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 28a256197e..e6706df53b 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -112,8 +112,7 @@ static unsigned inline int max_nr_maptrack_frames(void)
p2m_type_t __p2mt; \
unsigned long __x; \
__x = mfn_x(get_gfn_unshare((_d), (_gfn), &__p2mt)); \
- BUG_ON(p2m_is_shared(__p2mt)); /* XXX fixme */ \
- if ( !p2m_is_valid(__p2mt) ) \
+ if ( p2m_is_shared(__p2mt) || !p2m_is_valid(__p2mt) ) \
__x = INVALID_MFN; \
__x; })
#else
@@ -155,9 +154,11 @@ static int __get_paged_frame(unsigned long gfn, unsigned long *frame, int readon
else
{
mfn = get_gfn_unshare(rd, gfn, &p2mt);
- BUG_ON(p2m_is_shared(p2mt));
- /* XXX Here, and above in gfn_to_mfn_private, need to handle
- * XXX failure to unshare. */
+ if ( p2m_is_shared(p2mt) )
+ {
+ put_gfn(rd, gfn);
+ return GNTST_eagain;
+ }
}
if ( p2m_is_valid(p2mt) ) {