diff options
author | Dan Williams <dan.j.williams@intel.com> | 2010-06-15 17:55:41 -0700 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2010-06-15 17:55:41 -0700 |
commit | 33414a0182ae193150f65f7bca97a7e4d818a49e (patch) | |
tree | b468723303ac3fa1e9f452cf2dd43cd94ab4e0e5 /util.c | |
parent | 200871adf9e15d5ad985f28c349fd89c386ef48a (diff) | |
download | mdadm-33414a0182ae193150f65f7bca97a7e4d818a49e.tar.gz mdadm-33414a0182ae193150f65f7bca97a7e4d818a49e.tar.xz mdadm-33414a0182ae193150f65f7bca97a7e4d818a49e.zip |
Kill subarray v2
Support for deleting a subarray out of a container. When all subarrays
are deleted the component devices are converted back into spares, a
--zero-superblock is still needed to kill the remaining metadata at this
point. This operation is blocked when the subarray is active and may
also be blocked by the metadata handler when deleting the subarray might
change the uuid of other active subarrays. For example, with imsm,
deleting subarray 'n' may change the uuid of subarrays with indexes > n.
Deleting a subarray needs to be a container wide event to ensure
disks that record the modified subarray list perceive other disks that
did not receive this change as out of date.
Notes:
The st->subarray parsing in super-intel.c and super-ddf.c is updated to
be more strict now that we are reading user supplied subarray values.
Offline container modification shares actions that mdmon typically
handles so promote is_container_member() and version_to_superswitch()
(formerly find_metadata_methods()) to generic utility functions for the
cases where mdadm performs the operation.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'util.c')
-rw-r--r-- | util.c | 137 |
1 files changed, 137 insertions, 0 deletions
@@ -1392,6 +1392,143 @@ int open_container(int fd) return -1; } +struct superswitch *version_to_superswitch(char *vers) +{ + int i; + + for (i = 0; superlist[i]; i++) { + struct superswitch *ss = superlist[i]; + + if (strcmp(vers, ss->name) == 0) + return ss; + } + + return NULL; +} + +int is_container_member(struct mdstat_ent *mdstat, char *container) +{ + if (mdstat->metadata_version == NULL || + strncmp(mdstat->metadata_version, "external:", 9) != 0 || + !is_subarray(mdstat->metadata_version+9) || + strncmp(mdstat->metadata_version+10, container, strlen(container)) != 0 || + mdstat->metadata_version[10+strlen(container)] != '/') + return 0; + + return 1; +} + +int is_subarray_active(char *subarray, char *container) +{ + struct mdstat_ent *mdstat = mdstat_read(0, 0); + struct mdstat_ent *ent; + + for (ent = mdstat; ent; ent = ent->next) { + if (is_container_member(ent, container)) { + char *inst = &ent->metadata_version[10+strlen(container)+1]; + + if (strcmp(inst, subarray) == 0) + break; + } + } + + free_mdstat(mdstat); + + return ent != NULL; +} + +/* open_subarray - opens a subarray in a container + * @dev: container device name + * @st: supertype with only ->subarray set + * @quiet: block reporting errors flag + * + * On success returns an fd to a container and fills in *st + */ +int open_subarray(char *dev, struct supertype *st, int quiet) +{ + struct mdinfo *mdi; + int fd, err = 1; + + fd = open(dev, O_RDWR|O_EXCL); + if (fd < 0) { + if (!quiet) + fprintf(stderr, Name ": Couldn't open %s, aborting\n", + dev); + return 2; + } + + st->devnum = fd2devnum(fd); + if (st->devnum == NoMdDev) { + if (!quiet) + fprintf(stderr, + Name ": Failed to determine device number for %s\n", + dev); + goto close_fd; + } + + mdi = sysfs_read(fd, st->devnum, GET_VERSION|GET_LEVEL); + if (!mdi) { + if (!quiet) + fprintf(stderr, Name ": Failed to read sysfs for %s\n", + dev); + goto close_fd; + } + + if (mdi->array.level != UnSet) { + if (!quiet) + fprintf(stderr, Name ": %s is not a container\n", dev); + goto free_sysfs; + } + + st->ss = version_to_superswitch(mdi->text_version); + if (!st->ss) { + if (!quiet) + fprintf(stderr, + Name ": Operation not supported for %s metadata\n", + mdi->text_version); + goto free_sysfs; + } + + st->devname = devnum2devname(st->devnum); + if (!st->devname) { + if (!quiet) + fprintf(stderr, Name ": Failed to allocate device name\n"); + goto free_sysfs; + } + + if (st->ss->load_super(st, fd, NULL)) { + if (!quiet) + fprintf(stderr, Name ": Failed to find subarray-%s in %s\n", + st->subarray, dev); + goto free_name; + } + + if (!st->loaded_container) { + if (!quiet) + fprintf(stderr, Name ": %s is not a container\n", dev); + goto free_super; + } + + err = 0; + + free_super: + if (err) + st->ss->free_super(st); + free_name: + if (err) + free(st->devname); + free_sysfs: + sysfs_free(mdi); + close_fd: + if (err) + close(fd); + + if (err) + return -1; + else + return fd; +} + int add_disk(int mdfd, struct supertype *st, struct mdinfo *sra, struct mdinfo *info) { |