summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Manage.c43
-rw-r--r--managemon.c1
-rw-r--r--mdadm.h9
-rw-r--r--mdmon.h1
-rw-r--r--monitor.c22
5 files changed, 67 insertions, 9 deletions
diff --git a/Manage.c b/Manage.c
index 084e270..56bc2c3 100644
--- a/Manage.c
+++ b/Manage.c
@@ -45,11 +45,54 @@ int Manage_ro(char *devname, int fd, int readonly)
*
*/
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);
diff --git a/managemon.c b/managemon.c
index 1c329c5..15e431f 100644
--- a/managemon.c
+++ b/managemon.c
@@ -460,6 +460,7 @@ static void manage_new(struct mdstat_ent *mdstat,
new->action_fd = sysfs_open(new->devnum, NULL, "sync_action");
new->info.state_fd = sysfs_open(new->devnum, NULL, "array_state");
new->resync_start_fd = sysfs_open(new->devnum, NULL, "resync_start");
+ new->metadata_fd = sysfs_open(new->devnum, NULL, "metadata_version");
get_resync_start(new);
dprintf("%s: inst: %d action: %d state: %d\n", __func__, atoi(inst),
new->action_fd, new->info.state_fd);
diff --git a/mdadm.h b/mdadm.h
index 489fe30..4fbde1c 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -807,7 +807,14 @@ static inline int ROUND_UP(int a, int base)
static inline int is_subarray(char *vers)
{
- return (*vers == '/');
+ /* The version string for a 'subarray' (an array in a container)
+ * is
+ * /containername/componentname for normal read-write arrays
+ * -containername/componentname for read-only arrays.
+ * containername is e.g. md0, md_d1
+ * componentname is dependant on the metadata. e.g. '1' 'S1' ...
+ */
+ return (*vers == '/' || *vers == '-');
}
#define LEVEL_MULTIPATH (-4)
diff --git a/mdmon.h b/mdmon.h
index 6c1961a..b3f4d6e 100644
--- a/mdmon.h
+++ b/mdmon.h
@@ -19,6 +19,7 @@ struct active_array {
int action_fd;
int resync_start_fd;
+ int metadata_fd; /* for monitoring rw/ro status */
enum array_state prev_state, curr_state, next_state;
enum sync_action prev_action, curr_action, next_action;
diff --git a/monitor.c b/monitor.c
index 900cba3..45b5d5b 100644
--- a/monitor.c
+++ b/monitor.c
@@ -238,15 +238,21 @@ static int read_and_act(struct active_array *a)
}
if (a->curr_state == readonly) {
- /* Well, I'm ready to handle things, so
- * read-auto is OK. FIXME what if we really want
- * readonly ???
+ /* Well, I'm ready to handle things. If readonly
+ * wasn't requested, transition to read-auto.
*/
- get_resync_start(a);
- if (a->container->ss->set_array_state(a, 2))
- a->next_state = read_auto; /* array is clean */
- else
- a->next_state = active; /* Now active for recovery etc */
+ char buf[64];
+ read_attr(buf, sizeof(buf), a->metadata_fd);
+ if (strncmp(buf, "external:-", 10) == 0) {
+ /* explicit request for readonly array. Leave it alone */
+ ;
+ } else {
+ get_resync_start(a);
+ if (a->container->ss->set_array_state(a, 2))
+ a->next_state = read_auto; /* array is clean */
+ else
+ a->next_state = active; /* Now active for recovery etc */
+ }
}
if (!deactivate &&