コード例 #1
0
ファイル: config.c プロジェクト: DanielRussell/mdadm
struct mddev_dev *load_containers(void)
{
	struct mdstat_ent *mdstat = mdstat_read(0, 0);
	struct mdstat_ent *ent;
	struct mddev_dev *d;
	struct mddev_dev *rv = NULL;
	struct map_ent *map = NULL, *me;

	if (!mdstat)
		return NULL;

	for (ent = mdstat; ent; ent = ent->next)
		if (ent->metadata_version &&
		    strncmp(ent->metadata_version, "external:", 9) == 0 &&
		    !is_subarray(&ent->metadata_version[9])) {
			d = xmalloc(sizeof(*d));
			memset(d, 0, sizeof(*d));
			me = map_by_devnm(&map, ent->dev);
			if (me)
				d->devname = xstrdup(me->path);
			else if (asprintf(&d->devname, "/dev/%s", ent->dev) < 0) {
				free(d);
				continue;
			}
			d->next = rv;
			rv = d;
		}
	free_mdstat(mdstat);
	map_free(map);

	return rv;
}
コード例 #2
0
ファイル: msg.c プロジェクト: saschaefer/mdadm-deb-pkg
int ack(int fd, int tmo)
{
	struct metadata_update msg = { .len = 0 };

	return send_message(fd, &msg, tmo);
}

int wait_reply(int fd, int tmo)
{
	struct metadata_update msg;
	int err = receive_message(fd, &msg, tmo);

	/* mdmon sent extra data, but caller only cares that we got a
	 * successful reply
	 */
	if (err == 0 && msg.len > 0)
		free(msg.buf);

	return err;
}

int connect_monitor(char *devname)
{
	char path[100];
	int sfd;
	long fl;
	struct sockaddr_un addr;
	int pos;
	char *c;

	pos = sprintf(path, "%s/", MDMON_DIR);
	if (is_subarray(devname)) {
		devname++;
		c = strchr(devname, '/');
		if (!c)
			return -1;
		snprintf(&path[pos], c - devname + 1, "%s", devname);
		pos += c - devname;
	} else
		pos += sprintf(&path[pos], "%s", devname);
	sprintf(&path[pos], ".sock");

	sfd = socket(PF_LOCAL, SOCK_STREAM, 0);
	if (sfd < 0)
		return -1;

	addr.sun_family = PF_LOCAL;
	strcpy(addr.sun_path, path);
	if (connect(sfd, &addr, sizeof(addr)) < 0) {
		close(sfd);
		return -1;
	}

	fl = fcntl(sfd, F_GETFL, 0);
	fl |= O_NONBLOCK;
	fcntl(sfd, F_SETFL, fl);

	return sfd;
}
コード例 #3
0
ファイル: Monitor.c プロジェクト: Distrotech/mdadm
/* Not really Monitor but ... */
int Wait(char *dev)
{
	struct stat stb;
	char devnm[32];
	int rv = 1;
	int frozen_remaining = 3;

	if (stat(dev, &stb) != 0) {
		pr_err("Cannot find %s: %s\n", dev,
			strerror(errno));
		return 2;
	}
	strcpy(devnm, stat2devnm(&stb));

	while(1) {
		struct mdstat_ent *ms = mdstat_read(1, 0);
		struct mdstat_ent *e;

		for (e=ms ; e; e=e->next)
			if (strcmp(e->devnm, devnm) == 0)
				break;

		if (e && e->percent == RESYNC_NONE) {
			/* We could be in the brief pause before something
			 * starts. /proc/mdstat doesn't show that, but
			 * sync_action does.
			 */
			struct mdinfo mdi;
			char buf[21];
			sysfs_init(&mdi, -1, devnm);
			if (sysfs_get_str(&mdi, NULL, "sync_action",
					  buf, 20) > 0 &&
			    strcmp(buf,"idle\n") != 0) {
				e->percent = RESYNC_UNKNOWN;
				if (strcmp(buf, "frozen\n") == 0) {
					if (frozen_remaining == 0)
						e->percent = RESYNC_NONE;
					else
						frozen_remaining -= 1;
				}
			}
		}
		if (!e || e->percent == RESYNC_NONE) {
			if (e && e->metadata_version &&
			    strncmp(e->metadata_version, "external:", 9) == 0) {
				if (is_subarray(&e->metadata_version[9]))
					ping_monitor(&e->metadata_version[9]);
				else
					ping_monitor(devnm);
			}
			free_mdstat(ms);
			return rv;
		}
		free_mdstat(ms);
		rv = 0;
		mdstat_wait(5);
	}
}
コード例 #4
0
ファイル: mapfile.c プロジェクト: Distrotech/mdadm
/* sets the proper subarray and container_dev according to the metadata
 * version super_by_fd does this automatically, this routine is meant as
 * a supplement for guess_super()
 */
