*
*/
mdu_array_info_t array;
+ struct mdinfo *mdi;
if (md_get_version(fd) < 9000) {
fprintf(stderr, Name ": need md driver version 0.90.0 or later\n");
return 1;
}
+ /* 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 &&
+ mdi->array.level > 0 &&
+ 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);
+ }
+ return 0;
+ }
+
if (ioctl(fd, GET_ARRAY_INFO, &array)) {
fprintf(stderr, Name ": %s does not appear to be active.\n",
devname);
{
/* 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) fprintf(stderr, Name ": stopping device %s failed: %s\n",
- devname, strerror(errno));
+ if (quiet == 0) fprintf(stderr,
+ Name ": stopping device %s "
+ "failed: %s\n",
+ devname, strerror(errno));
return 1;
}
}
} else if (runstop < 0){
struct map_ent *map = NULL;
struct stat stb;
- if (ioctl(fd, STOP_ARRAY, NULL)) {
- if (quiet==0)
- fprintf(stderr, Name ": fail to stop array %s: %s\n",
+ struct mdinfo *mdi;
+ /* If this is an mdmon managed array, just write 'inactive'
+ * to the array state and let mdmon clear up.
+ */
+ mdi = sysfs_read(fd, -1, GET_LEVEL|GET_VERSION);
+ if (mdi &&
+ mdi->array.level > 0 &&
+ is_subarray(mdi->text_version)) {
+ char *cp;
+
+ /* This is mdmon managed. */
+ close(fd);
+ if (sysfs_set_str(mdi, NULL,
+ "array_state", "inactive") < 0) {
+ if (quiet == 0)
+ fprintf(stderr, Name
+ ": failed to stop array %s: %s\n",
+ devname, strerror(errno));
+ return 1;
+ }
+
+ /* Give monitor a chance to act */
+ cp = strchr(mdi->text_version+1, '/');
+ if (*cp)
+ *cp = 0;
+ ping_monitor(mdi->text_version+1);
+
+ fd = open(devname, O_RDONLY);
+ } else if (mdi &&
+ mdi->array.major_version == -1 &&
+ mdi->array.minor_version == -2 &&
+ !is_subarray(mdi->text_version)) {
+ /* container, possibly mdmon-managed.
+ * Make sure mdmon isn't opening it, which
+ * would interfere with the 'stop'
+ */
+ ping_monitor(mdi->sys_name);
+ }
+ if (mdi)
+ sysfs_free(mdi);
+
+ if (fd >= 0 && ioctl(fd, STOP_ARRAY, NULL)) {
+ 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");
+ }
return 1;
}
+
if (quiet <= 0)
fprintf(stderr, Name ": stopped %s\n", devname);
- if (fstat(fd, &stb) == 0) {
+ if (fd >= 0 && fstat(fd, &stb) == 0) {
int devnum;
if (major(stb.st_rdev) == MD_MAJOR)
devnum = minor(stb.st_rdev);
return 1;
}
/* Make sure it isn't in use (in 2.6 or later) */
- tfd = open(dv->devname, O_RDONLY|O_EXCL);
+ tfd = open(dv->devname, O_RDONLY|O_EXCL|O_DIRECT);
if (tfd < 0) {
fprintf(stderr, Name ": Cannot open %s: %s\n",
dv->devname, strerror(errno));
return 1;
}
- if (array.not_persistent == 0) {
-
+ if (array.not_persistent == 0 || tst->ss->external) {
/* Make sure device is large enough */
if (tst->ss->avail_size(tst, ldsize/512) <
array_size) {
}
/* need to find a sample superblock to copy, and
- * a spare slot to use
+ * a spare slot to use.
+ * For 'external' array (well, container based),
+ * We can just load the metadata for the array.
*/
- for (j = 0; j < tst->max_devs; j++) {
+ if (tst->ss->external) {
+ tst->ss->load_super(tst, fd, NULL);
+ } else for (j = 0; j < tst->max_devs; j++) {
char *dev;
int dfd;
disc.number = j;
close(dfd);
break;
}
+ /* FIXME this is a bad test to be using */
if (!tst->sb) {
fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n");
return 1;
disc.minor = minor(stb.st_rdev);
disc.number =j;
disc.state = 0;
- if (array.not_persistent==0) {
+ if (array.not_persistent==0 || tst->ss->external) {
int dfd;
if (dv->writemostly)
disc.state |= 1 << MD_DISK_WRITEMOSTLY;
- dfd = open(dv->devname, O_RDWR | O_EXCL);
+ dfd = open(dv->devname, O_RDWR | O_EXCL|O_DIRECT);
tst->ss->add_to_super(tst, &disc, dfd,
dv->devname);
/* write_init_super will close 'dfd' */
- if (tst->ss->write_init_super(tst))
+ if (tst->ss->external)
+ /* mdmon will write the metadata */
+ close(dfd);
+ else if (tst->ss->write_init_super(tst))
return 1;
} else if (dv->re_add) {
/* this had better be raid1.
}
if (dv->writemostly)
disc.state |= (1 << MD_DISK_WRITEMOSTLY);
- if (ioctl(fd,ADD_NEW_DISK, &disc)) {
+ if (tst->ss->external) {
+ /* add a disk to an external metadata container
+ * only if mdmon is around to see it
+ */
+ struct mdinfo new_mdi;
+ struct mdinfo *sra;
+ int container_fd;
+ int devnum = fd2devnum(fd);
+
+ container_fd = open_dev_excl(devnum);
+ if (container_fd < 0) {
+ fprintf(stderr, Name ": add failed for %s:"
+ " could not get exclusive access to container\n",
+ dv->devname);
+ return 1;
+ }
+
+ if (!mdmon_running(devnum)) {
+ fprintf(stderr, Name ": add failed for %s: mdmon not running\n",
+ dv->devname);
+ close(container_fd);
+ return 1;
+ }
+
+ sra = sysfs_read(container_fd, -1, 0);
+ if (!sra) {
+ fprintf(stderr, Name ": add failed for %s: sysfs_read failed\n",
+ dv->devname);
+ close(container_fd);
+ return 1;
+ }
+ sra->array.level = LEVEL_CONTAINER;
+ /* Need to set data_offset and component_size */
+ tst->ss->getinfo_super(tst, &new_mdi);
+ new_mdi.disk.major = disc.major;
+ new_mdi.disk.minor = disc.minor;
+ if (sysfs_add_disk(sra, &new_mdi) != 0) {
+ fprintf(stderr, Name ": add new device to external metadata"
+ " failed for %s\n", dv->devname);
+ close(container_fd);
+ return 1;
+ }
+ ping_monitor(devnum2devname(devnum));
+ sysfs_free(sra);
+ close(container_fd);
+ } else if (ioctl(fd, ADD_NEW_DISK, &disc)) {
fprintf(stderr, Name ": add new device failed for %s as %d: %s\n",
dv->devname, j, strerror(errno));
return 1;