Commit 858377e4 by Serge Hallyn

logs: introduce a thread-local 'current' lxc_config (v2)

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. Changelog (2015-04-21): . always re-set current_config to NULL at end of an API call, rather than storing the previous value. We don't nest API calls. . remove the log_lock stuff which wasn't used . lxc_conf_free: if the config is current_config, set current_config to NULL. (It can't be another thread's current_config, or we wouldn't be freeing it) . lxc_check_inherited: don't close fd if it is the current_config->logfd. Note this is only called when starting a container, so we have no other threads at this point. Changelog (2015-04-22) . Unset the per-container logfd on destroy . . Do so before we rm the containerdir. Otherwise if the logfile is set . to $lxcpath/$name/log, the containerdir won't be fully deleted. Signed-off-by: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com> Acked-by: 's avatarStéphane Graber <stgraber@ubuntu.com>
parent ed52814c
...@@ -249,6 +249,7 @@ endif ...@@ -249,6 +249,7 @@ endif
init_lxc_static_LDFLAGS = -static init_lxc_static_LDFLAGS = -static
init_lxc_static_LDADD = @CAP_LIBS@ init_lxc_static_LDADD = @CAP_LIBS@
init_lxc_static_CFLAGS = $(AM_CFLAGS) -DNO_LXC_CONF
endif endif
install-exec-local: install-soPROGRAMS install-exec-local: install-soPROGRAMS
......
...@@ -178,6 +178,17 @@ struct caps_opt { ...@@ -178,6 +178,17 @@ struct caps_opt {
int value; 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. */ /* Declare this here, since we don't want to reshuffle the whole file. */
static int in_caplist(int cap, struct lxc_list *caps); static int in_caplist(int cap, struct lxc_list *caps);
...@@ -2573,6 +2584,7 @@ struct lxc_conf *lxc_conf_init(void) ...@@ -2573,6 +2584,7 @@ struct lxc_conf *lxc_conf_init(void)
return NULL; return NULL;
} }
new->kmsg = 0; new->kmsg = 0;
new->logfd = -1;
lxc_list_init(&new->cgroup); lxc_list_init(&new->cgroup);
lxc_list_init(&new->network); lxc_list_init(&new->network);
lxc_list_init(&new->mount_list); lxc_list_init(&new->mount_list);
...@@ -4239,6 +4251,8 @@ void lxc_conf_free(struct lxc_conf *conf) ...@@ -4239,6 +4251,8 @@ void lxc_conf_free(struct lxc_conf *conf)
{ {
if (!conf) if (!conf)
return; return;
if (current_config == conf)
current_config = NULL;
free(conf->console.log_path); free(conf->console.log_path);
free(conf->console.path); free(conf->console.path);
free(conf->rootfs.mount); free(conf->rootfs.mount);
...@@ -4246,6 +4260,8 @@ void lxc_conf_free(struct lxc_conf *conf) ...@@ -4246,6 +4260,8 @@ void lxc_conf_free(struct lxc_conf *conf)
free(conf->rootfs.path); free(conf->rootfs.path);
free(conf->rootfs.pivot); free(conf->rootfs.pivot);
free(conf->logfile); free(conf->logfile);
if (conf->logfd != -1)
close(conf->logfd);
free(conf->utsname); free(conf->utsname);
free(conf->ttydir); free(conf->ttydir);
free(conf->fstab); free(conf->fstab);
......
...@@ -336,6 +336,7 @@ struct lxc_conf { ...@@ -336,6 +336,7 @@ struct lxc_conf {
// store the config file specified values here. // store the config file specified values here.
char *logfile; // the logfile as specifed in config char *logfile; // the logfile as specifed in config
int loglevel; // loglevel as specifed in config (if any) int loglevel; // loglevel as specifed in config (if any)
int logfd;
int inherit_ns_fd[LXC_NS_MAX]; int inherit_ns_fd[LXC_NS_MAX];
...@@ -365,6 +366,12 @@ struct lxc_conf { ...@@ -365,6 +366,12 @@ struct lxc_conf {
char *init_cmd; 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, int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
const char *lxcpath, char *argv[]); const char *lxcpath, char *argv[]);
......
...@@ -1171,15 +1171,15 @@ static int config_lsm_se_context(const char *key, const char *value, ...@@ -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, static int config_logfile(const char *key, const char *value,
struct lxc_conf *lxc_conf) struct lxc_conf *c)
{ {
int ret; int ret;
// store these values in the lxc_conf, and then try to set for // store these values in the lxc_conf, and then try to set for
// actual current logging. // actual current logging.
ret = config_path_item(&lxc_conf->logfile, value); ret = config_path_item(&c->logfile, value);
if (ret == 0) if (ret == 0)
ret = lxc_log_set_file(lxc_conf->logfile); ret = lxc_log_set_file(&c->logfd, c->logfile);
return ret; return ret;
} }
...@@ -1198,7 +1198,7 @@ static int config_loglevel(const char *key, const char *value, ...@@ -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 // store these values in the lxc_conf, and then try to set for
// actual current logging. // actual current logging.
lxc_conf->loglevel = newlevel; 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, 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, ...@@ -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) else if (strcmp(key, "lxc.se_context") == 0)
v = c->lsm_se_context; v = c->lsm_se_context;
else if (strcmp(key, "lxc.logfile") == 0) else if (strcmp(key, "lxc.logfile") == 0)
v = lxc_log_get_file(); v = c->logfile;
else if (strcmp(key, "lxc.loglevel") == 0) 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 else if (strcmp(key, "lxc.cgroup") == 0) // all cgroup info
return lxc_get_cgroup_entry(c, retv, inlen, "all"); return lxc_get_cgroup_entry(c, retv, inlen, "all");
else if (strncmp(key, "lxc.cgroup.", 11) == 0) // specific cgroup info else if (strncmp(key, "lxc.cgroup.", 11) == 0) // specific cgroup info
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <string.h> #include <string.h>
#include <pthread.h>
#define __USE_GNU /* for *_CLOEXEC */ #define __USE_GNU /* for *_CLOEXEC */
...@@ -40,27 +41,13 @@ ...@@ -40,27 +41,13 @@
#define LXC_LOG_PREFIX_SIZE 32 #define LXC_LOG_PREFIX_SIZE 32
#define LXC_LOG_BUFFER_SIZE 512 #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
int lxc_log_fd = -1; 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_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
static char *log_fname = NULL; 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); lxc_log_define(lxc_log, lxc);
...@@ -85,8 +72,17 @@ static int log_append_logfile(const struct lxc_log_appender *appender, ...@@ -85,8 +72,17 @@ static int log_append_logfile(const struct lxc_log_appender *appender,
char buffer[LXC_LOG_BUFFER_SIZE]; char buffer[LXC_LOG_BUFFER_SIZE];
int n; int n;
int ms; 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; return 0;
ms = event->timestamp.tv_usec / 1000; ms = event->timestamp.tv_usec / 1000;
...@@ -111,7 +107,7 @@ static int log_append_logfile(const struct lxc_log_appender *appender, ...@@ -111,7 +107,7 @@ static int log_append_logfile(const struct lxc_log_appender *appender,
buffer[n] = '\n'; 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 = { static struct lxc_log_appender log_appender_stderr = {
...@@ -136,7 +132,7 @@ static struct lxc_log_category log_root = { ...@@ -136,7 +132,7 @@ static struct lxc_log_category log_root = {
struct lxc_log_category lxc_log_category_lxc = { struct lxc_log_category lxc_log_category_lxc = {
.name = "lxc", .name = "lxc",
.priority = LXC_LOG_PRIORITY_ERROR, .priority = LXC_LOG_PRIORITY_ERROR,
.appender = &log_appender_stderr, .appender = &log_appender_logfile,
.parent = &log_root .parent = &log_root
}; };
...@@ -305,6 +301,11 @@ static int _lxc_log_set_file(const char *name, const char *lxcpath, int create_d ...@@ -305,6 +301,11 @@ static int _lxc_log_set_file(const char *name, const char *lxcpath, int create_d
return ret; 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, extern int lxc_log_init(const char *name, const char *file,
const char *priority, const char *prefix, int quiet, const char *priority, const char *prefix, int quiet,
const char *lxcpath) const char *lxcpath)
...@@ -320,10 +321,12 @@ extern int lxc_log_init(const char *name, const char *file, ...@@ -320,10 +321,12 @@ extern int lxc_log_init(const char *name, const char *file,
if (priority) if (priority)
lxc_priority = lxc_log_priority_to_int(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) { if (!lxc_quiet_specified) {
lxc_log_category_lxc.appender = &log_appender_logfile;
if (!quiet) if (!quiet)
lxc_log_category_lxc.appender->next = &log_appender_stderr; lxc_log_category_lxc.appender->next = &log_appender_stderr;
} }
...@@ -335,6 +338,7 @@ extern int lxc_log_init(const char *name, const char *file, ...@@ -335,6 +338,7 @@ extern int lxc_log_init(const char *name, const char *file,
if (strcmp(file, "none") == 0) if (strcmp(file, "none") == 0)
return 0; return 0;
ret = __lxc_log_set_file(file, 1); ret = __lxc_log_set_file(file, 1);
lxc_log_use_global_fd = 1;
} else { } else {
/* if no name was specified, there nothing to do */ /* if no name was specified, there nothing to do */
if (!name) if (!name)
...@@ -385,15 +389,13 @@ extern void lxc_log_close(void) ...@@ -385,15 +389,13 @@ extern void lxc_log_close(void)
* happens after processing command line arguments, which override the .conf * happens after processing command line arguments, which override the .conf
* settings. So only set the level if previously unset. * 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) { if (level < 0 || level >= LXC_LOG_PRIORITY_NOTSET) {
ERROR("invalid log priority %d", level); ERROR("invalid log priority %d", level);
return -1; return -1;
} }
lxc_log_category_lxc.priority = level; *dest = level;
return 0; return 0;
} }
...@@ -415,11 +417,23 @@ extern bool lxc_log_has_valid_level(void) ...@@ -415,11 +417,23 @@ extern bool lxc_log_has_valid_level(void)
* happens after processing command line arguments, which override the .conf * happens after processing command line arguments, which override the .conf
* settings. So only set the file if previously unset. * 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) if (*fd != -1) {
return 0; close(*fd);
return __lxc_log_set_file(fname, 0); *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) extern const char *lxc_log_get_file(void)
...@@ -440,11 +454,6 @@ extern const char *lxc_log_get_prefix(void) ...@@ -440,11 +454,6 @@ extern const char *lxc_log_get_prefix(void)
extern void lxc_log_options_no_override() 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_quiet_specified = 1;
lxc_loglevel_specified = 1;
} }
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include <strings.h> #include <strings.h>
#include <stdbool.h> #include <stdbool.h>
#include "conf.h"
#ifndef O_CLOEXEC #ifndef O_CLOEXEC
#define O_CLOEXEC 02000000 #define O_CLOEXEC 02000000
#endif #endif
...@@ -104,6 +106,10 @@ struct lxc_log_category { ...@@ -104,6 +106,10 @@ struct lxc_log_category {
const struct lxc_log_category *parent; 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 * Returns true if the chained priority is equal to or higher than
* given priority. * given priority.
...@@ -116,7 +122,14 @@ lxc_log_priority_is_enabled(const struct lxc_log_category* category, ...@@ -116,7 +122,14 @@ lxc_log_priority_is_enabled(const struct lxc_log_category* category,
category->parent) category->parent)
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, \ ...@@ -294,18 +307,14 @@ ATTR_UNUSED static inline void LXC_##PRIORITY(struct lxc_log_locinfo* locinfo, \
ERROR("%s - " format, strerror(errno), ##__VA_ARGS__); \ ERROR("%s - " format, strerror(errno), ##__VA_ARGS__); \
} while (0) } while (0)
#ifdef HAVE_TLS
extern __thread int lxc_log_fd;
#else
extern int lxc_log_fd; extern int lxc_log_fd;
#endif
extern int lxc_log_init(const char *name, const char *file, extern int lxc_log_init(const char *name, const char *file,
const char *priority, const char *prefix, int quiet, const char *priority, const char *prefix, int quiet,
const char *lxcpath); const char *lxcpath);
extern int lxc_log_set_file(const char *fname); extern int lxc_log_set_file(int *fd, const char *fname);
extern int lxc_log_set_level(int level); extern int lxc_log_set_level(int *dest, int level);
extern void lxc_log_set_prefix(const char *prefix); extern void lxc_log_set_prefix(const char *prefix);
extern const char *lxc_log_get_file(void); extern const char *lxc_log_get_file(void);
extern int lxc_log_get_level(void); extern int lxc_log_get_level(void);
......
...@@ -212,6 +212,9 @@ restart: ...@@ -212,6 +212,9 @@ restart:
if (fd == fddir || fd == lxc_log_fd || fd == fd_to_ignore) if (fd == fddir || fd == lxc_log_fd || fd == fd_to_ignore)
continue; continue;
if (current_config && fd == current_config->logfd)
continue;
if (match_fd(fd)) if (match_fd(fd))
continue; continue;
......
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