+
+static int scan_assemble(struct supertype *ss,
+ struct context *c,
+ struct mddev_ident *ident)
+{
+ struct mddev_ident *a, *array_list = conf_get_ident(NULL);
+ struct mddev_dev *devlist = conf_get_devs();
+ struct map_ent *map = NULL;
+ int cnt = 0;
+ int rv = 0;
+ int failures, successes;
+
+ if (conf_verify_devnames(array_list)) {
+ pr_err("Duplicate MD device names in conf file were found.\n");
+ return 1;
+ }
+ if (devlist == NULL) {
+ pr_err("No devices listed in conf file were found.\n");
+ return 1;
+ }
+ for (a = array_list; a ; a = a->next) {
+ a->assembled = 0;
+ if (a->autof == 0)
+ a->autof = c->autof;
+ }
+ if (map_lock(&map))
+ pr_err("failed to get exclusive lock on mapfile\n");
+ do {
+ failures = 0;
+ successes = 0;
+ rv = 0;
+ for (a = array_list; a ; a = a->next) {
+ int r;
+ if (a->assembled)
+ continue;
+ if (a->devname &&
+ strcasecmp(a->devname, "<ignore>") == 0)
+ continue;
+
+ r = Assemble(ss, a->devname,
+ a, NULL, c);
+ if (r == 0) {
+ a->assembled = 1;
+ successes++;
+ } else
+ failures++;
+ rv |= r;
+ cnt++;
+ }
+ } while (failures && successes);
+ if (c->homehost && cnt == 0) {
+ /* Maybe we can auto-assemble something.
+ * Repeatedly call Assemble in auto-assemble mode
+ * until it fails
+ */
+ int rv2;
+ int acnt;
+ ident->autof = c->autof;
+ do {
+ struct mddev_dev *devlist = conf_get_devs();
+ acnt = 0;
+ do {
+ rv2 = Assemble(ss, NULL,
+ ident,
+ devlist, c);
+ if (rv2==0) {
+ cnt++;
+ acnt++;
+ }
+ } while (rv2!=2);
+ /* Incase there are stacked devices, we need to go around again */
+ } while (acnt);
+ if (cnt == 0 && rv == 0) {
+ pr_err("No arrays found in config file or automatically\n");
+ rv = 1;
+ } else if (cnt)
+ rv = 0;
+ } else if (cnt == 0 && rv == 0) {
+ pr_err("No arrays found in config file\n");
+ rv = 1;
+ }
+ map_unlock(&map);
+ return rv;
+}
+
+static int misc_scan(char devmode, struct context *c)
+{
+ /* apply --detail or --wait-clean to
+ * all devices in /proc/mdstat
+ */
+ struct mdstat_ent *ms = mdstat_read(0, 1);
+ struct mdstat_ent *e;
+ struct map_ent *map = NULL;
+ int members;
+ int rv = 0;
+
+ for (members = 0; members <= 1; members++) {
+ for (e=ms ; e ; e=e->next) {
+ char *name = NULL;
+ struct map_ent *me;
+ struct stat stb;
+ int member = e->metadata_version &&
+ strncmp(e->metadata_version,
+ "external:/", 10) == 0;
+ if (members != member)
+ continue;
+ me = map_by_devnm(&map, e->devnm);
+ if (me && me->path
+ && strcmp(me->path, "/unknown") != 0)
+ name = me->path;
+ if (name == NULL ||
+ stat(name, &stb) != 0)
+ name = get_md_name(e->devnm);
+
+ if (!name) {
+ pr_err("cannot find device file for %s\n",
+ e->dev);
+ continue;
+ }
+ if (devmode == 'D')
+ rv |= Detail(name, c);
+ else
+ rv |= WaitClean(name, -1, c->verbose);
+ put_md_name(name);
+ }
+ }
+ free_mdstat(ms);
+ return rv;
+}
+
+static int stop_scan(int verbose)
+{
+ /* apply --stop to all devices in /proc/mdstat */
+ /* Due to possible stacking of devices, repeat until
+ * nothing more can be stopped
+ */
+ int progress=1, err;
+ int last = 0;
+ int rv = 0;
+ do {
+ struct mdstat_ent *ms = mdstat_read(0, 0);
+ struct mdstat_ent *e;
+
+ if (!progress) last = 1;
+ progress = 0; err = 0;
+ for (e=ms ; e ; e=e->next) {
+ char *name = get_md_name(e->devnm);
+ int mdfd;
+
+ if (!name) {
+ pr_err("cannot find device file for %s\n",
+ e->dev);
+ continue;
+ }
+ mdfd = open_mddev(name, 1);
+ if (mdfd >= 0) {
+ if (Manage_stop(name, mdfd, verbose, !last))
+ err = 1;
+ else
+ progress = 1;
+ close(mdfd);
+ }
+
+ put_md_name(name);
+ }
+ free_mdstat(ms);
+ } while (!last && err);
+ if (err)
+ rv |= 1;
+ return rv;
+}
+
+static int misc_list(struct mddev_dev *devlist,
+ struct mddev_ident *ident,
+ char *dump_directory,
+ struct supertype *ss, struct context *c)
+{
+ struct mddev_dev *dv;
+ int rv = 0;
+
+ for (dv=devlist ; dv; dv=(rv & 16) ? NULL : dv->next) {
+ int mdfd;
+
+ switch(dv->disposition) {
+ case 'D':
+ rv |= Detail(dv->devname, c);
+ continue;
+ case KillOpt: /* Zero superblock */
+ if (ss)
+ rv |= Kill(dv->devname, ss, c->force, c->verbose,0);
+ else {
+ int v = c->verbose;
+ do {
+ rv |= Kill(dv->devname, NULL, c->force, v, 0);
+ v = -1;
+ } while (rv == 0);
+ rv &= ~2;
+ }
+ continue;
+ case 'Q':
+ rv |= Query(dv->devname); continue;
+ case 'X':
+ rv |= ExamineBitmap(dv->devname, c->brief, ss); continue;
+ case ExamineBB:
+ rv |= ExamineBadblocks(dv->devname, c->brief, ss); continue;
+ case 'W':
+ case WaitOpt:
+ rv |= Wait(dv->devname); continue;
+ case Waitclean:
+ rv |= WaitClean(dv->devname, -1, c->verbose); continue;
+ case KillSubarray:
+ rv |= Kill_subarray(dv->devname, c->subarray, c->verbose);
+ continue;
+ case UpdateSubarray:
+ if (c->update == NULL) {
+ pr_err("-U/--update must be specified with --update-subarray\n");
+ rv |= 1;
+ continue;
+ }
+ rv |= Update_subarray(dv->devname, c->subarray,
+ c->update, ident, c->verbose);
+ continue;
+ case Dump:
+ rv |= Dump_metadata(dv->devname, dump_directory, c, ss);
+ continue;
+ case Restore:
+ rv |= Restore_metadata(dv->devname, dump_directory, c, ss,
+ (dv == devlist && dv->next == NULL));
+ continue;
+ case Action:
+ rv |= SetAction(dv->devname, c->action);
+ continue;
+ }
+ if (dv->devname[0] == '/')
+ mdfd = open_mddev(dv->devname, 1);
+ else {
+ mdfd = open_dev(dv->devname);
+ if (mdfd < 0)
+ pr_err("Cannot open %s\n", dv->devname);
+ }
+ if (mdfd>=0) {
+ switch(dv->disposition) {
+ case 'R':
+ c->runstop = 1;
+ rv |= Manage_run(dv->devname, mdfd, c); break;
+ case 'S':
+ rv |= Manage_stop(dv->devname, mdfd, c->verbose, 0); break;
+ case 'o':
+ rv |= Manage_ro(dv->devname, mdfd, 1); break;
+ case 'w':
+ rv |= Manage_ro(dv->devname, mdfd, -1); break;
+ }
+ close(mdfd);
+ } else
+ rv |= 1;
+ }
+ return rv;
+}
+
+int SetAction(char *dev, char *action)
+{
+ int fd = open(dev, O_RDONLY);
+ struct mdinfo mdi;
+ if (fd < 0) {
+ pr_err("Couldn't open %s: %s\n", dev, strerror(errno));
+ return 1;
+ }
+ sysfs_init(&mdi, fd, NULL);
+ close(fd);
+ if (!mdi.sys_name[0]) {
+ pr_err("%s is no an md array\n", dev);
+ return 1;
+ }
+
+ if (sysfs_set_str(&mdi, NULL, "sync_action", action) < 0) {
+ pr_err("Count not set action for %s to %s: %s\n",
+ dev, action, strerror(errno));
+ return 1;
+ }
+ return 0;
+}