diff options
Diffstat (limited to 'config.c')
-rw-r--r-- | config.c | 247 |
1 files changed, 246 insertions, 1 deletions
@@ -75,7 +75,7 @@ char DefaultConfFile[] = CONFFILE; char DefaultAltConfFile[] = CONFFILE2; enum linetype { Devices, Array, Mailaddr, Mailfrom, Program, CreateDev, - Homehost, AutoMode, LTEnd }; + Homehost, AutoMode, Domain, LTEnd }; char *keywords[] = { [Devices] = "devices", [Array] = "array", @@ -85,6 +85,7 @@ char *keywords[] = { [CreateDev]= "create", [Homehost] = "homehost", [AutoMode] = "auto", + [Domain] = "domain", [LTEnd] = NULL }; @@ -694,6 +695,164 @@ void autoline(char *line) } } +struct domain_ent { + char *spare_group; /* only set this in monitor mode + when we know what arrays we + are watching and can reconcile + them to domains by checking + constituent device paths */ + struct domain_path { + char *path; + struct domain_path *next; + } *paths; + int action; + struct supertype *st; + struct domain_ent *next; +}; +static struct domain_ent *domain_list = NULL; + +void free_domain(struct domain_ent *de) +{ + struct domain_path *dp; + + while (de->paths) { + dp = de->paths; + de->paths = dp->next; + free(dp->path); + free(dp); + } + free(de); +} + +void domainline(char *line) +{ + char *w; + struct domain_ent *de; + struct domain_path *path; + int offset, a_seen=0, m_seen=0, sg_seen=0; + + de = malloc(sizeof(struct domain_ent)); + if (!de) { + fprintf(stderr, Name ": unable to allocate memory for domain " + "entry\n"); + return; + } + de->paths = NULL; + de->spare_group = NULL; + de->action = incremental; + de->st = NULL; + de->next = NULL; + + for (w=dl_next(line); w!=line; w=dl_next(w)) { + if (strncasecmp("path=", w, 5) == 0) { + path = malloc(sizeof(struct domain_path)); + if (!path) { + fprintf(stderr, Name ": unable to allocate " + "memory for domain path\n"); + free_domain(de); + return; + } + path->path = strdup(w+5); + if (!path->path) { + fprintf(stderr, Name ": unable to allocate " + "memory for domain path\n"); + free_domain(de); + return; + } + path->next = de->paths; + de->paths = path; + } else if (strncasecmp("action=", w, 7) == 0) { + if (!a_seen) + a_seen = 1; + else { + fprintf(stderr, Name ": only one action= entry " + "allowed per domain line, ignoring\n"); + continue; + } + offset = 7; + if (strncasecmp("force-", w+offset, 6) == 0) + offset = 13; + if (strncasecmp("ign", w+offset, 3) == 0) + de->action = ignore; + else if (strncasecmp("inc", w+offset, 3) == 0) + de->action = incremental; + else if (strncasecmp("spa", w+offset, 3) == 0) + de->action = spare; + else if (strncasecmp("gro", w+offset, 3) == 0) + de->action = grow; + else if (strncasecmp("par", w+offset, 3) == 0) + de->action = partition; + if (offset == 13) + de->action |= force; + } else if (strncasecmp("metadata=", w, 9) == 0) { + int i; + if (!m_seen) + m_seen = 1; + else { + fprintf(stderr, Name ": only one metadata= " + "entry allowed per domain line, " + "ignoring\n"); + continue; + } + /* style of metadata on the devices. */ + + for(i=0; superlist[i] && !de->st; i++) + de->st = superlist[i]->match_metadata_desc(w+9); + + if (!de->st) + fprintf(stderr, Name ": metadata format %s " + "unknown, ignored.\n", w+9); + } else if (strncasecmp("spare-group=", w, 12) == 0) { + if (!sg_seen) + sg_seen = 1; + else { + fprintf(stderr, Name ": only one spare-group= " + "entry allowed per domain line, " + "ignoring\n"); + continue; + } + de->spare_group = strdup(w+12); + if (!de->spare_group) { + fprintf(stderr, Name ": failed to allocate " + "memory for spare_group\n"); + free_domain(de); + return; + } + } else { + fprintf(stderr, Name ": unrecognized option %s on " + "domain line\n", w); + } + } + /* Some sanity checks now that all the options are parsed */ + if ((de->action & force) && + ((de->action & (force - 1)) <= incremental)) { + fprintf(stderr, Name ": force makes no sense with ignore or " + "incremental, removing.\n"); + de->action &= (force - 1); + } + if (de->spare_group && de->action <= incremental) { + fprintf(stderr, Name ": defined a spare group when we aren't " + "allowed to add any spares, removing spare group.\n"); + free(de->spare_group); + de->spare_group = NULL; + } + de->next = domain_list; + domain_list = de; +} + +struct domain_ent *get_domain_from_devpath(char *devpath) +{ + struct domain_ent *de; + struct domain_path *path; + + for (de = domain_list; de; de = de->next) + for (path = de->paths; path; path = path->next) + if (fnmatch(path->path, devpath, 0) == 0) + return de; + return NULL; +} + + int loaded = 0; static char *conffile = NULL; @@ -766,6 +925,9 @@ void load_conffile(void) case AutoMode: autoline(line); break; + case Domain: + domainline(line); + break; default: fprintf(stderr, Name ": Unknown keyword %s\n", line); } @@ -1101,3 +1263,86 @@ struct mddev_ident_s *conf_match(struct mdinfo *info, struct supertype *st) } return match; } + +/* + * Return a linked list of arrays that are in the same domain as the + * constituent device devname. So, if we have a domain that lists ports 2 + * through 6 on the main SATA controller in a machine, and we plug in a + * new drive on port 6, we want to know what actual up and running arrays, + * as listed via /proc/mdstat, are also in the same domain. We will use + * this information to determine what array we might add our new device + * to either as a replacement drive or as a hot spare. + */ +struct mdstat_ent *arrays_in_domain(char *devname) +{ + struct mdstat_ent *me, *mdstat, *array_list = NULL; + struct dev_member *m; + struct domain_ent *domain, *de; + char *name; + char *devpath; + + load_conffile(); + /* make sure name is a kernel internal name, not a path */ + name = strrchr(devname, '/'); + if (!name++) + name = devname; + devpath = get_devpath_from_devname(name); + if (!devpath) + return NULL; + domain = get_domain_from_devpath(devpath); + if (!domain) + return NULL; + + mdstat = mdstat_read(0, 0); + while (mdstat) { + if (mdstat->metadata_version && + strncmp(mdstat->metadata_version, "external:", 9) == 0 && + is_subarray(mdstat->metadata_version+9)) + /* don't return subarrays, only containers */ + m = NULL; + else for (m = mdstat->members; m; m = m->next) { + char *member_path = get_devpath_from_devname(m->name); + if (member_path) { + de = get_domain_from_devpath(member_path); + free(member_path); + if (de == domain) + /* array has at least one member in our domain*/ + break; + } + } + if (m) { + me = mdstat; + mdstat = mdstat->next; + me->next = array_list; + array_list = me; + } else { + me = mdstat; + mdstat = mdstat->next; + me->next = NULL; + free_mdstat(me); + } + } + free(devpath); + return array_list; +} + +int conf_get_domain_action(char *devname) +{ + char *name = strrchr(devname, '/'); + char *path; + struct domain_ent *domain; + + load_conffile(); + if (!domain_list) + return incremental; + if (!name++) + name = devname; + path = get_devpath_from_devname(name); + if (!path) + return incremental; + domain = get_domain_from_devpath(path); + free(path); + if (!domain) + return incremental; + return domain->action; +} |