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 */