static char *get_member_info(struct mdstat_ent *ent)
{

	if (ent->metadata_version == NULL ||
	    strncmp(ent->metadata_version, "external:", 9) != 0)
		return NULL;

	if (is_subarray(&ent->metadata_version[9])) {
		char *subarray;

		subarray = strrchr(ent->metadata_version, '/');
		return subarray + 1;
	}
	return NULL;
}
コード例 #5
0
ファイル: Monitor.c プロジェクト: Jongil-Park/mdadm
/* Not really Monitor but ... */
int Wait(char *dev)
{
	struct stat stb;
	int devnum;
	int rv = 1;

	if (stat(dev, &stb) != 0) {
		fprintf(stderr, Name ": Cannot find %s: %s\n", dev,
			strerror(errno));
		return 2;
	}
	devnum = stat2devnum(&stb);

	while(1) {
		struct mdstat_ent *ms = mdstat_read(1, 0);
		struct mdstat_ent *e;

		for (e=ms ; e; e=e->next)
			if (e->devnum == devnum)
				break;

		if (!e || e->percent < 0) {
			if (e && e->metadata_version &&
			    strncmp(e->metadata_version, "external:", 9) == 0) {
				if (is_subarray(&e->metadata_version[9]))
					ping_monitor(&e->metadata_version[9]);
				else
					ping_monitor(devnum2devname(devnum));
			}
			free_mdstat(ms);
			return rv;
		}
		free_mdstat(ms);
		rv = 0;
		mdstat_wait(5);
	}
}
コード例 #6
0
ファイル: mdmon.c プロジェクト: DanielRussell/mdadm
int main(int argc, char *argv[])
{
	char *container_name = NULL;
	char *devnm = NULL;
	int status = 0;
	int opt;
	int all = 0;
	int takeover = 0;
	int dofork = 1;
	static struct option options[] = {
		{"all", 0, NULL, 'a'},
		{"takeover", 0, NULL, 't'},
		{"help", 0, NULL, 'h'},
		{"offroot", 0, NULL, OffRootOpt},
		{"foreground", 0, NULL, 'F'},
		{NULL, 0, NULL, 0}
	};

	if (in_initrd()) {
		/*
		 * set first char of argv[0] to @. This is used by
		 * systemd to signal that the task was launched from
		 * initrd/initramfs and should be preserved during shutdown
		 */
		argv[0][0] = '@';
	}

	while ((opt = getopt_long(argc, argv, "thaF", options, NULL)) != -1) {
		switch (opt) {
		case 'a':
			container_name = argv[optind-1];
			all = 1;
			break;
		case 't':
			takeover = 1;
			break;
		case 'F':
			dofork = 0;
			break;
		case OffRootOpt:
			argv[0][0] = '@';
			break;
		case 'h':
		default:
			usage();
			break;
		}
	}

	if (all == 0 && container_name == NULL) {
		if (argv[optind])
			container_name = argv[optind];
	}

	if (container_name == NULL)
		usage();

	if (argc - optind > 1)
		usage();

	if (strcmp(container_name, "/proc/mdstat") == 0)
		all = 1;

	if (all) {
		struct mdstat_ent *mdstat, *e;
		int container_len = strlen(container_name);

		/* launch an mdmon instance for each container found */
		mdstat = mdstat_read(0, 0);
		for (e = mdstat; e; e = e->next) {
			if (e->metadata_version &&
			    strncmp(e->metadata_version, "external:", 9) == 0 &&
			    !is_subarray(&e->metadata_version[9])) {
				/* update cmdline so this mdmon instance can be
				 * distinguished from others in a call to ps(1)
				 */
				if (strlen(e->devnm) <= (unsigned)container_len) {
					memset(container_name, 0, container_len);
					sprintf(container_name, "%s", e->devnm);
				}
				status |= mdmon(e->devnm, 1, takeover);
			}
		}
		free_mdstat(mdstat);

		return status;
	} else if (strncmp(container_name, "md", 2) == 0) {
		int id = devnm2devid(container_name);
		if (id)
			devnm = container_name;
	} else {
		struct stat st;

		if (stat(container_name, &st) == 0)
			devnm = xstrdup(stat2devnm(&st));
	}

	if (!devnm) {
		pr_err("%s is not a valid md device name\n",
			container_name);
		exit(1);
	}
	return mdmon(devnm, dofork && do_fork(), takeover);
}
コード例 #7
0
ファイル: Monitor.c プロジェクト: Distrotech/mdadm
static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
			  int test, struct alert_info *info)
{
	struct mdstat_ent *mse;
	int new_found = 0;
	char *name;

	for (mse=mdstat; mse; mse=mse->next)
		if (mse->devnm[0] &&
		    (!mse->level  || /* retrieve containers */
		     (strcmp(mse->level, "raid0") != 0 &&
		      strcmp(mse->level, "linear") != 0))
			) {
			struct state *st = xcalloc(1, sizeof *st);
			mdu_array_info_t array;
			int fd;

			name = get_md_name(mse->devnm);
			if (!name) {
				free(st);
				continue;
			}

			st->devname = xstrdup(name);
			if ((fd = open(st->devname, O_RDONLY)) < 0 ||
			    ioctl(fd, GET_ARRAY_INFO, &array)< 0) {
				/* no such array */
				if (fd >=0) close(fd);
				put_md_name(st->devname);
				free(st->devname);
				if (st->metadata) {
					st->metadata->ss->free_super(st->metadata);
					free(st->metadata);
				}
				free(st);
				continue;
			}
			close(fd);
			st->next = *statelist;
			st->err = 1;
			st->from_auto = 1;
			strcpy(st->devnm, mse->devnm);
			st->percent = RESYNC_UNKNOWN;
			st->expected_spares = -1;
			if (mse->metadata_version &&
			    strncmp(mse->metadata_version, "external:", 9) == 0 &&
			    is_subarray(mse->metadata_version+9)) {
				char *sl;
				strcpy(st->parent_devnm,
					mse->metadata_version+10);
				sl = strchr(st->parent_devnm, '/');
				*sl = 0;
			} else
				st->parent_devnm[0] = 0;
			*statelist = st;
			if (test)
				alert("TestMessage", st->devname, NULL, info);
			new_found = 1;
		}
	return new_found;
}
コード例 #8
0
ファイル: Monitor.c プロジェクト: Distrotech/mdadm
static int check_array(struct state *st, struct mdstat_ent *mdstat,
		       int test, struct alert_info *ainfo,
		       int increments, char *prefer)
{
	/* Update the state 'st' to reflect any changes shown in mdstat,
	 * or found by directly examining the array, and return
	 * '1' if the array is degraded, or '0' if it is optimal (or dead).
	 */
	struct { int state, major, minor; } info[MAX_DISKS];
	mdu_array_info_t array;
	struct mdstat_ent *mse = NULL, *mse2;
	char *dev = st->devname;
	int fd = -1;
	int i;
	int remaining_disks;
	int last_disk;
	int new_array = 0;

	if (test)
		alert("TestMessage", dev, NULL, ainfo);
	if (st->devnm[0])
		fd = open("/sys/block", O_RDONLY|O_DIRECTORY);
	if (fd >= 0) {
		/* Don't open the device unless it is present and
		 * active in sysfs.
		 */
		char buf[10];
		close(fd);
		fd = sysfs_open(st->devnm, NULL, "array_state");
		if (fd < 0 ||
		    read(fd, buf, 10) < 5 ||
		    strncmp(buf,"clear",5) == 0 ||
		    strncmp(buf,"inact",5) == 0) {
			if (fd >= 0)
				close(fd);
			fd = sysfs_open(st->devnm, NULL, "level");
			if (fd < 0 || read(fd, buf, 10) != 0) {
				if (fd >= 0)
					close(fd);
				if (!st->err)
					alert("DeviceDisappeared", dev, NULL, ainfo);
				st->err++;
				return 0;
			}
		}
		close(fd);
	}
	fd = open(dev, O_RDONLY);
	if (fd < 0) {
		if (!st->err)
			alert("DeviceDisappeared", dev, NULL, ainfo);
		st->err++;
		return 0;
	}
	fcntl(fd, F_SETFD, FD_CLOEXEC);
	if (ioctl(fd, GET_ARRAY_INFO, &array)<0) {
		if (!st->err)
			alert("DeviceDisappeared", dev, NULL, ainfo);
		st->err++;
		close(fd);
		return 0;
	}
	/* It's much easier to list what array levels can't
	 * have a device disappear than all of them that can
	 */
	if (array.level == 0 || array.level == -1) {
		if (!st->err && !st->from_config)
			alert("DeviceDisappeared", dev, " Wrong-Level", ainfo);
		st->err++;
		close(fd);
		return 0;
	}
	if (st->devnm[0] == 0)
		strcpy(st->devnm, fd2devnm(fd));

	for (mse2 = mdstat ; mse2 ; mse2=mse2->next)
		if (strcmp(mse2->devnm, st->devnm) == 0) {
			mse2->devnm[0] = 0; /* flag it as "used" */
			mse = mse2;
		}

	if (!mse) {
		/* duplicated array in statelist
		 * or re-created after reading mdstat*/
		st->err++;
		close(fd);
		return 0;
	}
	/* this array is in /proc/mdstat */
	if (array.utime == 0)
		/* external arrays don't update utime, so
		 * just make sure it is always different. */
		array.utime = st->utime + 1;;

	if (st->err) {
		/* New array appeared where previously had an error */
		st->err = 0;
		st->percent = RESYNC_NONE;
		new_array = 1;
		alert("NewArray", st->devname, NULL, ainfo);
	}

	if (st->utime == array.utime &&
	    st->failed == array.failed_disks &&
	    st->working == array.working_disks &&
	    st->spare == array.spare_disks &&
	    (mse == NULL  || (
		    mse->percent == st->percent
		    ))) {
		close(fd);
		if ((st->active < st->raid) && st->spare == 0)
			return 1;
		else
			return 0;
	}
	if (st->utime == 0 && /* new array */
	    mse->pattern && strchr(mse->pattern, '_') /* degraded */
		)
		alert("DegradedArray", dev, NULL, ainfo);

	if (st->utime == 0 && /* new array */
	    st->expected_spares > 0 &&
	    array.spare_disks < st->expected_spares)
		alert("SparesMissing", dev, NULL, ainfo);
	if (st->percent < 0 && st->percent != RESYNC_UNKNOWN &&
	    mse->percent >= 0)
		alert("RebuildStarted", dev, NULL, ainfo);
	if (st->percent >= 0 &&
	    mse->percent >= 0 &&
	    (mse->percent / increments) > (st->percent / increments)) {
		char percentalert[15]; // "RebuildNN" (10 chars) or "RebuildStarted" (15 chars)

		if((mse->percent / increments) == 0)
			snprintf(percentalert, sizeof(percentalert), "RebuildStarted");
		else
			snprintf(percentalert, sizeof(percentalert), "Rebuild%02d", mse->percent);

		alert(percentalert, dev, NULL, ainfo);
	}

	if (mse->percent == RESYNC_NONE &&
	    st->percent >= 0) {
		/* Rebuild/sync/whatever just finished.
		 * If there is a number in /mismatch_cnt,
		 * we should report that.
		 */
		struct mdinfo *sra =
			sysfs_read(-1, st->devnm, GET_MISMATCH);
		if (sra && sra->mismatch_cnt > 0) {
			char cnt[80];
			snprintf(cnt, sizeof(cnt),
				 " mismatches found: %d (on raid level %d)",
				sra->mismatch_cnt, array.level);
			alert("RebuildFinished", dev, cnt, ainfo);
		} else
			alert("RebuildFinished", dev, NULL, ainfo);
		if (sra)
			free(sra);
	}
	st->percent = mse->percent;

	remaining_disks = array.nr_disks;
	for (i=0; i<MAX_DISKS && remaining_disks > 0;
	     i++) {
		mdu_disk_info_t disc;
		disc.number = i;
		if (ioctl(fd, GET_DISK_INFO, &disc) >= 0) {
			info[i].state = disc.state;
			info[i].major = disc.major;
			info[i].minor = disc.minor;
			if (disc.major || disc.minor)
				remaining_disks --;
		} else
			info[i].major = info[i].minor = 0;
	}
	last_disk = i;

	if (mse->metadata_version &&
	    strncmp(mse->metadata_version, "external:", 9) == 0 &&
	    is_subarray(mse->metadata_version+9)) {
		char *sl;
		strcpy(st->parent_devnm,
		       mse->metadata_version+10);
		sl = strchr(st->parent_devnm, '/');
		if (sl)
			*sl = 0;
	} else
		st->parent_devnm[0] = 0;
	if (st->metadata == NULL &&
	    st->parent_devnm[0] == 0)
		st->metadata = super_by_fd(fd, NULL);

	close(fd);

	for (i=0; i<MAX_DISKS; i++) {
		mdu_disk_info_t disc = {0,0,0,0,0};
		int newstate=0;
		int change;
		char *dv = NULL;
		disc.number = i;
		if (i < last_disk &&
		    (info[i].major || info[i].minor)) {
			newstate = info[i].state;
			dv = map_dev_preferred(
				info[i].major, info[i].minor, 1,
				prefer);
			disc.state = newstate;
			disc.major = info[i].major;
			disc.minor = info[i].minor;
		} else
			newstate = (1 << MD_DISK_REMOVED);

		if (dv == NULL && st->devid[i])
			dv = map_dev_preferred(
				major(st->devid[i]),
				minor(st->devid[i]), 1, prefer);
		change = newstate ^ st->devstate[i];
		if (st->utime && change && !st->err && !new_array) {
			if ((st->devstate[i]&change)&(1<<MD_DISK_SYNC))
				alert("Fail", dev, dv, ainfo);
			else if ((newstate & (1<<MD_DISK_FAULTY)) &&
				 (disc.major || disc.minor) &&
				 st->devid[i] == makedev(disc.major, disc.minor))
				alert("FailSpare", dev, dv, ainfo);
			else if ((newstate&change)&(1<<MD_DISK_SYNC))
				alert("SpareActive", dev, dv, ainfo);
		}
		st->devstate[i] = newstate;
		st->devid[i] = makedev(disc.major, disc.minor);
	}
	st->active = array.active_disks;
	st->working = array.working_disks;
	st->spare = array.spare_disks;
	st->failed = array.failed_disks;
	st->utime = array.utime;
	st->raid = array.raid_disks;
	st->err = 0;
	if ((st->active < st->raid) && st->spare == 0)
		return 1;
	return 0;
}
コード例 #9
0
ファイル: Monitor.c プロジェクト: Distrotech/mdadm
int WaitClean(char *dev, int sock, int verbose)
{
	int fd;
	struct mdinfo *mdi;
	int rv = 1;
	char devnm[32];

	fd = open(dev, O_RDONLY);
	if (fd < 0) {
		if (verbose)
			pr_err("Couldn't open %s: %s\n", dev, strerror(errno));
		return 1;
	}

	strcpy(devnm, fd2devnm(fd));
	mdi = sysfs_read(fd, devnm, GET_VERSION|GET_LEVEL|GET_SAFEMODE);
	if (!mdi) {
		if (verbose)
			pr_err("Failed to read sysfs attributes for %s\n", dev);
		close(fd);
		return 0;
	}

	switch(mdi->array.level) {
	case LEVEL_LINEAR:
	case LEVEL_MULTIPATH:
	case 0:
		/* safemode delay is irrelevant for these levels */
		rv = 0;
	}

	/* for internal metadata the kernel handles the final clean
	 * transition, containers can never be dirty
	 */
	if (!is_subarray(mdi->text_version))
		rv = 0;

	/* safemode disabled ? */
	if (mdi->safe_mode_delay == 0)
		rv = 0;

	if (rv) {
		int state_fd = sysfs_open(fd2devnm(fd), NULL, "array_state");
		char buf[20];
		int delay = 5000;

		/* minimize the safe_mode_delay and prepare to wait up to 5s
		 * for writes to quiesce
		 */
		sysfs_set_safemode(mdi, 1);

		/* wait for array_state to be clean */
		while (1) {
			rv = read(state_fd, buf, sizeof(buf));
			if (rv < 0)
				break;
			if (sysfs_match_word(buf, clean_states) <= 4)
				break;
			rv = sysfs_wait(state_fd, &delay);
			if (rv < 0 && errno != EINTR)
				break;
			lseek(state_fd, 0, SEEK_SET);
		}
		if (rv < 0)
			rv = 1;
		else if (fping_monitor(sock) == 0 ||
			 ping_monitor(mdi->text_version) == 0) {
			/* we need to ping to close the window between array
			 * state transitioning to clean and the metadata being
			 * marked clean
			 */
			rv = 0;
		} else
			rv = 1;
		if (rv && verbose)
			pr_err("Error waiting for %s to be clean\n",
				dev);

		/* restore the original safe_mode_delay */
		sysfs_set_safemode(mdi, mdi->safe_mode_delay);
		close(state_fd);
	}

	sysfs_free(mdi);
	close(fd);

	return rv;
}
コード例 #10
0
ファイル: Manage.c プロジェクト: saschaefer/mdadm-deb-pkg
int Manage_ro(char *devname, int fd, int readonly)
{
	/* switch to readonly or rw
	 *
	 * requires >= 0.90.0
	 * first check that array is runing
	 * use RESTART_ARRAY_RW or STOP_ARRAY_RO
	 *
	 */
	mdu_array_info_t array;
#ifndef MDASSEMBLE
	struct mdinfo *mdi;
#endif

	if (md_get_version(fd) < 9000) {
		fprintf(stderr, Name ": need md driver version 0.90.0 or later\n");
		return 1;
	}
#ifndef MDASSEMBLE
	/* If this is an externally-manage array, we need to modify the
	 * metadata_version so that mdmon doesn't undo our change.
	 */
	mdi = sysfs_read(fd, -1, GET_LEVEL|GET_VERSION);
	if (mdi &&
	    mdi->array.major_version == -1 &&
	    is_subarray(mdi->text_version)) {
		char vers[64];
		strcpy(vers, "external:");
		strcat(vers, mdi->text_version);
		if (readonly > 0) {
			int rv;
			/* We set readonly ourselves. */
			vers[9] = '-';
			sysfs_set_str(mdi, NULL, "metadata_version", vers);

			close(fd);
			rv = sysfs_set_str(mdi, NULL, "array_state", "readonly");

			if (rv < 0) {
				fprintf(stderr, Name ": failed to set readonly for %s: %s\n",
					devname, strerror(errno));

				vers[9] = mdi->text_version[0];
				sysfs_set_str(mdi, NULL, "metadata_version", vers);
				return 1;
			}
		} else {
			char *cp;
			/* We cannot set read/write - must signal mdmon */
			vers[9] = '/';
			sysfs_set_str(mdi, NULL, "metadata_version", vers);

			cp = strchr(vers+10, '/');
			if (*cp)
				*cp = 0;
			ping_monitor(vers+10);
			if (mdi->array.level <= 0)
				sysfs_set_str(mdi, NULL, "array_state", "active");
		}
		return 0;
	}
#endif
	if (ioctl(fd, GET_ARRAY_INFO, &array)) {
		fprintf(stderr, Name ": %s does not appear to be active.\n",
			devname);
		return 1;
	}

	if (readonly>0) {
		if (ioctl(fd, STOP_ARRAY_RO, NULL)) {
			fprintf(stderr, Name ": failed to set readonly for %s: %s\n",
				devname, strerror(errno));
			return 1;
		}
	} else if (readonly < 0) {
		if (ioctl(fd, RESTART_ARRAY_RW, NULL)) {
			fprintf(stderr, Name ": failed to set writable for %s: %s\n",
				devname, strerror(errno));
			return 1;
		}
	}
	return 0;
}
コード例 #11
0
ファイル: Manage.c プロジェクト: saschaefer/mdadm-deb-pkg
int Manage_runstop(char *devname, int fd, int runstop, int quiet)
{
	/* Run or stop the array. array must already be configured
	 * required >= 0.90.0
	 * Only print failure messages if quiet == 0;
	 * quiet > 0 means really be quiet
	 * quiet < 0 means we will try again if it fails.
	 */
	mdu_param_t param; /* unused */

	if (runstop == -1 && md_get_version(fd) < 9000) {
		if (ioctl(fd, STOP_MD, 0)) {
			if (quiet == 0) fprintf(stderr,
						Name ": stopping device %s "
						"failed: %s\n",
						devname, strerror(errno));
			return 1;
		}
	}

	if (md_get_version(fd) < 9000) {
		fprintf(stderr, Name ": need md driver version 0.90.0 or later\n");
		return 1;
	}
	/*
	if (ioctl(fd, GET_ARRAY_INFO, &array)) {
		fprintf(stderr, Name ": %s does not appear to be active.\n",
			devname);
		return 1;
	}
	*/
	if (runstop>0) {
		if (ioctl(fd, RUN_ARRAY, &param)) {
			fprintf(stderr, Name ": failed to run array %s: %s\n",
				devname, strerror(errno));
			return 1;
		}
		if (quiet <= 0)
			fprintf(stderr, Name ": started %s\n", devname);
	} else if (runstop < 0){
		struct map_ent *map = NULL;
		struct stat stb;
		struct mdinfo *mdi;
		int devnum;
		int err;
		int count;
		/* If this is an mdmon managed array, just write 'inactive'
		 * to the array state and let mdmon clear up.
		 */
		devnum = fd2devnum(fd);
		/* Get EXCL access first.  If this fails, then attempting
		 * to stop is probably a bad idea.
		 */
		close(fd);
		fd = open(devname, O_RDONLY|O_EXCL);
		if (fd < 0 || fd2devnum(fd) != devnum) {
			if (fd >= 0)
				close(fd);
			fprintf(stderr,
				Name ": Cannot get exclusive access to %s:"
				"Perhaps a running "
				"process, mounted filesystem "
				"or active volume group?\n",
				devname);
			return 1;
		}
		mdi = sysfs_read(fd, -1, GET_LEVEL|GET_VERSION);
		if (mdi &&
		    mdi->array.level > 0 &&
		    is_subarray(mdi->text_version)) {
			int err;
			/* This is mdmon managed. */
			close(fd);

			count = 25;
			while (count &&
			       (err = sysfs_set_str(mdi, NULL,
						    "array_state",
						    "inactive")) < 0
			       && errno == EBUSY) {
				usleep(200000);
				count--;
			}
			if (err && !quiet) {
				fprintf(stderr, Name
					": failed to stop array %s: %s\n",
					devname, strerror(errno));
				return 1;
			}

			/* Give monitor a chance to act */
			ping_monitor(mdi->text_version);

			fd = open_dev_excl(devnum);
			if (fd < 0) {
				fprintf(stderr, Name
					": failed to completely stop %s"
					": Device is busy\n",
					devname);
				return 1;
			}
		} else if (mdi &&
			   mdi->array.major_version == -1 &&
			   mdi->array.minor_version == -2 &&
			   !is_subarray(mdi->text_version)) {
			struct mdstat_ent *mds, *m;
			/* container, possibly mdmon-managed.
			 * Make sure mdmon isn't opening it, which
			 * would interfere with the 'stop'
			 */
			ping_monitor(mdi->sys_name);

			/* now check that there are no existing arrays
			 * which are members of this array
			 */
			mds = mdstat_read(0, 0);
			for (m=mds; m; m=m->next)
				if (m->metadata_version &&
				    strncmp(m->metadata_version, "external:", 9)==0 &&
				    is_subarray(m->metadata_version+9) &&
				    devname2devnum(m->metadata_version+10) == devnum) {
					if (!quiet)
						fprintf(stderr, Name
							": Cannot stop container %s: "
							"member %s still active\n",
							devname, m->dev);
					free_mdstat(mds);
					if (mdi)
						sysfs_free(mdi);
					return 1;
				}
		}

		/* As we have an O_EXCL open, any use of the device
		 * which blocks STOP_ARRAY is probably a transient use,
		 * so it is reasonable to retry for a while - 5 seconds.
		 */
		count = 25; err = 0;
		while (count && fd >= 0
		       && (err = ioctl(fd, STOP_ARRAY, NULL)) < 0
		       && errno == EBUSY) {
			usleep(200000);
			count --;
		}
		if (fd >= 0 && err) {
			if (quiet == 0) {
				fprintf(stderr, Name
					": failed to stop array %s: %s\n",
					devname, strerror(errno));
				if (errno == EBUSY)
					fprintf(stderr, "Perhaps a running "
						"process, mounted filesystem "
						"or active volume group?\n");
			}
			if (mdi)
				sysfs_free(mdi);
			return 1;
		}
		/* prior to 2.6.28, KOBJ_CHANGE was not sent when an md array
		 * was stopped, so We'll do it here just to be sure.  Drop any
		 * partitions as well...
		 */
		if (fd >= 0)
			ioctl(fd, BLKRRPART, 0);
		if (mdi)
			sysfs_uevent(mdi, "change");

		
		if (devnum != NoMdDev &&
		    (stat("/dev/.udev", &stb) != 0 ||
		     check_env("MDADM_NO_UDEV"))) {
			struct map_ent *mp = map_by_devnum(&map, devnum);
			remove_devices(devnum, mp ? mp->path : NULL);
		}


		if (quiet <= 0)
			fprintf(stderr, Name ": stopped %s\n", devname);
		map_lock(&map);
		map_remove(&map, devnum);
		map_unlock(&map);
	}
	return 0;
}