]> xenbits.xensource.com Git - xen.git/commitdiff
Allow incremental access to hypervisor console log.
authorKeir Fraser <keir@xensource.com>
Mon, 29 Oct 2007 12:56:27 +0000 (12:56 +0000)
committerKeir Fraser <keir@xensource.com>
Mon, 29 Oct 2007 12:56:27 +0000 (12:56 +0000)
Signed-off-by: Keir Fraser <keir@xensource.com>
tools/console/daemon/io.c
tools/libxc/xc_misc.c
tools/libxc/xenctrl.h
tools/python/xen/lowlevel/xc/xc.c
xen/common/sysctl.c
xen/drivers/char/console.c
xen/include/public/sysctl.h
xen/include/xen/console.h

index c6dc6cd9732aa5e29d57c57b674274d8cd06ed37..e463a61b096ba29fc9b05a283b7422940e2a0dac 100644 (file)
@@ -53,7 +53,9 @@ extern int log_hv;
 extern char *log_dir;
 
 static int log_hv_fd = -1;
+static evtchn_port_or_error_t log_hv_evtchn = -1;
 static int xc_handle = -1;
+static int xce_handle = -1;
 
 struct buffer
 {
@@ -76,8 +78,8 @@ struct domain
        char *serialpath;
        int use_consolepath;
        int ring_ref;
-       evtchn_port_t local_port;
-       evtchn_port_t remote_port;
+       evtchn_port_or_error_t local_port;
+       evtchn_port_or_error_t remote_port;
        int xce_handle;
        struct xencons_interface *interface;
 };
@@ -713,7 +715,7 @@ static void handle_tty_write(struct domain *dom)
 
 static void handle_ring_read(struct domain *dom)
 {
-       evtchn_port_t port;
+       evtchn_port_or_error_t port;
 
        if ((port = xc_evtchn_pending(dom->xce_handle)) == -1)
                return;
@@ -752,12 +754,20 @@ static void handle_hv_logs(void)
        char buffer[1024*16];
        char *bufptr = buffer;
        unsigned int size = sizeof(buffer);
-       if (xc_readconsolering(xc_handle, &bufptr, &size, 1) == 0) {
+       static uint32_t index = 0;
+       evtchn_port_or_error_t port;
+
+       if ((port = xc_evtchn_pending(xce_handle)) == -1)
+               return;
+
+       if (xc_readconsolering(xc_handle, &bufptr, &size, 0, 1, &index) == 0) {
                int len = write(log_hv_fd, buffer, size);
                if (len < 0)
                        dolog(LOG_ERR, "Failed to write hypervisor log: %d (%s)",
                              errno, strerror(errno));
        }
+
+       (void)xc_evtchn_unmask(xce_handle, port);
 }
 
 static void handle_log_reload(void)
@@ -785,16 +795,30 @@ void handle_io(void)
 
        if (log_hv) {
                xc_handle = xc_interface_open();
-               if (xc_handle == -1)
+               if (xc_handle == -1) {
                        dolog(LOG_ERR, "Failed to open xc handle: %d (%s)",
                              errno, strerror(errno));
-               else
-                       log_hv_fd = create_hv_log();
+                       goto out;
+               }
+               xce_handle = xc_evtchn_open();
+               if (xce_handle == -1) {
+                       dolog(LOG_ERR, "Failed to open xce handle: %d (%s)",
+                             errno, strerror(errno));
+                       goto out;
+               }
+               log_hv_fd = create_hv_log();
+               if (log_hv_fd == -1)
+                       goto out;
+               log_hv_evtchn = xc_evtchn_bind_virq(xce_handle, VIRQ_CON_RING);
+               if (log_hv_evtchn == -1) {
+                       dolog(LOG_ERR, "Failed to bind to VIRQ_CON_RING: "
+                             "%d (%s)", errno, strerror(errno));
+                       goto out;
+               }
        }
 
        for (;;) {
                struct domain *d, *n;
-               struct timeval timeout = { 1, 0 }; /* Read HV logs every 1 second */
                int max_fd = -1;
 
                FD_ZERO(&readfds);
@@ -803,6 +827,11 @@ void handle_io(void)
                FD_SET(xs_fileno(xs), &readfds);
                max_fd = MAX(xs_fileno(xs), max_fd);
 
+               if (log_hv) {
+                       FD_SET(xc_evtchn_fd(xce_handle), &readfds);
+                       max_fd = MAX(xc_evtchn_fd(xce_handle), max_fd);
+               }
+
                for (d = dom_head; d; d = d->next) {
                        if (d->xce_handle != -1) {
                                int evtchn_fd = xc_evtchn_fd(d->xce_handle);
@@ -820,11 +849,7 @@ void handle_io(void)
                        }
                }
 
-               /* XXX I wish we didn't have to busy wait for hypervisor logs
-                * but there's no obvious way to get event channel notifications
-                * for new HV log data as we can with guest */
-               ret = select(max_fd + 1, &readfds, &writefds, 0,
-                            log_hv_fd != -1 ? &timeout : NULL);
+               ret = select(max_fd + 1, &readfds, &writefds, 0, NULL);
 
                if (log_reload) {
                        handle_log_reload();
@@ -841,12 +866,10 @@ void handle_io(void)
                        break;
                }
 
-               /* Always process HV logs even if not a timeout */
-               if (log_hv_fd != -1)
+               if (log_hv && FD_ISSET(xc_evtchn_fd(xce_handle), &readfds))
                        handle_hv_logs();
 
-               /* Must not check returned FDSET if it was a timeout */
-               if (ret == 0)
+               if (ret <= 0)
                        continue;
 
                if (FD_ISSET(xs_fileno(xs), &readfds))
@@ -869,6 +892,7 @@ void handle_io(void)
                }
        }
 
