]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - util.c
free_super after assembling a container
[thirdparty/mdadm.git] / util.c
diff --git a/util.c b/util.c
index 1ecce3b8fd73d598051955bd8c6343b65bf29a9b..38750b248892e5eef8dcc1e38e42521ba5a64553 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)
 {
@@ -270,6 +295,19 @@ int test_partition(int fd)
        return 1;
 }
 
+int test_partition_from_id(dev_t id)
+{
+       char buf[20];
+       int fd, rv;
+
+       sprintf(buf, "%d:%d", major(id), minor(id));
+       fd = dev_open(buf, O_RDONLY);
+       if (fd < 0)
+               return -1;
+       rv = test_partition(fd);
+       close(fd);
+       return rv;
+}
 
 int enough(int level, int raid_disks, int layout, int clean,
           char *avail, int avail_disks)
@@ -350,13 +388,10 @@ int enough_fd(int fd)
 }
 
 
-const int uuid_match_any[4] = { ~0, ~0, ~0, ~0 };
+const int uuid_zero[4] = { 0, 0, 0, 0 };
+
 int same_uuid(int a[4], int b[4], int swapuuid)
 {
-       if (memcmp(a, uuid_match_any, sizeof(int[4])) == 0 ||
-           memcmp(b, uuid_match_any, sizeof(int[4])) == 0)
-               return 1;
-
        if (swapuuid) {
                /* parse uuids are hostendian.
                 * uuid's from some superblocks are big-ending
@@ -1043,6 +1078,7 @@ struct supertype *super_by_fd(int fd, char **subarrayp)
        char version[20];
        int i;
        char *subarray = NULL;
+       int container = NoMdDev;
 
        sra = sysfs_read(fd, 0, GET_VERSION);
 
@@ -1064,15 +1100,15 @@ struct supertype *super_by_fd(int fd, char **subarrayp)
        }
        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
@@ -1088,13 +1124,16 @@ struct supertype *super_by_fd(int fd, char **subarrayp)
                st->sb = NULL;
                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(unsigned int id, unsigned long long *size)
+int dev_size_from_id(dev_t id, unsigned long long *size)
 {
        char buf[20];
        int fd;
@@ -1449,14 +1488,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);
 
@@ -1600,6 +1636,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.
@@ -1640,13 +1691,18 @@ unsigned long long min_recovery_start(struct mdinfo *array)
        return recovery_start;
 }
 
-char *devnum2devname(int num)
+void fmt_devname(char *name, int num)
 {
-       char name[100];
        if (num >= 0)
                sprintf(name, "md%d", num);
        else
                sprintf(name, "md_d%d", -1-num);
+}
+
+char *devnum2devname(int num)
+{
+       char name[100];
+       fmt_devname(name,num);
        return strdup(name);
 }
 
@@ -1686,7 +1742,7 @@ int stat2devnum(struct stat *st)
                link[n] = 0;
                cp = strrchr(link, '/');
                if (cp) *cp = 0;
-               cp = strchr(link, '/');
+               cp = strrchr(link, '/');
                if (cp && strncmp(cp, "/md", 3) == 0)
                        return devname2devnum(cp+1);
        }
@@ -1844,6 +1900,7 @@ void append_metadata_update(struct supertype *st, void *buf, int len)
        mu->buf = buf;
        mu->len = len;
        mu->space = NULL;
+       mu->space_list = NULL;
        mu->next = NULL;
        *st->update_tail = mu;
        st->update_tail = &mu->next;
@@ -1855,3 +1912,73 @@ void append_metadata_update(struct supertype *st, void *buf, int len)
 unsigned int __invalid_size_argument_for_IOC = 0;
 #endif
 
+int experimental(void)
+{
+       if (check_env("MDADM_EXPERIMENTAL"))
+               return 1;
+       else {
+               fprintf(stderr, Name ": To use this feature MDADM_EXPERIMENTAL enviroment variable has to defined.\n");
+               return 0;
+       }
+}
+
+/* Pick all spares matching given criteria from a container
+ * if min_size == 0 do not check size
+ * if domlist == NULL do not check domains
+ * if spare_group given add it to domains of each spare
+ * metadata allows to test domains using metadata of destination array */
+struct mdinfo *container_choose_spares(struct supertype *st,
+                                      unsigned long long min_size,
+                                      struct domainlist *domlist,
+                                      char *spare_group,
+                                      const char *metadata, int get_one)
+{
+       struct mdinfo *d, **dp, *disks = NULL;
+
+       /* get list of all disks in container */
+       if (st->ss->getinfo_super_disks)
+               disks = st->ss->getinfo_super_disks(st);
+
+       if (!disks)
+               return disks;
+       /* find spare devices on the list */
+       dp = &disks->devs;
+       disks->array.spare_disks = 0;
+       while (*dp) {
+               int found = 0;
+               d = *dp;
+               if (d->disk.state == 0) {
+                       /* check if size is acceptable */
+                       unsigned long long dev_size;
+                       dev_t dev = makedev(d->disk.major,d->disk.minor);
+
+                       if (!min_size ||
+                          (dev_size_from_id(dev,  &dev_size) &&
+                           dev_size >= min_size))
+                               found = 1;
+                       /* check if domain matches */
+                       if (found && domlist) {
+                               struct dev_policy *pol = devnum_policy(dev);
+                               if (spare_group)
+                                       pol_add(&pol, pol_domain,
+                                               spare_group, NULL);
+                               if (!domain_test(domlist, pol, metadata))
+                                       found = 0;
+                               dev_policy_free(pol);
+                       }
+               }
+               if (found) {
+                       dp = &d->next;
+                       disks->array.spare_disks++;
+                       if (get_one) {
+                               sysfs_free(*dp);
+                               d->next = NULL;
+                       }
+               } else {
+                       *dp = d->next;
+                       d->next = NULL;
+                       sysfs_free(d);
+               }
+       }
+       return disks;
+}