console: add ringbuffer

Closes #1857. Signed-off-by: 's avatarChristian Brauner <christian.brauner@ubuntu.com>
parent 7f135597
...@@ -80,6 +80,7 @@ ...@@ -80,6 +80,7 @@
#include "namespace.h" #include "namespace.h"
#include "network.h" #include "network.h"
#include "parse.h" #include "parse.h"
#include "ringbuf.h"
#include "storage.h" #include "storage.h"
#include "storage/aufs.h" #include "storage/aufs.h"
#include "storage/overlay.h" #include "storage/overlay.h"
...@@ -2428,6 +2429,7 @@ struct lxc_conf *lxc_conf_init(void) ...@@ -2428,6 +2429,7 @@ struct lxc_conf *lxc_conf_init(void)
new->autodev = 1; new->autodev = 1;
new->console.log_path = NULL; new->console.log_path = NULL;
new->console.log_fd = -1; new->console.log_fd = -1;
new->console.log_size = 0;
new->console.path = NULL; new->console.path = NULL;
new->console.peer = -1; new->console.peer = -1;
new->console.peerpty.busy = -1; new->console.peerpty.busy = -1;
...@@ -2436,6 +2438,7 @@ struct lxc_conf *lxc_conf_init(void) ...@@ -2436,6 +2438,7 @@ struct lxc_conf *lxc_conf_init(void)
new->console.master = -1; new->console.master = -1;
new->console.slave = -1; new->console.slave = -1;
new->console.name[0] = '\0'; new->console.name[0] = '\0';
memset(&new->console.ringbuf, 0, sizeof(struct lxc_ringbuf));
new->maincmd_fd = -1; new->maincmd_fd = -1;
new->nbd_idx = -1; new->nbd_idx = -1;
new->rootfs.mount = strdup(default_rootfs_mount); new->rootfs.mount = strdup(default_rootfs_mount);
...@@ -3079,6 +3082,64 @@ static bool verify_start_hooks(struct lxc_conf *conf) ...@@ -3079,6 +3082,64 @@ static bool verify_start_hooks(struct lxc_conf *conf)
return true; 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 lxc_setup_child(struct lxc_handler *handler)
{ {
int ret; int ret;
...@@ -3459,6 +3520,8 @@ void lxc_conf_free(struct lxc_conf *conf) ...@@ -3459,6 +3520,8 @@ void lxc_conf_free(struct lxc_conf *conf)
current_config = NULL; current_config = NULL;
free(conf->console.log_path); free(conf->console.log_path);
free(conf->console.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.mount);
free(conf->rootfs.bdev_type); free(conf->rootfs.bdev_type);
free(conf->rootfs.options); free(conf->rootfs.options);
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <stdbool.h> #include <stdbool.h>
#include "list.h" #include "list.h"
#include "ringbuf.h"
#include "start.h" /* for lxc_handler */ #include "start.h" /* for lxc_handler */
#if HAVE_SCMP_FILTER_CTX #if HAVE_SCMP_FILTER_CTX
...@@ -153,6 +154,7 @@ struct lxc_console { ...@@ -153,6 +154,7 @@ struct lxc_console {
struct termios *tios; struct termios *tios;
struct lxc_tty_state *tty_state; struct lxc_tty_state *tty_state;
uint64_t log_size; uint64_t log_size;
struct lxc_ringbuf ringbuf;
}; };
/* /*
...@@ -378,6 +380,7 @@ extern void lxc_clear_includes(struct lxc_conf *conf); ...@@ -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, extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
const char *lxcpath); const char *lxcpath);
extern int lxc_setup_child(struct lxc_handler *handler); 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 setup_resource_limits(struct lxc_list *limits, pid_t pid);
extern int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype); extern int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype);
extern int mapped_hostid(unsigned id, struct lxc_conf *conf, extern int mapped_hostid(unsigned id, struct lxc_conf *conf,
......
...@@ -51,6 +51,8 @@ ...@@ -51,6 +51,8 @@
#include <../include/openpty.h> #include <../include/openpty.h>
#endif #endif
#define LXC_CONSOLE_BUFFER_SIZE 1024
lxc_log_define(console, lxc); lxc_log_define(console, lxc);
static struct lxc_list lxc_ttys; static struct lxc_list lxc_ttys;
...@@ -167,12 +169,12 @@ static int lxc_console_cb_con(int fd, uint32_t events, void *data, ...@@ -167,12 +169,12 @@ static int lxc_console_cb_con(int fd, uint32_t events, void *data,
struct lxc_epoll_descr *descr) struct lxc_epoll_descr *descr)
{ {
struct lxc_console *console = (struct lxc_console *)data; struct lxc_console *console = (struct lxc_console *)data;
char buf[1024]; char buf[LXC_CONSOLE_BUFFER_SIZE];
int r, w; int r, w, w_log, w_rbuf;
w = r = lxc_read_nointr(fd, buf, sizeof(buf)); w = r = lxc_read_nointr(fd, buf, sizeof(buf));
if (r <= 0) { 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); lxc_mainloop_del_handler(descr, fd);
if (fd == console->peer) { if (fd == console->peer) {
if (console->tty_state) { if (console->tty_state) {
...@@ -190,16 +192,30 @@ static int lxc_console_cb_con(int fd, uint32_t events, void *data, ...@@ -190,16 +192,30 @@ static int lxc_console_cb_con(int fd, uint32_t events, void *data,
if (fd == console->peer) if (fd == console->peer)
w = lxc_write_nointr(console->master, buf, r); w = lxc_write_nointr(console->master, buf, r);
w_rbuf = w_log = 0;
if (fd == console->master) { if (fd == console->master) {
if (console->log_fd >= 0) /* write to peer first */
w = lxc_write_nointr(console->log_fd, buf, r);
if (console->peer >= 0) if (console->peer >= 0)
w = lxc_write_nointr(console->peer, buf, r); 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) 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; return 0;
} }
...@@ -632,7 +648,7 @@ int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata, ...@@ -632,7 +648,7 @@ int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
struct lxc_epoll_descr *descr) struct lxc_epoll_descr *descr)
{ {
struct lxc_tty_state *ts = cbdata; struct lxc_tty_state *ts = cbdata;
char buf[1024]; char buf[LXC_CONSOLE_BUFFER_SIZE];
int r, w; int r, w;
if (fd != ts->masterfd) if (fd != ts->masterfd)
......
...@@ -1254,6 +1254,11 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -1254,6 +1254,11 @@ static int lxc_spawn(struct lxc_handler *handler)
*/ */
flags &= ~CLONE_NEWNET; flags &= ~CLONE_NEWNET;
} }
ret = lxc_setup_parent(handler);
if (ret < 0)
goto out_delete_net;
handler->pid = lxc_clone(do_start, handler, flags); handler->pid = lxc_clone(do_start, handler, flags);
if (handler->pid < 0) { if (handler->pid < 0) {
SYSERROR("Failed to clone a new set of namespaces."); SYSERROR("Failed to clone a new set of namespaces.");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment