From e9dd159873cfa0da1ec3e4f173c24f330ea526f8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 19 Aug 2008 17:55:15 +1000 Subject: [PATCH] Allow an externally managed array to be marked readonly 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 --- Manage.c | 43 +++++++++++++++++++++++++++++++++++++++++++ managemon.c | 1 + mdadm.h | 9 ++++++++- mdmon.h | 1 + monitor.c | 22 ++++++++++++++-------- 5 files changed, 67 insertions(+), 9 deletions(-) diff --git a/Manage.c b/Manage.c index 084e2701..56bc2c31 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 1c329c58..15e431f7 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 489fe30c..4fbde1cb 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 6c1961ad..b3f4d6e7 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 900cba3c..45b5d5b5 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 && -- 2.39.2