xenpaging: page-in granttable entries

When converting a gfn to mfn, check if the page is paged-out.
If it is, request a page-in and return GNTST_eagain to the caller
to indicate a retry of the hypercall is required.
This fixes granttable errors when xenpaging is enabled in the guest.

Signed-off-by: Olaf Hering <olaf@aepfle.de>
This commit is contained in:
Keir Fraser committed 2010-09-22 18:29:24 +01:00
1 parent d8800299db
commit ecb35ecb79
1 file changed
+59 -38
+59 -38
View File
@@ -139,6 +139,34 @@ shared_entry_header(struct grant_table *t, grant_ref_t ref)
#define active_entry(t, e) \
((t)->active[(e)/ACGNT_PER_PAGE][(e)%ACGNT_PER_PAGE])
/* Check if the page has been paged out */
static int __get_paged_frame(unsigned long gfn, unsigned long *frame, int readonly, struct domain *rd)
{
struct p2m_domain *p2m;
p2m_type_t p2mt;
mfn_t mfn;
int rc = GNTST_okay;
p2m = p2m_get_hostp2m(rd);
if ( readonly )
mfn = gfn_to_mfn(p2m, gfn, &p2mt);
else
mfn = gfn_to_mfn_unshare(p2m, gfn, &p2mt, 1);
if ( p2m_is_valid(p2mt) ) {
*frame = mfn_x(mfn);
if ( p2m_is_paged(p2mt) )
p2m_mem_paging_populate(p2m, gfn);
if ( p2m_is_paging(p2mt) )
rc = GNTST_eagain;
} else {
*frame = INVALID_MFN;
rc = GNTST_bad_page;
}
return rc;
}
static inline int
__get_maptrack_handle(
struct grant_table *t)
@@ -527,14 +555,16 @@ __gnttab_map_grant_ref(
if ( !act->pin )
{
unsigned long gfn;
unsigned long frame;
gfn = sha1 ? sha1->frame : sha2->full_page.frame;
rc = __get_paged_frame(gfn, &frame, !!(op->flags & GNTMAP_readonly), rd);
if ( rc != GNTST_okay )
goto unlock_out;
act->gfn = gfn;
act->domid = ld->domain_id;
if ( sha1 )
act->gfn = sha1->frame;
else
act->gfn = sha2->full_page.frame;
act->frame = (op->flags & GNTMAP_readonly) ?
gmfn_to_mfn(rd, act->gfn) :
gfn_to_mfn_private(rd, act->gfn);
act->frame = frame;
act->start = 0;
act->length = PAGE_SIZE;
act->is_sub_page = 0;
@@ -1697,6 +1727,7 @@ __acquire_grant_for_copy(
domid_t trans_domid;
grant_ref_t trans_gref;
struct domain *rrd;
unsigned long gfn;
unsigned long grant_frame;
unsigned trans_page_off;
unsigned trans_length;
@@ -1814,9 +1845,11 @@ __acquire_grant_for_copy(
}
else if ( sha1 )
{
act->gfn = sha1->frame;
grant_frame = readonly ? gmfn_to_mfn(rd, act->gfn) :
gfn_to_mfn_private(rd, act->gfn);
gfn = sha1->frame;
rc = __get_paged_frame(gfn, &grant_frame, readonly, rd);
if ( rc != GNTST_okay )
goto unlock_out;
act->gfn = gfn;
is_sub_page = 0;
trans_page_off = 0;
trans_length = PAGE_SIZE;
@@ -1824,9 +1857,11 @@ __acquire_grant_for_copy(
}
else if ( !(sha2->hdr.flags & GTF_sub_page) )
{
act->gfn = sha2->full_page.frame;
grant_frame = readonly ? gmfn_to_mfn(rd, act->gfn) :
gfn_to_mfn_private(rd, act->gfn);
gfn = sha2->full_page.frame;
rc = __get_paged_frame(gfn, &grant_frame, readonly, rd);
if ( rc != GNTST_okay )
goto unlock_out;
act->gfn = gfn;
is_sub_page = 0;
trans_page_off = 0;
trans_length = PAGE_SIZE;
@@ -1834,9 +1869,11 @@ __acquire_grant_for_copy(
}
else
{
act->gfn = sha2->sub_page.frame;
grant_frame = readonly ? gmfn_to_mfn(rd, act->gfn) :
gfn_to_mfn_private(rd, act->gfn);
gfn = sha2->sub_page.frame;
rc = __get_paged_frame(gfn, &grant_frame, readonly, rd);
if ( rc != GNTST_okay )
goto unlock_out;
act->gfn = gfn;
is_sub_page = 1;
trans_page_off = sha2->sub_page.page_off;
trans_length = sha2->sub_page.length;
@@ -1932,17 +1969,9 @@ __gnttab_copy(
else
{
#ifdef CONFIG_X86
p2m_type_t p2mt;
struct p2m_domain *p2m = p2m_get_hostp2m(sd);
s_frame = mfn_x(gfn_to_mfn(p2m, op->source.u.gmfn, &p2mt));
if ( !p2m_is_valid(p2mt) )
s_frame = INVALID_MFN;
if ( p2m_is_paging(p2mt) )
{
p2m_mem_paging_populate(p2m, op->source.u.gmfn);
rc = -ENOENT;
goto error_out;
}
rc = __get_paged_frame(op->source.u.gmfn, &s_frame, 1, sd);
if ( rc != GNTST_okay )
goto error_out;
#else
s_frame = gmfn_to_mfn(sd, op->source.u.gmfn);
#endif
@@ -1979,17 +2008,9 @@ __gnttab_copy(
else
{
#ifdef CONFIG_X86
p2m_type_t p2mt;
struct p2m_domain *p2m = p2m_get_hostp2m(dd);
d_frame = mfn_x(gfn_to_mfn_unshare(p2m, op->dest.u.gmfn, &p2mt, 1));
if ( !p2m_is_valid(p2mt) )
d_frame = INVALID_MFN;
if ( p2m_is_paging(p2mt) )
{
p2m_mem_paging_populate(p2m, op->dest.u.gmfn);
rc = -ENOENT;
goto error_out;
}
rc = __get_paged_frame(op->dest.u.gmfn, &d_frame, 0, dd);
if ( rc != GNTST_okay )
goto error_out;
#else
d_frame = gmfn_to_mfn(dd, op->dest.u.gmfn);
#endif
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.