return 0;
}
+static int is_member_busy(char *metadata_version)
+{
+ /* check if the given member array is active */
+ struct mdstat_ent *mdstat = mdstat_read(1, 0);
+ struct mdstat_ent *ent;
+ int busy = 0;
+
+ for (ent = mdstat; ent; ent = ent->next) {
+ if (ent->metadata_version == NULL)
+ continue;
+ if (strncmp(ent->metadata_version, "external:", 9) != 0)
+ continue;
+ if (!is_subarray(&ent->metadata_version[9]))
+ continue;
+ /* Skip first char - it can be '/' or '-' */
+ if (strcmp(&ent->metadata_version[10], metadata_version+1) == 0) {
+ busy = 1;
+ break;
+ }
+ }
+ free_mdstat(mdstat);
+
+ return busy;
+}
+
int Assemble(struct supertype *st, char *mddev,
mddev_ident_t ident,
mddev_dev_t devlist, char *backup_file,
int chosen_drive;
int change = 0;
int inargv = 0;
+ int report_missmatch;
int bitmap_done;
int start_partial_ok = (runstop >= 0) &&
(force || devlist==NULL || auto_assem);
else if (mddev)
inargv = 1;
+ report_missmatch = ((inargv && verbose >= 0) || verbose > 0);
try_again:
/* We come back here when doing auto-assembly and attempting some
* set of devices failed. Those are now marked as ->used==2 and
if (ident->devices &&
!match_oneof(ident->devices, devname)) {
- if ((inargv && verbose>=0) || verbose > 0)
+ if (report_missmatch)
fprintf(stderr, Name ": %s is not one of %s\n", devname, ident->devices);
continue;
}
dfd = dev_open(devname, O_RDONLY|O_EXCL);
if (dfd < 0) {
- if ((inargv && verbose >= 0) || verbose > 0)
+ if (report_missmatch)
fprintf(stderr, Name ": cannot open device %s: %s\n",
devname, strerror(errno));
tmpdev->used = 2;
devname);
tmpdev->used = 2;
} else if (!tst && (tst = guess_super(dfd)) == NULL) {
- if ((inargv && verbose >= 0) || verbose > 0)
+ if (report_missmatch)
fprintf(stderr, Name ": no recogniseable superblock on %s\n",
devname);
tmpdev->used = 2;
} else if (tst->ss->load_super(tst,dfd, NULL)) {
- if ((inargv && verbose >= 0) || verbose > 0)
+ if (report_missmatch)
fprintf( stderr, Name ": no RAID superblock on %s\n",
devname);
} else {
}
if (dfd >= 0) close(dfd);
+ if (tst && tst->sb && tst->ss->container_content
+ && tst->loaded_container) {
+ /* tmpdev is a container. We need to be either
+ * looking for a member, or auto-assembling
+ */
+ if (st) {
+ /* already found some components, this cannot
+ * be another one.
+ */
+ if (report_missmatch)
+ fprintf(stderr, Name ": %s is a container, but we are looking for components\n",
+ devname);
+ goto loop;
+ }
+
+ if (ident->container) {
+ if (ident->container[0] == '/' &&
+ !same_dev(ident->container, devname)) {
+ if (report_missmatch)
+ fprintf(stderr, Name ": %s is not the container required (%s)\n",
+ devname, ident->container);
+ goto loop;
+ }
+ if (ident->container[0] != '/') {
+ /* we have a uuid */
+ int uuid[4];
+ if (!parse_uuid(ident->container, uuid) ||
+ !same_uuid(content->uuid, uuid, tst->ss->swapuuid)) {
+ if (report_missmatch)
+ fprintf(stderr, Name ": %s has wrong UUID to be required container\n",
+ devname);
+ goto loop;
+ }
+ }
+ }
+ /* It is worth looking inside this container.
+ */
+ next_member:
+ if (tmpdev->content)
+ content = tmpdev->content;
+ else
+ content = tst->ss->container_content(tst);
+
+ tmpdev->content = content->next;
+ if (tmpdev->content == NULL)
+ tmpdev->used = 1;
+
+ } else if (ident->container || ident->member) {
+ /* No chance of this matching if we don't have
+ * a container */
+ if (report_missmatch)
+ fprintf(stderr, Name "%s is not a container, and one is required.\n",
+ devname);
+ goto loop;
+ }
+
if (ident->uuid_set && (!update || strcmp(update, "uuid")!= 0) &&
(!tst || !tst->sb ||
same_uuid(content->uuid, ident->uuid, tst->ss->swapuuid)==0)) {
- if ((inargv && verbose >= 0) || verbose > 0)
+ if (report_missmatch)
fprintf(stderr, Name ": %s has wrong uuid.\n",
devname);
goto loop;
if (ident->name[0] && (!update || strcmp(update, "name")!= 0) &&
(!tst || !tst->sb ||
name_matches(content->name, ident->name, homehost)==0)) {
- if ((inargv && verbose >= 0) || verbose > 0)
+ if (report_missmatch)
fprintf(stderr, Name ": %s has wrong name.\n",
devname);
goto loop;
if (ident->super_minor != UnSet &&
(!tst || !tst->sb ||
ident->super_minor != content->array.md_minor)) {
- if ((inargv && verbose >= 0) || verbose > 0)
+ if (report_missmatch)
fprintf(stderr, Name ": %s has wrong super-minor.\n",
devname);
goto loop;
if (ident->level != UnSet &&
(!tst || !tst->sb ||
ident->level != content->array.level)) {
- if ((inargv && verbose >= 0) || verbose > 0)
+ if (report_missmatch)
fprintf(stderr, Name ": %s has wrong raid level.\n",
devname);
goto loop;
if (ident->raid_disks != UnSet &&
(!tst || !tst->sb ||
ident->raid_disks!= content->array.raid_disks)) {
- if ((inargv && verbose >= 0) || verbose > 0)
+ if (report_missmatch)
fprintf(stderr, Name ": %s requires wrong number of drives.\n",
devname);
goto loop;
return 1;
}
+ if (tst && tst->sb && tst->ss->container_content
+ && tst->loaded_container) {
+ /* we have the one container we need, don't keep
+ * looking. If the chosen member is active, skip.
+ */
+ if (is_member_busy(content->text_version)) {
+ if (auto_assem)
+ goto loop;
+ fprintf(stderr, Name ": member %s in %s is already assembled\n",
+ content->text_version,
+ devname);
+ tst->ss->free_super(tst);
+ return 1;
+ }
+ st = tst; tst = NULL;
+ if (!auto_assem && tmpdev->next != NULL) {
+ fprintf(stderr, Name ": %s is a container, but is not "
+ "only device given: confused and aborting\n",
+ devname);
+ st->ss->free_super(st);
+ return 1;
+ }
+ break;
+ }
if (st == NULL)
st = dup_super(tst);
if (st->minor_version == -1)
(first == 1 || last == 1)) {
/* We can do something */
if (first) {/* just ignore this one */
- if ((inargv && verbose >= 0) || verbose > 0)
+ if (report_missmatch)
fprintf(stderr, Name ": %s misses out due to wrong homehost\n",
devname);
goto loop;
} else { /* reject all those sofar */
mddev_dev_t td;
- if ((inargv && verbose >= 0) || verbose > 0)
+ if (report_missmatch)
fprintf(stderr, Name ": %s overrides previous devices due to good homehost\n",
devname);
for (td=devlist; td != tmpdev; td=td->next)
tmpdev->used = 1;
loop:
+ if (tmpdev->content)
+ goto next_member;
if (tst)
tst->ss->free_super(tst);
}
}
ioctl(mdfd, STOP_ARRAY, NULL); /* just incase it was started but has no content */
+#ifndef MDASSEMBLE
+ if (content != &info) {
+ /* This is a member of a container. Try starting the array. */
+ return assemble_container_content(st, mdfd, content, runstop,
+ chosen_name, verbose);
+ }
+#endif
/* Ok, no bad inconsistancy, we can try updating etc */
bitmap_done = 0;
for (tmpdev = devlist; tmpdev; tmpdev=tmpdev->next) if (tmpdev->used == 1) {
close(mdfd);
return 0;
}
+
+#ifndef MDASSEMBLE
+int assemble_container_content(struct supertype *st, int mdfd,
+ struct mdinfo *content, int runstop,
+ char *chosen_name, int verbose)
+{
+ struct mdinfo *dev, *sra;
+ int working = 0, preexist = 0;
+ struct map_ent *map = NULL;
+
+ sysfs_init(content, mdfd, 0);
+
+ sra = sysfs_read(mdfd, 0, GET_VERSION);
+ if (sra == NULL || strcmp(sra->text_version, content->text_version) != 0)
+ if (sysfs_set_array(content, md_get_version(mdfd)) != 0)
+ return 1;
+ if (sra)
+ sysfs_free(sra);
+
+ for (dev = content->devs; dev; dev = dev->next)
+ if (sysfs_add_disk(content, dev) == 0)
+ working++;
+ else if (errno == EEXIST)
+ preexist++;
+ if (working == 0)
+ /* Nothing new, don't try to start */ ;
+ else if (runstop > 0 ||
+ (working + preexist) >= content->array.working_disks) {
+ switch(content->array.level) {
+ case LEVEL_LINEAR:
+ case LEVEL_MULTIPATH:
+ case 0:
+ sysfs_set_str(content, NULL, "array_state",
+ "active");
+ break;
+ default:
+ sysfs_set_str(content, NULL, "array_state",
+ "readonly");
+ /* start mdmon if needed. */
+ if (!mdmon_running(st->container_dev))
+ start_mdmon(st->container_dev);
+ ping_monitor(devnum2devname(st->container_dev));
+ break;
+ }
+ sysfs_set_safemode(content, content->safe_mode_delay);
+ if (verbose >= 0) {
+ fprintf(stderr, Name
+ ": Started %s with %d devices",
+ chosen_name, working + preexist);
+ if (preexist)
+ fprintf(stderr, " (%d new)", working);
+ fprintf(stderr, "\n");
+ }
+ /* FIXME should have an O_EXCL and wait for read-auto */
+ } else
+ if (verbose >= 0)
+ fprintf(stderr, Name
+ ": %s assembled with %d devices but "
+ "not started\n",
+ chosen_name, working);
+ map_update(&map, fd2devnum(mdfd),
+ content->text_version,
+ content->uuid, chosen_name);
+
+ return 0;
+}
+#endif
+