summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2008-10-02 06:32:08 -0700
committerDan Williams <dan.j.williams@intel.com>2008-10-15 14:43:57 -0700
commit6144ed441445ee4d567614aaed78dd24148881ce (patch)
tree7c98537390691aca6739ea2ed9f4d151a9a9f027
parent57ed8c9155d31ca78c48979f4f98d40e4c0deac3 (diff)
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 <dan.j.williams@intel.com>
-rw-r--r--managemon.c6
-rw-r--r--mdmon.c19
-rw-r--r--mdmon.h1
-rw-r--r--monitor.c44
4 files changed, 63 insertions, 7 deletions
diff --git a/managemon.c b/managemon.c
index 730334cd..a8af614a 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 28b01398..7ef0c80f 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 41222e1c..2ce1fe69 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 1bf69a7e..d8ac45e8 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 */