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

[Xen-devel] [PATCH] xen/grant_table: introduce GNTTABOP_unmap_and_duplicate



GNTTABOP_unmap_and_replace has two issues:
- it unconditionally replaces the mapping passed in new_addr with 0;
- it doesn't support GNTMAP_contains_pte mappings on x86, returning a
general error instead of some form of ENOSYS.

Introduce a new operation called GNTTABOP_unmap_and_duplicate that
behaves like GNTTABOP_unmap_and_replace without zeroing the mapping
passed in new_addr. Also return GNTST_enosys instead of
GNTST_general_error if GNTMAP_contains_pte is specified.

Signed-off-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
Signed-off-by: Roger Pau Monnà <roger.pau@xxxxxxxxxx>
Cc: Tim Deegan <tim@xxxxxxx>
Cc: Jan Beulich <jbeulich@xxxxxxxx>
Cc: Keir Fraser <keir@xxxxxxx>
---
 xen/arch/arm/mm.c                 |    2 +-
 xen/arch/x86/mm.c                 |   36 ++++++++++++----
 xen/common/compat/grant_table.c   |    8 ++++
 xen/common/grant_table.c          |   83 ++++++++++++++++++++++++++++++++++++-
 xen/include/asm-arm/grant_table.h |    2 +-
 xen/include/asm-x86/grant_table.h |    3 +-
 xen/include/public/grant_table.h  |   23 ++++++++++
 xen/include/xlat.lst              |    1 +
 8 files changed, 145 insertions(+), 13 deletions(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 123280e..39e6071 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1289,7 +1289,7 @@ int create_grant_host_mapping(unsigned long addr, 
unsigned long frame,
 }
 
 int replace_grant_host_mapping(unsigned long addr, unsigned long mfn,
-        unsigned long new_addr, unsigned int flags)
+        unsigned long new_addr, unsigned int flags, bool_t zero_new_addr)
 {
     unsigned long gfn = (unsigned long)(addr >> PAGE_SHIFT);
     struct domain *d = current->domain;
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 43aaceb..89e1b43 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -4047,7 +4047,8 @@ static int replace_grant_p2m_mapping(
 }
 
 int replace_grant_host_mapping(
-    uint64_t addr, unsigned long frame, uint64_t new_addr, unsigned int flags)
+    uint64_t addr, unsigned long frame, uint64_t new_addr, unsigned int flags,
+    bool_t zero_new_addr)
 {
     struct vcpu *curr = current;
     l1_pgentry_t *pl1e, ol1e;
@@ -4064,7 +4065,7 @@ int replace_grant_host_mapping(
             return destroy_grant_pte_mapping(addr, frame, curr->domain);
         
         MEM_LOG("Unsupported grant table operation");
-        return GNTST_general_error;
+        return GNTST_enosys;
     }
 
     if ( !new_addr )
@@ -4102,14 +4103,31 @@ int replace_grant_host_mapping(
 
     ol1e = *pl1e;
 
-    if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, l1e_empty(),
-                                gl1mfn, curr, 0)) )
+    if ( zero_new_addr )
     {
-        page_unlock(l1pg);
-        put_page(l1pg);
-        MEM_LOG("Cannot delete PTE entry at %p", (unsigned long *)pl1e);
-        guest_unmap_l1e(curr, pl1e);
-        return GNTST_general_error;
+        if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, l1e_empty(),
+                                    gl1mfn, curr, 0)) )
+        {
+            page_unlock(l1pg);
+            put_page(l1pg);
+            MEM_LOG("Cannot delete PTE entry at %p", (unsigned long *)pl1e);
+            guest_unmap_l1e(curr, pl1e);
+            return GNTST_general_error;
+        }
+    }
+    else
+    {
+        /* Increase refcount */
+        if ( unlikely(!get_page_and_type(l1e_get_page(ol1e), curr->domain,
+                                         PGT_writable_page)) )
+        {
+            page_unlock(l1pg);
+            put_page(l1pg);
+            guest_unmap_l1e(curr, pl1e);
+            MEM_LOG("Cannot increase refcount of frame at %"PRI_mfn,
+                    page_to_mfn(l1e_get_page(ol1e)));
+            return GNTST_general_error;
+        }
     }
 
     page_unlock(l1pg);
diff --git a/xen/common/compat/grant_table.c b/xen/common/compat/grant_table.c
index 7ebbbc1..8ab5e78 100644
--- a/xen/common/compat/grant_table.c
+++ b/xen/common/compat/grant_table.c
@@ -51,6 +51,10 @@ CHECK_gnttab_get_version;
 CHECK_gnttab_swap_grant_ref;
 #undef xen_gnttab_swap_grant_ref
 
+#define xen_gnttab_unmap_and_duplicate gnttab_unmap_and_duplicate
+CHECK_gnttab_unmap_and_duplicate;
+#undef xen_gnttab_unmap_and_duplicate
+
 int compat_grant_table_op(unsigned int cmd,
                           XEN_GUEST_HANDLE_PARAM(void) cmp_uop,
                           unsigned int count)
@@ -106,6 +110,10 @@ int compat_grant_table_op(unsigned int cmd,
     CASE(swap_grant_ref);
 #endif
 
+#ifndef CHECK_gnttab_unmap_and_duplicate
+    CASE(unmap_and_duplicate);
+#endif
+
 #undef CASE
     default:
         return do_grant_table_op(cmd, cmp_uop, count);
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index f42bc7a..54ee952 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -70,6 +70,7 @@ struct gnttab_unmap_common {
     uint64_t dev_bus_addr;
     uint64_t new_addr;
     grant_handle_t handle;
+    bool_t zero_new_addr;
 
     /* Return */
     int16_t status;
@@ -920,7 +921,8 @@ __gnttab_unmap_common(
     {
         if ( (rc = replace_grant_host_mapping(op->host_addr,
                                               op->frame, op->new_addr, 
-                                              op->flags)) < 0 )
+                                              op->flags,
+                                              op->zero_new_addr)) < 0 )
             goto unmap_out;
 
         ASSERT(act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask));
@@ -1129,6 +1131,7 @@ __gnttab_unmap_and_replace(
     common->host_addr = op->host_addr;
     common->new_addr = op->new_addr;
     common->handle = op->handle;
+    common->zero_new_addr = 1;
     
     /* Intialise these in case common contains old state */
     common->dev_bus_addr = 0;
@@ -1184,6 +1187,70 @@ fault:
     return -EFAULT;    
 }
 
+static void
+__gnttab_unmap_and_duplicate(
+    struct gnttab_unmap_and_duplicate *op,
+    struct gnttab_unmap_common *common)
+{
+    common->host_addr = op->host_addr;
+    common->new_addr = op->new_addr;
+    common->handle = op->handle;
+    common->zero_new_addr = 0;
+
+    /* Intialise these in case common contains old state */
+    common->dev_bus_addr = 0;
+    common->rd = NULL;
+
+    __gnttab_unmap_common(common);
+    op->status = common->status;
+}
+
+static long
+gnttab_unmap_and_duplicate(
+    XEN_GUEST_HANDLE_PARAM(gnttab_unmap_and_duplicate_t) uop, unsigned int 
count)
+{
+    int i, c, partial_done, done = 0;
+    struct gnttab_unmap_and_duplicate op;
+    struct gnttab_unmap_common common[GNTTAB_UNMAP_BATCH_SIZE];
+
+    while ( count != 0 )
+    {
+        c = min(count, (unsigned int)GNTTAB_UNMAP_BATCH_SIZE);
+        partial_done = 0;
+
+        for ( i = 0; i < c; i++ )
+        {
+            if ( unlikely(__copy_from_guest(&op, uop, 1)) )
+                goto fault;
+            __gnttab_unmap_and_duplicate(&op, &(common[i]));
+            ++partial_done;
+            if ( unlikely(__copy_field_to_guest(uop, &op, status)) )
+                goto fault;
+            guest_handle_add_offset(uop, 1);
+        }
+
+        flush_tlb_mask(current->domain->domain_dirty_cpumask);
+
+        for ( i = 0; i < partial_done; i++ )
+            __gnttab_unmap_common_complete(&(common[i]));
+
+        count -= c;
+        done += c;
+
+        if (count && hypercall_preempt_check())
+            return done;
+    }
+
+    return 0;
+
+fault:
+    flush_tlb_mask(current->domain->domain_dirty_cpumask);
+
+    for ( i = 0; i < partial_done; i++ )
+        __gnttab_unmap_common_complete(&(common[i]));
+    return -EFAULT;
+}
+
 static int
 gnttab_populate_status_frames(struct domain *d, struct grant_table *gt,
                               unsigned int req_nr_frames)
@@ -2552,6 +2619,20 @@ do_grant_table_op(
         }
         break;
     }
+    case GNTTABOP_unmap_and_duplicate:
+    {
+        XEN_GUEST_HANDLE_PARAM(gnttab_unmap_and_duplicate_t) unmap =
+            guest_handle_cast(uop, gnttab_unmap_and_duplicate_t);
+        if ( unlikely(!guest_handle_okay(unmap, count)) )
+            goto out;
+        rc = gnttab_unmap_and_duplicate(unmap, count);
+        if ( rc > 0 )
+        {
+            guest_handle_add_offset(unmap, rc);
+            uop = guest_handle_cast(unmap, void);
+        }
+        break;
+    }
     default:
         rc = -ENOSYS;
         break;
