From 6144ed441445ee4d567614aaed78dd24148881ce Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 2 Oct 2008 06:32:08 -0700 Subject: [PATCH] mdmon: terminate clean We generally don't want mdmon to be terminated, but if a SIGTERM gets through try to leave the monitored arrays in a clean state, block attempts to mark the array dirty, and stop servicing the socket. When we are killed by sigterm don't remove the pidfile let that be cleaned up by the next monitor. Signed-off-by: Dan Williams --- managemon.c | 6 +++++- mdmon.c | 19 +++++++++++++++++++ mdmon.h | 1 + monitor.c | 44 ++++++++++++++++++++++++++++++++++++++------ 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/managemon.c b/managemon.c index 730334c..a8af614 100644 --- a/managemon.c +++ b/managemon.c @@ -555,7 +555,7 @@ static void handle_message(struct supertype *container, struct metadata_update * manage(mdstat, container); free_mdstat(mdstat); - } else { + } else if (!sigterm) { mu = malloc(sizeof(*mu)); mu->len = msg->len; mu->buf = msg->buf; @@ -612,6 +612,7 @@ void do_manager(struct supertype *container) sigdelset(&set, SIGUSR1); sigdelset(&set, SIGHUP); sigdelset(&set, SIGALRM); + sigdelset(&set, SIGTERM); proc_fd = open("/proc/mounts", O_RDONLY); do { @@ -647,6 +648,9 @@ void do_manager(struct supertype *container) manager_ready = 1; + if (sigterm) + wakeup_monitor(); + if (update_queue == NULL) { if (container->sock < 0) mdstat_wait_fd(proc_fd, &set); diff --git a/mdmon.c b/mdmon.c index 28b0139..7ef0c80 100644 --- a/mdmon.c +++ b/mdmon.c @@ -49,6 +49,8 @@ struct active_array *pending_discard; int mon_tid, mgr_tid; +int sigterm; + int run_child(void *v) { struct supertype *c = v; @@ -87,6 +89,9 @@ int make_pidfile(char *devname, int o_excl) int fd; int n; + if (sigterm) + return -1; + sprintf(path, "/var/run/mdadm/%s.pid", devname); fd = open(path, O_RDWR|O_CREAT|o_excl, 0600); @@ -138,6 +143,9 @@ void remove_pidfile(char *devname) { char buf[100]; + if (sigterm) + return; + sprintf(buf, "/var/run/mdadm/%s.pid", devname); unlink(buf); sprintf(buf, "/var/run/mdadm/%s.sock", devname); @@ -151,6 +159,9 @@ int make_control_sock(char *devname) long fl; struct sockaddr_un addr; + if (sigterm) + return -1; + sprintf(path, "/var/run/mdadm/%s.sock", devname); unlink(path); sfd = socket(PF_LOCAL, SOCK_STREAM, 0); @@ -176,6 +187,11 @@ static void hup(int sig) socket_hup_requested = 1; } +static void term(int sig) +{ + sigterm = 1; +} + static void wake_me(int sig) { @@ -355,6 +371,7 @@ int main(int argc, char *argv[]) sigaddset(&set, SIGUSR1); sigaddset(&set, SIGHUP); sigaddset(&set, SIGALRM); + sigaddset(&set, SIGTERM); sigprocmask(SIG_BLOCK, &set, NULL); act.sa_handler = wake_me; act.sa_flags = 0; @@ -362,6 +379,8 @@ int main(int argc, char *argv[]) sigaction(SIGALRM, &act, NULL); act.sa_handler = hup; sigaction(SIGHUP, &act, NULL); + act.sa_handler = term; + sigaction(SIGTERM, &act, NULL); act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &act, NULL); diff --git a/mdmon.h b/mdmon.h index 41222e1..2ce1fe6 100644 --- a/mdmon.h +++ b/mdmon.h @@ -50,6 +50,7 @@ void do_manager(struct supertype *container); int make_control_sock(char *devname); int make_pidfile(char *devname, int o_excl); extern int socket_hup_requested; +extern int sigterm; int read_dev_state(int fd); int get_resync_start(struct active_array *a); diff --git a/monitor.c b/monitor.c index 1bf69a7..d8ac45e 100644 --- a/monitor.c +++ b/monitor.c @@ -414,6 +414,7 @@ static int wait_and_act(struct supertype *container, int nowait) struct active_array *a, **ap; int rv; struct mdinfo *mdi; + static unsigned int dirty_arrays = ~0; /* start at some non-zero value */ FD_ZERO(&rfds); @@ -442,16 +443,20 @@ static int wait_and_act(struct supertype *container, int nowait) ap = &(*ap)->next; } - if (manager_ready && *aap == NULL) { - /* No interesting arrays. Lets see about exiting. - * Note that blocking at this point is not a problem - * as there are no active arrays, there is nothing that - * we need to be ready to do. + if (manager_ready && (*aap == NULL || (sigterm && !dirty_arrays))) { + /* No interesting arrays, or we have been told to + * terminate and everything is clean. Lets see about + * exiting. Note that blocking at this point is not a + * problem as there are no active arrays, there is + * nothing that we need to be ready to do. */ int fd = open(container->device_name, O_RDONLY|O_EXCL); if (fd >= 0 || errno != EBUSY) { /* OK, we are safe to leave */ - dprintf("no arrays to monitor... exiting\n"); + if (sigterm && !dirty_arrays) + dprintf("caught sigterm, all clean... exiting\n"); + else + dprintf("no arrays to monitor... exiting\n"); remove_pidfile(container->devname); exit_now = 1; signal_manager(); @@ -487,7 +492,10 @@ static int wait_and_act(struct supertype *container, int nowait) } rv = 0; + dirty_arrays = 0; for (a = *aap; a ; a = a->next) { + int is_dirty; + if (a->replaces && !discard_this) { struct active_array **ap; for (ap = &a->next; *ap && *ap != a->replaces; @@ -502,6 +510,30 @@ static int wait_and_act(struct supertype *container, int nowait) } if (a->container) rv += read_and_act(a); + else + continue; + + /* when terminating stop manipulating the array after it is + * clean, but make sure read_and_act() is given a chance to + * handle 'active_idle' + */ + switch (read_state(a->info.state_fd)) { + case active: + case active_idle: + case suspended: + case bad_word: + is_dirty = 1; + break; + default: + if (a->curr_state == active_idle) + is_dirty = 1; + else + is_dirty = 0; + break; + } + dirty_arrays += is_dirty; + if (sigterm && !is_dirty) + a->container = NULL; /* stop touching this array */ } /* propagate failures across container members */