[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [XEN] Add a new type of grant copy operation.



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID 247fc1245b217d33d299abfe88d10fa3ddb6a026
# Parent  4ee64035c0a3def8034ac3ed89b954eb985246a4
[XEN] Add a new type of grant copy operation.
Based on an original patch from Rolf Neugebauer at Intel.
Signed-off-by: Steven Smith <ssmith@xxxxxxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 xen/common/grant_table.c         |  221 +++++++++++++++++++++++++++++++++++++++
 xen/include/public/grant_table.h |   47 ++++++++
 2 files changed, 267 insertions(+), 1 deletion(-)

diff -r 4ee64035c0a3 -r 247fc1245b21 xen/common/grant_table.c
--- a/xen/common/grant_table.c  Thu Aug 10 11:36:27 2006 +0100
+++ b/xen/common/grant_table.c  Thu Aug 10 11:54:15 2006 +0100
@@ -704,6 +704,218 @@ gnttab_transfer(
     return 0;
 }
 
+/* Undo __acquire_grant_for_copy.  Again, this has no effect on page
+   type and reference counts. */
+static void
+__release_grant_for_copy(
+    struct domain *rd, unsigned long gref, int readonly)
+{
+    grant_entry_t *const sha = &rd->grant_table->shared[gref];
+    struct active_grant_entry *const act = &rd->grant_table->active[gref];
+    const unsigned long r_frame = act->frame;
+
+    if ( !readonly )
+        gnttab_log_dirty(rd, r_frame);
+
+    spin_lock(&rd->grant_table->lock);
+    if ( readonly )
+        act->pin -= GNTPIN_hstr_inc;
+    else
+        act->pin -= GNTPIN_hstw_inc;
+
+    if ( !(act->pin & GNTPIN_hstw_mask) && !readonly )
+        clear_bit(_GTF_writing, &sha->flags);
+
+    if ( !act->pin )
+        clear_bit(_GTF_reading, &sha->flags);
+    spin_unlock(&rd->grant_table->lock);
+}
+
+/* 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. */
+static int
+__acquire_grant_for_copy(
+    struct domain *rd, unsigned long gref, int readonly,
+    unsigned long *frame)
+{
+    grant_entry_t *sha;
+    struct active_grant_entry *act;
+    s16 rc = GNTST_okay;
+    int retries = 0;
+    u16 sflags;
+    domid_t sdom;
+
+    if ( unlikely(gref >= NR_GRANT_ENTRIES) )
+        PIN_FAIL(error_out, GNTST_bad_gntref,
+                 "Bad grant reference %ld\n", gref);
+    
+    act = &rd->grant_table->active[gref];
+    sha = &rd->grant_table->shared[gref];
+
+    spin_lock(&rd->grant_table->lock);
+    
+    if ( !act->pin ||
+         (!readonly && !(act->pin & GNTPIN_hstw_mask)) )
+    {
+        sflags = sha->flags;
+        sdom = sha->domid;
+
+        for ( ; ; )
+        {
+            u32 scombo;
+            u32 prev_scombo;
+            u32 new_scombo;
+
+            if ( unlikely((sflags & GTF_type_mask) != GTF_permit_access ||
+                          sdom != current->domain->domain_id ) )
+                PIN_FAIL(unlock_out, GNTST_general_error,
+                         "Bad flags (%x) or dom (%d). (NB. expected dom %d)\n",
+                         sflags, sdom, current->domain->domain_id);
+            scombo = ((u32)sdom << 16) | (u32)sflags;
+            new_scombo = scombo | GTF_reading;
+            if ( !readonly )
+            {
+                new_scombo |= GTF_writing;
+                if ( unlikely(sflags & GTF_readonly) )
+                    PIN_FAIL(unlock_out, GNTST_general_error,
+                             "Attempt to write-pin a r/o grant entry.\n");
+            }
+            prev_scombo = cmpxchg((u32 *)&sha->flags, scombo, new_scombo);
+            if ( likely(prev_scombo == scombo) )
+                break;
+
+            if ( retries++ == 4 )
+                PIN_FAIL(unlock_out, GNTST_general_error,
+                         "Shared grant entry is unstable.\n");
+            sflags = (u16)prev_scombo;
+            sdom = (u16)(prev_scombo >> 16);
+        }
+
+        if ( !act->pin )
+        {
+            act->domid = sdom;
+            act->frame = gmfn_to_mfn(rd, sha->frame);
+        }
+    }
+    else if ( (act->pin & 0x80808080U) != 0 )
+        PIN_FAIL(unlock_out, ENOSPC,
+                 "Risk of counter overflow %08x\n", act->pin);
+
+    act->pin += readonly ? GNTPIN_hstr_inc : GNTPIN_hstw_inc;
+
+    *frame = act->frame;
+
+ unlock_out:
+    spin_unlock(&rd->grant_table->lock);
+ error_out:
+    return rc;
+}
+
+static void
+__gnttab_copy(
+    struct gnttab_copy *op)
+{
+    struct domain *sd = NULL, *dd = NULL;
+    unsigned long s_frame, d_frame;
+    void *sp, *dp;
+    s16 rc = GNTST_okay;
+    int have_d_grant = 0, have_s_grant = 0;
+
+    if ( ((op->source.offset + op->len) > PAGE_SIZE) ||
+         ((op->dest.offset + op->len) > PAGE_SIZE) )
+        PIN_FAIL(error_out, GNTST_bad_copy_arg, "copy beyond page area.\n");
+
+    if ( op->source.domid == DOMID_SELF )
+    {
+        sd = current->domain;
+        get_knownalive_domain(sd);
+    }
+    else if ( (sd = find_domain_by_id(op->source.domid)) == NULL )
+    {
+        PIN_FAIL(error_out, GNTST_bad_domain,
+                 "couldn't find %d\n", op->source.domid);
+    }
+
+    if ( op->dest.domid == DOMID_SELF )
+    {
+        dd = current->domain;
+        get_knownalive_domain(dd);
+    }
+    else if ( (dd = find_domain_by_id(op->dest.domid)) == NULL )
+    {
+        PIN_FAIL(error_out, GNTST_bad_domain,
+                 "couldn't find %d\n", op->dest.domid);
+    }
+
+    if ( op->flags & GNTCOPY_source_gref )
+    {
+        rc = __acquire_grant_for_copy(sd, op->source.u.ref, 1, &s_frame);
+        if ( rc != GNTST_okay )
+            goto error_out;
+        have_s_grant = 1;
+    }
+    else
+    {
+        s_frame = gmfn_to_mfn(sd, op->source.u.gmfn);
+    }
+    if ( !get_page(mfn_to_page(s_frame), sd) )
+        PIN_FAIL(error_out, GNTST_general_error,
+                 "could not get source frame %lx.\n", s_frame);
+
+    if ( op->flags & GNTCOPY_dest_gref )
+    {
+        rc = __acquire_grant_for_copy(dd, op->dest.u.ref, 0, &d_frame);
+        if ( rc != GNTST_okay )
+            goto error_out;
+        have_d_grant = 1;
+    }
+    else
+    {
+        d_frame = gmfn_to_mfn(sd, op->dest.u.gmfn);
+    }
+    if ( !get_page_and_type(mfn_to_page(d_frame), dd, PGT_writable_page) )
+        PIN_FAIL(error_out, GNTST_general_error,
+                 "could not get source frame %lx.\n", d_frame);
+
+    sp = map_domain_page(s_frame);
+    dp = map_domain_page(d_frame);
+
+    memcpy(dp + op->dest.offset, sp + op->source.offset, op->len);
+
+    unmap_domain_page(dp);
+    unmap_domain_page(sp);
+
+ error_out:
+    if ( have_s_grant )
+        __release_grant_for_copy(sd, op->source.u.ref, 1);
+    if ( have_d_grant )
+        __release_grant_for_copy(dd, op->dest.u.ref, 0);
+    if ( sd )
+        put_domain(sd);
+    if ( dd )
+        put_domain(dd);
+    op->status = rc;
+}
+
+static long
+gnttab_copy(
+    XEN_GUEST_HANDLE(gnttab_copy_t) uop, unsigned int count)
+{
+    int i;
+    struct gnttab_copy op;
+
+    for ( i = 0; i < count; i++ )
+    {
+        if ( unlikely(__copy_from_guest_offset(&op, uop, i, 1)) )
+            return -EFAULT;
+        __gnttab_copy(&op);
+        if ( unlikely(__copy_to_guest_offset(uop, i, &op, 1)) )
+            return -EFAULT;
+    }
+    return 0;
+}
+
 long
 do_grant_table_op(
     unsigned int cmd, XEN_GUEST_HANDLE(void) uop, unsigned int count)
@@ -754,6 +966,15 @@ do_grant_table_op(
         rc = gnttab_transfer(transfer, count);
         break;
     }
+    case GNTTABOP_copy:
+    {
+        XEN_GUEST_HANDLE(gnttab_copy_t) copy =
+            guest_handle_cast(uop, gnttab_copy_t);
+        if ( unlikely(!guest_handle_okay(copy, count)) )
+            goto out;
+        rc = gnttab_copy(copy, count);
+        break;
+    }
     default:
         rc = -ENOSYS;
         break;
diff -r 4ee64035c0a3 -r 247fc1245b21 xen/include/public/grant_table.h
--- a/xen/include/public/grant_table.h  Thu Aug 10 11:36:27 2006 +0100
+++ b/xen/include/public/grant_table.h  Thu Aug 10 11:54:15 2006 +0100
@@ -248,6 +248,49 @@ struct gnttab_transfer {
 };
 typedef struct gnttab_transfer gnttab_transfer_t;
 DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_t);
