+static int validate_geometry_imsm(struct supertype *st, int level, int layout,
+ int raiddisks, int chunk, unsigned long long size,
+ char *dev, unsigned long long *freesize)
+{
+ int fd, cfd;
+ struct mdinfo *sra;
+
+ /* if given unused devices create a container
+ * if given given devices in a container create a member volume
+ */
+ if (level == LEVEL_CONTAINER) {
+ st->ss = &super_imsm_container;
+ if (dev) {
+ /* validate the container, dev == NULL */
+ int rv = st->ss->validate_geometry(st, level, layout,
+ raiddisks, chunk,
+ size,
+ NULL, freesize);
+ if (rv)
+ return rv;
+ }
+ return st->ss->validate_geometry(st, level, layout, raiddisks,
+ chunk, size, dev, freesize);
+ }
+
+ if (st->sb) {
+ /* creating in a given container */
+ st->ss = &super_imsm_volume;
+ if (dev) {
+ int rv = st->ss->validate_geometry(st, level, layout,
+ raiddisks, chunk,
+ size,
+ NULL, freesize);
+ if (rv)
+ return rv;
+ }
+ return st->ss->validate_geometry(st, level, layout, raiddisks,
+ chunk, size, dev, freesize);
+ }
+
+ /* limit creation to the following levels */
+ if (!dev)
+ switch (level) {
+ case 0:
+ case 1:
+ case 10:
+ case 5:
+ break;
+ default:
+ return 1;
+ }
+
+ /* This device needs to be a device in an 'imsm' container */
+ fd = open(dev, O_RDONLY|O_EXCL, 0);
+ if (fd >= 0) {
+ fprintf(stderr,
+ Name ": Cannot create this array on device %s\n",
+ dev);
+ close(fd);
+ return 0;
+ }
+ if (errno != EBUSY || (fd = open(dev, O_RDONLY, 0)) < 0) {
+ fprintf(stderr, Name ": Cannot open %s: %s\n",
+ dev, strerror(errno));
+ return 0;
+ }
+ /* Well, it is in use by someone, maybe an 'imsm' container. */
+ cfd = open_container(fd);
+ if (cfd < 0) {
+ close(fd);
+ fprintf(stderr, Name ": Cannot use %s: It is busy\n",
+ dev);
+ return 0;
+ }
+ sra = sysfs_read(cfd, 0, GET_VERSION);
+ close(fd);
+ if (sra && sra->array.major_version == -1 &&
+ strcmp(sra->text_version, "imsm") == 0) {
+ /* This is a member of a imsm container. Load the container
+ * and try to create a volume
+ */
+ struct intel_super *super;
+ st->ss = &super_imsm_volume;
+ if (load_super_imsm_all(st, cfd, (void **) &super, NULL, 1) == 0) {
+ st->sb = super;
+ st->container_dev = fd2devnum(cfd);
+ close(cfd);
+ return st->ss->validate_geometry(st, level, layout,
+ raiddisks, chunk, size,
+ dev, freesize);
+ }
+ close(cfd);
+ } else /* may belong to another container */
+ return 0;
+
+ return 1;
+}
+
+static int validate_geometry_imsm_container(struct supertype *st, int level,
+ int layout, int raiddisks, int chunk,
+ unsigned long long size, char *dev,
+ unsigned long long *freesize)
+{
+ int fd;
+ unsigned long long ldsize;
+
+ if (level != LEVEL_CONTAINER)
+ return 0;
+ if (!dev)
+ return 1;
+
+ fd = open(dev, O_RDONLY|O_EXCL, 0);
+ if (fd < 0) {
+ fprintf(stderr, Name ": Cannot open %s: %s\n",
+ dev, strerror(errno));
+ return 0;
+ }
+ if (!get_dev_size(fd, dev, &ldsize)) {
+ close(fd);
+ return 0;
+ }
+ close(fd);
+
+ *freesize = avail_size_imsm(st, ldsize >> 9);
+
+ return 1;
+}
+
+/* validate_geometry_imsm_volume - lifted from validate_geometry_ddf_bvd
+ * FIX ME add ahci details
+ */
+static int validate_geometry_imsm_volume(struct supertype *st, int level,
+ int layout, int raiddisks, int chunk,
+ unsigned long long size, char *dev,
+ unsigned long long *freesize)
+{
+ struct stat stb;
+ struct intel_super *super = st->sb;
+ struct dl *dl;
+ unsigned long long pos = 0;
+ unsigned long long maxsize;
+ struct extent *e;
+ int i;
+
+ if (level == LEVEL_CONTAINER)
+ return 0;
+
+ if (level == 1 && raiddisks > 2) {
+ fprintf(stderr, Name ": imsm does not support more than 2 "
+ "in a raid1 configuration\n");
+ return 0;
+ }
+
+ /* We must have the container info already read in. */
+ if (!super)
+ return 0;
+
+ if (!dev) {
+ /* General test: make sure there is space for
+ * 'raiddisks' device extents of size 'size'.
+ */
+ unsigned long long minsize = size*2 /* convert to blocks */;
+ int dcnt = 0;
+ if (minsize == 0)
+ minsize = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
+ for (dl = super->disks; dl ; dl = dl->next) {
+ int found = 0;
+
+ i = 0;
+ e = get_extents(super, dl);
+ if (!e) continue;
+ do {
+ unsigned long long esize;
+ esize = e[i].start - pos;
+ if (esize >= minsize)
+ found = 1;
+ pos = e[i].start + e[i].size;
+ i++;
+ } while (e[i-1].size);
+ if (found)
+ dcnt++;
+ free(e);
+ }
+ if (dcnt < raiddisks) {
+ fprintf(stderr, Name ": Not enough devices with space "
+ "for this array (%d < %d)\n",
+ dcnt, raiddisks);
+ return 0;
+ }
+ return 1;
+ }
+ /* This device must be a member of the set */
+ if (stat(dev, &stb) < 0)
+ return 0;
+ if ((S_IFMT & stb.st_mode) != S_IFBLK)
+ return 0;
+ for (dl = super->disks ; dl ; dl = dl->next) {
+ if (dl->major == major(stb.st_rdev) &&
+ dl->minor == minor(stb.st_rdev))
+ break;
+ }
+ if (!dl) {
+ fprintf(stderr, Name ": %s is not in the same imsm set\n",
+ dev);
+ return 0;
+ }
+ e = get_extents(super, dl);
+ maxsize = 0;
+ i = 0;
+ if (e) do {
+ unsigned long long esize;
+ esize = e[i].start - pos;
+ if (esize >= maxsize)
+ maxsize = esize;
+ pos = e[i].start + e[i].size;
+ i++;
+ } while (e[i-1].size);
+ *freesize = maxsize;
+
+ return 1;
+}
+
+static struct mdinfo *container_content_imsm(struct supertype *st)