]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
console: add ringbuffer
authorChristian Brauner <christian.brauner@ubuntu.com>
Wed, 18 Oct 2017 18:30:08 +0000 (20:30 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Sat, 21 Oct 2017 16:38:14 +0000 (18:38 +0200)
Closes #1857.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/conf.c
src/lxc/conf.h
src/lxc/console.c
src/lxc/start.c

index f6a0788c702d655fa9fa032b73a3a47576d30d46..d2fab94505998022ea3b086a255e2dca7d333fd4 100644 (file)
@@ -80,6 +80,7 @@
 #include "namespace.h"
 #include "network.h"
 #include "parse.h"
+#include "ringbuf.h"
 #include "storage.h"
 #include "storage/aufs.h"
 #include "storage/overlay.h"
@@ -2428,6 +2429,7 @@ struct lxc_conf *lxc_conf_init(void)
        new->autodev = 1;
        new->console.log_path = NULL;
        new->console.log_fd = -1;
+       new->console.log_size = 0;
        new->console.path = NULL;
        new->console.peer = -1;
        new->console.peerpty.busy = -1;
@@ -2436,6 +2438,7 @@ struct lxc_conf *lxc_conf_init(void)
        new->console.master = -1;
        new->console.slave = -1;
        new->console.name[0] = '\0';
+       memset(&new->console.ringbuf, 0, sizeof(struct lxc_ringbuf));
        new->maincmd_fd = -1;
        new->nbd_idx = -1;
        new->rootfs.mount = strdup(default_rootfs_mount);
@@ -3079,6 +3082,64 @@ static bool verify_start_hooks(struct lxc_conf *conf)
        return true;
 }
 