+
+
+/*
+ * GNTTABOP_copy: Hypervisor based copy
+ * source and destinations can be eithers MFNs or, for foreign domains,
+ * grant references. the foreign domain has to grant read/write access
+ * in its grant table.
+ *
+ * The flags specify what type source and destinations are (either MFN
+ * or grant reference).
+ *
+ * Note that this can also be used to copy data between two domains
+ * via a third party if the source and destination domains had previously
+ * grant appropriate access to their pages to the third party.
+ *
+ * source_offset specifies an offset in the source frame, dest_offset
+ * the offset in the target frame and  len specifies the number of
+ * bytes to be copied.
+ */
+
+#define _GNTCOPY_source_gref      (0)
+#define GNTCOPY_source_gref       (1<<_GNTCOPY_source_gref)
+#define _GNTCOPY_dest_gref        (1)
+#define GNTCOPY_dest_gref         (1<<_GNTCOPY_dest_gref)
+
+#define GNTTABOP_copy                 5
+typedef struct gnttab_copy {
+    /* IN parameters. */
+    struct {
+        union {
+            grant_ref_t ref;
+            xen_pfn_t   gmfn;
+        } u;
+        domid_t  domid;
+        uint16_t offset;
+    } source, dest;
+    uint16_t      len;
+    uint16_t      flags;          /* GNTCOPY_* */
+    /* OUT parameters. */
+    int16_t       status;
+} gnttab_copy_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_copy_t);
+
 
 /*
  * Bitfield values for update_pin_status.flags.
@@ -290,6 +333,7 @@ DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_
 #define GNTST_no_device_space  (-7) /* Out of space in I/O MMU.              */
 #define GNTST_permission_denied (-8) /* Not enough privilege for operation.  */
 #define GNTST_bad_page         (-9) /* Specified page was invalid for op.    */
+#define GNTST_bad_copy_arg    (-10) /* copy arguments cross page boundary */
 
 #define GNTTABOP_error_msgs {                   \
     "okay",                                     \
@@ -301,7 +345,8 @@ DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_
     "invalid device address",                   \
     "no spare translation slot in the I/O MMU", \
     "permission denied",                        \
-    "bad page"                                  \
+    "bad page",                                 \
+    "copy arguments cross page boundary"        \
 }
 
 #endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.