bitmap_info_t *bitmap_file_read(char *filename, int brief, struct supertype **stp) { int fd; bitmap_info_t *info; struct stat stb; struct supertype *st = *stp; fd = open(filename, O_RDONLY); if (fd < 0) { fprintf(stderr, Name ": failed to open bitmap file %s: %s\n", filename, strerror(errno)); return NULL; } fstat(fd, &stb); if ((S_IFMT & stb.st_mode) == S_IFBLK) { /* block device, so we are probably after an internal bitmap */ if (!st) st = guess_super(fd); if (!st) { /* just look at device... */ lseek(fd, 0, 0); } else { st->ss->locate_bitmap(st, fd, NULL); } ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */ *stp = st; } info = bitmap_fd_read(fd, brief); close(fd); return info; }
int Kill(char *dev, struct supertype *st, int force, int verbose, int noexcl) { /* * Nothing fancy about Kill. It just zeroes out a superblock * Definitely not safe. * Returns: * 0 - a zero superblock was successfully written out * 1 - failed to write the zero superblock * 2 - failed to open the device or find a superblock. */ int fd, rv = 0; if (force) noexcl = 1; fd = open(dev, O_RDWR|(noexcl ? 0 : O_EXCL)); if (fd < 0) { if (verbose >= 0) pr_err("Couldn't open %s for write - not zeroing\n", dev); return 2; } if (st == NULL) st = guess_super(fd); if (st == NULL || st->ss->init_super == NULL) { if (verbose >= 0) pr_err("Unrecognised md component device - %s\n", dev); close(fd); return 2; } st->ignore_hw_compat = 1; rv = st->ss->load_super(st, fd, dev); if (rv == 0 || (force && rv >= 2)) { st->ss->free_super(st); st->ss->init_super(st, NULL, NULL, "", NULL, NULL, INVALID_SECTORS); if (st->ss->store_super(st, fd)) { if (verbose >= 0) pr_err("Could not zero superblock on %s\n", dev); rv = 1; } else if (rv) { if (verbose >= 0) pr_err("superblock zeroed anyway\n"); rv = 0; } } close(fd); return rv; }
int Kill(char *dev, int force, int quiet) { /* * Nothing fancy about Kill. It just zeroes out a superblock * Definitely not safe. */ void *super; int fd, rv = 0; struct supertype *st; fd = open(dev, O_RDWR|O_EXCL); if (fd < 0) { if (!quiet) fprintf(stderr, Name ": Couldn't open %s for write - not zeroing\n", dev); close(fd); return 1; } st = guess_super(fd); if (st == NULL) { if (!quiet) fprintf(stderr, Name ": Unrecognised md component device - %s\n", dev); close(fd); return 1; } rv = st->ss->load_super(st, fd, &super, dev); if (force && rv >= 2) rv = 0; /* ignore bad data in superblock */ if (rv== 0 || (force && rv >= 2)) { mdu_array_info_t info; info.major_version = -1; /* zero superblock */ free(super); st->ss->init_super(st, &super, &info, 0, "", NULL, NULL); if (st->ss->store_super(st, fd, super)) { if (!quiet) fprintf(stderr, Name ": Could not zero superblock on %s\n", dev); rv = 1; } else if (rv) { if (!quiet) fprintf(stderr, Name ": superblock zeroed anyway\n"); rv = 0; } } close(fd); return rv; }
void RebuildMap(void) { struct mdstat_ent *mdstat = mdstat_read(0, 0); struct mdstat_ent *md; struct map_ent *map = NULL; int require_homehost; char sys_hostname[256]; char *homehost = conf_get_homehost(&require_homehost); if (homehost == NULL || strcmp(homehost, "<system>")==0) { if (gethostname(sys_hostname, sizeof(sys_hostname)) == 0) { sys_hostname[sizeof(sys_hostname)-1] = 0; homehost = sys_hostname; } } for (md = mdstat ; md ; md = md->next) { struct mdinfo *sra = sysfs_read(-1, md->devnm, GET_DEVS); struct mdinfo *sd; if (!sra) continue; for (sd = sra->devs ; sd ; sd = sd->next) { char namebuf[100]; char dn[30]; int dfd; int ok; int devid; struct supertype *st; char *subarray = NULL; char *path; struct mdinfo *info; sprintf(dn, "%d:%d", sd->disk.major, sd->disk.minor); dfd = dev_open(dn, O_RDONLY); if (dfd < 0) continue; st = guess_super(dfd); if ( st == NULL) ok = -1; else { subarray = get_member_info(md); ok = st->ss->load_super(st, dfd, NULL); } close(dfd); if (ok != 0) continue; if (subarray) info = st->ss->container_content(st, subarray); else { info = xmalloc(sizeof(*info)); st->ss->getinfo_super(st, info, NULL); } if (!info) continue; devid = devnm2devid(md->devnm); path = map_dev(major(devid), minor(devid), 0); if (path == NULL || strncmp(path, "/dev/md/", 8) != 0) { /* We would really like a name that provides * an MD_DEVNAME for udev. * The name needs to be unique both in /dev/md/ * and in this mapfile. * It needs to match what -I or -As would come * up with. * That means: * Check if array is in mdadm.conf * - if so use that. * determine trustworthy from homehost etc * find a unique name based on metadata name. * */ struct mddev_ident *match = conf_match(st, info, NULL, 0, NULL); struct stat stb; if (match && match->devname && match->devname[0] == '/') { path = match->devname; if (path[0] != '/') { strcpy(namebuf, "/dev/md/"); strcat(namebuf, path); path = namebuf; } } else { int unum = 0; char *sep = "_"; const char *name; int conflict = 1; if ((homehost == NULL || st->ss->match_home(st, homehost) != 1) && st->ss->match_home(st, "any") != 1 && (require_homehost || ! conf_name_is_free(info->name))) /* require a numeric suffix */ unum = 0; else /* allow name to be used as-is if no conflict */ unum = -1; name = info->name; if (!*name) { name = st->ss->name; if (!isdigit(name[strlen(name)-1]) && unum == -1) { unum = 0; sep = ""; } } if (strchr(name, ':')) { /* Probably a uniquifying * hostname prefix. Allow * without a suffix, and strip * hostname if it is us. */ if (homehost && unum == -1 && strncmp(name, homehost, strlen(homehost)) == 0 && name[strlen(homehost)] == ':') name += strlen(homehost)+1; unum = -1; } while (conflict) { if (unum >= 0) sprintf(namebuf, "/dev/md/%s%s%d", name, sep, unum); else sprintf(namebuf, "/dev/md/%s", name); unum++; if (lstat(namebuf, &stb) != 0 && (map == NULL || !map_by_name(&map, namebuf+8))) conflict = 0; } path = namebuf; } } map_add(&map, md->devnm, info->text_version, info->uuid, path); st->ss->free_super(st); free(info); break; } sysfs_free(sra); } /* Only trigger a change if we wrote a new map file */ if (map_write(map)) for (md = mdstat ; md ; md = md->next) { struct mdinfo *sra = sysfs_read(-1, md->devnm, GET_VERSION); if (sra) sysfs_uevent(sra, "change"); sysfs_free(sra); } map_free(map); free_mdstat(mdstat); }
int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust, struct supertype *forcest) { /* Read the raid superblock from a device and * display important content. * * If cannot be found, print reason: too small, bad magic * * Print: * version, ctime, level, size, raid+spare+ * prefered minor * uuid * * utime, state etc * * If (brief) gather devices for same array and just print a mdadm.conf line including devices= * if devlist==NULL, use conf_get_devs() */ int fd; void *super = NULL; int rv = 0; int err = 0; struct array { void *super; struct supertype *st; struct mdinfo info; struct mddev_ident_s ident; void *devs; struct array *next; int spares; } *arrays = NULL; for (; devlist ; devlist=devlist->next) { struct supertype *st = forcest; fd = dev_open(devlist->devname, O_RDONLY); if (fd < 0) { if (!scan) fprintf(stderr,Name ": cannot open %s: %s\n", devlist->devname, strerror(errno)); err = 1; } else { if (!st) st = guess_super(fd); if (st) err = st->ss->load_super(st, fd, &super, (brief||scan)?NULL:devlist->devname); else { if (!brief) fprintf(stderr, Name ": No md superblock detected on %s.\n", devlist->devname); err = 1; } close(fd); } if (err) { rv = 1; continue; } if (SparcAdjust) st->ss->update_super(NULL, super, "sparc2.2", devlist->devname, 0); /* Ok, its good enough to try, though the checksum could be wrong */ if (brief) { struct array *ap; char *d; for (ap=arrays; ap; ap=ap->next) { if (st->ss == ap->st->ss && st->ss->compare_super(&ap->super, super)==0) break; } if (!ap) { ap = malloc(sizeof(*ap)); ap->super = super; ap->devs = dl_head(); ap->next = arrays; ap->spares = 0; ap->st = st; arrays = ap; st->ss->getinfo_super(&ap->info, &ap->ident, super); } else { st->ss->getinfo_super(&ap->info, &ap->ident, super); free(super); } if (!(ap->info.disk.state & MD_DISK_SYNC)) ap->spares++; d = dl_strdup(devlist->devname); dl_add(ap->devs, d); } else { printf("%s:\n",devlist->devname); st->ss->examine_super(super); free(super); } } if (brief) { struct array *ap; for (ap=arrays; ap; ap=ap->next) { char sep='='; char *d; ap->st->ss->brief_examine_super(ap->super); if (ap->spares) printf(" spares=%d", ap->spares); if (brief > 1) { printf(" devices"); for (d=dl_next(ap->devs); d!= ap->devs; d=dl_next(d)) { printf("%c%s", sep, d); sep=','; } } free(ap->super); /* FIXME free ap */ if (ap->spares || brief > 1) printf("\n"); } } return rv; }
int Assemble(struct supertype *st, char *mddev, int mdfd, mddev_ident_t ident, char *conffile, mddev_dev_t devlist, int readonly, int runstop, char *update, int verbose, int force) { /* * The task of Assemble is to find a collection of * devices that should (according to their superblocks) * form an array, and to give this collection to the MD driver. * In Linux-2.4 and later, this involves submitting a * SET_ARRAY_INFO ioctl with no arg - to prepare * the array - and then submit a number of * ADD_NEW_DISK ioctls to add disks into * the array. Finally RUN_ARRAY might * be submitted to start the array. * * Much of the work of Assemble is in finding and/or * checking the disks to make sure they look right. * * If mddev is not set, then scan must be set and we * read through the config file for dev+uuid mapping * We recurse, setting mddev, for each device that * - isn't running * - has a valid uuid (or any uuid if !uuidset) * * If mddev is set, we try to determine state of md. * check version - must be at least 0.90.0 * check kernel version. must be at least 2.4. * If not, we can possibly fall back on START_ARRAY * Try to GET_ARRAY_INFO. * If possible, give up * If not, try to STOP_ARRAY just to make sure * * If !uuidset and scan, look in conf-file for uuid * If not found, give up * If !devlist and scan and uuidset, get list of devs from conf-file * * For each device: * Check superblock - discard if bad * Check uuid (set if we don't have one) - discard if no match * Check superblock similarity if we have a superblock - discard if different * Record events, devicenum * This should give us a list of devices for the array * We should collect the most recent event number * * Count disks with recent enough event count * While force && !enough disks * Choose newest rejected disks, update event count * mark clean and rewrite superblock * If recent kernel: * SET_ARRAY_INFO * foreach device with recent events : ADD_NEW_DISK * if runstop == 1 || "enough" disks and runstop==0 -> RUN_ARRAY * If old kernel: * Check the device numbers in superblock are right * update superblock if any changes * START_ARRAY * */ int old_linux = 0; int vers; void *first_super = NULL, *super = NULL; struct { char *devname; unsigned int major, minor; unsigned int oldmajor, oldminor; long long events; int uptodate; int state; int raid_disk; int disk_nr; } *devices; int *best = NULL; /* indexed by raid_disk */ unsigned int bestcnt = 0; int devcnt = 0; unsigned int okcnt, sparecnt; unsigned int req_cnt; unsigned int i; int most_recent = 0; int chosen_drive; int change = 0; int inargv = 0; int start_partial_ok = force || devlist==NULL; unsigned int num_devs; mddev_dev_t tmpdev; struct mdinfo info; struct mddev_ident_s ident2; char *avail; int nextspare = 0; vers = md_get_version(mdfd); if (vers <= 0) { fprintf(stderr, Name ": %s appears not to be an md device.\n", mddev); return 1; } if (vers < 9000) { fprintf(stderr, Name ": Assemble requires driver version 0.90.0 or later.\n" " Upgrade your kernel or try --build\n"); return 1; } if (get_linux_version() < 2004000) old_linux = 1; if (ioctl(mdfd, GET_ARRAY_INFO, &info.array)>=0) { fprintf(stderr, Name ": device %s already active - cannot assemble it\n", mddev); return 1; } ioctl(mdfd, STOP_ARRAY, NULL); /* just incase it was started but has no content */ /* * If any subdevs are listed, then any that don't * match ident are discarded. Remainder must all match and * become the array. * If no subdevs, then we scan all devices in the config file, but * there must be something in the identity */ if (!devlist && ident->uuid_set == 0 && ident->super_minor < 0 && ident->devices == NULL) { fprintf(stderr, Name ": No identity information available for %s - cannot assemble.\n", mddev); return 1; } if (devlist == NULL) devlist = conf_get_devs(conffile); else inargv = 1; tmpdev = devlist; num_devs = 0; while (tmpdev) { num_devs++; tmpdev = tmpdev->next; } devices = malloc(num_devs * sizeof(*devices)); if (!st && ident->st) st = ident->st; if (verbose>0) fprintf(stderr, Name ": looking for devices for %s\n", mddev); while ( devlist) { char *devname; int dfd; struct stat stb; struct supertype *tst = st; devname = devlist->devname; devlist = devlist->next; if (ident->devices && !match_oneof(ident->devices, devname)) { if ((inargv && verbose>=0) || verbose > 0) fprintf(stderr, Name ": %s is not one of %s\n", devname, ident->devices); continue; } if (super) { free(super); super = NULL; } dfd = dev_open(devname, O_RDONLY|O_EXCL); if (dfd < 0) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": cannot open device %s: %s\n", devname, strerror(errno)); } else if (fstat(dfd, &stb)< 0) { /* Impossible! */ fprintf(stderr, Name ": fstat failed for %s: %s\n", devname, strerror(errno)); } else if ((stb.st_mode & S_IFMT) != S_IFBLK) { fprintf(stderr, Name ": %s is not a block device.\n", devname); } else if (!tst && (tst = guess_super(dfd)) == NULL) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": no recogniseable superblock\n"); } else if (tst->ss->load_super(tst,dfd, &super, NULL)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf( stderr, Name ": no RAID superblock on %s\n", devname); } else { tst->ss->getinfo_super(&info, &ident2, super); } if (dfd >= 0) close(dfd); if (ident->uuid_set && (!update || strcmp(update, "uuid")!= 0) && (!super || same_uuid(info.uuid, ident->uuid, tst->ss->swapuuid)==0)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s has wrong uuid.\n", devname); continue; } if (ident->name[0] && (!super || strncmp(ident2.name, ident->name, 32)!=0)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s has wrong name.\n", devname); continue; } if (ident->super_minor != UnSet && (!super || ident->super_minor != info.array.md_minor)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s has wrong super-minor.\n", devname); continue; } if (ident->level != UnSet && (!super|| ident->level != info.array.level)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s has wrong raid level.\n", devname); continue; } if (ident->raid_disks != UnSet && (!super || ident->raid_disks!= info.array.raid_disks)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s requires wrong number of drives.\n", devname); continue; } /* If we are this far, then we are commited to this device. * If the super_block doesn't exist, or doesn't match others, * then we cannot continue */ if (!super) { fprintf(stderr, Name ": %s has no superblock - assembly aborted\n", devname); free(first_super); return 1; } st = tst; /* commit to this format, if haven't already */ if (st->ss->compare_super(&first_super, super)) { fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n", devname); free(super); free(first_super); return 1; } /* looks like a good enough match to update the super block if needed */ if (update) { /* prepare useful information in info structures */ struct stat stb2; fstat(mdfd, &stb2); info.array.md_minor = minor(stb2.st_rdev); if (strcmp(update, "uuid")==0 && !ident->uuid_set) { int rfd; if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 || read(rfd, ident->uuid, 16) != 16) { *(__u32*)(ident->uuid) = random(); *(__u32*)(ident->uuid+1) = random(); *(__u32*)(ident->uuid+2) = random(); *(__u32*)(ident->uuid+3) = random(); } if (rfd >= 0) close(rfd); ident->uuid_set = 1; } memcpy(info.uuid, ident->uuid, 16); st->ss->update_super(&info, super, update, devname, verbose); dfd = dev_open(devname, O_RDWR|O_EXCL); if (dfd < 0) fprintf(stderr, Name ": Cannot open %s for superblock update\n", devname); else if (st->ss->store_super(st, dfd, super)) fprintf(stderr, Name ": Could not re-write superblock on %s.\n", devname); if (dfd >= 0) close(dfd); } if (verbose > 0) fprintf(stderr, Name ": %s is identified as a member of %s, slot %d.\n", devname, mddev, info.disk.raid_disk); devices[devcnt].devname = devname; devices[devcnt].major = major(stb.st_rdev); devices[devcnt].minor = minor(stb.st_rdev); devices[devcnt].oldmajor = info.disk.major; devices[devcnt].oldminor = info.disk.minor; devices[devcnt].events = info.events; devices[devcnt].raid_disk = info.disk.raid_disk; devices[devcnt].disk_nr = info.disk.number; devices[devcnt].uptodate = 0; devices[devcnt].state = info.disk.state; if (most_recent < devcnt) { if (devices[devcnt].events > devices[most_recent].events) most_recent = devcnt; } if (info.array.level == -4) /* with multipath, the raid_disk from the superblock is meaningless */ i = devcnt; else i = devices[devcnt].raid_disk; if (i+1 == 0) { if (nextspare < info.array.raid_disks) nextspare = info.array.raid_disks; i = nextspare++; } if (i < 10000) { if (i >= bestcnt) { unsigned int newbestcnt = i+10; int *newbest = malloc(sizeof(int)*newbestcnt); unsigned int c; for (c=0; c < newbestcnt; c++) if (c < bestcnt) newbest[c] = best[c]; else newbest[c] = -1; if (best)free(best); best = newbest; bestcnt = newbestcnt; } if (best[i] == -1 || devices[best[i]].events < devices[devcnt].events) best[i] = devcnt; } devcnt++; } if (super) free(super); super = NULL; if (update && strcmp(update, "byteorder")==0) st->minor_version = 90; if (devcnt == 0) { fprintf(stderr, Name ": no devices found for %s\n", mddev); free(first_super); return 1; } st->ss->getinfo_super(&info, &ident2, first_super); /* now we have some devices that might be suitable. * I wonder how many */ avail = malloc(info.array.raid_disks); memset(avail, 0, info.array.raid_disks); okcnt = 0; sparecnt=0; for (i=0; i< bestcnt ;i++) { int j = best[i]; int event_margin = 1; /* always allow a difference of '1' * like the kernel does */ if (j < 0) continue; /* note: we ignore error flags in multipath arrays * as they don't make sense */ if (info.array.level != -4) if (!(devices[j].state & (1<<MD_DISK_SYNC))) { if (!(devices[j].state & (1<<MD_DISK_FAULTY))) sparecnt++; continue; } if (devices[j].events+event_margin >= devices[most_recent].events) { devices[j].uptodate = 1; if (i < info.array.raid_disks) { okcnt++; avail[i]=1; } else sparecnt++; } } while (force && !enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt)) { /* Choose the newest best drive which is * not up-to-date, update the superblock * and add it. */ int fd; chosen_drive = -1; for (i=0; i<info.array.raid_disks && i < bestcnt; i++) { int j = best[i]; if (j>=0 && !devices[j].uptodate && devices[j].events > 0 && (chosen_drive < 0 || devices[j].events > devices[chosen_drive].events)) chosen_drive = j; } if (chosen_drive < 0) break; if (verbose >= 0) fprintf(stderr, Name ": forcing event count in %s(%d) from %d upto %d\n", devices[chosen_drive].devname, devices[chosen_drive].raid_disk, (int)(devices[chosen_drive].events), (int)(devices[most_recent].events)); fd = dev_open(devices[chosen_drive].devname, O_RDWR|O_EXCL); if (fd < 0) { fprintf(stderr, Name ": Couldn't open %s for write - not updating\n", devices[chosen_drive].devname); devices[chosen_drive].events = 0; continue; } if (st->ss->load_super(st,fd, &super, NULL)) { close(fd); fprintf(stderr, Name ": RAID superblock disappeared from %s - not updating.\n", devices[chosen_drive].devname); devices[chosen_drive].events = 0; continue; } info.events = devices[most_recent].events; st->ss->update_super(&info, super, "force", devices[chosen_drive].devname, verbose); if (st->ss->store_super(st, fd, super)) { close(fd); fprintf(stderr, Name ": Could not re-write superblock on %s\n", devices[chosen_drive].devname); devices[chosen_drive].events = 0; free(super); continue; } close(fd); devices[chosen_drive].events = devices[most_recent].events; devices[chosen_drive].uptodate = 1; avail[chosen_drive] = 1; okcnt++; free(super); } /* Now we want to look at the superblock which the kernel will base things on * and compare the devices that we think are working with the devices that the * superblock thinks are working. * If there are differences and --force is given, then update this chosen * superblock. */ chosen_drive = -1; super = NULL; for (i=0; chosen_drive < 0 && i<bestcnt; i++) { int j = best[i]; int fd; if (j<0) continue; if (!devices[j].uptodate) continue; chosen_drive = j; if ((fd=dev_open(devices[j].devname, O_RDONLY|O_EXCL))< 0) { fprintf(stderr, Name ": Cannot open %s: %s\n", devices[j].devname, strerror(errno)); return 1; } if (st->ss->load_super(st,fd, &super, NULL)) { close(fd); fprintf(stderr, Name ": RAID superblock has disappeared from %s\n", devices[j].devname); return 1; } close(fd); } if (super == NULL) { fprintf(stderr, Name ": No suitable drives found for %s\n", mddev); return 1; } st->ss->getinfo_super(&info, &ident2, super); for (i=0; i<bestcnt; i++) { int j = best[i]; unsigned int desired_state; if (i < info.array.raid_disks) desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC); else desired_state = 0; if (j<0) continue; if (!devices[j].uptodate) continue; info.disk.number = devices[j].disk_nr; info.disk.raid_disk = i; info.disk.state = desired_state; if (devices[j].uptodate && st->ss->update_super(&info, super, "assemble", NULL, verbose)) { if (force) { if (verbose >= 0) fprintf(stderr, Name ": " "clearing FAULTY flag for device %d in %s for %s\n", j, mddev, devices[j].devname); change = 1; } else { if (verbose >= -1) fprintf(stderr, Name ": " "device %d in %s has wrong state in superblock, but %s seems ok\n", i, mddev, devices[j].devname); } } #if 0 if (!devices[j].uptodate && !(super.disks[i].state & (1 << MD_DISK_FAULTY))) { fprintf(stderr, Name ": devices %d of %s is not marked FAULTY in superblock, but cannot be found\n", i, mddev); } #endif } if (force && okcnt == info.array.raid_disks-1) { /* FIXME check event count */ change += st->ss->update_super(&info, super, "force", devices[chosen_drive].devname, verbose); } if (change) { int fd; fd = dev_open(devices[chosen_drive].devname, O_RDWR|O_EXCL); if (fd < 0) { fprintf(stderr, Name ": Could open %s for write - cannot Assemble array.\n", devices[chosen_drive].devname); return 1; } if (st->ss->store_super(st, fd, super)) { close(fd); fprintf(stderr, Name ": Could not re-write superblock on %s\n", devices[chosen_drive].devname); return 1; } close(fd); } /* count number of in-sync devices according to the superblock. * We must have this number to start the array without -s or -R */ req_cnt = info.array.working_disks; /* Almost ready to actually *do* something */ if (!old_linux) { int rv; if ((vers % 100) >= 1) { /* can use different versions */ mdu_array_info_t inf; memset(&inf, 0, sizeof(inf)); inf.major_version = st->ss->major; inf.minor_version = st->minor_version; rv = ioctl(mdfd, SET_ARRAY_INFO, &inf); } else rv = ioctl(mdfd, SET_ARRAY_INFO, NULL); if (rv) { fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n", mddev, strerror(errno)); return 1; } if (ident->bitmap_fd >= 0) { if (ioctl(mdfd, SET_BITMAP_FILE, ident->bitmap_fd) != 0) { fprintf(stderr, Name ": SET_BITMAP_FILE failed.\n"); return 1; } } /* First, add the raid disks, but add the chosen one last */ for (i=0; i<= bestcnt; i++) { int j; if (i < bestcnt) { j = best[i]; if (j == chosen_drive) continue; } else j = chosen_drive; if (j >= 0 /* && devices[j].uptodate */) { mdu_disk_info_t disk; memset(&disk, 0, sizeof(disk)); disk.major = devices[j].major; disk.minor = devices[j].minor; if (ioctl(mdfd, ADD_NEW_DISK, &disk)!=0) { fprintf(stderr, Name ": failed to add %s to %s: %s\n", devices[j].devname, mddev, strerror(errno)); if (i < info.array.raid_disks || i == bestcnt) okcnt--; else sparecnt--; } else if (verbose > 0) fprintf(stderr, Name ": added %s to %s as %d\n", devices[j].devname, mddev, devices[j].raid_disk); } else if (verbose > 0 && i < info.array.raid_disks) fprintf(stderr, Name ": no uptodate device for slot %d of %s\n", i, mddev); } if (runstop == 1 || (runstop == 0 && ( enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt) && (okcnt >= req_cnt || start_partial_ok) ))) { if (ioctl(mdfd, RUN_ARRAY, NULL)==0) { if (verbose >= 0) { fprintf(stderr, Name ": %s has been started with %d drive%s", mddev, okcnt, okcnt==1?"":"s"); if (okcnt < info.array.raid_disks) fprintf(stderr, " (out of %d)", info.array.raid_disks); if (sparecnt) fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); fprintf(stderr, ".\n"); } return 0; } fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n", mddev, strerror(errno)); return 1; } if (runstop == -1) { fprintf(stderr, Name ": %s assembled from %d drive%s, but not started.\n", mddev, okcnt, okcnt==1?"":"s"); return 0; } if (verbose >= 0) { fprintf(stderr, Name ": %s assembled from %d drive%s", mddev, okcnt, okcnt==1?"":"s"); if (sparecnt) fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); if (!enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt)) fprintf(stderr, " - not enough to start the array.\n"); else { if (req_cnt == info.array.raid_disks) fprintf(stderr, " - need all %d to start it", req_cnt); else fprintf(stderr, " - need %d of %d to start", req_cnt, info.array.raid_disks); fprintf(stderr, " (use --run to insist).\n"); } } return 1; } else { /* The "chosen_drive" is a good choice, and if necessary, the superblock has * been updated to point to the current locations of devices. * so we can just start the array */ unsigned long dev; dev = makedev(devices[chosen_drive].major, devices[chosen_drive].minor); if (ioctl(mdfd, START_ARRAY, dev)) { fprintf(stderr, Name ": Cannot start array: %s\n", strerror(errno)); } } return 0; }
int Query(char *dev) { /* Give a brief description of the device, * whether it is an md device and whether it has * a superblock */ int fd = open(dev, O_RDONLY); int vers; int ioctlerr; int superror; struct mdinfo info; mdu_array_info_t array; struct supertype *st = NULL; unsigned long long larray_size; struct stat stb; char *mddev; mdu_disk_info_t disc; char *activity; if (fd < 0){ pr_err("cannot open %s: %s\n", dev, strerror(errno)); return 1; } vers = md_get_version(fd); if (ioctl(fd, GET_ARRAY_INFO, &array)<0) ioctlerr = errno; else ioctlerr = 0; fstat(fd, &stb); if (vers>=9000 && !ioctlerr) { if (!get_dev_size(fd, NULL, &larray_size)) larray_size = 0; } if (vers < 0) printf("%s: is not an md array\n", dev); else if (vers < 9000) printf("%s: is an md device, but kernel cannot provide details\n", dev); else if (ioctlerr == ENODEV) printf("%s: is an md device which is not active\n", dev); else if (ioctlerr) printf("%s: is an md device, but gives \"%s\" when queried\n", dev, strerror(ioctlerr)); else { printf("%s: %s %s %d devices, %d spare%s. Use mdadm --detail for more detail.\n", dev, human_size_brief(larray_size), map_num(pers, array.level), array.raid_disks, array.spare_disks, array.spare_disks==1?"":"s"); } st = guess_super(fd); if (st) superror = st->ss->load_super(st, fd, dev); else superror = -1; close(fd); if (superror == 0) { /* array might be active... */ st->ss->getinfo_super(st, &info, NULL); if (st->ss == &super0) { mddev = get_md_name(info.array.md_minor); disc.number = info.disk.number; activity = "undetected"; if (mddev && (fd = open(mddev, O_RDONLY))>=0) { if (md_get_version(fd) >= 9000 && ioctl(fd, GET_ARRAY_INFO, &array)>= 0) { if (ioctl(fd, GET_DISK_INFO, &disc) >= 0 && makedev((unsigned)disc.major,(unsigned)disc.minor) == stb.st_rdev) activity = "active"; else activity = "mismatch"; } close(fd); } } else { activity = "unknown"; mddev = "array"; } printf("%s: device %d in %d device %s %s %s. Use mdadm --examine for more detail.\n", dev, info.disk.number, info.array.raid_disks, activity, map_num(pers, info.array.level), mddev); if (st->ss == &super0) put_md_name(mddev); } return 0; }