]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Allow an externally managed array to be marked readonly
authorNeilBrown <neilb@suse.de>
Tue, 19 Aug 2008 07:55:15 +0000 (17:55 +1000)
committerNeilBrown <neilb@suse.de>
Tue, 19 Aug 2008 07:55:15 +0000 (17:55 +1000)
If the metadata_version is
    -mdXXX/whatever
rather than
    /mdXXX/whatever

then the array is readonly and should be left alone by mdmon.

Signed-off-by: NeilBrown <neilb@suse.de>
Manage.c
managemon.c
mdadm.h
mdmon.h
monitor.c

index 084e2701324197d2302912d6ea17f276e882445f..56bc2c3188af1dec8ebcbf6bb866d5584be201f5 100644 (file)
--- 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);
index 1c329c583a2a8d58ce7d42bb311e21e7bcd28b8e..15e431f7fb9b03976919e1108b10c0648c1ed65b 100644 (file)
@@ -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 489fe30c5e7eab59380313ce9f004dba5dca701d..4fbde1cbbb32f2ad522931701f26f92a7f0bfe42 100644 (file)
--- 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 6c1961ad50a7e2fa2c4dc7414163e5d2fce9caab..b3f4d6e709ffb62666bc751041343ebe3e62b38e 100644 (file)
--- 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;
index 900cba3cf5404abc996c666609e475bd3c018062..45b5d5b5551bfa91e0ef80359ea088b471567aaf 100644 (file)
--- 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 &&