WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH 07 of 10] Transitive grant support

# HG changeset patch
# User Steven Smith <steven.smith@xxxxxxxxxxxxx>
# Date 1227887022 0
# Node ID 0f3f1ea314eabe9c73d11b7f68db1a479e0db006
# Parent  50e9196c995111491077834b7a3ff98d631df1f2
Transitive grant support.

Signed-off-by: Steven Smith <steven.smith@xxxxxxxxxx>

diff -r 50e9196c9951 -r 0f3f1ea314ea xen/common/grant_table.c
--- a/xen/common/grant_table.c  Mon Sep 22 13:09:07 2008 +0100
+++ b/xen/common/grant_table.c  Fri Nov 28 15:43:42 2008 +0000
@@ -309,11 +309,12 @@
 
     /* 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 @@
 
     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)) )
         {
@@ -735,7 +737,7 @@
     {
         if ( unlikely(op->frame != act->frame) )
             PIN_FAIL(unmap_out, GNTST_general_error,
-                     "Bad frame number doesn't match gntref. (%lx != %lx)\n",
+                     "Bad frame number doesn't match gntref. (%lx != %x)\n",
                      op->frame, act->frame);
         if ( op->flags & GNTMAP_device_map )
         {
@@ -1533,6 +1535,14 @@
     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 @@
     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 @@
 
         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 @@
    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,40 +1677,126 @@
 
     /* 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);
+            trans_page_off = 0;
+            trans_length = PAGE_SIZE;
+            is_sub_page = 0;
+            *owning_domain = rd;
+        }
+        else
+        {
+            act->gfn = sha2->frame;
+            grant_frame = gmfn_to_mfn(rd, act->gfn);
+            is_sub_page = !!(shah->flags & GTF_sub_page);
+            if ( is_sub_page )
+            {
+                trans_page_off = sha2->sub_page.page_off;
+                trans_length = sha2->sub_page.length;
+            }
+            else
+            {
+                trans_page_off = 0;
+                trans_length = PAGE_SIZE;
+            }
+            *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 ( sha2 && (shah->flags & GTF_sub_page) )
-            {
-                act->start = sha2->sub_page.page_off;
-                act->length = sha2->sub_page.length;
-                act->is_sub_page = 1;
-            }
-
-            if ( sha1 )
-                act->gfn = sha1->frame;
-            else
-                act->gfn = sha2->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;
@@ -1659,6 +1815,7 @@
     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;
@@ -1699,8 +1856,9 @@
     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;
@@ -1714,11 +1872,12 @@
     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);
@@ -1730,8 +1889,9 @@
     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;
@@ -1745,11 +1905,13 @@
     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 50e9196c9951 -r 0f3f1ea314ea xen/include/public/grant_table.h
--- a/xen/include/public/grant_table.h  Mon Sep 22 13:09:07 2008 +0100
+++ b/xen/include/public/grant_table.h  Fri Nov 28 15:43:42 2008 +0000
@@ -85,6 +85,11 @@
  */
 
 /*
+ * 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
  * page frames shared between Xen and a guest.
  * [XEN]: This field is written by Xen and read by the sharing guest.
@@ -118,10 +123,13 @@
  *  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)
 
 /*
@@ -209,6 +217,21 @@
             uint16_t length;
         } 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 {
+            domid_t trans_domid;
+            uint16_t pad0;
+            grant_ref_t gref;
+        } transitive;
+
         uint32_t __spacer[3]; /* Pad to a power of two */
     };
 };
@@ -221,11 +244,6 @@
 /***********************************
  * 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 50e9196c9951 -r 0f3f1ea314ea xen/include/xen/grant_table.h
--- a/xen/include/xen/grant_table.h     Mon Sep 22 13:09:07 2008 +0100
+++ b/xen/include/xen/grant_table.h     Fri Nov 28 15:43:42 2008 +0000
@@ -32,7 +32,9 @@
 struct active_grant_entry {
     u32           pin;    /* Reference count information.             */
     domid_t       domid;  /* Domain being granted access.             */
-    unsigned long frame;  /* Frame being granted.                     */
+    domid_t       trans_dom;
+    uint32_t      trans_gref;
+    uint32_t      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. */
     unsigned      start:15; /* For sub-page grants, the start offset
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
<Prev in Thread] Current Thread [Next in Thread>