]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - util.c
Disk removal support for Raid10->Raid0 takeover
[thirdparty/mdadm.git] / util.c
diff --git a/util.c b/util.c
index b965c8d7883ddae9d8f7ec66a978fcf7374f59ed..fde58ebbeffa6271c93e01abae14c5880221e0f6 100644 (file)
--- a/util.c
+++ b/util.c
@@ -160,6 +160,31 @@ int get_linux_version()
        return (a*1000000)+(b*1000)+c;
 }
 
+int mdadm_version(char *version)
+{
+       int a, b, c;
+       char *cp;
+
+       if (!version)
+               version = Version;
+
+       cp = strchr(version, '-');
+       if (!cp || *(cp+1) != ' ' || *(cp+2) != 'v')
+               return -1;
+       cp += 3;
+       a = strtoul(cp, &cp, 10);
+       if (*cp != '.')
+               return -1;
+       b = strtoul(cp+1, &cp, 10);
+       if (*cp == '.')
+               c = strtoul(cp+1, &cp, 10);
+       else
+               c = 0;
+       if (*cp != ' ' && *cp != '-')
+               return -1;
+       return (a*1000000)+(b*1000)+c;
+}
+
 #ifndef MDASSEMBLE
 long long parse_size(char *size)
 {
@@ -1032,7 +1057,7 @@ struct superswitch *superlist[] =
 
 #if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO)
 
-struct supertype *super_by_fd(int fd)
+struct supertype *super_by_fd(int fd, char **subarrayp)
 {
        mdu_array_info_t array;
        int vers;
@@ -1043,6 +1068,7 @@ struct supertype *super_by_fd(int fd)
        char version[20];
        int i;
        char *subarray = NULL;
+       int container = NoMdDev;
 
        sra = sysfs_read(fd, 0, GET_VERSION);
 
@@ -1064,15 +1090,15 @@ struct supertype *super_by_fd(int fd)
        }
        if (minor == -2 && is_subarray(verstr)) {
                char *dev = verstr+1;
+
                subarray = strchr(dev, '/');
-               int devnum;
                if (subarray)
                        *subarray++ = '\0';
-               devnum = devname2devnum(dev);
                subarray = strdup(subarray);
+               container = devname2devnum(dev);
                if (sra)
                        sysfs_free(sra);
-               sra = sysfs_read(-1, devnum, GET_VERSION);
+               sra = sysfs_read(-1, container, GET_VERSION);
                if (sra && sra->text_version[0])
                        verstr = sra->text_version;
                else
@@ -1086,17 +1112,33 @@ struct supertype *super_by_fd(int fd)
                sysfs_free(sra);
        if (st) {
                st->sb = NULL;
-               if (subarray) {
-                       strncpy(st->subarray, subarray, 32);
-                       st->subarray[31] = 0;
-                       free(subarray);
-               } else
-                       st->subarray[0] = 0;
-       }
+               if (subarrayp)
+                       *subarrayp = subarray;
+               st->container_dev = container;
+               st->devnum = fd2devnum(fd);
+       } else
+               free(subarray);
+
        return st;
 }
 #endif /* !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO) */
 
