if (auto_assem || !inargv)
/* Ignore unrecognised devices during auto-assembly */
goto loop;
- if (ident->uuid_set || ident->name[0] ||
+ if (ident->name[0] ||
ident->super_minor != UnSet)
/* Ignore unrecognised device if looking for
* specific array */
st->ss->free_super(st);
dev_policy_free(pol);
domain_free(domains);
+ if (tst)
+ tst->ss->free_super(tst);
return -1;
}
if (st->ss != tst->ss ||
st->minor_version != tst->minor_version ||
- st->ss->compare_super(st, tst) != 0) {
+ st->ss->compare_super(st, tst, 1) != 0) {
/* Some mismatch. If exactly one array matches this host,
* we can resolve on that one.
* Or, if we are auto assembling, we just ignore the second
struct supertype *tst;
int i;
int dfd;
+ int disk_state;
if (tmpdev->used != 1)
continue;
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;
}
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) {
if (best[i] >=0 &&
devices[best[i]].i.events ==
devices[devcnt].i.events &&
- (devices[best[i]].i.disk.minor
- != devices[devcnt].i.disk.minor) &&
+ (devices[best[i]].i.disk.minor !=
+ devices[devcnt].i.disk.minor) &&
st->ss == &super0 &&
content->array.level != LEVEL_MULTIPATH) {
/* two different devices with identical superblock.
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++;
}
/* 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)
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),
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;
}
pr_err("failed to add %s to %s: %s\n",
devices[j].devname, mddev,
strerror(errno));
+ if (errno == EINVAL && content->array.level == 0 &&
+ content->array.layout != 0) {
+ cont_err("Possibly your kernel doesn't support RAID0 layouts.\n");
+ cont_err("Please upgrade.\n");
+ }
if (i < content->array.raid_disks * 2 ||
i == bestcnt)
okcnt--;
mddev, okcnt + sparecnt + journalcnt,
okcnt + sparecnt + journalcnt == 1 ? "" : "s");
if (okcnt < (unsigned)content->array.raid_disks)
- fprintf(stderr, " (out of %d)",
+ fprintf(stderr, " (out of %d)\n",
content->array.raid_disks);
- fprintf(stderr, "\n");
+ else {
+ fprintf(stderr, "\n");
+ sysfs_rules_apply(mddev, content);
+ }
}
if (st->ss->validate_container) {
rv = ioctl(mdfd, RUN_ARRAY, NULL);
reopen_mddev(mdfd); /* drop O_EXCL */
if (rv == 0) {
+ sysfs_rules_apply(mddev, content);
if (c->verbose >= 0) {
pr_err("%s has been started with %d drive%s",
mddev, okcnt, okcnt==1?"":"s");
return 0;
}
pr_err("failed to RUN_ARRAY %s: %s\n", mddev, strerror(errno));
+ if (errno == 524 /* ENOTSUP */ &&
+ content->array.level == 0 && content->array.layout == 0)
+ cont_err("Please use --update=layout-original or --update=layout-alternate\n");
if (!enough(content->array.level, content->array.raid_disks,
content->array.layout, 1, avail))
* 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;
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,
name = content->name;
break;
}
+ if (mddev && map_by_name(&map, mddev) != NULL) {
+ pr_err("Cannot create device with %s because is in use\n", mddev);
+ goto out;
+ }
if (!auto_assem)
/* If the array is listed in mdadm.conf or on
* command line, then we trust the name
st->ss->free_super(st);
if (auto_assem)
goto try_again;
- return 1;
+ goto out;
}
mddev = chosen_name;
if (pre_exist == NULL) {
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);
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)
: (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 */
int j = best[i];
unsigned int desired_state;
+ if (j < 0)
+ continue;
if (devices[j].i.disk.raid_disk == MD_DISK_ROLE_JOURNAL)
desired_state = (1<<MD_DISK_JOURNAL);
else if (i >= content->array.raid_disks * 2)
else
desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC);
- if (j<0)
- continue;
+ desired_state |= devices[j].i.disk.state & ((1<<MD_DISK_FAILFAST) |
+ (1<<MD_DISK_WRITEMOSTLY));
+
if (!devices[j].uptodate)
continue;
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",
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;
}
}
if (rv == 1 && !pre_exist)
ioctl(mdfd, STOP_ARRAY, NULL);
free(devices);
+out:
map_unlock(&map);
if (rv == 0) {
wait_for(chosen_name, mdfd);
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;
}
free(avail);
return err;
}
+ } else if (c->force) {
+ /* Set the array as 'clean' so that we can proceed with starting
+ * it even if we don't have all devices. Mdmon doesn't care
+ * if the dirty flag is set in metadata, it will start managing
+ * it anyway.
+ * This is really important for raid456 (RWH case), other levels
+ * are started anyway.
+ */
+ content->array.state |= 1;
}
if (enough(content->array.level, content->array.raid_disks,
}
free(avail);
- if (c->runstop <= 0 &&
- (working + preexist + expansion) <
- content->array.working_disks) {
- if (c->export && result)
- *result |= INCR_UNSAFE;
- else if (c->verbose >= 0) {
- pr_err("%s assembled with %d device%s",
- chosen_name, preexist + working,
- preexist + working == 1 ? "":"s");
- if (preexist)
- fprintf(stderr, " (%d new)", working);
- fprintf(stderr, " but not safe to start\n");
+ if ((working + preexist + expansion) < content->array.working_disks) {
+ if (c->runstop <= 0) {
+ if (c->export && result)
+ *result |= INCR_UNSAFE;
+ else if (c->verbose >= 0) {
+ pr_err("%s assembled with %d device%s",
+ chosen_name, preexist + working,
+ preexist + working == 1 ? "":"s");
+ if (preexist)
+ fprintf(stderr, " (%d new)", working);
+ fprintf(stderr, " but not safe to start\n");
+ if (c->force)
+ pr_err("Consider --run to start array as degraded.\n");
+ }
+ return 1;
+ } else if (content->array.level >= 4 &&
+ content->array.level <= 6 &&
+ content->resync_start != MaxSector &&
+ c->force) {
+ /* Don't inform the kernel that the array is not
+ * clean and requires resync.
+ */
+ content->resync_start = MaxSector;
+ err = sysfs_set_num(content, NULL, "resync_start",
+ MaxSector);
+ if (err)
+ return 1;
+ pr_err("%s array state forced to clean. It may cause data corruption.\n",
+ chosen_name);
}
- return 1;
}
+ /*
+ * Before activating the array, perform extra steps required
+ * to configure the internal write-intent bitmap.
+ */
+ if (content->consistency_policy == CONSISTENCY_POLICY_BITMAP &&
+ st->ss->set_bitmap)
+ st->ss->set_bitmap(st, content);
if (start_reshape) {
int spare = content->array.raid_disks + expansion;
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;
pr_err("array %s now has %d device%s",
chosen_name, working + preexist,
working + preexist == 1 ? "":"s");
- else
+ else {
+ sysfs_rules_apply(chosen_name, content);
pr_err("Started %s with %d device%s",
chosen_name, working + preexist,
working + preexist == 1 ? "":"s");
+ }
if (preexist)
fprintf(stderr, " (%d new)", working);
if (expansion)