+/**
+ * Note that this function needs to run before the mainloop starts. Since we
+ * register a handler for the console's masterfd when we create the mainloop
+ * the console handler needs to see an allocated ringbuffer.
+ */
+static int lxc_setup_console_ringbuf(struct lxc_console *console)
+{
+       int ret;
+       struct lxc_ringbuf *buf = &console->ringbuf;
+       uint64_t size = console->log_size;
+
+       /* no ringbuffer previously allocated and no ringbuffer requested */
+       if (!buf->addr && size <= 0)
+               return 0;
+
+       /* ringbuffer allocated but no new ringbuffer requested */
+       if (buf->addr && size <= 0) {
+               lxc_ringbuf_release(buf);
+               buf->addr = NULL;
+               buf->r_off = 0;
+               buf->w_off = 0;
+               buf->size = 0;
+               TRACE("Deallocated console ringbuffer");
+               return 0;
+       }
+
+       if (size <= 0)
+               return 0;
+
+       /* check wether the requested size for the ringbuffer has changed */
+       if (buf->addr && buf->size != size) {
+               TRACE("Console ringbuffer size changed from %" PRIu64
+                     " to %" PRIu64 " bytes. Deallocating console ringbuffer",
+                     buf->size, size);
+               lxc_ringbuf_release(buf);
+       }
+
+       ret = lxc_ringbuf_create(buf, size);
+       if (ret < 0) {
+               ERROR("Failed to setup %" PRIu64 " byte console ringbuffer", size);
+               return -1;
+       }
+
+       TRACE("Allocated %" PRIu64 " byte console ringbuffer", size);
+       return 0;
+}
+
+int lxc_setup_parent(struct lxc_handler *handler)
+{
+       int ret;
+
+       ret = lxc_setup_console_ringbuf(&handler->conf->console);
+       if (ret < 0)
+               return -1;
+
+       return 0;
+}
+
 int lxc_setup_child(struct lxc_handler *handler)
 {
        int ret;
@@ -3459,6 +3520,8 @@ void lxc_conf_free(struct lxc_conf *conf)
                current_config = NULL;
        free(conf->console.log_path);
        free(conf->console.path);
+       if (conf->console.log_size > 0 && conf->console.ringbuf.addr)
+               lxc_ringbuf_release(&conf->console.ringbuf);
        free(conf->rootfs.mount);
        free(conf->rootfs.bdev_type);
        free(conf->rootfs.options);
index d228c94c1783fbe9a5b5a6b953cdd690b6c89727..c61f861ed7e9216856876a01da1552eed96a4619 100644 (file)
@@ -36,6 +36,7 @@
 #include <stdbool.h>
 
 #include "list.h"
+#include "ringbuf.h"
 #include "start.h" /* for lxc_handler */
 
 #if HAVE_SCMP_FILTER_CTX
@@ -153,6 +154,7 @@ struct lxc_console {
        struct termios *tios;
        struct lxc_tty_state *tty_state;
        uint64_t log_size;
+       struct lxc_ringbuf ringbuf;
 };
 
 /*
@@ -378,6 +380,7 @@ extern void lxc_clear_includes(struct lxc_conf *conf);
 extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
                           const char *lxcpath);
 extern int lxc_setup_child(struct lxc_handler *handler);
+extern int lxc_setup_parent(struct lxc_handler *handler);
 extern int setup_resource_limits(struct lxc_list *limits, pid_t pid);
 extern int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype);
 extern int mapped_hostid(unsigned id, struct lxc_conf *conf,
index c8e545eb43858d292fdec48f51c391c4e201d4d1..cbee9f8e8c0875ae0618366148561a05985d9993 100644 (file)
@@ -51,6 +51,8 @@
 #include <../include/openpty.h>
 #endif
 
+#define LXC_CONSOLE_BUFFER_SIZE 1024
+
 lxc_log_define(console, lxc);
 
 static struct lxc_list lxc_ttys;
@@ -167,12 +169,12 @@ static int lxc_console_cb_con(int fd, uint32_t events, void *data,
                              struct lxc_epoll_descr *descr)
 {
        struct lxc_console *console = (struct lxc_console *)data;
-       char buf[1024];
-       int r, w;
+       char buf[LXC_CONSOLE_BUFFER_SIZE];
+       int r, w, w_log, w_rbuf;
 
        w = r = lxc_read_nointr(fd, buf, sizeof(buf));
        if (r <= 0) {
-               INFO("console client on fd %d has exited", fd);
+               INFO("Console client on fd %d has exited", fd);
                lxc_mainloop_del_handler(descr, fd);
                if (fd == console->peer) {
                        if (console->tty_state) {
@@ -190,16 +192,30 @@ static int lxc_console_cb_con(int fd, uint32_t events, void *data,
        if (fd == console->peer)
                w = lxc_write_nointr(console->master, buf, r);
 
+       w_rbuf = w_log = 0;
        if (fd == console->master) {
-               if (console->log_fd >= 0)
-                       w = lxc_write_nointr(console->log_fd, buf, r);
-
+               /* write to peer first */
                if (console->peer >= 0)
                        w = lxc_write_nointr(console->peer, buf, r);
+
+               /* write to console ringbuffer */
+               if (console->log_size > 0)
+                       w_rbuf = lxc_ringbuf_write(&console->ringbuf, buf, r);
+
+               /* write to console log */
+               if (console->log_fd >= 0)
+                       w_log = lxc_write_nointr(console->log_fd, buf, r);
        }
 
        if (w != r)
-               WARN("console short write r:%d w:%d", r, w);
+               WARN("Console short write r:%d != w:%d", r, w);
+
+       if (w_rbuf < 0)
+               TRACE("%s - Failed to write %d bytes to console ringbuffer",
+                     strerror(-w_rbuf), r);
+
+       if (w_log < 0)
+               TRACE("Failed to write %d bytes to console log", r);
 
        return 0;
 }
@@ -632,7 +648,7 @@ int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
                struct lxc_epoll_descr *descr)
 {
        struct lxc_tty_state *ts = cbdata;
-       char buf[1024];
+       char buf[LXC_CONSOLE_BUFFER_SIZE];
        int r, w;
 
        if (fd != ts->masterfd)
index 28ddb721f7c87a8b665673b6756f0a1523a9b9cb..7748dbf61ba632d3d44a8f2a98a7933addb34c1e 100644 (file)
@@ -1254,6 +1254,11 @@ static int lxc_spawn(struct lxc_handler *handler)
                 */
                flags &= ~CLONE_NEWNET;
        }
+
+       ret = lxc_setup_parent(handler);
+       if (ret < 0)
+               goto out_delete_net;
+
        handler->pid = lxc_clone(do_start, handler, flags);
        if (handler->pid < 0) {
                SYSERROR("Failed to clone a new set of namespaces.");