#include "md_p.h"
#include <ctype.h>
+static int round_size_and_verify(unsigned long long *size, int chunk)
+{
+ if (*size == 0)
+ return 0;
+ *size &= ~(unsigned long long)(chunk - 1);
+ if (*size == 0) {
+ pr_err("Size cannot be smaller than chunk.\n");
+ return 1;
+ }
+ return 0;
+}
+
static int default_layout(struct supertype *st, int level, int verbose)
{
int layout = UnSet;
* RUN_ARRAY
*/
int mdfd;
- unsigned long long minsize=0, maxsize=0;
+ unsigned long long minsize = 0, maxsize = 0;
char *mindisc = NULL;
char *maxdisc = NULL;
int dnum, raid_disk_num;
struct mddev_dev *dv;
- int fail=0, warn=0;
- struct stat stb;
+ dev_t rdev;
+ int fail = 0, warn = 0;
int first_missing = subdevs * 2;
int second_missing = subdevs * 2;
int missing_disks = 0;
int insert_point = subdevs * 2; /* where to insert a missing drive */
int total_slots;
int pass;
- int vers;
int rv;
int bitmap_fd;
int have_container = 0;
char chosen_name[1024];
struct map_ent *map = NULL;
unsigned long long newsize;
+ mdu_array_info_t inf;
int major_num = BITMAP_MAJOR_HI;
if (s->bitmap_file && strcmp(s->bitmap_file, "clustered") == 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));
pr_err("unknown level %d\n", s->level);
return 1;
}
+
if (s->size == MAX_SIZE)
/* use '0' to mean 'max' now... */
s->size = 0;
if (s->size && s->chunk && s->chunk != UnSet)
- s->size &= ~(unsigned long long)(s->chunk - 1);
+ if (round_size_and_verify(&s->size, s->chunk))
+ return 1;
+
newsize = s->size * 2;
if (st && ! st->ss->validate_geometry(st, s->level, s->layout, s->raiddisks,
&s->chunk, s->size*2,
data_offset, NULL,
&newsize, s->consistency_policy,
- c->verbose>=0))
+ c->verbose >= 0))
return 1;
if (s->chunk && s->chunk != UnSet) {
/* default chunk was just set */
if (c->verbose > 0)
pr_err("chunk size defaults to %dK\n", s->chunk);
- s->size &= ~(unsigned long long)(s->chunk - 1);
+ if (round_size_and_verify(&s->size, s->chunk))
+ return 1;
do_default_chunk = 0;
}
}
info.array.active_disks = 0;
info.array.working_disks = 0;
dnum = 0;
- for (dv = devlist; dv ; dv = dv->next)
+ for (dv = devlist; dv; dv = dv->next)
if (data_offset == VARIABLE_OFFSET)
dv->data_offset = INVALID_SECTORS;
else
int dfd;
char *doff;
- if (strcasecmp(dname, "missing")==0) {
+ if (strcasecmp(dname, "missing") == 0) {
if (first_missing > dnum)
first_missing = dnum;
if (second_missing > dnum && dnum > first_missing)
dname, strerror(errno));
exit(2);
}
- if (fstat(dfd, &stb) != 0 ||
- (stb.st_mode & S_IFMT) != S_IFBLK) {
+ if (!fstat_is_blkdev(dfd, dname, NULL)) {
close(dfd);
- pr_err("%s is not a block device\n",
- dname);
exit(2);
}
close(dfd);
*/
int i;
char *name = "default";
- for(i=0; !st && superlist[i]; i++) {
+ for(i = 0; !st && superlist[i]; i++) {
st = superlist[i]->match_metadata_desc(name);
if (!st)
continue;
/* default chunk was just set */
if (c->verbose > 0)
pr_err("chunk size defaults to %dK\n", s->chunk);
- s->size &= ~(unsigned long long)(s->chunk - 1);
+ if (round_size_and_verify(&s->size, s->chunk))
+ return 1;
do_default_chunk = 0;
}
}
skip_size_check:
if (c->runstop != 1 || c->verbose >= 0) {
int fd = open(dname, O_RDONLY);
- if (fd <0 ) {
+ if (fd < 0) {
pr_err("Cannot open %s: %s\n",
dname, strerror(errno));
- fail=1;
+ fail = 1;
continue;
}
warn |= check_ext2(fd, dname);
close(fd);
}
}
+ if (missing_disks == dnum && !have_container) {
+ pr_err("Subdevs can't be all missing\n");
+ return 1;
+ }
if (s->raiddisks + s->sparedisks > st->max_devs) {
pr_err("Too many devices: %s metadata only supports %d\n",
st->ss->name, st->max_devs);
return 1;
}
if (s->level > 0 || s->level == LEVEL_MULTIPATH ||
- s->level == LEVEL_FAULTY || st->ss->external ) {
+ s->level == LEVEL_FAULTY || st->ss->external) {
/* size is meaningful */
if (!st->ss->validate_geometry(st, s->level, s->layout,
s->raiddisks,
* as missing, so that a reconstruct happens (faster than re-parity)
* FIX: Can we do this for raid6 as well?
*/
- if (st->ss->external == 0 &&
- s->assume_clean==0 && c->force == 0 && first_missing >= s->raiddisks) {
- switch ( s->level ) {
+ if (st->ss->external == 0 && s->assume_clean == 0 &&
+ c->force == 0 && first_missing >= s->raiddisks) {
+ switch (s->level) {
case 4:
case 5:
insert_point = s->raiddisks-1;
/* We need to create the device */
map_lock(&map);
- mdfd = create_mddev(mddev, name, c->autof, LOCAL, chosen_name);
+ mdfd = create_mddev(mddev, name, c->autof, LOCAL, chosen_name, 1);
if (mdfd < 0) {
map_unlock(&map);
return 1;
chosen_name);
close(mdfd);
map_unlock(&map);
+ udev_unblock();
return 1;
}
mddev = chosen_name;
- vers = md_get_version(mdfd);
- if (vers < 9000) {
- pr_err("Create requires md driver version 0.90.0 or later\n");
+ memset(&inf, 0, sizeof(inf));
+ md_get_array_info(mdfd, &inf);
+ if (inf.working_disks != 0) {
+ pr_err("another array by this name is already running.\n");
goto abort_locked;
- } else {
- mdu_array_info_t inf;
- memset(&inf, 0, sizeof(inf));
- md_get_array_info(mdfd, &inf);
- if (inf.working_disks != 0) {
- pr_err("another array by this name is already running.\n");
- goto abort_locked;
- }
}
/* Ok, lets try some ioctls */
* with, but it chooses to trust me instead. Sigh
*/
info.array.md_minor = 0;
- if (fstat(mdfd, &stb)==0)
- info.array.md_minor = minor(stb.st_rdev);
+ if (fstat_is_blkdev(mdfd, mddev, &rdev))
+ info.array.md_minor = minor(rdev);
info.array.not_persistent = 0;
if (((s->level == 4 || s->level == 5) &&
name = strrchr(mddev, '/');
if (name) {
name++;
- if (strncmp(name, "md_", 3)==0 &&
- strlen(name) > 3 &&
- (name-mddev) == 5 /* /dev/ */)
+ if (strncmp(name, "md_", 3) == 0 &&
+ strlen(name) > 3 && (name-mddev) == 5 /* /dev/ */)
name += 3;
- else if (strncmp(name, "md", 2)==0 &&
- strlen(name) > 2 &&
- isdigit(name[2]) &&
+ else if (strncmp(name, "md", 2) == 0 &&
+ strlen(name) > 2 && isdigit(name[2]) &&
(name-mddev) == 5 /* /dev/ */)
name += 2;
}
* to stop another mdadm from finding and using those devices.
*/
- if (s->bitmap_file && vers < 9003) {
- major_num = BITMAP_MAJOR_HOSTENDIAN;
-#ifdef __BIG_ENDIAN
- pr_err("Warning - bitmaps created on this kernel are not portable\n"
- " between different architectured. Consider upgrading the Linux kernel.\n");
-#endif
- }
-
- if (s->bitmap_file && (strcmp(s->bitmap_file, "internal")==0 ||
- strcmp(s->bitmap_file, "clustered")==0)) {
- if ((vers%100) < 2) {
- pr_err("internal bitmaps not supported by this kernel.\n");
- goto abort_locked;
- }
+ if (s->bitmap_file && (strcmp(s->bitmap_file, "internal") == 0 ||
+ strcmp(s->bitmap_file, "clustered") == 0)) {
if (!st->ss->add_internal_bitmap) {
pr_err("internal bitmaps not supported with %s metadata\n",
st->ss->name);
}
bitmap_fd = open(s->bitmap_file, O_RDWR);
if (bitmap_fd < 0) {
- pr_err("weird: %s cannot be openned\n",
+ pr_err("weird: %s cannot be opened\n",
s->bitmap_file);
goto abort_locked;
}
infos = xmalloc(sizeof(*infos) * total_slots);
enable_fds(total_slots);
- for (pass=1; pass <=2 ; pass++) {
+ for (pass = 1; pass <= 2; pass++) {
struct mddev_dev *moved_disk = NULL; /* the disk that was moved out of the insert point */
- for (dnum=0, raid_disk_num=0, dv = devlist ; dv ;
- dv=(dv->next)?(dv->next):moved_disk, dnum++) {
+ for (dnum = 0, raid_disk_num = 0, dv = devlist; dv;
+ dv = (dv->next) ? (dv->next) : moved_disk, dnum++) {
int fd;
- struct stat stb2;
struct mdinfo *inf = &infos[dnum];
if (dnum >= total_slots)
moved_disk = dv;
continue;
}
- if (strcasecmp(dv->devname, "missing")==0) {
+ if (strcasecmp(dv->devname, "missing") == 0) {
raid_disk_num += 1;
continue;
}
dv->devname);
goto abort_locked;
}
- fstat(fd, &stb2);
- inf->disk.major = major(stb2.st_rdev);
- inf->disk.minor = minor(stb2.st_rdev);
+ if (!fstat_is_blkdev(fd, dv->devname, &rdev))
+ return 1;
+ inf->disk.major = major(rdev);
+ inf->disk.minor = minor(rdev);
}
if (fd >= 0)
remove_partitions(fd);
if (!have_container) {
/* getinfo_super might have lost these ... */
- inf->disk.major = major(stb2.st_rdev);
- inf->disk.minor = minor(stb2.st_rdev);
+ inf->disk.major = major(rdev);
+ inf->disk.minor = minor(rdev);
}
break;
case 2:
pr_err("not starting array - not enough devices.\n");
}
close(mdfd);
+ /* Give udev a moment to process the Change event caused
+ * by the close.
+ */
+ usleep(100*1000);
+ udev_unblock();
return 0;
abort:
+ udev_unblock();
map_lock(&map);
abort_locked:
map_remove(&map, fd2devnm(mdfd));