int vers;
int rv;
int bitmap_fd;
+ int have_container = 0;
unsigned long long bitmapsize;
+ struct mdinfo *sra;
struct mdinfo info;
int major_num = BITMAP_MAJOR_HI;
return 1;
}
}
+ if (level == UnSet) {
+ /* "ddf" metadata only supports one level - should possibly
+ * push this into metadata handler??
+ */
+ if (st && st->ss == &super_ddf)
+ level = LEVEL_CONTAINER;
+ }
+
if (level == UnSet) {
fprintf(stderr,
Name ": a RAID level is needed to create an array.\n");
Name ": This level does not support spare devices\n");
return 1;
}
+
+ if (subdevs == 1 && strcmp(devlist->devname, "missing") != 0) {
+ /* If given a single device, it might be a container, and we can
+ * extract a device list from there
+ */
+ mdu_array_info_t inf;
+ int fd;
+
+ memset(&inf, 0, sizeof(inf));
+ fd = open(devlist->devname, O_RDONLY, 0);
+ if (fd >= 0 &&
+ ioctl(fd, GET_ARRAY_INFO, &inf) == 0 &&
+ inf.raid_disks == 0) {
+ /* yep, looks like a container */
+ if (st) {
+ rv = st->ss->load_super(st, fd,
+ devlist->devname);
+ if (rv == 0)
+ have_container = 1;
+ } else {
+ st = guess_super(fd);
+ if (st && !(rv = st->ss->
+ load_super(st, fd,
+ devlist->devname)))
+ have_container = 1;
+ else
+ st = NULL;
+ }
+ }
+ if (fd >= 0)
+ close(fd);
+ if (have_container) {
+ subdevs = 0;
+ devlist = NULL;
+ }
+ }
if (subdevs > raiddisks+sparedisks) {
fprintf(stderr, Name ": You have listed more devices (%d) than are in the array(%d)!\n", subdevs, raiddisks+sparedisks);
return 1;
}
- if (subdevs < raiddisks+sparedisks) {
+ if (!have_container && subdevs < raiddisks+sparedisks) {
fprintf(stderr, Name ": You haven't given enough devices (real or missing) to create this array\n");
return 1;
}
return 1;
}
if (size == 0) {
- if (mindisc == NULL) {
+ if (mindisc == NULL && !have_container) {
fprintf(stderr, Name ": no size and no drives given - aborting create.\n");
return 1;
}
- if (level > 0 || level == LEVEL_MULTIPATH || level == LEVEL_FAULTY) {
+ if (level > 0 || level == LEVEL_MULTIPATH
+ || level == LEVEL_FAULTY
+ || (st && st->ss->external) ) {
/* size is meaningful */
if (minsize > 0x100000000ULL && st->ss->major == 0) {
fprintf(stderr, Name ": devices too large for RAID level %d\n", level);
missing_disks++;
}
- if (level <= 0 && first_missing != subdevs * 2) {
+ if (level <= 0 && first_missing < subdevs * 2) {
fprintf(stderr,
Name ": This level does not support missing devices\n");
return 1;
}
+ sra = sysfs_read(mdfd, 0, 0);
- if ((vers % 100) >= 1) { /* can use different versions */
+ if (st->ss->external) {
+ char ver[100];
+ strcat(strcpy(ver, "external:"), st->ss->text_version);
+ if ((vers % 100) < 2 ||
+ sra == NULL ||
+ sysfs_set_str(sra, NULL, "metadata_version",
+ ver) < 0) {
+ fprintf(stderr, Name ": This kernel does not "
+ "support external metadata.\n");
+ return 1;
+ }
+ rv = sysfs_set_array(sra, &info);
+ } else if ((vers % 100) >= 1) { /* can use different versions */
mdu_array_info_t inf;
memset(&inf, 0, sizeof(inf));
inf.major_version = st->ss->major;
}
-
for (pass=1; pass <=2 ; pass++) {
mddev_dev_t moved_disk = NULL; /* the disk that was moved out of the insert point */
info.disk.state |= (1<<MD_DISK_WRITEMOSTLY);
if (dnum == insert_point ||
- strcasecmp(dv->devname, "missing")==0) {
- info.disk.major = 0;
- info.disk.minor = 0;
- info.disk.state = (1<<MD_DISK_FAULTY);
- } else {
- fd = open(dv->devname, O_RDONLY|O_EXCL, 0);
- if (fd < 0) {
- fprintf(stderr, Name ": failed to open %s after earlier success - aborting\n",
- dv->devname);
- return 1;
- }
- fstat(fd, &stb);
- info.disk.major = major(stb.st_rdev);
- info.disk.minor = minor(stb.st_rdev);
- remove_partitions(fd);
- close(fd);
+ strcasecmp(dv->devname, "missing")==0)
+ continue;
+
+ if (st->ss->external == 2)
+ fd = open(dv->devname, O_RDWR, 0);
+ else
+ fd = open(dv->devname, O_RDWR|O_EXCL,0);
+
+ if (fd < 0) {
+ fprintf(stderr, Name ": failed to open %s "
+ "after earlier success - aborting\n",
+ dv->devname);
+ return 1;
}
+ fstat(fd, &stb);
+ info.disk.major = major(stb.st_rdev);
+ info.disk.minor = minor(stb.st_rdev);
+
switch(pass){
case 1:
- st->ss->add_to_super(st, &info.disk);
+ remove_partitions(fd);
+ st->ss->add_to_super(st, &info.disk,
+ fd, dv->devname);
break;
case 2:
- if (info.disk.state == 1) break;
- Kill(dv->devname, 0, 1); /* Just be sure it is clean */
- Kill(dv->devname, 0, 1); /* and again, there could be two superblocks */
- st->ss->write_init_super(st, &info.disk,
- dv->devname);
-
- if (ioctl(mdfd, ADD_NEW_DISK, &info.disk)) {
- fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n",
+ info.component_size = info.array.size * 2;
+ info.errors = 0;
+ rv = 0;
+
+ if (st->ss->external) {
+ st->ss->getinfo_super_n(st, &info);
+ rv = sysfs_add_disk(sra, fd, &info);
+ close(fd);
+ } else {
+ close(fd);
+ rv = ioctl(mdfd, ADD_NEW_DISK,
+ &info.disk);
+ }
+ if (rv) {
+ fprintf(stderr,
+ Name ": ADD_NEW_DISK for %s "
+ "failed: %s\n",
dv->devname, strerror(errno));
st->ss->free_super(st);
return 1;
}
-
break;
}
if (dv == moved_disk && dnum != insert_point) break;
}
+ if (pass == 1)
+ st->ss->write_init_super(st);
}
st->ss->free_super(st);
/* No need to start */
;
else if (runstop == 1 || subdevs >= raiddisks) {
- mdu_param_t param;
- if (ioctl(mdfd, RUN_ARRAY, ¶m)) {
- fprintf(stderr, Name ": RUN_ARRAY failed: %s\n",
- strerror(errno));
- Manage_runstop(mddev, mdfd, -1, 0);
- return 1;
+ if (st->ss->external) {
+ switch(level) {
+ case LEVEL_LINEAR:
+ case LEVEL_MULTIPATH:
+ case 0:
+ sysfs_set_str(sra, NULL, "array_state",
+ "active");
+ break;
+ default:
+ sysfs_set_str(sra, NULL, "array_state",
+ "readonly");
+ break;
+ }
+ } else {
+ mdu_param_t param;
+ if (ioctl(mdfd, RUN_ARRAY, ¶m)) {
+ fprintf(stderr, Name ": RUN_ARRAY failed: %s\n",
+ strerror(errno));
+ Manage_runstop(mddev, mdfd, -1, 0);
+ return 1;
+ }
}
if (verbose >= 0)
fprintf(stderr, Name ": array %s started.\n", mddev);