+ out:
        if (log_hv_fd != -1) {
                close(log_hv_fd);
                log_hv_fd = -1;
@@ -877,6 +901,11 @@ void handle_io(void)
                xc_interface_close(xc_handle);
                xc_handle = -1;
        }
+       if (xce_handle != -1) {
+               xc_evtchn_close(xce_handle);
+               xce_handle = -1;
+       }
+       log_hv_evtchn = -1;
 }
 
 /*
index ba50866b5668294482f6cfcfd898208fe8dd8bac..c79e14a5636dfc0cab10364c28e2264a0e1d96fe 100644 (file)
@@ -10,7 +10,7 @@
 int xc_readconsolering(int xc_handle,
                        char **pbuffer,
                        unsigned int *pnr_chars,
-                       int clear)
+                       int clear, int incremental, uint32_t *pindex)
 {
     int ret;
     DECLARE_SYSCTL;
@@ -19,14 +19,24 @@ int xc_readconsolering(int xc_handle,
 
     sysctl.cmd = XEN_SYSCTL_readconsole;
     set_xen_guest_handle(sysctl.u.readconsole.buffer, buffer);
-    sysctl.u.readconsole.count  = nr_chars;
-    sysctl.u.readconsole.clear  = clear;
+    sysctl.u.readconsole.count = nr_chars;
+    sysctl.u.readconsole.clear = clear;
+    sysctl.u.readconsole.incremental = 0;
+    if ( pindex )
+    {
+        sysctl.u.readconsole.index = *pindex;
+        sysctl.u.readconsole.incremental = incremental;
+    }
 
     if ( (ret = lock_pages(buffer, nr_chars)) != 0 )
         return ret;
 
     if ( (ret = do_sysctl(xc_handle, &sysctl)) == 0 )
+    {
         *pnr_chars = sysctl.u.readconsole.count;
+        if ( pindex )
+            *pindex = sysctl.u.readconsole.index;
+    }
 
     unlock_pages(buffer, nr_chars);
 
index 207328e6eea55d11e33d2a58f29b001ae8077d4c..0e82a5fbd3dcf47ad673e5fcf922d2b3c77428f4 100644 (file)
@@ -549,7 +549,7 @@ int xc_physdev_pci_access_modify(int xc_handle,
 int xc_readconsolering(int xc_handle,
                        char **pbuffer,
                        unsigned int *pnr_chars,
-                       int clear);
+                       int clear, int incremental, uint32_t *pindex);
 
 int xc_send_debug_keys(int xc_handle, char *keys);
 
index 6a2e848b0bb8b68d98aeabee185c576ffc49acd0..2a09947be30340a98d3d46d822f71a718d0ac93f 100644 (file)
@@ -716,17 +716,19 @@ static PyObject *pyxc_readconsolering(XcObject *self,
                                       PyObject *args,
                                       PyObject *kwds)
 {
-    unsigned int clear = 0;
+    unsigned int clear = 0, index = 0, incremental = 0;
     char         _str[32768], *str = _str;
     unsigned int count = 32768;
     int          ret;
 
-    static char *kwd_list[] = { "clear", NULL };
+    static char *kwd_list[] = { "clear", "index", "incremental", NULL };
 
-    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &clear) )
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|iii", kwd_list,
+                                      &clear, &index, &incremental) )
         return NULL;
 
-    ret = xc_readconsolering(self->xc_handle, &str, &count, clear);
+    ret = xc_readconsolering(self->xc_handle, &str, &count, clear,
+                             incremental, &index);
     if ( ret < 0 )
         return pyxc_error_to_exception();
 
index cde2ca8b36c4ce2e26bd888ed2c75d225b9898a5..1b9c6a58a8cf3bff468d395835711d68eec40cdb 100644 (file)
@@ -53,10 +53,7 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl)
         if ( ret )
             break;
 
-        ret = read_console_ring(
-            guest_handle_cast(op->u.readconsole.buffer, char),
-            &op->u.readconsole.count,
-            op->u.readconsole.clear);
+        ret = read_console_ring(&op->u.readconsole);
         if ( copy_to_guest(u_sysctl, op, 1) )
             ret = -EFAULT;
     }
index 5d47071cd6395a12a578c62d37a4741d93b4e82e..0bd11fc33db814a3aa292b427a7b57ec1ba98c57 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/io.h>
 #include <asm/div64.h>
 #include <xsm/xsm.h>
+#include <public/sysctl.h>
 
 /* console: comma-separated list of console outputs. */
 static char opt_console[30] = OPT_CONSOLE_STR;
