diff options
Diffstat (limited to 'mdmon.c')
-rw-r--r-- | mdmon.c | 107 |
1 files changed, 60 insertions, 47 deletions
@@ -113,6 +113,14 @@ static struct superswitch *find_metadata_methods(char *vers) 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) { @@ -149,26 +157,29 @@ int is_container_member(struct mdstat_ent *mdstat, char *container) return 1; } -void remove_pidfile(char *devname); -static void try_kill_monitor(char *devname) +pid_t devname2mdmon(char *devname) { char buf[100]; + pid_t pid = -1; int fd; - pid_t pid; - struct mdstat_ent *mdstat; sprintf(buf, "/var/run/mdadm/%s.pid", devname); - fd = open(buf, O_RDONLY); + fd = open(buf, O_RDONLY|O_NOATIME); if (fd < 0) - return; - - if (read(fd, buf, sizeof(buf)) < 0) { - close(fd); - return; - } + return -1; + if (read(fd, buf, sizeof(buf)) > 0) + sscanf(buf, "%d\n", &pid); close(fd); - pid = strtoul(buf, NULL, 10); + + return pid; +} + +static void try_kill_monitor(pid_t pid, char *devname, int sock) +{ + char buf[100]; + int fd; + struct mdstat_ent *mdstat; /* first rule of survival... don't off yourself */ if (pid == getpid()) @@ -194,10 +205,9 @@ static void try_kill_monitor(char *devname) for ( ; mdstat; mdstat = mdstat->next) if (is_container_member(mdstat, devname)) { sprintf(buf, "/dev/%s", mdstat->dev); - WaitClean(buf, 0); + WaitClean(buf, sock, 0); } free_mdstat(mdstat); - remove_pidfile(devname); } void remove_pidfile(char *devname) @@ -355,9 +365,34 @@ int mdmon(char *devname, int devnum, int scan, char *switchroot) int pfd[2]; int status; int ignore; + 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; + } + } + mdfd = open_dev(devnum); if (mdfd < 0) { fprintf(stderr, "mdmon: %s: %s\n", devname, @@ -400,6 +435,7 @@ int mdmon(char *devname, int devnum, int scan, char *switchroot) container->devname = devname; container->arrays = NULL; container->subarray[0] = 0; + container->sock = -1; if (!container->devname) { fprintf(stderr, "mdmon: failed to allocate container name string\n"); @@ -464,12 +500,10 @@ int mdmon(char *devname, int devnum, int scan, char *switchroot) if (switchroot) { /* we assume we assume that /sys /proc /dev are available in - * the new root (see nash:setuproot) - * - * kill any monitors in the current namespace and change - * to the new one + * the new root */ - try_kill_monitor(container->devname); + victim = devname2mdmon(container->devname); + victim_sock = connect_monitor(container->devname); if (chroot(switchroot) != 0) { fprintf(stderr, "mdmon: failed to chroot to '%s': %s\n", switchroot, strerror(errno)); @@ -477,40 +511,15 @@ int mdmon(char *devname, int devnum, int scan, char *switchroot) } } - /* If this fails, we hope it already exists - * pid file lives in /var/run/mdadm/mdXX.pid - */ - mkdir("/var", 0600); - mkdir("/var/run", 0600); - mkdir("/var/run/mdadm", 0600); ignore = chdir("/"); - if (make_pidfile(container->devname, O_EXCL) < 0) { + if (victim < 0 && test_pidfile(container->devname) == 0) { if (ping_monitor(container->devname) == 0) { fprintf(stderr, "mdmon: %s already managed\n", container->devname); exit(3); - } else { - int err; - - /* cleanup the old monitor, this one is taking over */ - try_kill_monitor(container->devname); - err = make_pidfile(container->devname, 0); - if (err < 0) { - fprintf(stderr, "mdmon: %s Cannot create pidfile\n", - container->devname); - if (err == -EROFS) { - /* FIXME implement a mechanism to - * prevent duplicate monitor instances - */ - fprintf(stderr, - "mdmon: continuing on read-only file system\n"); - } else - exit(3); - } - } + } else if (victim < 0) + victim = devname2mdmon(container->devname); } - container->sock = make_control_sock(container->devname); - if (container->ss->load_super(container, mdfd, devname)) { fprintf(stderr, "mdmon: Cannot load metadata for %s\n", devname); @@ -544,6 +553,10 @@ int mdmon(char *devname, int devnum, int scan, char *switchroot) exit(2); } + if (victim > -1) { + try_kill_monitor(victim, container->devname, victim_sock); + close(victim_sock); + } do_manager(container); exit(0); |