]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Incremental.c
mdadm.h: Introduced unaligned {get,put}_unaligned{16,32}()
[thirdparty/mdadm.git] / Incremental.c
index b73eabd7f85babc7d71259ba774d3ef8a0a13f52..d4d3c353560d8fb4946c8fad1b0840a0de82e0dd 100644 (file)
@@ -684,6 +684,7 @@ static int count_active(struct supertype *st, struct mdinfo *sra,
        int cnt = 0;
        int replcnt = 0;
        __u64 max_events = 0;
+       __u64 max_journal_events = 0;
        char *avail = NULL;
        int *best = NULL;
        char *devmap = NULL;
@@ -714,8 +715,9 @@ static int count_active(struct supertype *st, struct mdinfo *sra,
 
                info.array.raid_disks = raid_disks;
                st->ss->getinfo_super(st, &info, devmap + raid_disks * devnum);
-               if (info.disk.raid_disk == MD_DISK_ROLE_JOURNAL)
-                       bestinfo->journal_clean = 1;
+               if (info.disk.raid_disk == MD_DISK_ROLE_JOURNAL &&
+                   info.events > max_journal_events)
+                       max_journal_events = info.events;
                if (!avail) {
                        raid_disks = info.array.raid_disks;
                        avail = xcalloc(raid_disks, 1);
@@ -765,6 +767,8 @@ static int count_active(struct supertype *st, struct mdinfo *sra,
                        replcnt++;
                st->ss->free_super(st);
        }
+       if (max_journal_events >= max_events - 1)
+               bestinfo->journal_clean = 1;
 
        if (!avail)
                return 0;
@@ -866,8 +870,8 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
                struct supertype *st2;
                struct domainlist *dl = NULL;
                struct mdinfo *sra;
-               unsigned long long devsize;
-               unsigned long long component_size = 0;
+               unsigned long long devsize, freesize = 0;
+               struct spare_criteria sc = {0, 0};
 
                if (is_subarray(mp->metadata))
                        continue;
@@ -886,16 +890,10 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
                }
                sra = sysfs_read(-1, mp->devnm,
                                 GET_DEVS|GET_OFFSET|GET_SIZE|GET_STATE|
-                                GET_DEGRADED|GET_COMPONENT|GET_VERSION);
-               if (!sra) {
-                       /* Probably a container - no degraded info */
-                       sra = sysfs_read(-1, mp->devnm,
-                                        GET_DEVS|GET_OFFSET|GET_SIZE|GET_STATE|
-                                        GET_COMPONENT|GET_VERSION);
-                       if (sra)
-                               sra->array.failed_disks = -1;
-               }
-               if (!sra)
+                                GET_COMPONENT|GET_VERSION);
+               if (sra)
+                       sra->array.failed_disks = -1;
+               else
                        continue;
                if (st == NULL) {
                        int i;
@@ -936,18 +934,22 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
                        }
                        if (st3->ss->load_container &&
                            !st3->ss->load_container(st3, mdfd, mp->path)) {
-                               component_size = st3->ss->min_acceptable_spare_size(st3);
+                               if (st3->ss->get_spare_criteria)
+                                       st3->ss->get_spare_criteria(st3, &sc);
                                st3->ss->free_super(st3);
                        }
                        free(st3);
                        close(mdfd);
                }
                if ((sra->component_size > 0 &&
-                    st2->ss->avail_size(st2, devsize,
-                                        sra->devs ? sra->devs->data_offset :
-                                        INVALID_SECTORS) <
-                    sra->component_size) ||
-                   (sra->component_size == 0 && devsize < component_size)) {
+                    st2->ss->validate_geometry(st2, sra->array.level, sra->array.layout,
+                                               sra->array.raid_disks, &sra->array.chunk_size,
+                                               sra->component_size,
+                                               sra->devs ? sra->devs->data_offset : INVALID_SECTORS,
+                                               devname, &freesize, sra->consistency_policy,
+                                               0) &&
+                    freesize < sra->component_size) ||
+                   (sra->component_size == 0 && devsize < sc.min_size)) {
                        if (verbose > 1)
                                pr_err("not adding %s to %s as it is too small\n",
                                        devname, mp->path);
@@ -1078,6 +1080,7 @@ static int partition_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
                struct supertype *st2 = NULL;
                char *devname = NULL;
                unsigned long long devsectors;
+               char *pathlist[2];
 
                if (de->d_ino == 0 || de->d_name[0] == '.' ||
                    (de->d_type != DT_LNK && de->d_type != DT_UNKNOWN))
@@ -1092,7 +1095,9 @@ static int partition_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
                        /* This is a partition - skip it */
                        goto next;
 
-               pol2 = path_policy(de->d_name, type_disk);
+               pathlist[0] = de->d_name;
+               pathlist[1] = NULL;
+               pol2 = path_policy(pathlist, type_disk);
 
                domain_merge(&domlist, pol2, st ? st->ss->name : NULL);
                if (domain_test(domlist, pol, st ? st->ss->name : NULL) != 1)
@@ -1266,7 +1271,7 @@ static int try_spare(char *devname, int *dfdp, struct dev_policy *pol,
         * what arrays might be candidates.
         */
        if (st) {
-               /* just try try 'array' or 'partition' based on this metadata */
+               /* just try to add 'array' or 'partition' based on this metadata */
                if (st->ss->add_to_super)
                        return array_try_spare(devname, dfdp, pol, target, bare,
                                               st, verbose);
@@ -1317,7 +1322,6 @@ int IncrementalScan(struct context *c, char *devnm)
 
 restart:
        for (me = mapl ; me ; me = me->next) {
-               mdu_array_info_t array;
                struct mdinfo *sra;
                int mdfd;
 
@@ -1362,7 +1366,7 @@ restart:
                                rv = 1;
                        continue;
                }
-               if (md_get_array_info(mdfd, &array) == 0 || errno != ENODEV) {
+               if (md_array_active(mdfd)) {
                        close(mdfd);
                        continue;
                }
@@ -1412,6 +1416,7 @@ restart:
                        sysfs_free(sra);
                }
        }
+       map_free(mapl);
        return rv;
 }
 
@@ -1586,6 +1591,8 @@ static int Incremental_container(struct supertype *st, char *devname,
 
                assemble_container_content(st, mdfd, ra, c,
                                           chosen_name, &result);
+               map_free(map);
+               map = NULL;
                close(mdfd);
        }
        if (c->export && result) {
@@ -1625,12 +1632,15 @@ static int Incremental_container(struct supertype *st, char *devname,
                struct supertype *sst =
                        super_imsm.match_metadata_desc("imsm");
                struct mdinfo *sinfo;
-               unsigned long long min_size = 0;
-               if (st->ss->min_acceptable_spare_size)
-                       min_size = st->ss->min_acceptable_spare_size(st);
+
                if (!sst->ss->load_container(sst, sfd, NULL)) {
+                       struct spare_criteria sc = {0, 0};
+
+                       if (st->ss->get_spare_criteria)
+                               st->ss->get_spare_criteria(st, &sc);
+
                        close(sfd);
-                       sinfo = container_choose_spares(sst, min_size,
+                       sinfo = container_choose_spares(sst, &sc,
                                                        domains, NULL,
                                                        st->ss->name, 0);
                        sst->ss->free_super(sst);
@@ -1659,6 +1669,7 @@ static int Incremental_container(struct supertype *st, char *devname,
                        close(sfd);
        }
        domain_free(domains);
+       map_free(map);
        return 0;
 }
 
@@ -1675,6 +1686,44 @@ static void run_udisks(char *arg1, char *arg2)
                ;
 }
 
+static int force_remove(char *devnm, int fd, struct mdinfo *mdi, int verbose)
+{
+       int rv;
+       int devid = devnm2devid(devnm);
+
+       run_udisks("--unmount", map_dev(major(devid), minor(devid), 0));
+       rv = Manage_stop(devnm, fd, verbose, 1);
+       if (rv) {
+               /* At least we can try to trigger a 'remove' */
+               sysfs_uevent(mdi, "remove");
+               if (verbose)
+                       pr_err("Fail to stop %s too.\n", devnm);
+       }
+       return rv;
+}
+
+static void remove_from_member_array(struct mdstat_ent *memb,
+                                   struct mddev_dev *devlist, int verbose)
+{
+       int rv;
+       struct mdinfo mmdi;
+       int subfd = open_dev(memb->devnm);
+
+       if (subfd >= 0) {
+               rv = Manage_subdevs(memb->devnm, subfd, devlist, verbose,
+                                   0, NULL, 0);
+               if (rv & 2) {
+                       if (sysfs_init(&mmdi, -1, memb->devnm))
+                               pr_err("unable to initialize sysfs for: %s\n",
+                                      memb->devnm);
+                       else
+                               force_remove(memb->devnm, subfd, &mmdi,
+                                            verbose);
+               }
+               close(subfd);
+       }
+}
+
 /*
  * IncrementalRemove - Attempt to see if the passed in device belongs to any
  * raid arrays, and if so first fail (if needed) and then remove the device.
@@ -1746,40 +1795,28 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
            strncmp(ent->metadata_version, "external:", 9) == 0) {
                struct mdstat_ent *mdstat = mdstat_read(0, 0);
                struct mdstat_ent *memb;
-               for (memb = mdstat ; memb ; memb = memb->next)
-                       if (is_container_member(memb, ent->devnm)) {
-                               int subfd = open_dev(memb->devnm);
-                               if (subfd >= 0) {
-                                       rv |= Manage_subdevs(
-                                               memb->devnm, subfd,
-                                               &devlist, verbose, 0,
-                                               NULL, 0);
-                                       close(subfd);
-                               }
-                       }
+               for (memb = mdstat ; memb ; memb = memb->next) {
+                       if (is_container_member(memb, ent->devnm))
+                               remove_from_member_array(memb,
+                                       &devlist, verbose);
+               }
                free_mdstat(mdstat);
-       } else
+       } else {
                rv |= Manage_subdevs(ent->devnm, mdfd, &devlist,
                                    verbose, 0, NULL, 0);
-       if (rv & 2) {
+               if (rv & 2) {
                /* Failed due to EBUSY, try to stop the array.
                 * Give udisks a chance to unmount it first.
                 */
-               int devid = devnm2devid(ent->devnm);
-               run_udisks("--unmount", map_dev(major(devid),minor(devid), 0));
-               rv = Manage_stop(ent->devnm, mdfd, verbose, 1);
-               if (rv)
-                       /* At least we can try to trigger a 'remove' */
-                       sysfs_uevent(&mdi, "remove");
-               if (verbose) {
-                       if (rv)
-                               pr_err("Fail to stop %s too.\n", ent->devnm);
+                       rv = force_remove(ent->devnm, mdfd, &mdi, verbose);
+                       goto end;
                }
-       } else {
-               devlist.disposition = 'r';
-               rv = Manage_subdevs(ent->devnm, mdfd, &devlist,
-                                   verbose, 0, NULL, 0);
        }
+
+       devlist.disposition = 'r';
+       rv = Manage_subdevs(ent->devnm, mdfd, &devlist,
+                           verbose, 0, NULL, 0);
+end:
        close(mdfd);
        free_mdstat(ent);
        return rv;