]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - mdmon.c
ping_manager() to prevent 'add' before 'remove' completes
[thirdparty/mdadm.git] / mdmon.c
diff --git a/mdmon.c b/mdmon.c
index 7ba8be04a8d547653eb520b276d61eae7785c19f..9485757a3d6d2de68f33752840d51b638ce36c1d 100644 (file)
--- a/mdmon.c
+++ b/mdmon.c
 
 #include       <unistd.h>
 #include       <stdlib.h>
+#include       <sys/types.h>
 #include       <sys/stat.h>
 #include       <sys/socket.h>
 #include       <sys/un.h>
 #include       <sys/mman.h>
+#include       <sys/syscall.h>
+#include       <sys/wait.h>
 #include       <stdio.h>
 #include       <errno.h>
 #include       <string.h>
 
 struct active_array *discard_this;
 struct active_array *pending_discard;
-struct md_generic_cmd *active_cmd;
+
+int mon_tid, mgr_tid;
 
 int run_child(void *v)
 {
        struct supertype *c = v;
-       sigset_t set;
-       /* SIGUSR is sent from child to parent,  So child must block it */
-       sigemptyset(&set);
-       sigaddset(&set, SIGUSR1);
-       sigprocmask(SIG_BLOCK, &set, NULL);
 
        do_monitor(c);
        return 0;
@@ -61,37 +60,22 @@ int run_child(void *v)
 int clone_monitor(struct supertype *container)
 {
        static char stack[4096];
-       int rv;
 
-       rv = pipe(container->mgr_pipe);
-       if (rv < 0)
-               return rv;
-       rv = pipe(container->mon_pipe);
-       if (rv < 0)
-               goto err_mon_pipe;
-
-       rv = clone(run_child, stack+4096-64,
+       mon_tid = clone(run_child, stack+4096-64,
                   CLONE_FS|CLONE_FILES|CLONE_VM|CLONE_SIGHAND|CLONE_THREAD,
                   container);
-       if (rv < 0)
-               goto err_clone;
-       else
-               return rv;
-
- err_clone:
-       close(container->mon_pipe[0]);
-       close(container->mon_pipe[1]);
- err_mon_pipe:
-       close(container->mgr_pipe[0]);
-       close(container->mgr_pipe[1]);
-
-       return rv;
+
+       mgr_tid = syscall(SYS_gettid);
+
+       return mon_tid;
 }
 
 static struct superswitch *find_metadata_methods(char *vers)
 {
        if (strcmp(vers, "ddf") == 0)
                return &super_ddf;
+       if (strcmp(vers, "imsm") == 0)
+               return &super_imsm;
        return NULL;
 }
 
@@ -146,6 +130,14 @@ static void try_kill_monitor(char *devname)
                kill(pid, SIGTERM);
 }
 
+void remove_pidfile(char *devname)
+{
+       char buf[100];
+
+       sprintf(buf, "/var/run/mdadm/%s.pid", devname);
+       unlink(buf);
+}
+
 static int make_control_sock(char *devname)
 {
        char path[100];
@@ -172,11 +164,34 @@ static int make_control_sock(char *devname)
        return sfd;
 }
 
+static void wake_me(int sig)
+{
+
+}
+
+/* if we are debugging and starting mdmon by hand then don't fork */
+static int do_fork(void)
+{
+       #ifdef DEBUG
+       if (env_no_mdmon())
+               return 0;
+       #endif
+
+       return 1;
+}
+
+
+
 int main(int argc, char *argv[])
 {
        int mdfd;
        struct mdinfo *mdi, *di;
        struct supertype *container;
+       sigset_t set;
+       struct sigaction act;
+       int pfd[2];
+       int status;
+
        if (argc != 2) {
                fprintf(stderr, "Usage: md-manage /device/name/for/container\n");
                exit(2);
@@ -193,12 +208,33 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
+       /* Fork, and have the child tell us when they are ready */
+       if (do_fork()) {
+               pipe(pfd);
+               switch(fork()) {
+               case -1:
+                       fprintf(stderr, "mdmon: failed to fork: %s\n",
+                               strerror(errno));
+                       exit(1);
+               case 0: /* child */
+                       close(pfd[0]);
+                       break;
+               default: /* parent */
+                       close(pfd[1]);
+                       if (read(pfd[0], &status, sizeof(status)) != sizeof(status)) {
+                               wait(&status);
+                               status = WEXITSTATUS(status);
+                       }
+                       exit(status);
+               }
+       } else
+               pfd[0] = pfd[1] = -1;
        /* hopefully it is a container - we'll check later */
 
        container = malloc(sizeof(*container));
-       container->devfd = mdfd;
        container->devnum = fd2devnum(mdfd);
        container->devname = devnum2devname(container->devnum);
+       container->device_name = argv[1];
 
        /* If this fails, we hope it already exists */
        mkdir("/var/run/mdadm", 0600);
@@ -256,7 +292,7 @@ int main(int argc, char *argv[])
        container->devs = NULL;
        for (di = mdi->devs; di; di = di->next) {
                struct mdinfo *cd = malloc(sizeof(*cd));
-               cd = di;
+               *cd = *di;
                cd->next = container->devs;
                container->devs = cd;
        }
@@ -269,9 +305,37 @@ int main(int argc, char *argv[])
                exit(3);
        }
 
+       /* Ok, this is close enough.  We can say goodbye to our parent now.
+        */
+       status = 0;
+       write(pfd[1], &status, sizeof(status));
+       close(pfd[1]);
+
+       chdir("/");
+       setsid();
+       close(0);
+       open("/dev/null", O_RDWR);
+       close(1);
+       dup(0);
+#ifndef DEBUG
+       close(2);
+       dup(0);
+#endif
 
        mlockall(MCL_FUTURE);
 
+       /* SIGUSR is sent between parent and child.  So both block it
+        * and enable it only with pselect.
+        */
+       sigemptyset(&set);
+       sigaddset(&set, SIGUSR1);
+       sigprocmask(SIG_BLOCK, &set, NULL);
+       act.sa_handler = wake_me;
+       act.sa_flags = 0;
+       sigaction(SIGUSR1, &act, NULL);
+       act.sa_handler = SIG_IGN;
+       sigaction(SIGPIPE, &act, NULL);
+
        if (clone_monitor(container) < 0) {
                fprintf(stderr, "md-manage: failed to start monitor process: %s\n",
                        strerror(errno));