Skip to content

Commit

Permalink
Merge pull request #1864 from brauner/2017-10-18/ringbuffer
Browse files Browse the repository at this point in the history
ringbuffer: implement efficient and performant ringbuffer
  • Loading branch information
hallyn committed Oct 21, 2017
2 parents c01db84 + a2028b8 commit f3d91bf
Show file tree
Hide file tree
Showing 14 changed files with 711 additions and 73 deletions.
1 change: 1 addition & 0 deletions src/lxc/Makefile.am
Expand Up @@ -116,6 +116,7 @@ liblxc_la_SOURCES = \
log.c log.h \
attach.c attach.h \
criu.c criu.h \
ringbuf.c ringbuf.h \
\
network.c network.h \
nl.c nl.h \
Expand Down
122 changes: 64 additions & 58 deletions src/lxc/conf.c
Expand Up @@ -68,10 +68,6 @@
#include <../include/openpty.h>
#endif

#ifdef HAVE_LINUX_MEMFD_H
#include <linux/memfd.h>
#endif

#include "af_unix.h"
#include "caps.h" /* for lxc_caps_last_cap() */
#include "cgroup.h"
Expand All @@ -84,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"
Expand Down Expand Up @@ -181,59 +178,6 @@ static int sethostname(const char * name, size_t len)
#define MS_LAZYTIME (1<<25)
#endif

/* memfd_create() */
#ifndef MFD_CLOEXEC
#define MFD_CLOEXEC 0x0001U
#endif

#ifndef MFD_ALLOW_SEALING
#define MFD_ALLOW_SEALING 0x0002U
#endif

#ifndef HAVE_MEMFD_CREATE
static int memfd_create(const char *name, unsigned int flags) {
#ifndef __NR_memfd_create
#if defined __i386__
#define __NR_memfd_create 356
#elif defined __x86_64__
#define __NR_memfd_create 319
#elif defined __arm__
#define __NR_memfd_create 385
#elif defined __aarch64__
#define __NR_memfd_create 279
#elif defined __s390__
#define __NR_memfd_create 350
#elif defined __powerpc__
#define __NR_memfd_create 360
#elif defined __sparc__
#define __NR_memfd_create 348
#elif defined __blackfin__
#define __NR_memfd_create 390
#elif defined __ia64__
#define __NR_memfd_create 1340
#elif defined _MIPS_SIM
#if _MIPS_SIM == _MIPS_SIM_ABI32
#define __NR_memfd_create 4354
#endif
#if _MIPS_SIM == _MIPS_SIM_NABI32
#define __NR_memfd_create 6318
#endif
#if _MIPS_SIM == _MIPS_SIM_ABI64
#define __NR_memfd_create 5314
#endif
#endif
#endif
#ifdef __NR_memfd_create
return syscall(__NR_memfd_create, name, flags);
#else
errno = ENOSYS;
return -1;
#endif
}
#else
extern int memfd_create(const char *name, unsigned int flags);
#endif

char *lxchook_names[NUM_LXC_HOOKS] = {"pre-start", "pre-mount", "mount",
"autodev", "start", "stop",
"post-stop", "clone", "destroy",
Expand Down Expand Up @@ -2485,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;
Expand All @@ -2493,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);
Expand Down Expand Up @@ -3136,7 +3082,65 @@ static bool verify_start_hooks(struct lxc_conf *conf)
return true;
}

int lxc_setup(struct lxc_handler *handler)
/**
* 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;
const char *name = handler->name;
Expand Down Expand Up @@ -3516,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);
Expand Down
6 changes: 5 additions & 1 deletion src/lxc/conf.h
Expand Up @@ -36,6 +36,7 @@
#include <stdbool.h>

#include "list.h"
#include "ringbuf.h"
#include "start.h" /* for lxc_handler */

#if HAVE_SCMP_FILTER_CTX
Expand Down Expand Up @@ -152,6 +153,8 @@ struct lxc_console {
char name[MAXPATHLEN];
struct termios *tios;
struct lxc_tty_state *tty_state;
uint64_t log_size;
struct lxc_ringbuf ringbuf;
};

