summaryrefslogtreecommitdiffstats
path: root/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'config.c')
-rw-r--r--config.c247
1 files changed, 246 insertions, 1 deletions
diff --git a/config.c b/config.c
index 20c46e9..2ccd2fd 100644
--- a/config.c
+++ b/config.c
@@ -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;
+}