]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - util.c
Grow: fix problem with reshaping RAID4 to RAID0.
[thirdparty/mdadm.git] / util.c
diff --git a/util.c b/util.c
index 5e653f49e0076014e857b8d1c02796a9177268ce..8817a3e22ac35bbd235a2e995dd39ac1df1e2698 100644 (file)
--- a/util.c
+++ b/util.c
@@ -32,8 +32,6 @@
 #include       <dirent.h>
 #include       <signal.h>
 
-int __offroot;
-
 /*
  * following taken from linux/blkpg.h because they aren't
  * anywhere else and it isn't safe to #include linux/ * stuff.
@@ -43,10 +41,10 @@ int __offroot;
 
 /* The argument structure */
 struct blkpg_ioctl_arg {
-        int op;
-        int flags;
-        int datalen;
-        void *data;
+       int op;
+       int flags;
+       int datalen;
+       void *data;
 };
 
 /* The subfunctions (for the op field) */
@@ -127,21 +125,21 @@ int parse_uuid(char *str, int uuid[4])
 
 int md_get_version(int fd)
 {
-    struct stat stb;
-    mdu_version_t vers;
+       struct stat stb;
+       mdu_version_t vers;
 
-    if (fstat(fd, &stb)<0)
-       return -1;
-    if ((S_IFMT&stb.st_mode) != S_IFBLK)
-       return -1;
+       if (fstat(fd, &stb)<0)
+               return -1;
+       if ((S_IFMT&stb.st_mode) != S_IFBLK)
+               return -1;
 
-    if (ioctl(fd, RAID_VERSION, &vers) == 0)
-       return  (vers.major*10000) + (vers.minor*100) + vers.patchlevel;
-    if (errno == EACCES)
-           return -1;
-    if (major(stb.st_rdev) == MD_MAJOR)
-       return (3600);
-    return -1;
+       if (ioctl(fd, RAID_VERSION, &vers) == 0)
+               return  (vers.major*10000) + (vers.minor*100) + vers.patchlevel;
+       if (errno == EACCES)
+               return -1;
+       if (major(stb.st_rdev) == MD_MAJOR)
+               return (3600);
+       return -1;
 }
 
 int get_linux_version()
@@ -559,8 +557,8 @@ int check_raid(int fd, char *name)
        char *level;
        struct supertype *st = guess_super(fd);
 
