From 31ffa6decdc76966bf0879e3c5e2d812f27a2cae Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Fri, 19 Jan 2007 17:22:17 +0000 Subject: [PATCH] Add cmdline debug & version options to dmeventd. Fix oom_adj handling. --- WHATS_NEW | 1 + dmeventd/dmeventd.c | 151 ++++++++++++++++++++++++++++++++------------ 2 files changed, 112 insertions(+), 40 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index b697a9b..f87bdf3 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 1.02.16 - =================================== + Add cmdline debug & version options to dmeventd. Add DM_LIB_VERSION definition to configure.h. Suppress 'Unrecognised field' error if report field is 'help'. Add --separator and --sort to dmsetup (unused). diff --git a/dmeventd/dmeventd.c b/dmeventd/dmeventd.c index cdc73f2..6c44f83 100644 --- a/dmeventd/dmeventd.c +++ b/dmeventd/dmeventd.c @@ -39,7 +39,12 @@ #include /* for htonl, ntohl */ #ifdef linux -#include +# include + +/* From linux/oom.h */ +# define OOM_DISABLE (-17) +# define OOM_ADJUST_MIN (-16) + #endif /* FIXME We use syslog for now, because multilog is not yet implemented */ @@ -47,6 +52,7 @@ static volatile sig_atomic_t _exit_now = 0; /* set to '1' when signal is given to exit */ static volatile sig_atomic_t _thread_registries_empty = 1; /* registries are empty initially */ +static int _debug = 0; /* List (un)link macros. */ #define LINK(x, head) list_add(head, &(x)->list) @@ -58,9 +64,10 @@ static volatile sig_atomic_t _thread_registries_empty = 1; /* registries are emp #define UNLINK_THREAD(x) UNLINK(x) #define DAEMON_NAME "dmeventd" +#define OOM_ADJ_FILE "/proc/self/oom_adj" /* - Global mutex for thread list access. Has to be held when: + Global mutex for thread list access. Has to be held when: - iterating thread list - adding or removing elements from thread list - changing or reading thread_status's fields: @@ -75,6 +82,8 @@ static pthread_mutex_t _global_mutex; #define THREAD_STACK_SIZE (300*1024) +#define DEBUGLOG(fmt, args...) _debuglog(fmt, ## args) + /* Data kept about a DSO. */ struct dso_data { struct list list; @@ -172,6 +181,24 @@ static LIST_INIT(_timeout_registry); static pthread_mutex_t _timeout_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t _timeout_cond = PTHREAD_COND_INITIALIZER; +static void _debuglog(const char *fmt, ...) +{ + time_t P; + va_list ap; + + if (!_debug) + return; + + va_start(ap,fmt); + + time(&P); + fprintf(stderr, "dmeventd[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 ); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + + va_end(ap); +} + /* Allocate/free the status structure for a monitoring thread. */ static struct thread_status *_alloc_thread_status(struct message_data *data, struct dso_data *dso_data) @@ -883,11 +910,11 @@ static int _register_for_event(struct message_data *message_data) almost as good as dead already... */ if (thread_new->events & DM_EVENT_TIMEOUT) { ret = -_register_for_timeout(thread); - if (ret) { - _unlock_mutex(); - goto out; - } - } + if (ret) { + _unlock_mutex(); + goto out; + } + } if (!(thread = _lookup_thread_status(message_data))) { _unlock_mutex(); @@ -1361,7 +1388,7 @@ static void _cleanup_unused_threads(void) if (thread->status == DM_THREAD_RUNNING) { thread->status = DM_THREAD_SHUTDOWN; break; - } + } if (thread->status == DM_THREAD_SHUTDOWN) { if (!thread->events) { @@ -1377,7 +1404,7 @@ static void _cleanup_unused_threads(void) stack; } break; - } + } list_del(l); syslog(LOG_ERR, @@ -1465,31 +1492,39 @@ static int _lock_pidfile(void) return 0; } +/* + * Protection against OOM killer if kernel supports it + */ static int _set_oom_adj(int val) { FILE *fp; struct stat st; - if (stat("/proc/self/oom_adj", &st) == -1) - return -errno; - - fp = fopen("/proc/self/oom_adj", "w"); + if (stat(OOM_ADJ_FILE, &st) == -1) { + if (errno == ENOENT) + DEBUGLOG(OOM_ADJ_FILE " not found"); + else + perror(OOM_ADJ_FILE ": stat failed"); + return 1; + } - if (!fp) - return -1; + if (!(fp = fopen(OOM_ADJ_FILE, "w"))) { + perror(OOM_ADJ_FILE ": fopen failed"); + return 0; + } fprintf(fp, "%i", val); fclose(fp); - return 0; + return 1; } static void _daemonize(void) { - int status; - int pid; + int child_status; int fd; + pid_t pid; struct rlimit rlim; struct timeval tval; sigset_t my_sigset; @@ -1501,14 +1536,17 @@ static void _daemonize(void) } signal(SIGTERM, &_exit_handler); - pid = fork(); - - if (pid < 0) + switch (pid = fork()) { + case -1: + perror("fork failed:"); exit(EXIT_FAILURE); - if (pid) { + case 0: /* Child */ + break; + + default: /* Wait for response from child */ - while (!waitpid(pid, &status, WNOHANG) && !_exit_now) { + while (!waitpid(pid, &child_status, WNOHANG) && !_exit_now) { tval.tv_sec = 0; tval.tv_usec = 250000; /* .25 sec */ select(0, NULL, NULL, NULL, &tval); @@ -1518,7 +1556,7 @@ static void _daemonize(void) exit(EXIT_SUCCESS); /* Problem with child. Determine what it is by exit code */ - switch (WEXITSTATUS(status)) { + switch (WEXITSTATUS(child_status)) { case EXIT_LOCKFILE_INUSE: break; case EXIT_DESC_CLOSE_FAILURE: @@ -1535,10 +1573,9 @@ static void _daemonize(void) break; } - exit(EXIT_FAILURE); /* Redundant */ + exit(child_status); } - setsid(); if (chdir("/")) exit(EXIT_CHDIR_FAILURE); @@ -1555,28 +1592,61 @@ static void _daemonize(void) (open("/dev/null", O_WRONLY) < 0)) exit(EXIT_DESC_OPEN_FAILURE); - openlog("dmeventd", LOG_PID, LOG_DAEMON); - - _lock_pidfile(); /* exits if failure */ + setsid(); +} - /* Set the rest of the signals to cause '_exit_now' to be set */ - signal(SIGINT, &_exit_handler); - signal(SIGHUP, &_exit_handler); - signal(SIGQUIT, &_exit_handler); +static void usage(char *prog, FILE *file) +{ + fprintf(file, "Usage:\n"); + fprintf(file, "%s [Vhd]\n", prog); + fprintf(file, "\n"); + fprintf(file, " -V Show version of dmeventd\n"); + fprintf(file, " -h Show this help information\n"); + fprintf(file, " -d Don't fork, run in the foreground\n"); + fprintf(file, "\n"); } int main(int argc, char *argv[]) { int ret; + signed char opt; struct dm_event_fifos fifos; //struct sys_log logdata = {DAEMON_NAME, LOG_DAEMON}; - _daemonize(); + opterr = 0; + optind = 0; + + while ((opt = getopt(argc, argv, "?hVd")) != EOF) { + switch (opt) { + case 'h': + usage(argv[0], stdout); + exit(0); + case '?': + usage(argv[0], stderr); + exit(0); + case 'd': + _debug++; + break; + case 'V': + printf("dmeventd version: %s\n", DM_LIB_VERSION); + exit(1); + break; + } + } + + if (!_debug) + _daemonize(); - /* - * ENOENT means the kernel does not support oom_adj - */ - if (_set_oom_adj(-16) != -ENOENT) + openlog("dmeventd", LOG_PID, LOG_DAEMON); + + _lock_pidfile(); /* exits if failure */ + + /* Set the rest of the signals to cause '_exit_now' to be set */ + signal(SIGINT, &_exit_handler); + signal(SIGHUP, &_exit_handler); + signal(SIGQUIT, &_exit_handler); + + if (!_set_oom_adj(OOM_DISABLE) && !_set_oom_adj(OOM_ADJUST_MIN)) syslog(LOG_ERR, "Failed to set oom_adj to protect against OOM killer"); _init_thread_signals(); @@ -1600,7 +1670,7 @@ int main(int argc, char *argv[]) /* Signal parent, letting them know we are ready to go. */ kill(getppid(), SIGTERM); - syslog(LOG_INFO, "dmeventd ready for processing."); + syslog(LOG_NOTICE, "dmeventd ready for processing."); while (!_exit_now) { _process_request(&fifos); @@ -1619,7 +1689,8 @@ int main(int argc, char *argv[]) #endif pthread_mutex_destroy(&_global_mutex); - syslog(LOG_INFO, "dmeventd shutting down."); + syslog(LOG_NOTICE, "dmeventd shutting down."); closelog(); + exit(EXIT_SUCCESS); } -- 2.43.5