diff options
Diffstat (limited to 'mdstat.c')
-rw-r--r-- | mdstat.c | 145 |
1 files changed, 106 insertions, 39 deletions
@@ -80,6 +80,8 @@ #include "mdadm.h" #include "dlink.h" +#include "xmalloc.h" + #include <sys/select.h> #include <ctype.h> @@ -110,6 +112,30 @@ static int add_member_devname(struct dev_member **m, char *name) return 1; } +/* Detach element from the list, it may modify list_head */ +static void mdstat_ent_list_detach_element(struct mdstat_ent **list_head, struct mdstat_ent *el) +{ + struct mdstat_ent *ent = *list_head; + + if (ent == el) { + *list_head = ent->next; + } else { + while (ent) { + if (ent->next == el) { + ent->next = el->next; + break; + } + + ent = ent->next; + } + + } + + /* Guard if not found or list is empty - not allowed */ + assert(ent); + el->next = NULL; +} + void free_mdstat(struct mdstat_ent *ms) { while (ms) { @@ -124,6 +150,32 @@ void free_mdstat(struct mdstat_ent *ms) } } +bool is_mdstat_ent_external(struct mdstat_ent *ent) +{ + if (!ent->metadata_version) + return false; + + if (strncmp(ent->metadata_version, "external:", 9) == 0) + return true; + return false; +} + +bool is_mdstat_ent_subarray(struct mdstat_ent *ent) +{ + if (is_mdstat_ent_external(ent) && is_subarray(ent->metadata_version + 9)) + return true; + return false; +} + +bool is_container_member(struct mdstat_ent *mdstat, char *container) +{ + if (is_mdstat_ent_external(mdstat) && + metadata_container_matches(mdstat->metadata_version + 9, container)) + return true; + + return false; +} + static int mdstat_fd = -1; struct mdstat_ent *mdstat_read(int hold, int start) { @@ -146,8 +198,11 @@ struct mdstat_ent *mdstat_read(int hold, int start) f = fopen("/proc/mdstat", "r"); if (f == NULL) return NULL; - else - fcntl(fileno(f), F_SETFD, FD_CLOEXEC); + + if (fcntl(fileno(f), F_SETFD, FD_CLOEXEC) < 0) { + fclose(f); + return NULL; + } all = NULL; end = &all; @@ -281,7 +336,10 @@ struct mdstat_ent *mdstat_read(int hold, int start) } if (hold && mdstat_fd == -1) { mdstat_fd = dup(fileno(f)); - fcntl(mdstat_fd, F_SETFD, FD_CLOEXEC); + if (fcntl(mdstat_fd, F_SETFD, FD_CLOEXEC) < 0) { + fclose(f); + return NULL; + } } fclose(f); @@ -382,61 +440,70 @@ int mddev_busy(char *devnm) return me != NULL; } -struct mdstat_ent *mdstat_by_component(char *name) +/** + * mdstat_find_by_member_devnm()- Return first array or external container with member device. + * @mdstat: Preloaded mdstat to iterate over. + * @member_devnm: devnm of the device to find. + * + * External subarrays are skipped. + */ +struct mdstat_ent *mdstat_find_by_member_name(struct mdstat_ent *mdstat, char *member_devnm) { - struct mdstat_ent *mdstat = mdstat_read(0, 0); + struct mdstat_ent *ent; - while (mdstat) { - struct dev_member *m; - struct mdstat_ent *ent; - if (mdstat->metadata_version && - strncmp(mdstat->metadata_version, "external:", 9) == 0 && - is_subarray(mdstat->metadata_version+9)) - /* don't return subarrays, only containers */ - ; - else for (m = mdstat->members; m; m = m->next) { - if (strcmp(m->name, name) == 0) { - free_mdstat(mdstat->next); - mdstat->next = NULL; - return mdstat; - } - } - ent = mdstat; - mdstat = mdstat->next; - ent->next = NULL; - free_mdstat(ent); + for (ent = mdstat; ent; ent = ent->next) { + struct dev_member *member; + + if (is_mdstat_ent_subarray(ent)) + continue; + + for (member = ent->members; member; member = member->next) + if (strcmp(member->name, member_devnm) == 0) + return ent; } + return NULL; } + +struct mdstat_ent *mdstat_by_component(char *name) +{ + struct mdstat_ent *mdstat = mdstat_read(0, 0); + struct mdstat_ent *ent = mdstat_find_by_member_name(mdstat, name); + + if (ent) + mdstat_ent_list_detach_element(&mdstat, ent); + + free_mdstat(mdstat); + + return ent; +} + struct mdstat_ent *mdstat_by_subdev(char *subdev, char *container) { struct mdstat_ent *mdstat = mdstat_read(0, 0); struct mdstat_ent *ent = NULL; - while (mdstat) { + for (ent = mdstat; ent; ent = ent->next) { /* metadata version must match: * external:[/-]%s/%s * where first %s is 'container' and second %s is 'subdev' */ - if (ent) - free_mdstat(ent); - ent = mdstat; - mdstat = mdstat->next; - ent->next = NULL; - if (ent->metadata_version == NULL || - strncmp(ent->metadata_version, "external:", 9) != 0) + if (!is_mdstat_ent_external(ent)) continue; - if (!metadata_container_matches(ent->metadata_version+9, - container) || - !metadata_subdev_matches(ent->metadata_version+9, - subdev)) + if (!metadata_container_matches(ent->metadata_version + 9, container)) + continue; + if (!metadata_subdev_matches(ent->metadata_version + 9, subdev)) continue; - free_mdstat(mdstat); - return ent; + break; } - return NULL; + + if (ent) + mdstat_ent_list_detach_element(&mdstat, ent); + + free_mdstat(mdstat); + return ent; } |