Subject: 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. (xen-unstable changeset: 22209:50c1cc209f8f) Signed-off-by: Olaf Hering Already-Acked-by: Patrick Colp Already-Acked-by: Keir Fraser --- xen/common/grant_table.c | 94 ++++++++++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 34 deletions(-) Index: xen-4.0.2-testing/xen/common/grant_table.c =================================================================== --- xen-4.0.2-testing.orig/xen/common/grant_table.c +++ xen-4.0.2-testing/xen/common/grant_table.c @@ -139,6 +139,37 @@ shared_entry_header(struct grant_table * #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) +{ + p2m_type_t p2mt; + mfn_t mfn; + int rc = GNTST_okay; + + if ( readonly ) + mfn = gfn_to_mfn(rd, gfn, &p2mt); + else + mfn = gfn_to_mfn_unshare(rd, gfn, &p2mt, 1); + + if ( p2m_is_valid(p2mt) ) + { + *frame = mfn_x(mfn); + if ( p2m_is_paging(p2mt) ) + { + if ( p2m_is_paged(p2mt) ) + p2m_mem_paging_populate(rd, gfn); + 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 +558,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 +1730,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 +1848,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 +1860,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 +1872,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,16 +1972,9 @@ __gnttab_copy( else { #ifdef CONFIG_X86 - p2m_type_t p2mt; - s_frame = mfn_x(gfn_to_mfn(sd, op->source.u.gmfn, &p2mt)); - if ( !p2m_is_valid(p2mt) ) - s_frame = INVALID_MFN; - if ( p2m_is_paging(p2mt) ) - { - p2m_mem_paging_populate(sd, op->source.u.gmfn); - rc = -ENOENT; + 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 @@ -1978,16 +2011,9 @@ __gnttab_copy( else { #ifdef CONFIG_X86 - p2m_type_t p2mt; - d_frame = mfn_x(gfn_to_mfn_unshare(dd, op->dest.u.gmfn, &p2mt, 1)); - if ( !p2m_is_valid(p2mt) ) - d_frame = INVALID_MFN; - if ( p2m_is_paging(p2mt) ) - { - p2m_mem_paging_populate(dd, op->dest.u.gmfn); - rc = -ENOENT; + 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