-       if (!st) return 0;
-       st->ignore_hw_compat = 1;
+       if (!st)
+               return 0;
        st->ss->load_super(st, fd, name);
        /* Looks like a raid array .. */
        pr_err("%s appears to be part of a raid array:\n",
@@ -839,7 +837,6 @@ int find_free_devnum(int use_partitions)
        int devnum;
        for (devnum = 127; devnum != 128;
             devnum = devnum ? devnum-1 : (1<<20)-1) {
-               char *dn;
                int _devnum;
                char nbuf[50];
 
@@ -849,11 +846,14 @@ int find_free_devnum(int use_partitions)
                sprintf(nbuf, "%s%d", use_partitions?"mdp":"md", devnum);
                if (!conf_name_is_free(nbuf))
                        continue;
-               /* make sure it is new to /dev too, at least as a
-                * non-standard */
-               dn = map_dev(dev2major(_devnum), dev2minor(_devnum), 0);
-               if (dn && ! is_standard(dn, NULL))
-                       continue;
+               if (!use_udev()) {
+                       /* make sure it is new to /dev too, at least as a
+                        * non-standard */
+                       char *dn = map_dev(dev2major(_devnum),
+                                          dev2minor(_devnum), 0);
+                       if (dn && ! is_standard(dn, NULL))
+                               continue;
+               }
                break;
        }
        if (devnum == 128)
@@ -880,18 +880,14 @@ int dev_open(char *dev, int flags)
        if (e > dev && *e == ':' && e[1] &&
            (minor = strtoul(e+1, &e, 0)) >= 0 &&
            *e == 0) {
-               char *path = map_dev(major, minor, 0);
-               if (path)
-                       fd = open(path, flags);
-               if (fd < 0) {
-                       snprintf(devname, sizeof(devname), "/dev/.tmp.md.%d:%d:%d",
-                                (int)getpid(), major, minor);
-                       if (mknod(devname, S_IFBLK|0600, makedev(major, minor)) == 0) {
-                               fd = open(devname, flags);
-                               unlink(devname);
-                       }
+               snprintf(devname, sizeof(devname), "/dev/.tmp.md.%d:%d:%d",
+                        (int)getpid(), major, minor);
+               if (mknod(devname, S_IFBLK|0600, makedev(major, minor)) == 0) {
+                       fd = open(devname, flags);
+                       unlink(devname);
                }
                if (fd < 0) {
+                       /* Try /tmp as /dev appear to be read-only */
                        snprintf(devname, sizeof(devname), "/tmp/.tmp.md.%d:%d:%d",
                                 (int)getpid(), major, minor);
                        if (mknod(devname, S_IFBLK|0600, makedev(major, minor)) == 0) {
@@ -1077,6 +1073,7 @@ struct supertype *dup_super(struct supertype *orig)
        st->ss = orig->ss;
        st->max_devs = orig->max_devs;
        st->minor_version = orig->minor_version;
+       st->ignore_hw_compat = orig->ignore_hw_compat;
        st->sb = NULL;
        st->info = NULL;
        return st;
@@ -1124,7 +1121,6 @@ struct supertype *guess_super_type(int fd, enum guess_types guess_type)
                rv = superlist[bestsuper]->load_super(st, fd, NULL);
                if (rv == 0) {
                        superlist[bestsuper]->free_super(st);
-                       st->ignore_hw_compat = 0;
                        return st;
                }
        }
@@ -1312,18 +1308,6 @@ int check_partitions(int fd, char *dname, unsigned long long freesize,
        return 0;
 }
 
-void get_one_disk(int mdfd, mdu_array_info_t *ainf, mdu_disk_info_t *disk)
-{
-       int d;
-
-       ioctl(mdfd, GET_ARRAY_INFO, ainf);
-       for (d = 0 ; d < MAX_DISKS ; d++) {
-               if (ioctl(mdfd, GET_DISK_INFO, disk) == 0 &&
-                   (disk->major || disk->minor))
-                       return;
-       }
-}
-
 int open_container(int fd)
 {
        /* 'fd' is a block device.  Find out if it is in use
@@ -1352,6 +1336,20 @@ int open_container(int fd)
                        continue;
                if (de->d_name[0] == '.')
                        continue;
+               /* Need to make sure it is a container and not a volume */
+               sprintf(e, "/%s/md/metadata_version", de->d_name);
+               dfd = open(path, O_RDONLY);
+               if (dfd < 0)
+                       continue;
+               n = read(dfd, buf, sizeof(buf));
+               close(dfd);
+               if (n <= 0 || (unsigned)n >= sizeof(buf))
+                       continue;
+               buf[n] = 0;
+               if (strncmp(buf, "external", 8) != 0 ||
+                   n < 10 ||
+                   buf[9] == '/')
+                       continue;
                sprintf(e, "/%s/dev", de->d_name);
                dfd = open(path, O_RDONLY);
                if (dfd < 0)
@@ -1662,6 +1660,34 @@ int start_mdmon(int devnum)
        } else
                pathbuf[0] = '\0';
 
+       /* First try to run systemctl */
+       switch(fork()) {
+       case 0:
+               /* FIXME yuk. CLOSE_EXEC?? */
+               skipped = 0;
+               for (i = 3; skipped < 20; i++)
+                       if (close(i) < 0)
+                               skipped++;
+                       else
+                               skipped = 0;
+
+               snprintf(pathbuf, sizeof(pathbuf), "mdmon@%s.service",
+                        devnum2devname(devnum));
+               status = execl("/usr/bin/systemctl", "systemctl", "start",
+                              pathbuf, NULL);
+               status = execl("/bin/systemctl", "systemctl", "start",
+                              pathbuf, NULL);
+               exit(1);
+       case -1: pr_err("cannot run mdmon. "
+                        "Array remains readonly\n");
+               return -1;
+       default: /* parent - good */
+               pid = wait(&status);
+               if (pid >= 0 && status == 0)
+                       return 0;
+       }
+
+       /* That failed, try running mdmon directly */
        switch(fork()) {
        case 0:
                /* FIXME yuk. CLOSE_EXEC?? */
@@ -1674,15 +1700,8 @@ int start_mdmon(int devnum)
 
                for (i = 0; paths[i]; i++)
                        if (paths[i][0]) {
-                               if (__offroot) {
-                                       execl(paths[i], "mdmon", "--offroot",
-                                             devnum2devname(devnum),
-                                             NULL);
-                               } else {
-                                       execl(paths[i], "mdmon",
-                                             devnum2devname(devnum),
-                                             NULL);
-                               }
+                               execl(paths[i], "mdmon",
+                                     devnum2devname(devnum), NULL);
                        }
                exit(1);
        case -1: pr_err("cannot run mdmon. "
@@ -1690,8 +1709,11 @@ int start_mdmon(int devnum)
                return -1;
        default: /* parent - good */
                pid = wait(&status);
-               if (pid < 0 || status != 0)
+               if (pid < 0 || status != 0) {
+                       pr_err("failed to launch mdmon. "
+                              "Array remains readonly\n");
                        return -1;
+               }
        }
        return 0;
 }