]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Assemble.c
mdadm.h: Introduced unaligned {get,put}_unaligned{16,32}()
[thirdparty/mdadm.git] / Assemble.c
index 9e19246caccadf3ccb97b0189e04ac181cd019e0..420c7b3943eabc4cca8611867f77dc67c5b5b953 100644 (file)
@@ -281,6 +281,8 @@ static int select_devices(struct mddev_dev *devlist,
                                st->ss->free_super(st);
                        dev_policy_free(pol);
                        domain_free(domains);
+                       if (tst)
+                               tst->ss->free_super(tst);
                        return -1;
                }
 
@@ -576,6 +578,7 @@ static int load_devices(struct devs *devices, char *devmap,
                struct supertype *tst;
                int i;
                int dfd;
+               int disk_state;
 
                if (tmpdev->used != 1)
                        continue;
@@ -592,6 +595,9 @@ static int load_devices(struct devs *devices, char *devmap,
                        if (strcmp(c->update, "ppl") == 0 &&
                            ident->bitmap_fd >= 0) {
                                pr_err("PPL is not compatible with bitmap\n");
+                               close(mdfd);
+                               free(devices);
+                               free(devmap);
                                return -1;
                        }
 
@@ -706,7 +712,9 @@ static int load_devices(struct devs *devices, char *devmap,
                devices[devcnt].i.disk.major = major(stb.st_rdev);
                devices[devcnt].i.disk.minor = minor(stb.st_rdev);
 
-               if (devices[devcnt].i.disk.state == 6) {
+               disk_state = devices[devcnt].i.disk.state & ~((1<<MD_DISK_FAILFAST) |
+                                                             (1<<MD_DISK_WRITEMOSTLY));
+               if (disk_state == ((1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC))) {
                        if (most_recent < 0 ||
                            devices[devcnt].i.events
                            > devices[most_recent].i.events) {
@@ -779,6 +787,8 @@ static int load_devices(struct devs *devices, char *devmap,
                        if (best[i] == -1 || (devices[best[i]].i.events
                                              < devices[devcnt].i.events))
                                best[i] = devcnt;
+                       else if (st->ss == &super_imsm)
+                               best[i+1] = devcnt;
                }
                devcnt++;
        }
@@ -846,7 +856,19 @@ static int force_array(struct mdinfo *content,
                                        /* OK */;
                                else
                                        continue;
-                       }
+                       } else if (devices[j].i.reshape_active !=
+                           content->reshape_active ||
+                           (devices[j].i.reshape_active &&
+                           devices[j].i.reshape_progress !=
+                           content->reshape_progress))
+                               /* Here, it may be a source of data. If two
+                                * devices claim different progresses, it
+                                * means that reshape boundaries differ for
+                                * their own devices. Kernel will only treat
+                                * the first one as reshape progress and
+                                * go on. It may cause disaster, so avoid it.
+                                */
+                               continue;
                        if (chosen_drive < 0 ||
                             devices[j].i.events
                            > devices[chosen_drive].i.events)
@@ -857,7 +879,7 @@ static int force_array(struct mdinfo *content,
                current_events = devices[chosen_drive].i.events;
        add_another:
                if (c->verbose >= 0)
-                       pr_err("forcing event count in %s(%d) from %d upto %d\n",
+                       pr_err("forcing event count in %s(%d) from %d up to %d\n",
                               devices[chosen_drive].devname,
                               devices[chosen_drive].i.disk.raid_disk,
                               (int)(devices[chosen_drive].i.events),
@@ -908,7 +930,13 @@ static int force_array(struct mdinfo *content,
                        if (j >= 0 &&
                            !devices[j].uptodate &&
                            devices[j].i.recovery_start == MaxSector &&
-                           devices[j].i.events == current_events) {
+                           devices[j].i.events == current_events &&
+                           ((!devices[j].i.reshape_active &&
+                           !content->reshape_active) ||
+                           (devices[j].i.reshape_active ==
+                           content->reshape_active &&
+                           devices[j].i.reshape_progress ==
+                           content->reshape_progress))) {
                                chosen_drive = j;
                                goto add_another;
                        }
@@ -1295,13 +1323,13 @@ int Assemble(struct supertype *st, char *mddev,
         *    START_ARRAY
         *
         */
-       int rv;
-       int mdfd;
+       int rv = -1;
+       int mdfd = -1;
        int clean;
        int auto_assem = (mddev == NULL && !ident->uuid_set &&
                          ident->super_minor == UnSet && ident->name[0] == 0 &&
                          (ident->container == NULL || ident->member == NULL));
-       struct devs *devices;
+       struct devs *devices = NULL;
        char *devmap;
        int *best = NULL; /* indexed by raid_disk */
        int bestcnt = 0;
@@ -1399,7 +1427,7 @@ try_again:
                        pr_err("Found some drive for an array that is already active: %s\n",
                               mp->path);
                        pr_err("giving up.\n");
-                       return 1;
+                       goto out;
                }
                for (dv = pre_exist->devs; dv; dv = dv->next) {
                        /* We want to add this device to our list,
@@ -1472,7 +1500,7 @@ try_again:
                st->ss->free_super(st);
                if (auto_assem)
                        goto try_again;
-               return 1;
+               goto out;
        }
        mddev = chosen_name;
        if (pre_exist == NULL) {
@@ -1491,7 +1519,7 @@ try_again:
                        st->ss->free_super(st);
                        if (auto_assem)
                                goto try_again;
-                       return 1;
+                       goto out;
                }
                /* just incase it was started but has no content */
                ioctl(mdfd, STOP_ARRAY, NULL);
@@ -1512,18 +1540,23 @@ try_again:
        devcnt = load_devices(devices, devmap, ident, &st, devlist,
                              c, content, mdfd, mddev,
                              &most_recent, &bestcnt, &best, inargv);
-       if (devcnt < 0)
-               return 1;
+       if (devcnt < 0) {
+               mdfd = -3;
+               /*
+                * devices is already freed in load_devices, so set devices
+                * to NULL to avoid double free devices.
+                */
+               devices = NULL;
+               goto out;
+       }
 
        if (devcnt == 0) {
                pr_err("no devices found for %s\n",
                       mddev);
                if (st)
                        st->ss->free_super(st);
-               close(mdfd);
-               free(devices);
                free(devmap);
-               return 1;
+               goto out;
        }
 
        if (c->update && strcmp(c->update, "byteorder")==0)
@@ -1637,32 +1670,24 @@ try_again:
                                 : (O_RDONLY|O_EXCL)))< 0) {
                        pr_err("Cannot open %s: %s\n",
                               devices[j].devname, strerror(errno));
-                       close(mdfd);
-                       free(devices);
-                       return 1;
+                       goto out;
                }
                if (st->ss->load_super(st,fd, NULL)) {
                        close(fd);
                        pr_err("RAID superblock has disappeared from %s\n",
                               devices[j].devname);
-                       close(mdfd);
-                       free(devices);
-                       return 1;
+                       goto out;
                }
                close(fd);
        }
        if (st->sb == NULL) {
                pr_err("No suitable drives found for %s\n", mddev);
-               close(mdfd);
-               free(devices);
-               return 1;
+               goto out;
        }
        st->ss->getinfo_super(st, content, NULL);
        if (sysfs_init(content, mdfd, NULL)) {
                pr_err("Unable to initialize sysfs\n");
-               close(mdfd);
-               free(devices);
-               return 1;
+               goto out;
        }
 
        /* after reload context, store journal_clean in context */
@@ -1682,6 +1707,9 @@ try_again:
                else
                        desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC);
 
+               desired_state |= devices[j].i.disk.state & ((1<<MD_DISK_FAILFAST) |
+                                                           (1<<MD_DISK_WRITEMOSTLY));
+
                if (!devices[j].uptodate)
                        continue;
 
@@ -1728,17 +1756,13 @@ try_again:
                if (fd < 0) {
                        pr_err("Could not open %s for write - cannot Assemble array.\n",
                               devices[chosen_drive].devname);
-                       close(mdfd);
-                       free(devices);
-                       return 1;
+                       goto out;
                }
                if (st->ss->store_super(st, fd)) {
                        close(fd);
                        pr_err("Could not re-write superblock on %s\n",
                               devices[chosen_drive].devname);
-                       close(mdfd);
-                       free(devices);
-                       return 1;
+                       goto out;
                }
                if (c->verbose >= 0)
                        pr_err("Marking array %s as 'clean'\n",
@@ -1796,9 +1820,7 @@ try_again:
                        pr_err("Failed to restore critical section for reshape, sorry.\n");
                        if (c->backup_file == NULL)
                                cont_err("Possibly you needed to specify the --backup-file\n");
-                       close(mdfd);
-                       free(devices);
-                       return err;
+                       goto out;
                }
        }
 
@@ -1826,6 +1848,7 @@ try_again:
        if (rv == 1 && !pre_exist)
                ioctl(mdfd, STOP_ARRAY, NULL);
        free(devices);
+out:
        map_unlock(&map);
        if (rv == 0) {
                wait_for(chosen_name, mdfd);
@@ -1856,10 +1879,14 @@ try_again:
                                usecs <<= 1;
                        }
                }
-       } else
+       } else if (mdfd >= 0)
                close(mdfd);
 
        /* '2' means 'OK, but not started yet' */
+       if (rv == -1) {
+               free(devices);
+               return 1;
+       }
        return rv == 2 ? 0 : rv;
 }
 
@@ -2034,8 +2061,22 @@ int assemble_container_content(struct supertype *st, int mdfd,
                                   spare, &c->backup_file, c->verbose) == 1)
                        return 1;
 
-               err = sysfs_set_str(content, NULL,
-                                   "array_state", "readonly");
+               if (content->reshape_progress == 0) {
+                       /* If reshape progress is 0 - we are assembling the
+                        * array that was stopped, before reshape has started.
+                        * Array needs to be started as active, Grow_continue()
+                        * will start the reshape.
+                        */
+                       sysfs_set_num(content, NULL, "reshape_position",
+                                     MaxSector);
+                       err = sysfs_set_str(content, NULL,
+                                           "array_state", "active");
+                       sysfs_set_num(content, NULL, "reshape_position", 0);
+               } else {
+                       err = sysfs_set_str(content, NULL,
+                                           "array_state", "readonly");
+               }
+
                if (err)
                        return 1;