+int dev_size_from_id(dev_t id, unsigned long long *size)
+{
+       char buf[20];
+       int fd;
+
+       sprintf(buf, "%d:%d", major(id), minor(id));
+       fd = dev_open(buf, O_RDONLY);
+       if (fd < 0)
+               return 0;
+       if (get_dev_size(fd, NULL, size)) {
+               close(fd);
+               return 1;
+       }
+       close(fd);
+       return 0;
+}
 
 struct supertype *dup_super(struct supertype *orig)
 {
@@ -1111,7 +1153,6 @@ struct supertype *dup_super(struct supertype *orig)
        st->ss = orig->ss;
        st->max_devs = orig->max_devs;
        st->minor_version = orig->minor_version;
-       strcpy(st->subarray, orig->subarray);
        st->sb = NULL;
        st->info = NULL;
        return st;
@@ -1129,6 +1170,9 @@ struct supertype *guess_super_type(int fd, enum guess_types guess_type)
        int i;
 
        st = malloc(sizeof(*st));
+       memset(st, 0, sizeof(*st));
+       st->container_dev = NoMdDev;
+
        for (i=0 ; superlist[i]; i++) {
                int rv;
                ss = superlist[i];
@@ -1190,6 +1234,20 @@ int get_dev_size(int fd, char *dname, unsigned long long *sizep)
        return 1;
 }
 
+/* Return true if this can only be a container, not a member device.
+ * i.e. is and md device and size is zero
+ */
+int must_be_container(int fd)
+{
+       unsigned long long size;
+       if (md_get_version(fd) < 0)
+               return 0;
+       if (get_dev_size(fd, NULL, &size) == 0)
+               return 1;
+       if (size == 0)
+               return 1;
+       return 0;
+}
 
 /* Sets endofpart parameter to the last block used by the last GPT partition on the device.
  * Returns: 1 if successful
@@ -1420,14 +1478,11 @@ int is_subarray_active(char *subarray, char *container)
        struct mdstat_ent *mdstat = mdstat_read(0, 0);
        struct mdstat_ent *ent;
 
-       for (ent = mdstat; ent; ent = ent->next) {
-               if (is_container_member(ent, container)) {
-                       char *inst = &ent->metadata_version[10+strlen(container)+1];
-
-                       if (!subarray || strcmp(inst, subarray) == 0)
+       for (ent = mdstat; ent; ent = ent->next)
+               if (is_container_member(ent, container))
+                       if (!subarray ||
+                           strcmp(to_subarray(ent, container), subarray) == 0)
                                break;
-               }
-       }
 
        free_mdstat(mdstat);
 
@@ -1449,6 +1504,7 @@ int is_container_active(char *container)
 int open_subarray(char *dev, char *subarray, struct supertype *st, int quiet)
 {
        struct mdinfo *mdi;
+       struct mdinfo *info;
        int fd, err = 1;
 
        fd = open(dev, O_RDWR|O_EXCL);
@@ -1498,20 +1554,27 @@ int open_subarray(char *dev, char *subarray, struct supertype *st, int quiet)
                goto free_sysfs;
        }
 
-       strncpy(st->subarray, subarray, sizeof(st->subarray)-1);
+       if (!st->ss->load_container) {
+               if (!quiet)
+                       fprintf(stderr, Name ": %s is not a container\n", dev);
+               goto free_name;
+       }
 
-       if (st->ss->load_super(st, fd, NULL)) {
+       if (st->ss->load_container(st, fd, NULL)) {
                if (!quiet)
-                       fprintf(stderr, Name ": Failed to find subarray-%s in %s\n",
-                               st->subarray, dev);
+                       fprintf(stderr, Name ": Failed to load metadata for %s\n",
+                               dev);
                goto free_name;
        }
 
-       if (!st->loaded_container) {
+       info = st->ss->container_content(st, subarray);
+       if (!info) {
                if (!quiet)
-                       fprintf(stderr, Name ": %s is not a container\n", dev);
+                       fprintf(stderr, Name ": Failed to find subarray-%s in %s\n",
+                               subarray, dev);
                goto free_super;
        }
+       free(info);
 
        err = 0;
 
@@ -1563,6 +1626,21 @@ int add_disk(int mdfd, struct supertype *st,
        return rv;
 }
 
+int remove_disk(int mdfd, struct supertype *st,
+               struct mdinfo *sra, struct mdinfo *info)
+{
+       int rv;
+       /* Remove the disk given by 'info' from the array */
+#ifndef MDASSEMBLE
+       if (st->ss->external)
+               rv = sysfs_set_str(sra, info, "slot", "none");
+       else
+#endif
+               rv = ioctl(mdfd, HOT_REMOVE_DISK, makedev(info->disk.major,
+                                                         info->disk.minor));
+       return rv;
+}
+
 int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info)
 {
        /* Initialise kernel's knowledge of array.