diff --git a/Create.c b/Create.c index 8407579..d423585 100644 --- a/Create.c +++ b/Create.c @@ -182,6 +182,7 @@ int Create(struct supertype *st, char *mddev, int mdfd, case 1: case LEVEL_FAULTY: case LEVEL_MULTIPATH: + case LEVEL_CONTAINER: if (chunk) { chunk = 0; if (verbose > 0) @@ -193,13 +194,17 @@ int Create(struct supertype *st, char *mddev, int mdfd, return 1; } + if (st && ! st->ss->validate_geometry(st, level, layout, raiddisks, + chunk, size, NULL, NULL)) + return 1; + /* now look at the subdevs */ info.array.active_disks = 0; info.array.working_disks = 0; dnum = 0; for (dv=devlist; dv; dv=dv->next, dnum++) { char *dname = dv->devname; - unsigned long long ldsize, freesize; + unsigned long long freesize; int fd; if (strcasecmp(dname, "missing")==0) { if (first_missing > dnum) @@ -219,11 +224,6 @@ int Create(struct supertype *st, char *mddev, int mdfd, fail=1; continue; } - if (!get_dev_size(fd, dname, &ldsize)) { - fail = 1; - close(fd); - continue; - } if (st == NULL) { struct createinfo *ci = conf_get_create_info(); if (ci) @@ -231,17 +231,22 @@ int Create(struct supertype *st, char *mddev, int mdfd, } if (st == NULL) { /* Need to choose a default metadata, which is different - * depending on the sizes of devices + * depending on geometry of array. */ int i; char *name = "default"; - if (level >= 1 && ldsize > (0x7fffffffULL<<10)) - name = "default/large"; - for(i=0; !st && superlist[i]; i++) + for(i=0; !st && superlist[i]; i++) { st = superlist[i]->match_metadata_desc(name); + if (st && !st->ss->validate_geometry + (st, level, layout, raiddisks, + chunk, size, dname, &freesize)) + st = NULL; + } if (!st) { - fprintf(stderr, Name ": internal error - no default metadata style\n"); + fprintf(stderr, Name ": device %s not suitable " + "for any style of array\n", + dname); exit(2); } if (st->ss->major != 0 || @@ -250,14 +255,19 @@ int Create(struct supertype *st, char *mddev, int mdfd, " %d.%d metadata\n", st->ss->major, st->minor_version); - } - freesize = st->ss->avail_size(st, ldsize >> 9); - if (freesize == 0) { - fprintf(stderr, Name ": %s is too small: %luK\n", - dname, (unsigned long)(ldsize>>10)); - fail = 1; - close(fd); - continue; + } else { + if (!st->ss->validate_geometry(st, level, layout, + raiddisks, + chunk, size, dname, + &freesize)) { + + fprintf(stderr, + Name ": %s is not suitable for " + "this array.\n", + dname); + fail = 1; + continue; + } } freesize /= 2; /* convert to K */ @@ -268,7 +278,8 @@ int Create(struct supertype *st, char *mddev, int mdfd, if (size && freesize < size) { fprintf(stderr, Name ": %s is smaller that given size." - " %lluK < %lluK + superblock\n", dname, freesize, size); + " %lluK < %lluK + metadata\n", + dname, freesize, size); fail = 1; close(fd); continue; @@ -581,7 +592,10 @@ int Create(struct supertype *st, char *mddev, int mdfd, st->ss->free_super(st); /* param is not actually used */ - if (runstop == 1 || subdevs >= raiddisks) { + if (level == LEVEL_CONTAINER) + /* 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", diff --git a/ReadMe.c b/ReadMe.c index 1b55395..a52f080 100644 --- a/ReadMe.c +++ b/ReadMe.c @@ -610,6 +610,7 @@ mapping_t pers[] = { { "raid10", 10}, { "10", 10}, { "faulty", LEVEL_FAULTY}, + { "container", LEVEL_CONTAINER}, { NULL, 0} }; diff --git a/mdadm.h b/mdadm.h index 5c18d15..7b5a08e 100644 --- a/mdadm.h +++ b/mdadm.h @@ -358,6 +358,10 @@ extern struct superswitch { void (*locate_bitmap)(struct supertype *st, int fd); int (*write_bitmap)(struct supertype *st, int fd); void (*free_super)(struct supertype *st); + int (*validate_geometry)(struct supertype *st, int level, int layout, + int raiddisks, + int chunk, unsigned long long size, + char *subdev, unsigned long long *freesize); int major; int swapuuid; /* true if uuid is bigending rather than hostendian */ } super0, super1, *superlist[]; @@ -531,6 +535,9 @@ extern int open_mddev_devnum(char *devname, int devnum, char *name, #define LEVEL_LINEAR (-1) #define LEVEL_FAULTY (-5) +/* kernel module doesn't know about these */ +#define LEVEL_CONTAINER (-100) + /* faulty stuff */ diff --git a/super0.c b/super0.c index 7e81482..a1c97f8 100644 --- a/super0.c +++ b/super0.c @@ -991,6 +991,43 @@ static void free_super0(struct supertype *st) st->sb = NULL; } +static int validate_geometry0(struct supertype *st, int level, + int layout, int raiddisks, + int chunk, unsigned long long size, + char *subdev, unsigned long long *freesize) +{ + unsigned long long ldsize; + int fd; + + if (level == LEVEL_CONTAINER) + return 0; + if (raiddisks > MD_SB_DISKS) + return 0; + if (size > (0x7fffffffULL<<10)) + return 0; + if (!subdev) + return 1; + + fd = open(subdev, O_RDONLY|O_EXCL, 0); + if (fd < 0) { + fprintf(stderr, Name ": Cannot open %s: %s\n", + subdev, strerror(errno)); + return 0; + } + if (!get_dev_size(fd, subdev, &ldsize)) { + close(fd); + return 0; + } + close(fd); + + if (ldsize < MD_RESERVED_SECTORS * 512) + return 0; + if (size > (0x7fffffffULL<<10)) + return 0; + *freesize = MD_NEW_SIZE_SECTORS(ldsize >> 9); + return 1; +} + struct superswitch super0 = { #ifndef MDASSEMBLE .examine_super = examine_super0, @@ -1016,6 +1053,7 @@ struct superswitch super0 = { .locate_bitmap = locate_bitmap0, .write_bitmap = write_bitmap0, .free_super = free_super0, + .validate_geometry = validate_geometry0, .major = 0, .swapuuid = 0, }; diff --git a/super1.c b/super1.c index fe915f8..c510899 100644 --- a/super1.c +++ b/super1.c @@ -1199,7 +1199,7 @@ static struct supertype *match_metadata_desc1(char *arg) return st; } if (strcmp(arg, "1") == 0 || - strcmp(arg, "default/large") == 0) { + strcmp(arg, "default") == 0) { st->minor_version = -1; return st; } @@ -1416,6 +1416,35 @@ static void free_super1(struct supertype *st) st->sb = NULL; } +static int validate_geometry1(struct supertype *st, int level, + int layout, int raiddisks, + int chunk, unsigned long long size, + char *subdev, unsigned long long *freesize) +{ + unsigned long long ldsize; + int fd; + + if (level == LEVEL_CONTAINER) + return 0; + if (!subdev) + return 1; + + fd = open(subdev, O_RDONLY|O_EXCL, 0); + if (fd < 0) { + fprintf(stderr, Name ": Cannot open %s: %s\n", + subdev, strerror(errno)); + return 0; + } + if (!get_dev_size(fd, subdev, &ldsize)) { + close(fd); + return 0; + } + close(fd); + + *freesize = avail_size1(st, ldsize >> 9); + return 1; +} + struct superswitch super1 = { #ifndef MDASSEMBLE .examine_super = examine_super1, @@ -1441,6 +1470,7 @@ struct superswitch super1 = { .locate_bitmap = locate_bitmap1, .write_bitmap = write_bitmap1, .free_super = free_super1, + .validate_geometry = validate_geometry1, .major = 1, #if __BYTE_ORDER == BIG_ENDIAN .swapuuid = 0,