fix fd leak in test-concurrent

Opening a debug log for every thread at every iteration of test-concurrent
causes it to quickly run out of fd's because this fd is leaked. Fix this
by adding a new api: lxc_log_close().

As Caglar noted, the log handling is in general a bit "interesting" because
a logfile can be opened through the per-container api
c->set_config_item("lxc.logfile") but lxc_log_fd is now per-thread data. It
just so happens in test-concurrent that there is a 1:1 mapping of threads
to logfiles.

Split out getting debug logs from quiet since I think they are useful
separately. If debug is specified, get a log of any mode, not just during
start.

Signed-off-by: Dwight Engen <dwight.engen@oracle.com>
Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
This commit is contained in:
Dwight Engen 2014-03-07 16:49:25 -05:00 committed by Serge Hallyn
parent d3de16bb56
commit 36eaa69415
3 changed files with 29 additions and 5 deletions

View File

@ -368,6 +368,16 @@ extern int lxc_log_init(const char *name, const char *file,
return ret; return ret;
} }
extern void lxc_log_close(void)
{
if (lxc_log_fd == -1)
return;
close(lxc_log_fd);
lxc_log_fd = -1;
free(log_fname);
log_fname = NULL;
}
/* /*
* This is called when we read a lxc.loglevel entry in a lxc.conf file. This * This is called when we read a lxc.loglevel entry in a lxc.conf file. This
* happens after processing command line arguments, which override the .conf * happens after processing command line arguments, which override the .conf

View File

@ -865,6 +865,11 @@ int list_active_containers(const char *lxcpath, char ***names, struct lxc_contai
*/ */
int list_all_containers(const char *lxcpath, char ***names, struct lxc_container ***cret); int list_all_containers(const char *lxcpath, char ***names, struct lxc_container ***cret);
/*!
* \brief Close log file.
*/
void lxc_log_close(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -29,6 +29,7 @@
static int nthreads = 5; static int nthreads = 5;
static int iterations = 1; static int iterations = 1;
static int debug = 0;
static int quiet = 0; static int quiet = 0;
static int delay = 0; static int delay = 0;
static const char *template = "busybox"; static const char *template = "busybox";
@ -40,6 +41,7 @@ static const struct option options[] = {
{ "delay", required_argument, NULL, 'd' }, { "delay", required_argument, NULL, 'd' },
{ "modes", required_argument, NULL, 'm' }, { "modes", required_argument, NULL, 'm' },
{ "quiet", no_argument, NULL, 'q' }, { "quiet", no_argument, NULL, 'q' },
{ "debug", no_argument, NULL, 'D' },
{ "help", no_argument, NULL, '?' }, { "help", no_argument, NULL, '?' },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 },
}; };
@ -54,6 +56,7 @@ static void usage(void) {
" -d, --delay=N Delay in seconds between start and stop\n" " -d, --delay=N Delay in seconds between start and stop\n"
" -m, --modes=<mode,mode,...> Modes to run (create, start, stop, destroy)\n" " -m, --modes=<mode,mode,...> Modes to run (create, start, stop, destroy)\n"
" -q, --quiet Don't produce any output\n" " -q, --quiet Don't produce any output\n"
" -D, --debug Create a debug log\n"
" -?, --help Give this help list\n" " -?, --help Give this help list\n"
"\n" "\n"
"Mandatory or optional arguments to long options are also mandatory or optional\n" "Mandatory or optional arguments to long options are also mandatory or optional\n"
@ -81,6 +84,11 @@ static void do_function(void *arguments)
return; return;
} }
if (debug) {
c->set_config_item(c, "lxc.loglevel", "DEBUG");
c->set_config_item(c, "lxc.logfile", name);
}
if (strcmp(args->mode, "create") == 0) { if (strcmp(args->mode, "create") == 0) {
if (!c->is_defined(c)) { if (!c->is_defined(c)) {
if (!c->create(c, template, NULL, NULL, 1, NULL)) { if (!c->create(c, template, NULL, NULL, 1, NULL)) {
@ -91,10 +99,6 @@ static void do_function(void *arguments)
} else if(strcmp(args->mode, "start") == 0) { } else if(strcmp(args->mode, "start") == 0) {
if (c->is_defined(c) && !c->is_running(c)) { if (c->is_defined(c) && !c->is_running(c)) {
c->want_daemonize(c, true); c->want_daemonize(c, true);
if (!quiet) {
c->set_config_item(c, "lxc.loglevel", "DEBUG");
c->set_config_item(c, "lxc.logfile", name);
}
if (!c->start(c, false, NULL)) { if (!c->start(c, false, NULL)) {
fprintf(stderr, "Starting the container (%s) failed...\n", name); fprintf(stderr, "Starting the container (%s) failed...\n", name);
goto out; goto out;
@ -127,6 +131,8 @@ static void do_function(void *arguments)
args->return_code = 0; args->return_code = 0;
out: out:
lxc_container_put(c); lxc_container_put(c);
if (debug)
lxc_log_close();
} }
static void *concurrent(void *arguments) static void *concurrent(void *arguments)
@ -148,7 +154,7 @@ int main(int argc, char *argv[]) {
pthread_attr_init(&attr); pthread_attr_init(&attr);
while ((opt = getopt_long(argc, argv, "j:i:t:d:m:q", options, NULL)) != -1) { while ((opt = getopt_long(argc, argv, "j:i:t:d:m:qD", options, NULL)) != -1) {
switch(opt) { switch(opt) {
case 'j': case 'j':
nthreads = atoi(optarg); nthreads = atoi(optarg);
@ -165,6 +171,9 @@ int main(int argc, char *argv[]) {
case 'q': case 'q':
quiet = 1; quiet = 1;
break; break;
case 'D':
debug = 1;
break;
case 'm': { case 'm': {
char *mode_tok, *tok, *saveptr = NULL; char *mode_tok, *tok, *saveptr = NULL;