X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=blobdiff_plain;f=Create.c;h=c1d607fa7c20d224aeb522e241e722c9baaaa872;hp=6e58b53526ab3a5d768d445d527348d47b403776;hb=2f6079dc96180335fdb56d0b89e462e903abbb50;hpb=d03373f1deea242eaacfab6b2b0c4afc6d7702d2 diff --git a/Create.c b/Create.c index 6e58b535..c1d607fa 100644 --- a/Create.c +++ b/Create.c @@ -70,6 +70,7 @@ int Create(struct supertype *st, char *mddev, int mdfd, int vers; int rv; int bitmap_fd; + int have_container = 0; unsigned long long bitmapsize; struct mdinfo *sra; struct mdinfo info; @@ -92,6 +93,14 @@ int Create(struct supertype *st, char *mddev, int mdfd, 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"); @@ -117,11 +126,47 @@ int Create(struct supertype *st, char *mddev, int mdfd, 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; } @@ -303,11 +348,13 @@ int Create(struct supertype *st, char *mddev, int mdfd, 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); @@ -367,7 +414,7 @@ int Create(struct supertype *st, char *mddev, int mdfd, 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; @@ -490,7 +537,15 @@ int Create(struct supertype *st, char *mddev, int mdfd, if (st->ss->external) { char ver[100]; - strcat(strcpy(ver, "external:"), st->ss->text_version); + if (st->ss->external == 1) + /* container */ + strcat(strcpy(ver, "external:"), st->ss->text_version); + else { + /* member */ + sprintf(ver, "external:/%s/%d", + devnum2devname(st->container_dev), + st->container_member); + } if ((vers % 100) < 2 || sra == NULL || sysfs_set_str(sra, NULL, "metadata_version", @@ -499,7 +554,7 @@ int Create(struct supertype *st, char *mddev, int mdfd, "support external metadata.\n"); return 1; } - rv = 0; + 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)); @@ -563,7 +618,11 @@ int Create(struct supertype *st, char *mddev, int mdfd, strcasecmp(dv->devname, "missing")==0) continue; - fd = open(dv->devname, O_RDWR|O_EXCL, 0); + 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", @@ -581,18 +640,20 @@ int Create(struct supertype *st, char *mddev, int mdfd, fd, dv->devname); break; case 2: - close(fd); + info.component_size = info.array.size * 2; + info.errors = 0; + rv = 0; if (st->ss->external) { - char dv[100]; - sprintf(dv, "%d:%d\n", - info.disk.major, - info.disk.minor); - sysfs_set_str(sra, NULL, "new_dev", dv); - /* FIXME check error */ - /*FIXME find that device and set it up*/ - } else if (ioctl(mdfd, ADD_NEW_DISK, - &info.disk)) { + 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", @@ -614,12 +675,27 @@ int Create(struct supertype *st, char *mddev, int mdfd, /* 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);