X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=mdmon.c;h=75fdcaad2fb047141b9e6f7715a8c2b7807a4c87;hb=c61c4dd01df75d3a56809db19ec827203505830b;hp=0ec42591500de9f6e5ca978fd1d5b20606009e2e;hpb=1373b07d758213b643f72a09384b840e4f08057a;p=thirdparty%2Fmdadm.git diff --git a/mdmon.c b/mdmon.c index 0ec42591..75fdcaad 100644 --- a/mdmon.c +++ b/mdmon.c @@ -58,8 +58,11 @@ #include #include #include - +#ifdef USE_PTHREADS +#include +#else #include +#endif #include "mdadm.h" #include "mdmon.h" @@ -71,7 +74,39 @@ int mon_tid, mgr_tid; int sigterm; -int run_child(void *v) +#ifdef USE_PTHREADS +static void *run_child(void *v) +{ + struct supertype *c = v; + + mon_tid = syscall(SYS_gettid); + do_monitor(c); + return 0; +} + +static int clone_monitor(struct supertype *container) +{ + pthread_attr_t attr; + pthread_t thread; + int rc; + + mon_tid = -1; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 4096); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + rc = pthread_create(&thread, &attr, run_child, container); + if (rc) + return rc; + while (mon_tid == -1) + usleep(10); + pthread_attr_destroy(&attr); + + mgr_tid = syscall(SYS_gettid); + + return mon_tid; +} +#else /* USE_PTHREADS */ +static int run_child(void *v) { struct supertype *c = v; @@ -85,7 +120,7 @@ int __clone2(int (*fn)(void *), int flags, void *arg, ... /* pid_t *pid, struct user_desc *tls, pid_t *ctid */ ); #endif - int clone_monitor(struct supertype *container) +static int clone_monitor(struct supertype *container) { static char stack[4096]; @@ -103,38 +138,21 @@ int __clone2(int (*fn)(void *), return mon_tid; } +#endif /* USE_PTHREADS */ -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; -} - -static int test_pidfile(char *devname) -{ - char path[100]; - struct stat st; - - sprintf(path, "/var/run/mdadm/%s.pid", devname); - return stat(path, &st); -} - -int make_pidfile(char *devname, int o_excl) +static int make_pidfile(char *devname) { char path[100]; char pid[10]; int fd; int n; - if (sigterm) - return -1; - - sprintf(path, "/var/run/mdadm/%s.pid", devname); + if (mkdir(MDMON_DIR, 0755) < 0 && + errno != EEXIST) + return -errno; + sprintf(path, "%s/%s.pid", MDMON_DIR, devname); - fd = open(path, O_RDWR|O_CREAT|o_excl, 0600); + fd = open(path, O_RDWR|O_CREAT|O_EXCL, 0600); if (fd < 0) return -errno; sprintf(pid, "%d\n", getpid()); @@ -145,41 +163,12 @@ int make_pidfile(char *devname, int o_excl) return 0; } -int is_container_member(struct mdstat_ent *mdstat, char *container) -{ - if (mdstat->metadata_version == NULL || - strncmp(mdstat->metadata_version, "external:", 9) != 0 || - !is_subarray(mdstat->metadata_version+9) || - strncmp(mdstat->metadata_version+10, container, strlen(container)) != 0 || - mdstat->metadata_version[10+strlen(container)] != '/') - return 0; - - return 1; -} - -pid_t devname2mdmon(char *devname) -{ - char buf[100]; - pid_t pid = -1; - int fd; - - sprintf(buf, "/var/run/mdadm/%s.pid", devname); - fd = open(buf, O_RDONLY|O_NOATIME); - if (fd < 0) - return -1; - - if (read(fd, buf, sizeof(buf)) > 0) - sscanf(buf, "%d\n", &pid); - close(fd); - - return pid; -} - static void try_kill_monitor(pid_t pid, char *devname, int sock) { char buf[100]; int fd; - struct mdstat_ent *mdstat; + int n; + long fl; /* first rule of survival... don't off yourself */ if (pid == getpid()) @@ -191,39 +180,37 @@ static void try_kill_monitor(pid_t pid, char *devname, int sock) if (fd < 0) return; - if (read(fd, buf, sizeof(buf)) < 0) { - close(fd); - return; - } + n = read(fd, buf, sizeof(buf)-1); + buf[sizeof(buf)-1] = 0; + close(fd); - if (!strstr(buf, "mdmon")) + if (n < 0 || !strstr(buf, "mdmon")) return; kill(pid, SIGTERM); - mdstat = mdstat_read(0, 0); - for ( ; mdstat; mdstat = mdstat->next) - if (is_container_member(mdstat, devname)) { - sprintf(buf, "/dev/%s", mdstat->dev); - WaitClean(buf, sock, 0); - } - free_mdstat(mdstat); + /* Wait for monitor to exit by reading from the socket, after + * clearing the non-blocking flag */ + fl = fcntl(sock, F_GETFL, 0); + fl &= ~O_NONBLOCK; + fcntl(sock, F_SETFL, fl); + n = read(sock, buf, 100); + /* Ignore result, it is just the wait that + * matters + */ } void remove_pidfile(char *devname) { char buf[100]; - if (sigterm) - return; - - sprintf(buf, "/var/run/mdadm/%s.pid", devname); + sprintf(buf, "%s/%s.pid", MDMON_DIR, devname); unlink(buf); - sprintf(buf, "/var/run/mdadm/%s.sock", devname); + sprintf(buf, "%s/%s.sock", MDMON_DIR, devname); unlink(buf); } -int make_control_sock(char *devname) +static int make_control_sock(char *devname) { char path[100]; int sfd; @@ -233,7 +220,7 @@ int make_control_sock(char *devname) if (sigterm) return -1; - sprintf(path, "/var/run/mdadm/%s.sock", devname); + sprintf(path, "%s/%s.sock", MDMON_DIR, devname); unlink(path); sfd = socket(PF_LOCAL, SOCK_STREAM, 0); if (sfd < 0) @@ -252,12 +239,6 @@ int make_control_sock(char *devname) return sfd; } -int socket_hup_requested; -static void hup(int sig) -{ - socket_hup_requested = 1; -} - static void term(int sig) { sigterm = 1; @@ -281,36 +262,42 @@ static int do_fork(void) void usage(void) { - fprintf(stderr, "Usage: mdmon /device/name/for/container [target_dir]\n"); + fprintf(stderr, "Usage: mdmon [--all] [--takeover] CONTAINER\n"); exit(2); } -int mdmon(char *devname, int devnum, int scan, char *switchroot); +static int mdmon(char *devname, int devnum, int must_fork, int takeover); int main(int argc, char *argv[]) { char *container_name = NULL; - char *switchroot = NULL; int devnum; char *devname; - int scan = 0; int status = 0; - - switch (argc) { - case 3: - switchroot = argv[2]; - case 2: - container_name = argv[1]; - break; - default: - usage(); + int arg; + int all = 0; + int takeover = 0; + + for (arg = 1; arg < argc; arg++) { + if (strncmp(argv[arg], "--all",5) == 0 || + strcmp(argv[arg], "/proc/mdstat") == 0) { + container_name = argv[arg]; + all = 1; + } else if (strcmp(argv[arg], "--takeover") == 0) + takeover = 1; + else if (container_name == NULL) + container_name = argv[arg]; + else + usage(); } + if (container_name == NULL) + usage(); - if (strcmp(container_name, "/proc/mdstat") == 0) { + if (all) { struct mdstat_ent *mdstat, *e; + int container_len = strlen(container_name); /* launch an mdmon instance for each container found */ - scan = 1; mdstat = mdstat_read(0, 0); for (e = mdstat; e; e = e->next) { if (strncmp(e->metadata_version, "external:", 9) == 0 && @@ -319,12 +306,12 @@ int main(int argc, char *argv[]) /* update cmdline so this mdmon instance can be * distinguished from others in a call to ps(1) */ - if (strlen(devname) <= strlen(container_name)) { - memset(container_name, 0, strlen(container_name)); + if (strlen(devname) <= container_len) { + memset(container_name, 0, container_len); sprintf(container_name, "%s", devname); } - status |= mdmon(devname, e->devnum, scan, - switchroot); + status |= mdmon(devname, e->devnum, 1, + takeover); } } free_mdstat(mdstat); @@ -352,10 +339,10 @@ int main(int argc, char *argv[]) container_name); exit(1); } - return mdmon(devname, devnum, scan, switchroot); + return mdmon(devname, devnum, do_fork(), takeover); } -int mdmon(char *devname, int devnum, int scan, char *switchroot) +static int mdmon(char *devname, int devnum, int must_fork, int takeover) { int mdfd; struct mdinfo *mdi, *di; @@ -368,30 +355,7 @@ int mdmon(char *devname, int devnum, int scan, char *switchroot) pid_t victim = -1; int victim_sock = -1; - dprintf("starting mdmon for %s in %s\n", - devname, switchroot ? : "/"); - - /* try to spawn mdmon instances from the target file system */ - if (switchroot && strcmp(switchroot, "/") != 0) { - char path[1024]; - pid_t pid; - - sprintf(path, "%s/sbin/mdmon", switchroot); - switch (fork()) { - case 0: - execl(path, "mdmon", devname, NULL); - exit(1); - case -1: - return 1; - default: - pid = wait(&status); - if (pid > -1 && WIFEXITED(status) && - WEXITSTATUS(status) == 0) - return 0; - else - return 1; - } - } + dprintf("starting mdmon for %s\n", devname); mdfd = open_dev(devnum); if (mdfd < 0) { @@ -406,7 +370,7 @@ int mdmon(char *devname, int devnum, int scan, char *switchroot) } /* Fork, and have the child tell us when they are ready */ - if (do_fork() || scan) { + if (must_fork) { if (pipe(pfd) != 0) { fprintf(stderr, "mdmon: failed to create pipe\n"); return 1; @@ -442,8 +406,7 @@ int mdmon(char *devname, int devnum, int scan, char *switchroot) exit(3); } - mdi = sysfs_read(mdfd, container->devnum, - GET_VERSION|GET_LEVEL|GET_DEVS|SKIP_GONE_DEVS); + mdi = sysfs_read(mdfd, container->devnum, GET_VERSION|GET_LEVEL|GET_DEVS); if (!mdi) { fprintf(stderr, "mdmon: failed to load sysfs info for %s\n", @@ -462,9 +425,9 @@ int mdmon(char *devname, int devnum, int scan, char *switchroot) exit(3); } - container->ss = find_metadata_methods(mdi->text_version); + container->ss = version_to_superswitch(mdi->text_version); if (container->ss == NULL) { - fprintf(stderr, "mdmon: %s uses unknown metadata: %s\n", + fprintf(stderr, "mdmon: %s uses unsupported metadata: %s\n", devname, mdi->text_version); exit(3); } @@ -483,42 +446,28 @@ int mdmon(char *devname, int devnum, int scan, char *switchroot) */ sigemptyset(&set); 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; sigaction(SIGUSR1, &act, NULL); - 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); - if (switchroot) { - /* we assume we assume that /sys /proc /dev are available in - * the new root - */ - victim = devname2mdmon(container->devname); + victim = mdmon_pid(container->devnum); + if (victim >= 0) victim_sock = connect_monitor(container->devname); - if (chroot(switchroot) != 0) { - fprintf(stderr, "mdmon: failed to chroot to '%s': %s\n", - switchroot, strerror(errno)); - exit(4); - } - } ignore = chdir("/"); - if (victim < 0 && test_pidfile(container->devname) == 0) { - if (ping_monitor(container->devname) == 0) { + if (!takeover && victim > 0 && victim_sock >= 0) { + if (fping_monitor(victim_sock) == 0) { fprintf(stderr, "mdmon: %s already managed\n", container->devname); exit(3); - } else if (victim < 0) - victim = devname2mdmon(container->devname); + } + close(victim_sock); } if (container->ss->load_super(container, mdfd, devname)) { fprintf(stderr, "mdmon: Cannot load metadata for %s\n", @@ -529,22 +478,19 @@ int mdmon(char *devname, int devnum, int scan, char *switchroot) /* Ok, this is close enough. We can say goodbye to our parent now. */ + if (victim > 0) + remove_pidfile(devname); + if (make_pidfile(devname) < 0) { + exit(3); + } + container->sock = make_control_sock(devname); + status = 0; if (write(pfd[1], &status, sizeof(status)) < 0) fprintf(stderr, "mdmon: failed to notify our parent: %d\n", getppid()); close(pfd[1]); - setsid(); - close(0); - open("/dev/null", O_RDWR); - close(1); - ignore = dup(0); -#ifndef DEBUG - close(2); - ignore = dup(0); -#endif - mlockall(MCL_CURRENT | MCL_FUTURE); if (clone_monitor(container) < 0) { @@ -553,10 +499,21 @@ int mdmon(char *devname, int devnum, int scan, char *switchroot) exit(2); } - if (victim > -1) { + if (victim > 0) { try_kill_monitor(victim, container->devname, victim_sock); close(victim_sock); } + + setsid(); + close(0); + open("/dev/null", O_RDWR); + close(1); + ignore = dup(0); +#ifndef DEBUG + close(2); + ignore = dup(0); +#endif + do_manager(container); exit(0);