[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Transitive grant support.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1254898041 -3600 # Node ID 47cf6033d2cc08198c267ed9d17bdafb1fe0c490 # Parent ef9f401b32ca43e1fc066f260a999dcbf0992010 Transitive grant support. Signed-off-by: Steven Smith <steven.smith@xxxxxxxxxx> --- xen/common/grant_table.c | 238 ++++++++++++++++++++++++++++++++------- xen/include/public/grant_table.h | 29 +++- xen/include/xen/grant_table.h | 2 3 files changed, 224 insertions(+), 45 deletions(-) diff -r ef9f401b32ca -r 47cf6033d2cc xen/common/grant_table.c --- a/xen/common/grant_table.c Wed Oct 07 07:46:59 2009 +0100 +++ b/xen/common/grant_table.c Wed Oct 07 07:47:21 2009 +0100 @@ -309,11 +309,12 @@ static int _set_status_v2(domid_t domid /* If not already pinned, check the grant domid and type. */ if ( !act->pin && - (((flags & mask) != GTF_permit_access) || + ( (((flags & mask) != GTF_permit_access) && + ((flags & mask) != GTF_transitive)) || (id != domid)) ) PIN_FAIL(done, GNTST_general_error, - "Bad flags (%x) or dom (%d). (expected dom %d)\n", - flags, id, domid); + "Bad flags (%x) or dom (%d). (expected dom %d, flags %x)\n", + flags, id, domid, mask); if ( readonly ) { @@ -338,7 +339,8 @@ static int _set_status_v2(domid_t domid if ( !act->pin ) { - if ( ((flags & mask) != GTF_permit_access) || + if ( (((flags & mask) != GTF_permit_access) && + ((flags & mask) != GTF_transitive)) || (id != domid) || (!readonly && (flags & GTF_readonly)) ) { @@ -1533,6 +1535,14 @@ __release_grant_for_copy( struct active_grant_entry *act; unsigned long r_frame; uint16_t *status; + domid_t trans_domid; + grant_ref_t trans_gref; + int released_read; + int released_write; + struct domain *trans_dom; + + released_read = 0; + released_write = 0; spin_lock(&rd->grant_table->lock); @@ -1541,9 +1551,19 @@ __release_grant_for_copy( r_frame = act->frame; if (rd->grant_table->gt_version == 1) + { status = &sha->flags; + trans_domid = rd->domain_id; + /* Shut the compiler up. This'll never be used, because + trans_domid == rd->domain_id, but gcc doesn't know that. */ + trans_gref = 0x1234567; + } else + { status = &status_entry(rd->grant_table, gref); + trans_domid = act->trans_dom; + trans_gref = act->trans_gref; + } if ( readonly ) { @@ -1555,13 +1575,51 @@ __release_grant_for_copy( act->pin -= GNTPIN_hstw_inc; if ( !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) ) + { + released_write = 1; gnttab_clear_flag(_GTF_writing, status); + } } if ( !act->pin ) + { gnttab_clear_flag(_GTF_reading, status); + released_read = 1; + } spin_unlock(&rd->grant_table->lock); + + if ( trans_domid != rd->domain_id ) + { + if ( released_write || released_read ) + { + trans_dom = rcu_lock_domain_by_id(trans_domid); + if ( trans_dom != NULL ) + { + /* Recursive calls, but they're tail calls, so it's + okay. */ + if ( released_write ) + __release_grant_for_copy(trans_dom, trans_gref, 0); + else if ( released_read ) + __release_grant_for_copy(trans_dom, trans_gref, 1); + } + } + } +} + +/* The status for a grant indicates that we're taking more access than + the pin requires. Fix up the status to match the pin. Called + under the domain's grant table lock. */ +/* Only safe on transitive grants. Even then, note that we don't + attempt to drop any pin on the referent grant. */ +static void __fixup_status_for_pin(struct active_grant_entry *act, + uint16_t *status) +{ + if ( !(act->pin & GNTPIN_hstw_mask) ) + *status &= ~_GTF_writing; + + if ( !(act->pin & GNTPIN_hstr_mask) ) + *status &= ~_GTF_reading; } /* Grab a frame number from a grant entry and update the flags and pin @@ -1570,15 +1628,27 @@ __release_grant_for_copy( actually valid. */ static int __acquire_grant_for_copy( - struct domain *rd, unsigned long gref, int readonly, - unsigned long *frame, unsigned *page_off, unsigned *length) + struct domain *rd, unsigned long gref, struct domain *ld, int readonly, + unsigned long *frame, unsigned *page_off, unsigned *length, + unsigned allow_transitive, struct domain **owning_domain) { grant_entry_v1_t *sha1; grant_entry_v2_t *sha2; grant_entry_header_t *shah; struct active_grant_entry *act; grant_status_t *status; + uint32_t old_pin; + domid_t trans_domid; + grant_ref_t trans_gref; + struct domain *rrd; + unsigned long grant_frame; + unsigned trans_page_off; + unsigned trans_length; + int is_sub_page; + struct domain *ignore; s16 rc = GNTST_okay; + + *owning_domain = NULL; spin_lock(&rd->grant_table->lock); @@ -1607,45 +1677,127 @@ __acquire_grant_for_copy( /* If already pinned, check the active domid and avoid refcnt overflow. */ if ( act->pin && - ((act->domid != current->domain->domain_id) || + ((act->domid != ld->domain_id) || (act->pin & 0x80808080U) != 0) ) PIN_FAIL(unlock_out, GNTST_general_error, "Bad domain (%d != %d), or risk of counter overflow %08x\n", - act->domid, current->domain->domain_id, act->pin); - + act->domid, ld->domain_id, act->pin); + + old_pin = act->pin; if ( !act->pin || (!readonly && !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) ) { if ( (rc = _set_status(rd->grant_table->gt_version, - current->domain->domain_id, - readonly, 0, shah, act, status) ) != GNTST_okay ) + ld->domain_id, + readonly, 0, shah, act, + status) ) != GNTST_okay ) goto unlock_out; + trans_domid = ld->domain_id; + trans_gref = 0; + if ( sha2 && (shah->flags & GTF_type_mask) == GTF_transitive ) + { + if ( !allow_transitive ) + PIN_FAIL(unlock_out, GNTST_general_error, + "transitive grant when transitivity not allowed\n"); + + trans_domid = sha2->transitive.trans_domid; + trans_gref = sha2->transitive.gref; + barrier(); /* Stop the compiler from re-loading + trans_domid from shared memory */ + if ( trans_domid == rd->domain_id ) + PIN_FAIL(unlock_out, GNTST_general_error, + "transitive grants cannot be self-referential\n"); + + /* We allow the trans_domid == ld->domain_id case, which + corresponds to a grant being issued by one domain, sent + to another one, and then transitively granted back to + the original domain. Allowing it is easy, and means + that you don't need to go out of your way to avoid it + in the guest. */ + + rrd = rcu_lock_domain_by_id(trans_domid); + if ( rrd == NULL ) + PIN_FAIL(unlock_out, GNTST_general_error, + "transitive grant referenced bad domain %d\n", + trans_domid); + spin_unlock(&rd->grant_table->lock); + + rc = __acquire_grant_for_copy(rrd, trans_gref, rd, + readonly, &grant_frame, + &trans_page_off, &trans_length, + 0, &ignore); + + spin_lock(&rd->grant_table->lock); + if ( rc != GNTST_okay ) { + __fixup_status_for_pin(act, status); + spin_unlock(&rd->grant_table->lock); + return rc; + } + + /* We dropped the lock, so we have to check that nobody + else tried to pin (or, for that matter, unpin) the + reference in *this* domain. If they did, just give up + and try again. */ + if ( act->pin != old_pin ) + { + __fixup_status_for_pin(act, status); + spin_unlock(&rd->grant_table->lock); + return __acquire_grant_for_copy(rd, gref, ld, readonly, + frame, page_off, length, + allow_transitive, + owning_domain); + } + + /* 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 = rrd; + act->gfn = INVALID_GFN; + } + else if ( sha1 ) + { + act->gfn = sha1->frame; + grant_frame = gmfn_to_mfn(rd, act->gfn); + is_sub_page = 0; + trans_page_off = 0; + trans_length = PAGE_SIZE; + *owning_domain = rd; + } + else if ( !(sha2->hdr.flags & GTF_sub_page) ) + { + act->gfn = sha2->full_page.frame; + grant_frame = gmfn_to_mfn(rd, act->gfn); + is_sub_page = 0; + trans_page_off = 0; + trans_length = PAGE_SIZE; + *owning_domain = rd; + } + else + { + act->gfn = sha2->sub_page.frame; + grant_frame = gmfn_to_mfn(rd, act->gfn); + is_sub_page = 1; + trans_page_off = sha2->sub_page.page_off; + trans_length = sha2->sub_page.length; + *owning_domain = rd; + } + if ( !act->pin ) { - act->domid = current->domain->domain_id; - act->is_sub_page = 0; - act->start = 0; - act->length = PAGE_SIZE; - - if ( sha1 ) - { - act->gfn = sha1->frame; - } - else if ( shah->flags & GTF_sub_page ) - { - act->start = sha2->sub_page.page_off; - act->length = sha2->sub_page.length; - act->is_sub_page = 1; - act->gfn = sha2->sub_page.frame; - } - else - { - act->gfn = sha2->full_page.frame; - } - - act->frame = gmfn_to_mfn(rd, act->gfn); - } + act->domid = ld->domain_id; + act->is_sub_page = is_sub_page; + act->start = trans_page_off; + act->length = trans_length; + act->trans_dom = trans_domid; + act->trans_gref = trans_gref; + act->frame = grant_frame; + } + } + else + { + *owning_domain = rd; } act->pin += readonly ? GNTPIN_hstr_inc : GNTPIN_hstw_inc; @@ -1664,6 +1816,7 @@ __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; char *sp, *dp; s16 rc = GNTST_okay; @@ -1704,8 +1857,9 @@ __gnttab_copy( if ( src_is_gref ) { unsigned source_off, source_len; - rc = __acquire_grant_for_copy(sd, op->source.u.ref, 1, &s_frame, - &source_off, &source_len); + rc = __acquire_grant_for_copy(sd, op->source.u.ref, current->domain, 1, + &s_frame, &source_off, &source_len, 1, + &source_domain); if ( rc != GNTST_okay ) goto error_out; have_s_grant = 1; @@ -1719,11 +1873,12 @@ __gnttab_copy( else { s_frame = gmfn_to_mfn(sd, op->source.u.gmfn); + source_domain = sd; } if ( unlikely(!mfn_valid(s_frame)) ) PIN_FAIL(error_out, GNTST_general_error, "source frame %lx invalid.\n", s_frame); - if ( !get_page(mfn_to_page(s_frame), sd) ) + if ( !get_page(mfn_to_page(s_frame), source_domain) ) { if ( !sd->is_dying ) gdprintk(XENLOG_WARNING, "Could not get src frame %lx\n", s_frame); @@ -1735,8 +1890,9 @@ __gnttab_copy( if ( dest_is_gref ) { unsigned dest_off, dest_len; - rc = __acquire_grant_for_copy(dd, op->dest.u.ref, 0, &d_frame, - &dest_off, &dest_len); + rc = __acquire_grant_for_copy(dd, op->dest.u.ref, current->domain, 0, + &d_frame, &dest_off, &dest_len, 1, + &dest_domain); if ( rc != GNTST_okay ) goto error_out; have_d_grant = 1; @@ -1750,11 +1906,13 @@ __gnttab_copy( else { d_frame = gmfn_to_mfn(dd, op->dest.u.gmfn); + dest_domain = dd; } if ( unlikely(!mfn_valid(d_frame)) ) PIN_FAIL(error_out, GNTST_general_error, "destination frame %lx invalid.\n", d_frame); - if ( !get_page_and_type(mfn_to_page(d_frame), dd, PGT_writable_page) ) + if ( !get_page_and_type(mfn_to_page(d_frame), dest_domain, + PGT_writable_page) ) { if ( !dd->is_dying ) gdprintk(XENLOG_WARNING, "Could not get dst frame %lx\n", d_frame); diff -r ef9f401b32ca -r 47cf6033d2cc xen/include/public/grant_table.h --- a/xen/include/public/grant_table.h Wed Oct 07 07:46:59 2009 +0100 +++ b/xen/include/public/grant_table.h Wed Oct 07 07:47:21 2009 +0100 @@ -83,6 +83,11 @@ * Changing a GTF_permit_access from read-only to writable: * Use SMP-safe bit-setting instruction. */ + +/* + * Reference to a grant entry in a specified domain's grant table. + */ +typedef uint32_t grant_ref_t; /* * A grant table comprises a packed array of grant entries in one or more @@ -118,10 +123,13 @@ typedef struct grant_entry_v1 grant_entr * GTF_permit_access: Allow @domid to map/access @frame. * GTF_accept_transfer: Allow @domid to transfer ownership of one page frame * to this guest. Xen writes the page number to @frame. + * GTF_transitive: Allow @domid to transitively access a subrange of + * @trans_grant in @trans_domid. No mappings are allowed. */ #define GTF_invalid (0U<<0) #define GTF_permit_access (1U<<0) #define GTF_accept_transfer (2U<<0) +#define GTF_transitive (3U<<0) #define GTF_type_mask (3U<<0) /* @@ -218,6 +226,22 @@ union grant_entry_v2 { uint64_t frame; } sub_page; + /* + * If the grant is GTF_transitive, @domid is allowed to use the + * grant @gref in domain @trans_domid, as if it was the local + * domain. Obviously, the transitive access must be compatible + * with the original grant. + * + * The current version of Xen does not allow transitive grants + * to be mapped. + */ + struct { + grant_entry_header_t hdr; + domid_t trans_domid; + uint16_t pad0; + grant_ref_t gref; + } transitive; + uint32_t __spacer[4]; /* Pad to a power of two */ }; typedef union grant_entry_v2 grant_entry_v2_t; @@ -229,11 +253,6 @@ typedef uint16_t grant_status_t; /*********************************** * GRANT TABLE QUERIES AND USES */ - -/* - * Reference to a grant entry in a specified domain's grant table. - */ -typedef uint32_t grant_ref_t; /* * Handle to track a mapping created via a grant reference. diff -r ef9f401b32ca -r 47cf6033d2cc xen/include/xen/grant_table.h --- a/xen/include/xen/grant_table.h Wed Oct 07 07:46:59 2009 +0100 +++ b/xen/include/xen/grant_table.h Wed Oct 07 07:47:21 2009 +0100 @@ -32,6 +32,8 @@ struct active_grant_entry { struct active_grant_entry { u32 pin; /* Reference count information. */ domid_t domid; /* Domain being granted access. */ + domid_t trans_dom; + uint32_t trans_gref; unsigned long frame; /* Frame being granted. */ unsigned long gfn; /* Guest's idea of the frame being granted. */ unsigned is_sub_page:1; /* True if this is a sub-page grant. */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |