[xen staging] argo: implement the unregister op

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[xen staging] argo: implement the unregister op

patchbot
commit a00ee1ec8f732940eb76f83057095c585d253e04
Author:     Christopher Clark <[hidden email]>
AuthorDate: Wed Feb 6 10:04:00 2019 +0100
Commit:     Jan Beulich <[hidden email]>
CommitDate: Thu Feb 7 14:23:39 2019 +0100

    argo: implement the unregister op
   
    Takes a single argument: a handle to the ring unregistration struct,
    which specifies the port and partner domain id or wildcard.
   
    The ring's entry is removed from the hashtable of registered rings;
    any entries for pending notifications are removed; and the ring is
    unmapped from Xen's address space.
   
    If the ring had been registered to communicate with a single specified
    domain (ie. a non-wildcard ring) then the partner domain state is removed
    from the partner domain's argo send_info hash table.
   
    Signed-off-by: Christopher Clark <[hidden email]>
    Reviewed-by: Roger Pau Monné <[hidden email]>
    Tested-by: Chris Patterson <[hidden email]>
    Release-acked-by: Juergen Gross <[hidden email]>
---
 xen/common/argo.c         | 126 ++++++++++++++++++++++++++++++++++++++++++++++
 xen/include/public/argo.h |  19 +++++++
 xen/include/xlat.lst      |   1 +
 3 files changed, 146 insertions(+)

diff --git a/xen/common/argo.c b/xen/common/argo.c
index 814dd0cf1c..f3e468dffd 100644
--- a/xen/common/argo.c
+++ b/xen/common/argo.c
@@ -37,6 +37,7 @@ CHECK_argo_addr;
 CHECK_argo_register_ring;
 CHECK_argo_ring;
 CHECK_argo_ring_message_header;
+CHECK_argo_unregister_ring;
 #endif
 
 #define MAX_RINGS_PER_DOMAIN            128U
@@ -53,6 +54,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_argo_addr_t);
 DEFINE_XEN_GUEST_HANDLE(xen_argo_gfn_t);
 DEFINE_XEN_GUEST_HANDLE(xen_argo_register_ring_t);
 DEFINE_XEN_GUEST_HANDLE(xen_argo_ring_t);
+DEFINE_XEN_GUEST_HANDLE(xen_argo_unregister_ring_t);
 
 static bool __read_mostly opt_argo;
 static bool __read_mostly opt_argo_mac_permissive;
@@ -360,6 +362,36 @@ find_ring_info(const struct domain *d, const struct argo_ring_id *id)
     return NULL;
 }
 
+static struct argo_send_info *
+find_send_info(const struct domain *d, const struct argo_ring_id *id)
+{
+    struct argo_send_info *send_info;
+    const struct list_head *bucket;
+
+    ASSERT(LOCKING_send_L2(d));
+
+    /* List is not modified here. Search and return the match if found. */
+    bucket = &d->argo->send_hash[hash_index(id)];
+
+    list_for_each_entry(send_info, bucket, node)
+    {
+        const struct argo_ring_id *cmpid = &send_info->id;
+
+        if ( cmpid->aport == id->aport &&
+             cmpid->domain_id == id->domain_id &&
+             cmpid->partner_id == id->partner_id )
+        {
+            argo_dprintk("found send_info for ring(%u:%x %u)\n",
+                         id->domain_id, id->aport, id->partner_id);
+            return send_info;
+        }
+    }
+    argo_dprintk("no send_info for ring(%u:%x %u)\n",
+                 id->domain_id, id->aport, id->partner_id);
+
+    return NULL;
+}
+
 static void
 ring_unmap(const struct domain *d, struct argo_ring_info *ring_info)
 {
@@ -738,6 +770,85 @@ find_ring_mfns(struct domain *d, struct argo_ring_info *ring_info,
 }
 
 static long
+unregister_ring(struct domain *currd,
+                XEN_GUEST_HANDLE_PARAM(xen_argo_unregister_ring_t) unreg_hnd)
+{
+    xen_argo_unregister_ring_t unreg;
+    struct argo_ring_id ring_id;
+    struct argo_ring_info *ring_info = NULL;
+    struct argo_send_info *send_info = NULL;
+    struct domain *dst_d = NULL;
+
+    ASSERT(currd == current->domain);
+
+    if ( copy_from_guest(&unreg, unreg_hnd, 1) )
+        return -EFAULT;
+
+    if ( unreg.pad )
+        return -EINVAL;
+
+    ring_id.partner_id = unreg.partner_id;
+    ring_id.aport = unreg.aport;
+    ring_id.domain_id = currd->domain_id;
+
+    read_lock(&L1_global_argo_rwlock);
+
+    if ( unlikely(!currd->argo) )
+    {
+        read_unlock(&L1_global_argo_rwlock);
+        return -ENODEV;
+    }
+
+    write_lock(&currd->argo->rings_L2_rwlock);
+
+    ring_info = find_ring_info(currd, &ring_id);
+    if ( !ring_info )
+        goto out;
+
+    ring_remove_info(currd, ring_info);
+    currd->argo->ring_count--;
+
+    if ( ring_id.partner_id == XEN_ARGO_DOMID_ANY )
+        goto out;
+
+    dst_d = get_domain_by_id(ring_id.partner_id);
+    if ( !dst_d || !dst_d->argo )
+    {
+        ASSERT_UNREACHABLE();
+        goto out;
+    }
+
+    spin_lock(&dst_d->argo->send_L2_lock);
+
+    send_info = find_send_info(dst_d, &ring_id);
+    if ( send_info )
+        list_del(&send_info->node);
+    else
+        ASSERT_UNREACHABLE();
+
+    spin_unlock(&dst_d->argo->send_L2_lock);
+
+ out:
+    write_unlock(&currd->argo->rings_L2_rwlock);
+
+    read_unlock(&L1_global_argo_rwlock);
+
+    if ( dst_d )
+        put_domain(dst_d);
+
+    xfree(send_info);
+
+    if ( !ring_info )
+    {
+        argo_dprintk("unregister_ring: no ring_info found for ring(%u:%x %u)\n",
+                     ring_id.domain_id, ring_id.aport, ring_id.partner_id);
+        return -ENOENT;
+    }
+
+    return 0;
+}
+
+static long
 register_ring(struct domain *currd,
               XEN_GUEST_HANDLE_PARAM(xen_argo_register_ring_t) reg_hnd,
               XEN_GUEST_HANDLE_PARAM(xen_argo_gfn_t) gfn_hnd,
@@ -1029,6 +1140,21 @@ do_argo_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) arg1,
         break;
     }
 
