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 <neilb@suse.de>
This commit is contained in:
NeilBrown 2008-08-19 17:55:15 +10:00
parent 3c558363a1
commit e9dd159873
5 changed files with 67 additions and 9 deletions

View File

@ -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);

View 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);

View File

@ -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)

View File

@ -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;

View File

@ -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 &&