return (a*1000000)+(b*1000)+c;
}
+#ifndef MDASSEMBLE
int mdadm_version(char *version)
{
int a, b, c;
return (a*1000000)+(b*1000)+c;
}
-#ifndef MDASSEMBLE
long long parse_size(char *size)
{
/* parse 'size' which should be a number optionally
return 1;
}
+int test_partition_from_id(dev_t id)
+{
+ char buf[20];
+ int fd, rv;
+
+ sprintf(buf, "%d:%d", major(id), minor(id));
+ fd = dev_open(buf, O_RDONLY);
+ if (fd < 0)
+ return -1;
+ rv = test_partition(fd);
+ close(fd);
+ return rv;
+}
int enough(int level, int raid_disks, int layout, int clean,
char *avail, int avail_disks)
array.raid_disks <= 0)
return 0;
avail = calloc(array.raid_disks, 1);
- for (i=0; i<array.raid_disks + array.nr_disks; i++) {
+ for (i=0; i < 1024 && array.nr_disks > 0; i++) {
disk.number = i;
if (ioctl(fd, GET_DISK_INFO, &disk) != 0)
continue;
+ if (disk.major == 0 && disk.minor == 0)
+ continue;
+ array.nr_disks--;
+
if (! (disk.state & (1<<MD_DISK_SYNC)))
continue;
if (disk.raid_disk < 0 || disk.raid_disk >= array.raid_disks)
}
#endif /* MDASSEMBLE */
-char *map_num(mapping_t *map, int num)
-{
- while (map->name) {
- if (map->num == num)
- return map->name;
- map++;
- }
- return NULL;
-}
-
-int map_name(mapping_t *map, char *name)
-{
- while (map->name) {
- if (strcmp(map->name, name)==0)
- return map->num;
- map++;
- }
- return UnSet;
-}
-
-
int is_standard(char *dev, int *nump)
{
/* tests if dev is a "standard" md dev name.
return type;
}
-
-/*
- * convert a major/minor pair for a block device into a name in /dev, if possible.
- * On the first call, walk /dev collecting name.
- * Put them in a simple linked listfor now.
- */
-struct devmap {
- int major, minor;
- char *name;
- struct devmap *next;
-} *devlist = NULL;
-int devlist_ready = 0;
-
-int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s)
-{
- struct stat st;
-
- if (S_ISLNK(stb->st_mode)) {
- if (stat(name, &st) != 0)
- return 0;
- stb = &st;
- }
-
- if ((stb->st_mode&S_IFMT)== S_IFBLK) {
- char *n = strdup(name);
- struct devmap *dm = malloc(sizeof(*dm));
- if (strncmp(n, "/dev/./", 7)==0)
- strcpy(n+4, name+6);
- if (dm) {
- dm->major = major(stb->st_rdev);
- dm->minor = minor(stb->st_rdev);
- dm->name = n;
- dm->next = devlist;
- devlist = dm;
- }
- }
- return 0;
-}
-
-#ifndef HAVE_NFTW
-#ifdef HAVE_FTW
-int add_dev_1(const char *name, const struct stat *stb, int flag)
-{
- return add_dev(name, stb, flag, NULL);
-}
-int nftw(const char *path, int (*han)(const char *name, const struct stat *stb, int flag, struct FTW *s), int nopenfd, int flags)
-{
- return ftw(path, add_dev_1, nopenfd);
-}
-#else
-int nftw(const char *path, int (*han)(const char *name, const struct stat *stb, int flag, struct FTW *s), int nopenfd, int flags)
-{
- return 0;
-}
-#endif /* HAVE_FTW */
-#endif /* HAVE_NFTW */
-
-/*
- * Find a block device with the right major/minor number.
- * If we find multiple names, choose the shortest.
- * If we find a name in /dev/md/, we prefer that.
- * This applies only to names for MD devices.
- */
-char *map_dev(int major, int minor, int create)
-{
- struct devmap *p;
- char *regular = NULL, *preferred=NULL;
- int did_check = 0;
-
- if (major == 0 && minor == 0)
- return NULL;
-
- retry:
- if (!devlist_ready) {
- char *dev = "/dev";
- struct stat stb;
- while(devlist) {
- struct devmap *d = devlist;
- devlist = d->next;
- free(d->name);
- free(d);
- }
- if (lstat(dev, &stb)==0 &&
- S_ISLNK(stb.st_mode))
- dev = "/dev/.";
- nftw(dev, add_dev, 10, FTW_PHYS);
- devlist_ready=1;
- did_check = 1;
- }
-
- for (p=devlist; p; p=p->next)
- if (p->major == major &&
- p->minor == minor) {
- if (strncmp(p->name, "/dev/md/",8) == 0) {
- if (preferred == NULL ||
- strlen(p->name) < strlen(preferred))
- preferred = p->name;
- } else {
- if (regular == NULL ||
- strlen(p->name) < strlen(regular))
- regular = p->name;
- }
- }
- if (!regular && !preferred && !did_check) {
- devlist_ready = 0;
- goto retry;
- }
- if (create && !regular && !preferred) {
- static char buf[30];
- snprintf(buf, sizeof(buf), "%d:%d", major, minor);
- regular = buf;
- }
-
- return preferred ? preferred : regular;
-}
-
unsigned long calc_csum(void *super, int bytes)
{
unsigned long long newcsum = 0;
return data_disks * devsize;
}
-int get_mdp_major(void)
-{
-static int mdp_major = -1;
- FILE *fl;
- char *w;
- int have_block = 0;
- int have_devices = 0;
- int last_num = -1;
-
- if (mdp_major != -1)
- return mdp_major;
- fl = fopen("/proc/devices", "r");
- if (!fl)
- return -1;
- while ((w = conf_word(fl, 1))) {
- if (have_block && strcmp(w, "devices:")==0)
- have_devices = 1;
- have_block = (strcmp(w, "Block")==0);
- if (isdigit(w[0]))
- last_num = atoi(w);
- if (have_devices && strcmp(w, "mdp")==0)
- mdp_major = last_num;
- free(w);
- }
- fclose(fl);
- return mdp_major;
-}
-
#if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO)
char *get_md_name(int dev)
{
return fd;
}
-int open_dev(int devnum)
+int open_dev_flags(int devnum, int flags)
{
char buf[20];
sprintf(buf, "%d:%d", dev2major(devnum), dev2minor(devnum));
- return dev_open(buf, O_RDWR);
+ return dev_open(buf, flags);
+}
+
+int open_dev(int devnum)
+{
+ return open_dev_flags(devnum, O_RDONLY);
}
int open_dev_excl(int devnum)
{
char buf[20];
int i;
+ int flags = O_RDWR;
sprintf(buf, "%d:%d", dev2major(devnum), dev2minor(devnum));
for (i=0 ; i<25 ; i++) {
- int fd = dev_open(buf, O_RDWR|O_EXCL);
+ int fd = dev_open(buf, flags|O_EXCL);
if (fd >= 0)
return fd;
+ if (errno == EACCES && flags == O_RDWR) {
+ flags = O_RDONLY;
+ continue;
+ }
if (errno != EBUSY)
return fd;
usleep(200000);
if (guess_type == guess_partitions && ss->add_to_super != NULL)
continue;
memset(st, 0, sizeof(*st));
+ st->ignore_hw_compat = 1;
rv = ss->load_super(st, fd, NULL);
if (rv == 0) {
struct mdinfo info;
if (bestsuper != -1) {
int rv;
memset(st, 0, sizeof(*st));
+ st->ignore_hw_compat = 1;
rv = superlist[bestsuper]->load_super(st, fd, NULL);
if (rv == 0) {
superlist[bestsuper]->free_super(st);
+ st->ignore_hw_compat = 0;
return st;
}
}
return retval;
}
-int check_partitions(int fd, char *dname, unsigned long long freesize)
+int check_partitions(int fd, char *dname, unsigned long long freesize,
+ unsigned long long size)
{
/*
* Check where the last partition ends
Name ": metadata will over-write last partition on %s.\n",
dname);
return 1;
+ } else if (size && endofpart > size) {
+ /* partitions will be truncated in new device */
+ fprintf(stderr,
+ Name ": array size is too small to cover all partitions on %s.\n",
+ dname);
+ return 1;
}
}
return 0;
void get_one_disk(int mdfd, mdu_array_info_t *ainf, mdu_disk_info_t *disk)
{
int d;
+
ioctl(mdfd, GET_ARRAY_INFO, ainf);
- for (d = 0 ; d < ainf->raid_disks + ainf->nr_disks ; d++)
- if (ioctl(mdfd, GET_DISK_INFO, disk) == 0)
+ for (d = 0 ; d < 1024 ; d++) {
+ if (ioctl(mdfd, GET_DISK_INFO, disk) == 0 &&
+ (disk->major || disk->minor))
return;
+ }
}
int open_container(int fd)
for (ent = mdstat; ent; ent = ent->next)
if (is_container_member(ent, container))
- if (!subarray ||
- strcmp(to_subarray(ent, container), subarray) == 0)
+ if (strcmp(to_subarray(ent, container), subarray) == 0)
break;
free_mdstat(mdstat);
return ent != NULL;
}
-int is_container_active(char *container)
-{
- return is_subarray_active(NULL, container);
-}
-
/* open_subarray - opens a subarray in a container
* @dev: container device name
* @st: empty supertype
return recovery_start;
}
-void fmt_devname(char *name, int num)
-{
- if (num >= 0)
- sprintf(name, "md%d", num);
- else
- sprintf(name, "md_d%d", -1-num);
-}
-
-char *devnum2devname(int num)
-{
- char name[100];
- fmt_devname(name,num);
- return strdup(name);
-}
-
-int devname2devnum(char *name)
-{
- char *ep;
- int num;
- if (strncmp(name, "md_d", 4)==0)
- num = -1-strtoul(name+4, &ep, 10);
- else
- num = strtoul(name+2, &ep, 10);
- return num;
-}
-
-int stat2devnum(struct stat *st)
-{
- char path[30];
- char link[200];
- char *cp;
- int n;
-
- if ((S_IFMT & st->st_mode) == S_IFBLK) {
- if (major(st->st_rdev) == MD_MAJOR)
- return minor(st->st_rdev);
- else if (major(st->st_rdev) == (unsigned)get_mdp_major())
- return -1- (minor(st->st_rdev)>>MdpMinorShift);
-
- /* must be an extended-minor partition. Look at the
- * /sys/dev/block/%d:%d link which must look like
- * ../../block/mdXXX/mdXXXpYY
- */
- sprintf(path, "/sys/dev/block/%d:%d", major(st->st_rdev),
- minor(st->st_rdev));
- n = readlink(path, link, sizeof(link)-1);
- if (n <= 0)
- return NoMdDev;
- link[n] = 0;
- cp = strrchr(link, '/');
- if (cp) *cp = 0;
- cp = strchr(link, '/');
- if (cp && strncmp(cp, "/md", 3) == 0)
- return devname2devnum(cp+1);
- }
- return NoMdDev;
-
-}
-
-int fd2devnum(int fd)
-{
- struct stat stb;
- if (fstat(fd, &stb) == 0)
- return stat2devnum(&stb);
- return NoMdDev;
-}
-
int mdmon_pid(int devnum)
{
char path[100];
}
}
+/* Pick all spares matching given criteria from a container
+ * if min_size == 0 do not check size
+ * if domlist == NULL do not check domains
+ * if spare_group given add it to domains of each spare
+ * metadata allows to test domains using metadata of destination array */
+struct mdinfo *container_choose_spares(struct supertype *st,
+ unsigned long long min_size,
+ struct domainlist *domlist,
+ char *spare_group,
+ const char *metadata, int get_one)
+{
+ struct mdinfo *d, **dp, *disks = NULL;
+
+ /* get list of all disks in container */
+ if (st->ss->getinfo_super_disks)
+ disks = st->ss->getinfo_super_disks(st);
+
+ if (!disks)
+ return disks;
+ /* find spare devices on the list */
+ dp = &disks->devs;
+ disks->array.spare_disks = 0;
+ while (*dp) {
+ int found = 0;
+ d = *dp;
+ if (d->disk.state == 0) {
+ /* check if size is acceptable */
+ unsigned long long dev_size;
+ dev_t dev = makedev(d->disk.major,d->disk.minor);
+
+ if (!min_size ||
+ (dev_size_from_id(dev, &dev_size) &&
+ dev_size >= min_size))
+ found = 1;
+ /* check if domain matches */
+ if (found && domlist) {
+ struct dev_policy *pol = devnum_policy(dev);
+ if (spare_group)
+ pol_add(&pol, pol_domain,
+ spare_group, NULL);
+ if (domain_test(domlist, pol, metadata) != 1)
+ found = 0;
+ dev_policy_free(pol);
+ }
+ }
+ if (found) {
+ dp = &d->next;
+ disks->array.spare_disks++;
+ if (get_one) {
+ sysfs_free(*dp);
+ d->next = NULL;
+ }
+ } else {
+ *dp = d->next;
+ d->next = NULL;
+ sysfs_free(d);
+ }
+ }
+ return disks;
+}