grant-tables: Use get_page_from_gfn() instead of get_gfn()/put_gfn.

This requires some careful re-engineering of __get_paged_frame and its callers.
Functions that previously returned gfn's to be put now return pages to be put.

Tested with Win7 + Citrix PV drivers guest, using speedtest for networking
(yes!) plus the loginVSI framework to constantly hit disk.

Signed-off-by: Andres Lagar-Cavilla <andres@lagarcavilla.org>
This commit is contained in:
Andres Lagar-Cavilla committed 2012-05-17 10:24:54 +01:00
1 parent 06e7bfed20
commit d8cbecb1ee
1 file changed
+90 -133
+90 -133
View File
@@ -107,18 +107,6 @@ static unsigned inline int max_nr_maptrack_frames(void)
return (max_nr_grant_frames * MAX_MAPTRACK_TO_GRANTS_RATIO);
}
#ifdef CONFIG_X86
#define gfn_to_mfn_private(_d, _gfn) ({ \
p2m_type_t __p2mt; \
unsigned long __x; \
__x = mfn_x(get_gfn_unshare((_d), (_gfn), &__p2mt)); \
if ( p2m_is_shared(__p2mt) || !p2m_is_valid(__p2mt) ) \
__x = INVALID_MFN; \
__x; })
#else
#define gfn_to_mfn_private(_d, _gfn) gmfn_to_mfn(_d, _gfn)
#endif
#define SHGNT_PER_PAGE_V1 (PAGE_SIZE / sizeof(grant_entry_v1_t))
#define shared_entry_v1(t, e) \
((t)->shared_v1[(e)/SHGNT_PER_PAGE_V1][(e)%SHGNT_PER_PAGE_V1])
@@ -141,41 +129,41 @@ 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. If rc == GNTST_okay, caller must do put_gfn(rd, gfn) */
static int __get_paged_frame(unsigned long gfn, unsigned long *frame, int readonly, struct domain *rd)
/* Check if the page has been paged out, or needs unsharing.
If rc == GNTST_okay, *page contains the page struct with a ref taken.
Caller must do put_page(*page).
If any error, *page = NULL, *frame = INVALID_MFN, no ref taken. */
static int __get_paged_frame(unsigned long gfn, unsigned long *frame, struct page_info **page,
int readonly, struct domain *rd)
{
int rc = GNTST_okay;
#if defined(P2M_PAGED_TYPES) || defined(P2M_SHARED_TYPES)
p2m_type_t p2mt;
mfn_t mfn;
if ( readonly )
mfn = get_gfn(rd, gfn, &p2mt);
else
*page = get_page_from_gfn(rd, gfn, &p2mt,
(readonly) ? P2M_ALLOC : P2M_UNSHARE);
if ( !(*page) )
{
mfn = get_gfn_unshare(rd, gfn, &p2mt);
*frame = INVALID_MFN;
if ( p2m_is_shared(p2mt) )
{
put_gfn(rd, gfn);
return GNTST_eagain;
}
}
if ( p2m_is_valid(p2mt) ) {
*frame = mfn_x(mfn);
if ( p2m_is_paging(p2mt) )
{
put_gfn(rd, gfn);
p2m_mem_paging_populate(rd, gfn);
rc = GNTST_eagain;
return GNTST_eagain;
}
} else {
put_gfn(rd, gfn);
*frame = INVALID_MFN;
rc = GNTST_bad_page;
return GNTST_bad_page;
}
*frame = page_to_mfn(*page);
#else
*frame = readonly ? gmfn_to_mfn(rd, gfn) : gfn_to_mfn_private(rd, gfn);
*frame = gmfn_to_mfn(rd, gfn);
*page = mfn_valid(*frame) ? mfn_to_page(*frame) : NULL;
if ( (!(*page)) || (!get_page(*page, rd)) )
{
*frame = INVALID_MFN;
*page = NULL;
rc = GNTST_bad_page;
}
#endif
return rc;
@@ -470,12 +458,11 @@ static void
__gnttab_map_grant_ref(
struct gnttab_map_grant_ref *op)
{
struct domain *ld, *rd, *owner;
struct domain *ld, *rd, *owner = NULL;
struct vcpu *led;
int handle;
unsigned long gfn = INVALID_GFN;
unsigned long frame = 0, nr_gets = 0;
struct page_info *pg;
struct page_info *pg = NULL;
int rc = GNTST_okay;
u32 old_pin;
u32 act_pin;
@@ -573,13 +560,11 @@ __gnttab_map_grant_ref(
{
unsigned long frame;
gfn = sha1 ? sha1->frame : sha2->full_page.frame;
rc = __get_paged_frame(gfn, &frame, !!(op->flags & GNTMAP_readonly), rd);
unsigned long gfn = sha1 ? sha1->frame : sha2->full_page.frame;
rc = __get_paged_frame(gfn, &frame, &pg,
!!(op->flags & GNTMAP_readonly), rd);
if ( rc != GNTST_okay )
{
gfn = INVALID_GFN;
goto unlock_out_clear;
}
act->gfn = gfn;
act->domid = ld->domain_id;
act->frame = frame;
@@ -606,9 +591,17 @@ __gnttab_map_grant_ref(
spin_unlock(&rd->grant_table->lock);
pg = mfn_valid(frame) ? mfn_to_page(frame) : NULL;
/* pg may be set, with a refcount included, from __get_paged_frame */
if ( !pg )
{
pg = mfn_valid(frame) ? mfn_to_page(frame) : NULL;
if ( pg )
owner = page_get_owner_and_reference(pg);
}
else
owner = page_get_owner(pg);
if ( !pg || (owner = page_get_owner_and_reference(pg)) == dom_io )
if ( !pg || (owner == dom_io) )
{
/* Only needed the reference to confirm dom_io ownership. */
if ( pg )
@@ -708,8 +701,6 @@ __gnttab_map_grant_ref(
op->handle = handle;
op->status = GNTST_okay;
if ( gfn != INVALID_GFN )
put_gfn(rd, gfn);
rcu_unlock_domain(rd);
return;
@@ -748,8 +739,6 @@ __gnttab_map_grant_ref(
gnttab_clear_flag(_GTF_reading, status);
unlock_out:
if ( gfn != INVALID_GFN )
put_gfn(rd, gfn);
spin_unlock(&rd->grant_table->lock);
op->status = rc;
put_maptrack_handle(ld->grant_table, handle);
@@ -1479,7 +1468,16 @@ gnttab_transfer(
return -EFAULT;
}
mfn = gfn_to_mfn_private(d, gop.mfn);
#ifdef CONFIG_X86
{
p2m_type_t __p2mt;
mfn = mfn_x(get_gfn_unshare(d, gop.mfn, &__p2mt));
if ( p2m_is_shared(__p2mt) || !p2m_is_valid(__p2mt) )
mfn = INVALID_MFN;
}
#else
mfn = gmfn_to_mfn(d, gop.mfn);
#endif
/* Check the passed page frame for basic validity. */
if ( unlikely(!mfn_valid(mfn)) )
@@ -1723,15 +1721,14 @@ static void __fixup_status_for_pin(const struct active_grant_entry *act,
}
/* Grab a frame number from a grant entry and update the flags and pin
count as appropriate. Note that this does *not* update the page
type or reference counts, and does not check that the mfn is
actually valid. If *gfn != INVALID_GFN, and rc == GNTST_okay, then
we leave this function holding the p2m entry for *gfn in *owning_domain */
count as appropriate. If rc == GNTST_okay, note that this *does*
take one ref count on the target page, stored in *page.
If there is any error, *page = NULL, no ref taken. */
static int
__acquire_grant_for_copy(
struct domain *rd, unsigned long gref, struct domain *ld, int readonly,
unsigned long *frame, unsigned long *gfn, unsigned *page_off, unsigned *length,
unsigned allow_transitive, struct domain **owning_domain)
unsigned long *frame, struct page_info **page,
unsigned *page_off, unsigned *length, unsigned allow_transitive)
{
grant_entry_v1_t *sha1;
grant_entry_v2_t *sha2;
@@ -1746,11 +1743,9 @@ __acquire_grant_for_copy(
unsigned trans_page_off;
unsigned trans_length;
int is_sub_page;
struct domain *ignore;
s16 rc = GNTST_okay;
*owning_domain = NULL;
*gfn = INVALID_GFN;
*page = NULL;
spin_lock(&rd->grant_table->lock);
@@ -1827,14 +1822,13 @@ __acquire_grant_for_copy(
spin_unlock(&rd->grant_table->lock);
rc = __acquire_grant_for_copy(td, trans_gref, rd,
readonly, &grant_frame, gfn,
&trans_page_off, &trans_length,
0, &ignore);
readonly, &grant_frame, page,
&trans_page_off, &trans_length, 0);
spin_lock(&rd->grant_table->lock);
if ( rc != GNTST_okay ) {
__fixup_status_for_pin(act, status);
rcu_unlock_domain(td);
rcu_unlock_domain(td);
spin_unlock(&rd->grant_table->lock);
return rc;
}
@@ -1846,56 +1840,49 @@ __acquire_grant_for_copy(
if ( act->pin != old_pin )
{
__fixup_status_for_pin(act, status);
rcu_unlock_domain(td);
rcu_unlock_domain(td);
spin_unlock(&rd->grant_table->lock);
put_page(*page);
return __acquire_grant_for_copy(rd, gref, ld, readonly,
frame, gfn, page_off, length,
allow_transitive,
owning_domain);
frame, page, page_off, length,
allow_transitive);
}
/* The actual remote remote grant may or may not be a
sub-page, but we always treat it as one because that
blocks mappings of transitive grants. */
is_sub_page = 1;
*owning_domain = td;
act->gfn = -1ul;
}
else if ( sha1 )
{
*gfn = sha1->frame;
rc = __get_paged_frame(*gfn, &grant_frame, readonly, rd);
rc = __get_paged_frame(sha1->frame, &grant_frame, page, readonly, rd);
if ( rc != GNTST_okay )
goto unlock_out;
act->gfn = *gfn;
act->gfn = sha1->frame;
is_sub_page = 0;
trans_page_off = 0;
trans_length = PAGE_SIZE;
*owning_domain = rd;
}
else if ( !(sha2->hdr.flags & GTF_sub_page) )
{
*gfn = sha2->full_page.frame;
rc = __get_paged_frame(*gfn, &grant_frame, readonly, rd);
rc = __get_paged_frame(sha2->full_page.frame, &grant_frame, page, readonly, rd);
if ( rc != GNTST_okay )
goto unlock_out;
act->gfn = *gfn;
act->gfn = sha2->full_page.frame;
is_sub_page = 0;
trans_page_off = 0;
trans_length = PAGE_SIZE;
*owning_domain = rd;
}
else
{
*gfn = sha2->sub_page.frame;
rc = __get_paged_frame(*gfn, &grant_frame, readonly, rd);
rc = __get_paged_frame(sha2->sub_page.frame, &grant_frame, page, readonly, rd);
if ( rc != GNTST_okay )
goto unlock_out;
act->gfn = *gfn;
act->gfn = sha2->sub_page.frame;
is_sub_page = 1;
trans_page_off = sha2->sub_page.page_off;
trans_length = sha2->sub_page.length;
*owning_domain = rd;
}
if ( !act->pin )
@@ -1911,7 +1898,9 @@ __acquire_grant_for_copy(
}
else
{
*owning_domain = rd;
ASSERT(mfn_valid(act->frame));
*page = mfn_to_page(act->frame);
(void)page_get_owner_and_reference(*page);
}
act->pin += readonly ? GNTPIN_hstr_inc : GNTPIN_hstw_inc;
@@ -1930,11 +1919,11 @@ __gnttab_copy(
struct gnttab_copy *op)
{
struct domain *sd = NULL, *dd = NULL;
struct domain *source_domain = NULL, *dest_domain = NULL;
unsigned long s_frame, d_frame, s_gfn = INVALID_GFN, d_gfn = INVALID_GFN;
unsigned long s_frame, d_frame;
struct page_info *s_pg = NULL, *d_pg = NULL;
char *sp, *dp;
s16 rc = GNTST_okay;
int have_d_grant = 0, have_s_grant = 0, have_s_ref = 0;
int have_d_grant = 0, have_s_grant = 0;
int src_is_gref, dest_is_gref;
if ( ((op->source.offset + op->len) > PAGE_SIZE) ||
@@ -1972,82 +1961,54 @@ __gnttab_copy(
{
unsigned source_off, source_len;
rc = __acquire_grant_for_copy(sd, op->source.u.ref, current->domain, 1,
&s_frame, &s_gfn, &source_off, &source_len, 1,
&source_domain);
&s_frame, &s_pg, &source_off, &source_len, 1);
if ( rc != GNTST_okay )
goto error_out;
have_s_grant = 1;
if ( op->source.offset < source_off ||
op->len > source_len )
PIN_FAIL(error_put_s_gfn, GNTST_general_error,
PIN_FAIL(error_out, GNTST_general_error,
"copy source out of bounds: %d < %d || %d > %d\n",
op->source.offset, source_off,
op->len, source_len);
}
else
{
#ifdef CONFIG_X86
s_gfn = op->source.u.gmfn;
rc = __get_paged_frame(op->source.u.gmfn, &s_frame, 1, sd);
rc = __get_paged_frame(op->source.u.gmfn, &s_frame, &s_pg, 1, sd);
if ( rc != GNTST_okay )
goto error_out;
#else
s_frame = gmfn_to_mfn(sd, op->source.u.gmfn);
#endif
source_domain = sd;
PIN_FAIL(error_out, rc,
"source frame %lx invalid.\n", s_frame);
}
if ( unlikely(!mfn_valid(s_frame)) )
PIN_FAIL(error_put_s_gfn, GNTST_general_error,
"source frame %lx invalid.\n", s_frame);
/* For the source frame, the page could still be shared, so
* don't assume ownership by source_domain */
if ( !page_get_owner_and_reference(mfn_to_page(s_frame)) )
{
if ( !sd->is_dying )
gdprintk(XENLOG_WARNING, "Could not get src frame %lx\n", s_frame);
rc = GNTST_general_error;
goto error_put_s_gfn;
}
have_s_ref = 1;
if ( dest_is_gref )
{
unsigned dest_off, dest_len;
rc = __acquire_grant_for_copy(dd, op->dest.u.ref, current->domain, 0,
&d_frame, &d_gfn, &dest_off, &dest_len, 1,
&dest_domain);
&d_frame, &d_pg, &dest_off, &dest_len, 1);
if ( rc != GNTST_okay )
goto error_put_s_gfn;
goto error_out;
have_d_grant = 1;
if ( op->dest.offset < dest_off ||
op->len > dest_len )
PIN_FAIL(error_put_d_gfn, GNTST_general_error,
PIN_FAIL(error_out, GNTST_general_error,
"copy dest out of bounds: %d < %d || %d > %d\n",
op->dest.offset, dest_off,
op->len, dest_len);
}
else
{
#ifdef CONFIG_X86
d_gfn = op->dest.u.gmfn;
rc = __get_paged_frame(op->dest.u.gmfn, &d_frame, 0, dd);
rc = __get_paged_frame(op->dest.u.gmfn, &d_frame, &d_pg, 0, dd);
if ( rc != GNTST_okay )
goto error_put_s_gfn;
#else
d_frame = gmfn_to_mfn(dd, op->dest.u.gmfn);
#endif
dest_domain = dd;
PIN_FAIL(error_out, rc,
"destination frame %lx invalid.\n", d_frame);
}
if ( unlikely(!mfn_valid(d_frame)) )
PIN_FAIL(error_put_d_gfn, GNTST_general_error,
"destination frame %lx invalid.\n", d_frame);
if ( !get_page_and_type(mfn_to_page(d_frame), dest_domain,
PGT_writable_page) )
if ( !get_page_type(d_pg, PGT_writable_page) )
{
if ( !dd->is_dying )
gdprintk(XENLOG_WARNING, "Could not get dst frame %lx\n", d_frame);
rc = GNTST_general_error;
goto error_put_d_gfn;
goto error_out;
}
sp = map_domain_page(s_frame);
@@ -2060,16 +2021,12 @@ __gnttab_copy(
gnttab_mark_dirty(dd, d_frame);
put_page_and_type(mfn_to_page(d_frame));
error_put_d_gfn:
if ( (d_gfn != INVALID_GFN) && (dest_domain) )
put_gfn(dest_domain, d_gfn);
error_put_s_gfn:
if ( (s_gfn != INVALID_GFN) && (source_domain) )
put_gfn(source_domain, s_gfn);
put_page_type(d_pg);
error_out:
if ( have_s_ref )
put_page(mfn_to_page(s_frame));
if ( d_pg )
put_page(d_pg);
if ( s_pg )
put_page(s_pg);
if ( have_s_grant )
__release_grant_for_copy(sd, op->source.u.ref, 1);
if ( have_d_grant )
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.