From 732375f5f5363f4eb0d4b4575f509f764c76ea1d Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 18 Oct 2017 20:30:08 +0200 Subject: [PATCH] console: add ringbuffer Closes #1857. Signed-off-by: Christian Brauner --- src/lxc/conf.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/conf.h | 3 +++ src/lxc/console.c | 32 ++++++++++++++++++------ src/lxc/start.c | 5 ++++ 4 files changed, 95 insertions(+), 8 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index f6a0788c7..d2fab9450 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -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); diff --git a/src/lxc/conf.h b/src/lxc/conf.h index d228c94c1..c61f861ed 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -36,6 +36,7 @@ #include #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, diff --git a/src/lxc/console.c b/src/lxc/console.c index c8e545eb4..cbee9f8e8 100644 --- a/src/lxc/console.c +++ b/src/lxc/console.c @@ -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) diff --git a/src/lxc/start.c b/src/lxc/start.c index 28ddb721f..7748dbf61 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -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."); -- 2.47.2