@@ -60,7 +61,7 @@ boolean_param("console_timestamps", opt_console_timestamps);
 #define CONRING_SIZE 16384
 #define CONRING_IDX_MASK(i) ((i)&(CONRING_SIZE-1))
 static char conring[CONRING_SIZE];
-static unsigned int conringc, conringp;
+static uint32_t conringc, conringp;
 
 static int sercon_handle = -1;
 
@@ -175,20 +176,25 @@ static char * __init loglvl_str(int lvl)
 
 static void putchar_console_ring(int c)
 {
+    ASSERT(spin_is_locked(&console_lock));
     conring[CONRING_IDX_MASK(conringp++)] = c;
-    if ( (conringp - conringc) > CONRING_SIZE )
+    if ( (uint32_t)(conringp - conringc) > CONRING_SIZE )
         conringc = conringp - CONRING_SIZE;
 }
 
-long read_console_ring(XEN_GUEST_HANDLE(char) str, u32 *pcount, int clear)
+long read_console_ring(struct xen_sysctl_readconsole *op)
 {
-    unsigned int idx, len, max, sofar, c;
-    unsigned long flags;
+    XEN_GUEST_HANDLE(char) str;
+    uint32_t idx, len, max, sofar, c;
 
-    max   = *pcount;
+    str   = guest_handle_cast(op->buffer, char),
+    max   = op->count;
     sofar = 0;
 
     c = conringc;
+    if ( op->incremental && ((int32_t)(op->index - c) < 0) )
+        c = op->index;
+
     while ( (c != conringp) && (sofar < max) )
     {
         idx = CONRING_IDX_MASK(c);
@@ -203,17 +209,19 @@ long read_console_ring(XEN_GUEST_HANDLE(char) str, u32 *pcount, int clear)
         c += len;
     }
 
-    if ( clear )
+    if ( op->clear )
     {
-        spin_lock_irqsave(&console_lock, flags);
-        if ( (conringp - c) > CONRING_SIZE )
+        spin_lock_irq(&console_lock);
+        if ( (uint32_t)(conringp - c) > CONRING_SIZE )
             conringc = conringp - CONRING_SIZE;
         else
             conringc = c;
-        spin_unlock_irqrestore(&console_lock, flags);
+        spin_unlock_irq(&console_lock);
     }
 
-    *pcount = sofar;
+    op->count = sofar;
+    op->index = c;
+
     return 0;
 }
 
