Commit 42e56013 by Serge Hallyn Committed by Stéphane Graber

logs: introduce a thread-local 'current' lxc_config

The logging code uses a global log_fd and log_level to direct logging (ERROR(), etc). While the container configuration file allows for lxc.loglevel and lxc.logfile, those are only used at configuration file read time to set the global variables. This works ok in the lxc front-end programs, but becomes a problem with threaded API users. The simplest solution would be to not allow per-container configuration files, but it'd be nice to avoid that. Passing a logfd or lxc_conf into every ERROR/INFO/etc call is "possible", but would be a huge complication as there are many functions, including struct member functions and callbacks, which don't have that info and would need to get it from somewhere. So the approach I'm taking here is to say that all real container work is done inside api calls, and therefore the API calls themselves can set a thread-local variable indicating which log info to use. If unset, then use the global values. The lxc-* programs, when called with a '-o logfile' argument, set a global variable to indicate that the user-specified value should be used. In this patch: If the lxc container configuration specifies a loglevel/logfile, only set the lxc_config's logfd and loglevel according to those, not the global values. Each API call is wrapped to set/unset the current_config. (The few exceptions are calls which do not result in any log actions) Update logfile appender to use the logfile specified in lxc_conf if (a) current_config is set and (b) the lxc-* command did not override it. Signed-off-by: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com> Acked-by: 's avatarStéphane Graber <stgraber@ubuntu.com>
parent 0dbb4b2d
......@@ -248,6 +248,7 @@ endif
init_lxc_static_LDFLAGS = -static
init_lxc_static_LDADD = @CAP_LIBS@
init_lxc_static_CFLAGS = $(AM_CFLAGS) -DNO_LXC_CONF
endif
install-exec-local: install-soPROGRAMS
......
......@@ -178,6 +178,17 @@ struct caps_opt {
int value;
};
/*
* The lxc_conf of the container currently being worked on in an
* API call
* This is used in the error calls
*/
#ifdef HAVE_TLS
__thread struct lxc_conf *current_config;
#else
struct lxc_conf *current_config;
#endif
/* Declare this here, since we don't want to reshuffle the whole file. */
static int in_caplist(int cap, struct lxc_list *caps);
......@@ -2563,6 +2574,7 @@ struct lxc_conf *lxc_conf_init(void)
return NULL;
}
new->kmsg = 0;
new->logfd = -1;
lxc_list_init(&new->cgroup);
lxc_list_init(&new->network);
lxc_list_init(&new->mount_list);
......@@ -4236,6 +4248,8 @@ void lxc_conf_free(struct lxc_conf *conf)
free(conf->rootfs.path);
free(conf->rootfs.pivot);
free(conf->logfile);
if (conf->logfd != -1)
close(conf->logfd);
free(conf->utsname);
free(conf->ttydir);
free(conf->fstab);
......
......@@ -335,6 +335,7 @@ struct lxc_conf {
// store the config file specified values here.
char *logfile; // the logfile as specifed in config
int loglevel; // loglevel as specifed in config (if any)
int logfd;
int inherit_ns_fd[LXC_NS_MAX];
......@@ -364,6 +365,12 @@ struct lxc_conf {
char *init_cmd;
};
#ifdef HAVE_TLS
extern __thread struct lxc_conf *current_config;
#else
extern struct lxc_conf *current_config;
#endif
int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
const char *lxcpath, char *argv[]);
......
......@@ -1171,15 +1171,15 @@ static int config_lsm_se_context(const char *key, const char *value,
}
static int config_logfile(const char *key, const char *value,
struct lxc_conf *lxc_conf)
struct lxc_conf *c)
{
int ret;
// store these values in the lxc_conf, and then try to set for
// actual current logging.
ret = config_path_item(&lxc_conf->logfile, value);
ret = config_path_item(&c->logfile, value);
if (ret == 0)
ret = lxc_log_set_file(lxc_conf->logfile);
ret = lxc_log_set_file(&c->logfd, c->logfile);
return ret;
}
......@@ -1198,7 +1198,7 @@ static int config_loglevel(const char *key, const char *value,
// store these values in the lxc_conf, and then try to set for
// actual current logging.
lxc_conf->loglevel = newlevel;
return lxc_log_set_level(newlevel);
return lxc_log_set_level(&lxc_conf->loglevel, newlevel);
}
static int config_autodev(const char *key, const char *value,
......@@ -2381,9 +2381,9 @@ int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv,
else if (strcmp(key, "lxc.se_context") == 0)
v = c->lsm_se_context;
else if (strcmp(key, "lxc.logfile") == 0)
v = lxc_log_get_file();
v = c->logfile;
else if (strcmp(key, "lxc.loglevel") == 0)
v = lxc_log_priority_to_string(lxc_log_get_level());
v = lxc_log_priority_to_string(c->loglevel);
else if (strcmp(key, "lxc.cgroup") == 0) // all cgroup info
return lxc_get_cgroup_entry(c, retv, inlen, "all");
else if (strncmp(key, "lxc.cgroup.", 11) == 0) // specific cgroup info
......
......@@ -27,6 +27,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>
#define __USE_GNU /* for *_CLOEXEC */
......@@ -40,27 +41,44 @@
#define LXC_LOG_PREFIX_SIZE 32
#define LXC_LOG_BUFFER_SIZE 512
#ifdef HAVE_TLS
__thread int lxc_log_fd = -1;
static __thread char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
static __thread char *log_fname = NULL;
/* command line values for logfile or logpriority should always override
* values from the configuration file or defaults
*/
static __thread int lxc_logfile_specified = 0;
static __thread int lxc_loglevel_specified = 0;
static __thread int lxc_quiet_specified = 0;
#else
static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
static void lock_mutex(pthread_mutex_t *l)
{
int ret;
if ((ret = pthread_mutex_lock(l)) != 0) {
fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, strerror(ret));
exit(1);
}
}
static void unlock_mutex(pthread_mutex_t *l)
{
int ret;
if ((ret = pthread_mutex_unlock(l)) != 0) {
fprintf(stderr, "pthread_mutex_unlock returned:%d %s\n", ret, strerror(ret));
exit(1);
}
}
void log_lock(void)
{
lock_mutex(&log_mutex);
}
void log_unlock(void)
{
unlock_mutex(&log_mutex);
}
int lxc_log_fd = -1;
int lxc_quiet_specified;
int lxc_log_use_global_fd;
static int lxc_loglevel_specified;
static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
static char *log_fname = NULL;
static int lxc_quiet_specified = 0;
/* command line values for logfile or logpriority should always override
* values from the configuration file or defaults
*/
static int lxc_logfile_specified = 0;
static int lxc_loglevel_specified = 0;
#endif
lxc_log_define(lxc_log, lxc);
......@@ -85,8 +103,17 @@ static int log_append_logfile(const struct lxc_log_appender *appender,
char buffer[LXC_LOG_BUFFER_SIZE];
int n;
int ms;
int fd_to_use = -1;
if (lxc_log_fd == -1)
#ifndef NO_LXC_CONF
if (!lxc_log_use_global_fd && current_config)
fd_to_use = current_config->logfd;
#endif
if (fd_to_use == -1)
fd_to_use = lxc_log_fd;
if (fd_to_use == -1)
return 0;
ms = event->timestamp.tv_usec / 1000;
......@@ -111,7 +138,7 @@ static int log_append_logfile(const struct lxc_log_appender *appender,
buffer[n] = '\n';
return write(lxc_log_fd, buffer, n + 1);
return write(fd_to_use, buffer, n + 1);
}
static struct lxc_log_appender log_appender_stderr = {
......@@ -136,7 +163,7 @@ static struct lxc_log_category log_root = {
struct lxc_log_category lxc_log_category_lxc = {
.name = "lxc",
.priority = LXC_LOG_PRIORITY_ERROR,
.appender = &log_appender_stderr,
.appender = &log_appender_logfile,
.parent = &log_root
};
......@@ -305,6 +332,11 @@ static int _lxc_log_set_file(const char *name, const char *lxcpath, int create_d
return ret;
}
/*
* lxc_log_init:
* Called from lxc front-end programs (like lxc-create, lxc-start) to
* initalize the log defaults.
*/
extern int lxc_log_init(const char *name, const char *file,
const char *priority, const char *prefix, int quiet,
const char *lxcpath)
......@@ -320,10 +352,12 @@ extern int lxc_log_init(const char *name, const char *file,
if (priority)
lxc_priority = lxc_log_priority_to_int(priority);
lxc_log_category_lxc.priority = lxc_priority;
if (!lxc_loglevel_specified) {
lxc_log_category_lxc.priority = lxc_priority;
lxc_loglevel_specified = 1;
}
if (!lxc_quiet_specified) {
lxc_log_category_lxc.appender = &log_appender_logfile;
if (!quiet)
lxc_log_category_lxc.appender->next = &log_appender_stderr;
}
......@@ -335,6 +369,7 @@ extern int lxc_log_init(const char *name, const char *file,
if (strcmp(file, "none") == 0)
return 0;
ret = __lxc_log_set_file(file, 1);
lxc_log_use_global_fd = 1;
} else {
/* if no name was specified, there nothing to do */
if (!name)
......@@ -385,15 +420,13 @@ extern void lxc_log_close(void)
* happens after processing command line arguments, which override the .conf
* settings. So only set the level if previously unset.
*/
extern int lxc_log_set_level(int level)
extern int lxc_log_set_level(int *dest, int level)
{
if (lxc_loglevel_specified)
return 0;
if (level < 0 || level >= LXC_LOG_PRIORITY_NOTSET) {
ERROR("invalid log priority %d", level);
return -1;
}
lxc_log_category_lxc.priority = level;
*dest = level;
return 0;
}
......@@ -415,11 +448,23 @@ extern bool lxc_log_has_valid_level(void)
* happens after processing command line arguments, which override the .conf
* settings. So only set the file if previously unset.
*/
extern int lxc_log_set_file(const char *fname)
extern int lxc_log_set_file(int *fd, const char *fname)
{
if (lxc_logfile_specified)
return 0;
return __lxc_log_set_file(fname, 0);
if (*fd != -1) {
close(*fd);
*fd = -1;
}
if (build_dir(fname)) {
ERROR("failed to create dir for log file \"%s\" : %s", fname,
strerror(errno));
return -1;
}
*fd = log_open(fname);
if (*fd == -1)
return -errno;
return 0;
}
extern const char *lxc_log_get_file(void)
......@@ -440,11 +485,6 @@ extern const char *lxc_log_get_prefix(void)
extern void lxc_log_options_no_override()
{
if (lxc_log_get_file())
lxc_logfile_specified = 1;
if (lxc_log_get_level() != LXC_LOG_PRIORITY_NOTSET)
lxc_loglevel_specified = 1;
lxc_quiet_specified = 1;
lxc_loglevel_specified = 1;
}
......@@ -33,6 +33,8 @@
#include <strings.h>
#include <stdbool.h>
#include "conf.h"
#ifndef O_CLOEXEC
#define O_CLOEXEC 02000000
#endif
......@@ -104,6 +106,10 @@ struct lxc_log_category {
const struct lxc_log_category *parent;
};
#ifndef NO_LXC_CONF
extern int lxc_log_use_global_fd;
#endif
/*
* Returns true if the chained priority is equal to or higher than
* given priority.
......@@ -116,7 +122,14 @@ lxc_log_priority_is_enabled(const struct lxc_log_category* category,
category->parent)
category = category->parent;
return priority >= category->priority;
int cmp_prio = category->priority;
#ifndef NO_LXC_CONF
if (!lxc_log_use_global_fd && current_config &&
current_config->loglevel != LXC_LOG_PRIORITY_NOTSET)
cmp_prio = current_config->loglevel;
#endif
return priority >= cmp_prio;
}
/*
......@@ -294,18 +307,14 @@ ATTR_UNUSED static inline void LXC_##PRIORITY(struct lxc_log_locinfo* locinfo, \
ERROR("%s - " format, strerror(errno), ##__VA_ARGS__); \
} while (0)
#ifdef HAVE_TLS
extern __thread int lxc_log_fd;
#else
extern int lxc_log_fd;
#endif
extern int lxc_log_init(const char *name, const char *file,
const char *priority, const char *prefix, int quiet,
const char *lxcpath);
extern int lxc_log_set_file(const char *fname);
extern int lxc_log_set_level(int level);
extern int lxc_log_set_file(int *fd, const char *fname);
extern int lxc_log_set_level(int *dest, int level);
extern void lxc_log_set_prefix(const char *prefix);
extern const char *lxc_log_get_file(void);
extern int lxc_log_get_level(void);
......
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