diff --git a/xen/include/asm-arm/grant_table.h 
b/xen/include/asm-arm/grant_table.h
index 6e0cc59..0410355 100644
--- a/xen/include/asm-arm/grant_table.h
+++ b/xen/include/asm-arm/grant_table.h
@@ -12,7 +12,7 @@ int create_grant_host_mapping(unsigned long gpaddr,
         cache_flags);
 #define gnttab_host_mapping_get_page_type(op, d, rd) (0)
 int replace_grant_host_mapping(unsigned long gpaddr, unsigned long mfn,
-        unsigned long new_gpaddr, unsigned int flags);
+        unsigned long new_gpaddr, unsigned int flags, bool_t zero_new_addr);
 void gnttab_mark_dirty(struct domain *d, unsigned long l);
 #define gnttab_create_status_page(d, t, i) do {} while (0)
 #define gnttab_status_gmfn(d, t, i) (0)
diff --git a/xen/include/asm-x86/grant_table.h 
b/xen/include/asm-x86/grant_table.h
index 3013869..e985968 100644
--- a/xen/include/asm-x86/grant_table.h
+++ b/xen/include/asm-x86/grant_table.h
@@ -16,7 +16,8 @@
 int create_grant_host_mapping(uint64_t addr, unsigned long frame,
                              unsigned int flags, unsigned int cache_flags);
 int replace_grant_host_mapping(
-    uint64_t addr, unsigned long frame, uint64_t new_addr, unsigned int flags);
+    uint64_t addr, unsigned long frame, uint64_t new_addr, unsigned int flags,
+    bool_t zero_new_addr);
 
 #define gnttab_create_shared_page(d, t, i)                               \
     do {                                                                 \
diff --git a/xen/include/public/grant_table.h b/xen/include/public/grant_table.h
index b8a3d6c..a4ad98d 100644
--- a/xen/include/public/grant_table.h
+++ b/xen/include/public/grant_table.h
@@ -309,6 +309,7 @@ typedef uint16_t grant_status_t;
 #define GNTTABOP_get_status_frames    9
 #define GNTTABOP_get_version          10
 #define GNTTABOP_swap_grant_ref              11
+#define GNTTABOP_unmap_and_duplicate  12
 #endif /* __XEN_INTERFACE_VERSION__ */
 /* ` } */
 
@@ -574,6 +575,27 @@ struct gnttab_swap_grant_ref {
 typedef struct gnttab_swap_grant_ref gnttab_swap_grant_ref_t;
 DEFINE_XEN_GUEST_HANDLE(gnttab_swap_grant_ref_t);
 
+/*
+ * GNTTABOP_unmap_and_duplicate: Destroy one or more grant-reference mappings
+ * tracked by <handle> but atomically replace the page table entry with one
+ * pointing to the machine address under <new_addr>.
+ * NOTES:
+ *  1. The call may fail in an undefined manner if either mapping is not
+ *     tracked by <handle>.
+ *  2. After executing a batch of unmaps, it is guaranteed that no stale
+ *     mappings will remain in the device or host TLBs.
+ */
+struct gnttab_unmap_and_duplicate {
+    /* IN parameters. */
+    uint64_t host_addr;
+    uint64_t new_addr;
+    grant_handle_t handle;
+    /* OUT parameters. */
+    int16_t  status;              /* => enum grant_status */
+};
+typedef struct gnttab_unmap_and_duplicate gnttab_unmap_and_duplicate_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_unmap_and_duplicate_t);
+
 #endif /* __XEN_INTERFACE_VERSION__ */
 
 /*
@@ -631,6 +653,7 @@ DEFINE_XEN_GUEST_HANDLE(gnttab_swap_grant_ref_t);
 #define GNTST_bad_copy_arg    (-10) /* copy arguments cross page boundary.   */
 #define GNTST_address_too_big (-11) /* transfer page address too large.      */
 #define GNTST_eagain          (-12) /* Operation not done; try again.        */
+#define GNTST_enosys          (-13) /* Operation not implemented.            */
 /* ` } */
 
 #define GNTTABOP_error_msgs {                   \
diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst
index f00cef3..8b967f1 100644
--- a/xen/include/xlat.lst
+++ b/xen/include/xlat.lst
@@ -51,6 +51,7 @@
 ?       grant_entry_header              grant_table.h
 ?      grant_entry_v2                  grant_table.h
 ?      gnttab_swap_grant_ref           grant_table.h
+?      gnttab_unmap_and_duplicate      grant_table.h
 ?      kexec_exec                      kexec.h
 !      kexec_image                     kexec.h
 !      kexec_range                     kexec.h
-- 
1.7.7.5 (Apple Git-26)


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel

 


Rackspace

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