summaryrefslogtreecommitdiff
path: root/mdmon.c
diff options
context:
space:
mode:
Diffstat (limited to 'mdmon.c')
-rw-r--r--mdmon.c107
1 files changed, 60 insertions, 47 deletions
diff --git a/mdmon.c b/mdmon.c
index 31994d8..50c7be6 100644
--- a/mdmon.c
+++ b/mdmon.c
@@ -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);