@@ -333,15 +341,19 @@ static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count)
             return -EFAULT;
         kbuf[kcount] = '\0';
 
+        spin_lock_irq(&console_lock);
+
         sercon_puts(kbuf);
         vga_puts(kbuf);
 
         if ( opt_console_to_ring )
+        {
             for ( kptr = kbuf; *kptr != '\0'; kptr++ )
                 putchar_console_ring(*kptr);
-
-        if ( opt_console_to_ring )
             send_guest_global_virq(dom0, VIRQ_CON_RING);
+        }
+
+        spin_unlock_irq(&console_lock);
 
         guest_handle_add_offset(buffer, kcount);
         count -= kcount;
@@ -408,6 +420,8 @@ static void __putstr(const char *str)
 {
     int c;
 
+    ASSERT(spin_is_locked(&console_lock));
+
     sercon_puts(str);
     vga_puts(str);
 
@@ -540,7 +554,9 @@ void __init init_console(void)
     serial_set_rx_handler(sercon_handle, serial_rx);
 
     /* HELLO WORLD --- start-of-day banner text. */
+    spin_lock(&console_lock);
     __putstr(xen_banner());
+    spin_unlock(&console_lock);
     printk("Xen version %d.%d%s (%s@%s) (%s) %s\n",
            xen_major_version(), xen_minor_version(), xen_extra_version(),
            xen_compile_by(), xen_compile_domain(),
index 0ea67c5b5f40400ff721960930b6913ca2bfc1e6..59db4c49d3e8ea5d961767fb06531f5d589fa66e 100644 (file)
 #include "xen.h"
 #include "domctl.h"
 
-#define XEN_SYSCTL_INTERFACE_VERSION 0x00000005
+#define XEN_SYSCTL_INTERFACE_VERSION 0x00000006
 
 /*
  * Read console content from Xen buffer ring.
  */
 #define XEN_SYSCTL_readconsole       1
 struct xen_sysctl_readconsole {
-    /* IN variables. */
-    uint32_t clear;                /* Non-zero -> clear after reading. */
-    XEN_GUEST_HANDLE_64(char) buffer; /* Buffer start */
-    /* IN/OUT variables. */
-    uint32_t count;            /* In: Buffer size;  Out: Used buffer size  */
+    /* IN: Non-zero -> clear after reading. */
+    uint8_t clear;
+    /* IN: Non-zero -> start index specified by @index field. */
+    uint8_t incremental;
+    uint8_t pad0, pad1;
+    /*
+     * IN:  Start index for consuming from ring buffer (if @incremental);
+     * OUT: End index after consuming from ring buffer.
+     */
+    uint32_t index; 
+    /* IN: Virtual address to write console data. */
+    XEN_GUEST_HANDLE_64(char) buffer;
+    /* IN: Size of buffer; OUT: Bytes written to buffer. */
+    uint32_t count;
 };
 typedef struct xen_sysctl_readconsole xen_sysctl_readconsole_t;
 DEFINE_XEN_GUEST_HANDLE(xen_sysctl_readconsole_t);
index bb5fe07e937f9a8d7337fd1d84f6657598799004..5817f74958a1e6fadd6e974cae61cd7fc170e83a 100644 (file)
@@ -11,7 +11,8 @@
 #include <xen/guest_access.h>
 #include <public/xen.h>
 
-long read_console_ring(XEN_GUEST_HANDLE(char), u32 *, int);
+struct xen_sysctl_readconsole;
+long read_console_ring(struct xen_sysctl_readconsole *op);
 
 void init_console(void);
 void console_endboot(void);