]> xenbits.xensource.com Git - people/andrewcoop/xen-test-framework.git/commitdiff
Basic xenstore read implementation
authorAndrew Cooper <andrew.cooper3@citrix.com>
Sat, 2 Apr 2016 13:36:09 +0000 (14:36 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Wed, 9 Aug 2017 15:37:25 +0000 (16:37 +0100)
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
common/xenbus.c
include/xen/io/xs_wire.h
include/xtf.h
include/xtf/xenstore.h [new file with mode: 0644]
tests/selftest/main.c

index 4a640adb8e2576371a889424e24cb3d37c810c2f..2888ab03c1a3592dcf9cf02e22182d576d7d4f7d 100644 (file)
@@ -1,9 +1,13 @@
+#include <xtf/atomic.h>
+#include <xtf/bitops.h>
+#include <xtf/hypercall.h>
 #include <xtf/lib.h>
 #include <xtf/traps.h>
 #include <xtf/xenbus.h>
 
 static xenbus_interface_t *xb_ring;
 static evtchn_port_t xb_port;
+static char payload[XENSTORE_PAYLOAD_MAX + 1];
 
 void init_xenbus(xenbus_interface_t *ring, evtchn_port_t port)
 {
@@ -14,6 +18,143 @@ void init_xenbus(xenbus_interface_t *ring, evtchn_port_t port)
     xb_port = port;
 }
 
+/*
+ * Write some raw data into the xenbus ring.  Waits for sufficient space to
+ * appear if necessary.
+ */
+static void xenbus_write(const void *data, size_t len)
+{
+    uint32_t part, done = 0;
+
+    while ( len )
+    {
+        uint32_t prod = ACCESS_ONCE(xb_ring->req_prod);
+        uint32_t cons = ACCESS_ONCE(xb_ring->req_cons);
+
+        uint32_t used = mask_xenbus_idx(prod - cons);
+
+        part = (XENBUS_RING_SIZE - 1) - used;
+
+        /* No space?  Kick xenstored and wait for it to consume some data. */
+        if ( !part )
+        {
+            hypercall_evtchn_send(xb_port);
+
+            if ( !test_and_clear_bit(xb_port, shared_info.evtchn_pending) )
+                hypercall_poll(xb_port);
+
+            continue;
+        }
+
+        /* Don't overrun the ring. */
+        part = min(part, XENBUS_RING_SIZE - used);
+
+        /* Don't write more than necessary. */
+        part = min(part, (unsigned int)len);
+
+        memcpy(xb_ring->req + mask_xenbus_idx(prod), data + done, part);
+
+        /* Complete the data read before updating the new producer index. */
+        smp_wmb();
+
+        ACCESS_ONCE(xb_ring->req_prod) = prod + part;
+
+        len -= part;
+        done += part;
+    }
+}
+
+/*
+ * Read some raw data from the xenbus ring.  Waits for sufficient data to
+ * appear if necessary.
+ */
+static void xenbus_read(void *data, size_t len)
+{
+    uint32_t part, done = 0;
+
+    while ( len )
+    {
+        uint32_t prod = ACCESS_ONCE(xb_ring->rsp_prod);
+        uint32_t cons = ACCESS_ONCE(xb_ring->rsp_cons);
+
+        part = mask_xenbus_idx(prod - cons);
+
+        /* No data?  Kick xenstored and wait for it to produce some data. */
+        if ( !part )
+        {
+            hypercall_evtchn_send(xb_port);
+
+            if ( !test_and_clear_bit(xb_port, shared_info.evtchn_pending) )
+                hypercall_poll(xb_port);
+
+            continue;
+        }
+
+        /* Avoid overrunning the ring. */
+        part = min(part, XENBUS_RING_SIZE - mask_xenbus_idx(cons));
+
+        /* Don't read more than necessary. */
+        part = min(part, (unsigned int)len);
+
+        memcpy(data + done, xb_ring->rsp + mask_xenbus_idx(cons), part);
+
+        /* Complete the data read before updating the new consumer index. */
+        smp_mb();
+
+        ACCESS_ONCE(xb_ring->rsp_cons) = cons + part;
+
+        len -= part;
+        done += part;
+    }
+}
+
+const char *xenstore_read(const char *path)
+{
+    struct xenstore_msg_hdr hdr = {
+        .type = XS_READ,
+        .len = strlen(path) + 1, /* Must send the NUL terminator. */
+    };
+
+    /* Write the header and path to read. */
+    xenbus_write(&hdr, sizeof(hdr));
+    xenbus_write(path, hdr.len);
+
+    /* Kick xenstored. */
+    hypercall_evtchn_send(xb_port);
+
+    /* Read the response header. */
+    xenbus_read(&hdr, sizeof(hdr));
+
+    if ( hdr.type != XS_READ )
+        return NULL;
+
+    if ( hdr.len > XENSTORE_PAYLOAD_MAX )
+    {
+        /*
+         * Xenstored handed back too much data.  Drain it safely attempt to
+         * prevent the protocol from stalling.
+         */
+        while ( hdr.len )
+        {
+            unsigned int part = min(hdr.len, XENSTORE_PAYLOAD_MAX + 0u);
+
+            xenbus_read(payload, part);
+
+            hdr.len -= part;
+        }
+
+        return NULL;
+    }
+
+    /* Read the response payload. */
+    xenbus_read(payload, hdr.len);
+
+    /* Safely terminate the reply, just in case xenstored didn't. */
+    payload[hdr.len] = '\0';
+
+    return payload;
+}
+
 /*
  * Local variables:
  * mode: C
index a963c7d4f2897867533c6b3d5c0c35651c514ff1..739a45f9b2d06fe861c99ea78e71528db1fc1196 100644 (file)
@@ -24,6 +24,53 @@ typedef struct xenbus_interface xenbus_interface_t;
 #define XENBUS_CONNECTED 0
 #define XENBUS_RECONNECT 1
 
+
+/* API/ABI relevent to the Xenstore protocol. */
+
+struct xenstore_msg_hdr {
+    uint32_t type;
+    uint32_t req_id;
+    uint32_t tx_id;
+    uint32_t len;
+};
+
+enum xenstore_msg_type
+{
+    XS_CONTROL,
+    XS_DIRECTORY,
+    XS_READ,
+    XS_GET_PERMS,
+    XS_WATCH,
+    XS_UNWATCH,
+    XS_TRANSACTION_START,
+    XS_TRANSACTION_END,
+    XS_INTRODUCE,
+    XS_RELEASE,
+    XS_GET_DOMAIN_PATH,
+    XS_WRITE,
+    XS_MKDIR,
+    XS_RM,
+    XS_SET_PERMS,
+    XS_WATCH_EVENT,
+    XS_ERROR,
+    XS_IS_DOMAIN_INTRODUCED,
+    XS_RESUME,
+    XS_SET_TARGET,
+    /* XS_RESTRICT has been removed */
+    XS_RESET_WATCHES = XS_SET_TARGET + 2,
+    XS_DIRECTORY_PART,
+
+    XS_TYPE_COUNT,      /* Number of valid types. */
+
+    XS_INVALID = 0xffff /* Guaranteed to remain an invalid type */
+};
+
+
+#define XENSTORE_PAYLOAD_MAX 4096
+
+#define XENSTORE_ABS_PATH_MAX 3072
+#define XENSTORE_REL_PATH_MAX 2048
+
 #endif /* XEN_PUBLIC_IO_XS_WIRE_H */
 
 /*
index f1cebfafcfd812af2b215abd5bda1d6782530555..7d1e90a4ac6b617e463f73b5951b99543264ad1c 100644 (file)
@@ -24,6 +24,7 @@
 #include <xtf/hypercall.h>
 #include <xtf/traps.h>
 #include <xtf/xenbus.h>
+#include <xtf/xenstore.h>
 
 /* Arch specific headers. */
 #include <arch/xtf.h>
diff --git a/include/xtf/xenstore.h b/include/xtf/xenstore.h
new file mode 100644 (file)
index 0000000..2c0778e
--- /dev/null
@@ -0,0 +1,28 @@
+/**
+ * @file include/xtf/xenstore.h
+ *
+ * Xenstore driver.
+ */
+#ifndef XTF_XENSTORE_H
+#define XTF_XENSTORE_H
+
+/**
+ * Issue a #XS_READ operation for @p key, waiting synchronously for the reply.
+ *
+ * Returns NULL on error.  The current implementation unmarshals data into a
+ * static buffer, so the return pointer is only valid until a subsequent
+ * xenstore operation.
+ */
+const char *xenstore_read(const char *key);
+
+#endif /* XTF_XENSTORE_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index bb12afcf95e404534464fa17c4d384a01f0db7e5..fa74f6098d290329c571213b4499f36527a81156 100644 (file)
 
 const char test_title[] = "XTF Selftests";
 
+static void test_xenstore(void)
+{
+    printk("Test: Xenstore read\n");
+
+    const char *domid_str = xenstore_read("domid");
+
+    if ( !domid_str )
+        return xtf_failure("Fail: No domid value returned\n");
+
+    if ( domid_str[0] == '\0' )
+        return xtf_failure("Fail: domid value empty\n");
+
+    unsigned int i;
+    for ( i = 0; domid_str[i]; ++i )
+    {
+        if ( domid_str[i] < '0' || domid_str[i] > '9' )
+            return xtf_failure("Fail: unexpected domid value '%s'\n",
+                               domid_str);
+    }
+
+    printk("  Found domid %s\n", domid_str);
+}
+
 static void test_extable(void)
 {
     printk("Test: Exception Table\n");
@@ -314,6 +337,7 @@ void test_main(void)
             write_cr4(cr4);
     }
 
+    test_xenstore();
     test_extable();
     test_exlog();
     test_exec_user();