+    case XEN_ARGO_OP_unregister_ring:
+    {
+        XEN_GUEST_HANDLE_PARAM(xen_argo_unregister_ring_t) unreg_hnd =
+            guest_handle_cast(arg1, xen_argo_unregister_ring_t);
+
+        if ( unlikely((!guest_handle_is_null(arg2)) || arg3 || arg4) )
+        {
+            rc = -EINVAL;
+            break;
+        }
+
+        rc = unregister_ring(currd, unreg_hnd);
+        break;
+    }
+
     default:
         rc = -EOPNOTSUPP;
         break;
diff --git a/xen/include/public/argo.h b/xen/include/public/argo.h
index 8b763e7159..29856df34a 100644
--- a/xen/include/public/argo.h
+++ b/xen/include/public/argo.h
@@ -75,6 +75,13 @@ typedef struct xen_argo_register_ring
     uint32_t len;
 } xen_argo_register_ring_t;
 
+typedef struct xen_argo_unregister_ring
+{
+    xen_argo_port_t aport;
+    domid_t partner_id;
+    uint16_t pad;
+} xen_argo_unregister_ring_t;
+
 /* Messages on the ring are padded to a multiple of this size. */
 #define XEN_ARGO_MSG_SLOT_SIZE 0x10
 
@@ -130,4 +137,16 @@ struct xen_argo_ring_message_header
 #define XEN_ARGO_REGISTER_FLAG_MASK XEN_ARGO_REGISTER_FLAG_FAIL_EXIST
 #endif
 
+/*
+ * XEN_ARGO_OP_unregister_ring
+ *
+ * Unregister a previously-registered ring, ending communication.
+ *
+ * arg1: XEN_GUEST_HANDLE(xen_argo_unregister_ring_t)
+ * arg2: NULL
+ * arg3: 0 (ZERO)
+ * arg4: 0 (ZERO)
+ */
+#define XEN_ARGO_OP_unregister_ring     2
+
 #endif
diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst
index 349fbad38c..ee7dffc7e8 100644
--- a/xen/include/xlat.lst
+++ b/xen/include/xlat.lst
@@ -34,6 +34,7 @@
 ? argo_register_ring argo.h
 ? argo_ring argo.h
 ? argo_ring_message_header argo.h
+? argo_unregister_ring argo.h
 ? evtchn_alloc_unbound event_channel.h
 ? evtchn_bind_interdomain event_channel.h
 ? evtchn_bind_ipi event_channel.h
--
generated by git-patchbot for /home/xen/git/xen.git#staging


_______________________________________________
Xen-changelog mailing list
[hidden email]
https://lists.xenproject.org/xen-changelog