/*
Expand Down Expand Up @@ -376,7 +379,8 @@ extern int lxc_delete_autodev(struct lxc_handler *handler);
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(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 find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype);
extern int mapped_hostid(unsigned id, struct lxc_conf *conf,
Expand Down
62 changes: 62 additions & 0 deletions src/lxc/confile.c
Expand Up @@ -83,6 +83,7 @@ lxc_config_define(cap_keep);
lxc_config_define(cgroup_controller);
lxc_config_define(cgroup_dir);
lxc_config_define(console_logfile);
lxc_config_define(console_logsize);
lxc_config_define(console_path);
lxc_config_define(environment);
lxc_config_define(ephemeral);
Expand Down Expand Up @@ -148,6 +149,7 @@ static struct lxc_config_t config[] = {
{ "lxc.cgroup.dir", false, set_config_cgroup_dir, get_config_cgroup_dir, clr_config_cgroup_dir, },
{ "lxc.cgroup", false, set_config_cgroup_controller, get_config_cgroup_controller, clr_config_cgroup_controller, },
{ "lxc.console.logfile", false, set_config_console_logfile, get_config_console_logfile, clr_config_console_logfile, },
{ "lxc.console.logsize", false, set_config_console_logsize, get_config_console_logsize, clr_config_console_logsize, },
{ "lxc.console.path", false, set_config_console_path, get_config_console_path, clr_config_console_path, },
{ "lxc.environment", false, set_config_environment, get_config_environment, clr_config_environment, },
{ "lxc.ephemeral", false, set_config_ephemeral, get_config_ephemeral, clr_config_ephemeral, },
Expand Down Expand Up @@ -1790,6 +1792,53 @@ static int set_config_console_logfile(const char *key, const char *value,
return set_config_path_item(&lxc_conf->console.log_path, value);
}

static int set_config_console_logsize(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{
int ret;
int64_t size;
uint64_t logsize, pgsz;

if (lxc_config_value_empty(value)) {
lxc_conf->console.log_size = 0;
return 0;
}

/* If the user specified "auto" the default log size is 2^17 = 128 Kib */
if (!strcmp(value, "auto")) {
lxc_conf->console.log_size = 1 << 17;
return 0;
}

ret = parse_byte_size_string(value, &size);
if (ret < 0)
return -1;

if (size < 0)
return -EINVAL;

/* must be at least a page size */
pgsz = lxc_getpagesize();
if ((uint64_t)size < pgsz) {
NOTICE("Requested ringbuffer size for the console is %" PRId64
" but must be at least %" PRId64
" bytes. Setting ringbuffer size to %" PRId64 " bytes",
size, pgsz, pgsz);
size = pgsz;
}

logsize = lxc_find_next_power2((uint64_t)size);
if (logsize == 0)
return -EINVAL;

if (logsize != size)
NOTICE("Passed size was not a power of 2. Rounding log size to "
"next power of two: %" PRIu64 " bytes", logsize);

lxc_conf->console.log_size = logsize;
return 0;
}

int append_unexp_config_line(const char *line, struct lxc_conf *conf)
{
size_t len = conf->unexpanded_len, linelen = strlen(line);
Expand Down Expand Up @@ -3023,6 +3072,12 @@ static int get_config_console_logfile(const char *key, char *retv, int inlen,
return lxc_get_conf_str(retv, inlen, c->console.log_path);
}

static int get_config_console_logsize(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data)
{
return lxc_get_conf_uint64(c, retv, inlen, c->autodev);
}

static int get_config_seccomp_profile(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data)
{
Expand Down Expand Up @@ -3405,6 +3460,13 @@ static inline int clr_config_console_logfile(const char *key,
return 0;
}

static inline int clr_config_console_logsize(const char *key,
struct lxc_conf *c, void *data)
{
c->console.log_size = 0;
return 0;
}

static inline int clr_config_seccomp_profile(const char *key,
struct lxc_conf *c, void *data)
{
Expand Down
10 changes: 10 additions & 0 deletions src/lxc/confile_utils.c
Expand Up @@ -672,6 +672,16 @@ int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
return snprintf(retv, inlen, "%d", v);
}

int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v)
{
if (!retv)
inlen = 0;
else
memset(retv, 0, inlen);

return snprintf(retv, inlen, "%"PRIu64, v);
}

bool parse_limit_value(const char **value, rlim_t *res)
{
char *endptr = NULL;
Expand Down
2 changes: 2 additions & 0 deletions src/lxc/confile_utils.h
Expand Up @@ -84,5 +84,7 @@ extern void update_hwaddr(const char *line);
extern bool new_hwaddr(char *hwaddr);
extern int lxc_get_conf_str(char *retv, int inlen, const char *value);
extern int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v);
extern int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v);
extern bool parse_limit_value(const char **value, rlim_t *res);

#endif /* __LXC_CONFILE_UTILS_H */
32 changes: 24 additions & 8 deletions src/lxc/console.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit f3d91bf

Please sign in to comment.