mdadm/mdadm-3.0-foreign.patch
2009-03-21 01:25:02 +00:00

300 lines
9.7 KiB
Diff

--- mdadm-3.0-devel3/Incremental.c.foreign 2009-03-20 17:49:20.000000000 -0400
+++ mdadm-3.0-devel3/Incremental.c 2009-03-20 21:19:50.000000000 -0400
@@ -29,12 +29,14 @@
*/
#include "mdadm.h"
+#include <ctype.h>
static int count_active(struct supertype *st, int mdfd, char **availp,
struct mdinfo *info);
static void find_reject(int mdfd, struct supertype *st, struct mdinfo *sra,
int number, __u64 events, int verbose,
char *array_name);
+static int compare_array_name(char *conf_name, char *sb_name);
int Incremental(char *devname, int verbose, int runstop,
struct supertype *st, char *homehost, int autof)
@@ -48,8 +50,10 @@ int Incremental(char *devname, int verbo
* 2/ Find metadata, reject if none appropriate (check
* version/name from args)
* 3/ Check if there is a match in mdadm.conf
- * 3a/ if not, check for homehost match. If no match, assemble as
- * a 'foreign' array.
+ * 3a/ Evalutate the quality of match and whether or not we have a
+ * conf file at all, and make a decision about whether or not
+ * to allow this array to keep its preferred name based upon
+ * that
* 4/ Determine device number.
* - If in mdadm.conf with std name, use that
* - UUID in /dev/md/mdadm.map use that
@@ -78,7 +82,7 @@ int Incremental(char *devname, int verbo
*/
struct stat stb;
struct mdinfo info;
- struct mddev_ident_s *array_list, *match;
+ struct mddev_ident_s *array_list, *match, *match_uuid, *match_name;
char chosen_name[1024];
int rv;
struct map_ent *mp, *map = NULL;
@@ -148,26 +152,42 @@ int Incremental(char *devname, int verbo
st->ss->getinfo_super(st, &info);
/* 3/ Check if there is a match in mdadm.conf */
+ name_to_use = strchr(info.name, ':');
+ if (name_to_use)
+ name_to_use++;
+ else
+ name_to_use = info.name;
array_list = conf_get_ident(NULL);
match = NULL;
+ match_uuid = NULL;
+ match_name = NULL;
for (; array_list; array_list = array_list->next) {
+ /* Check for matching uuid, then drop through to check and see
+ * if we also have a matching name, and to catch cases of
+ * matching names without a corresponding uuid match */
if (array_list->uuid_set &&
same_uuid(array_list->uuid, info.uuid, st->ss->swapuuid)
- == 0) {
- if (verbose >= 2 && array_list->devname)
+ != 0)
+ match_uuid = array_list;
+ else if (array_list->uuid_set && verbose >= 2 &&
+ array_list->devname)
fprintf(stderr, Name
": UUID differs from %s.\n",
array_list->devname);
- continue;
- }
+ /* If we match name, save it off separately so we can tell if
+ * we matched uuid, name, or both, and if both, if they were
+ * the same entry */
if (array_list->name[0] &&
- strcasecmp(array_list->name, info.name) != 0) {
- if (verbose >= 2 && array_list->devname)
+ compare_array_name(array_list->name, info.name))
+ match_name = array_list;
+ else if (array_list->name[0] && verbose >= 2 &&
+ array_list->devname)
fprintf(stderr, Name
": Name differs from %s.\n",
array_list->devname);
+ if ((!match_uuid || match == match_uuid) &&
+ (!match_name || match == match_name))
continue;
- }
if (array_list->devices &&
!match_oneof(array_list->devices, devname)) {
if (verbose >= 2 && array_list->devname)
@@ -197,7 +217,13 @@ int Incremental(char *devname, int verbo
/* FIXME, should I check raid_disks and level too?? */
if (match) {
- if (verbose >= 0) {
+ if (match_uuid != match_name) {
+ if (match_uuid->devname)
+ fprintf(stderr, Name ": more than one "
+ "match for %s, using the UUID "
+ "match\n", match_uuid->devname);
+ match = match_uuid;
+ } else if (verbose >= 0) {
if (match->devname && array_list->devname)
fprintf(stderr, Name
": we match both %s and %s - cannot decide which to use.\n",
@@ -205,23 +231,52 @@ int Incremental(char *devname, int verbo
else
fprintf(stderr, Name
": multiple lines in mdadm.conf match\n");
+ return 2;
}
- return 2;
}
match = array_list;
}
- /* 3a/ if not, check for homehost match. If no match, continue
- * but don't trust the 'name' in the array. Thus a 'random' minor
- * number will be assigned, and the device name will be based
- * on that. */
- if (match)
+ /* 3a/ Decide if we got a good match, two matches, no matches, or a
+ * likely foreign match. I dropped the homehost test entirely because
+ * it didn't seem to add any value whatsoever above and beyond what
+ * these tests can do. */
+ if (match && match_uuid == match_name) {
+ /* found in conf, both name and uuid match */
trustworthy = LOCAL;
- else if (homehost == NULL ||
- st->ss->match_home(st, homehost) != 1)
- trustworthy = FOREIGN;
- else
+ } else if (match_uuid && match_name) {
+ /* found both a name and a uuid match, but not on the same
+ * entry, so prefer the uuid match (done above) */
trustworthy = LOCAL;
+ } else if (!match_uuid && match_name) {
+ /* no uuid match, but name match */
+ if (match_name->uuid_set) {
+ /* oops, name that matched had a uuid, it just wasn't
+ * right, assume there is a local device with both
+ * a matching name and uuid, so this needs a random
+ * name */
+ trustworthy = FOREIGN;
+ match = NULL;
+ } else
+ /* matched name, and the matching entry in conf file
+ * didn't include a uuid, and this uuid never showed
+ * up anywhere else in the conf file, so consider it
+ * a soft match and allow it...although users should
+ * *REALLY* include the uuid on array lines in the
+ * conf file */
+ trustworthy = LOCAL;
+ } else { /* no match at all */
+ if (!conf_exists())
+ /* If we don't even have a conf file, this is foreign,
+ * but also not likely to conflict with anything
+ * local, so let it keep its preferred name */
+ trustworthy = LOCAL;
+ else
+ /* We have a conf file, this didn't match any uuids
+ * or names, so also not likely to conflict, let it
+ * keep its own name */
+ trustworthy = LOCAL;
+ }
/* There are three possible sources for 'autof': command line,
* ARRAY line in mdadm.conf, or CREATE line in mdadm.conf.
@@ -240,11 +295,6 @@ int Incremental(char *devname, int verbo
return Incremental_container(st, devname, verbose, runstop,
autof, trustworthy);
}
- name_to_use = strchr(info.name, ':');
- if (name_to_use)
- name_to_use++;
- else
- name_to_use = info.name;
if ((!name_to_use || name_to_use[0] == 0) &&
info.array.level == LEVEL_CONTAINER &&
@@ -797,3 +847,45 @@ int Incremental_container(struct superty
map_unlock(&map);
return 0;
}
+
+static int compare_array_name(char *conf_name, char *sb_name)
+{
+ char *cptr, *sptr;
+ int conf_num = -1;
+
+ /* usage of the name variable in the superblock comes in several
+ * flavors:
+ * A) full md pathname (/dev/md0)
+ * B) just the md name (md0)
+ * C) just the md number (0)
+ * D) all of the above, but with hostname: prefixed to it
+ *
+ * Depending on which of those variants we have, we need to alter
+ * how we attempt to match the array name in the mdadm.conf file
+ * which is always a full pathname. We don't match on hostname:
+ * though, so eliminate it from the equation.
+ */
+
+ if ((sptr = strchr(sb_name, ':')) == NULL)
+ sptr = sb_name;
+ else
+ sptr++;
+
+ /* Do we have a full pathname in the superblock name field? */
+ if (strchr(sptr, '/'))
+ return !strcasecmp(conf_name, sptr);
+ /* If not, is it just a number or an md device name? */
+ else if (isdigit(sptr[0])) {
+ cptr = conf_name + strlen(conf_name);
+ while (cptr > conf_name && isdigit(cptr[-1]))
+ cptr--;
+ if (cptr[0])
+ conf_num = strtoul(cptr, NULL, 10);
+ return conf_num == strtoul(sptr, NULL, 10);
+ } /* fall through else, it's a device name but not a full path */
+
+ cptr = strcasestr(conf_name, sptr);
+ if (cptr)
+ return !strcasecmp(cptr, sptr);
+ return 0;
+}
--- mdadm-3.0-devel3/mdadm.h.foreign 2009-03-10 01:39:41.000000000 -0400
+++ mdadm-3.0-devel3/mdadm.h 2009-03-20 17:49:20.000000000 -0400
@@ -785,6 +785,7 @@ extern mddev_dev_t conf_get_devs(void);
extern int conf_test_dev(char *devname);
extern struct createinfo *conf_get_create_info(void);
extern void set_conffile(char *file);
+extern int conf_exists(void);
extern char *conf_get_mailaddr(void);
extern char *conf_get_mailfrom(void);
extern char *conf_get_program(void);
--- mdadm-3.0-devel3/mdopen.c.foreign 2009-03-20 19:02:38.000000000 -0400
+++ mdadm-3.0-devel3/mdopen.c 2009-03-20 19:02:43.000000000 -0400
@@ -159,7 +159,6 @@ int create_mddev(char *dev, char *name,
strcpy(chosen, "/dev/md/");
cname = chosen + strlen(chosen);
-
if (dev) {
if (strncmp(dev, "/dev/md/", 8) == 0) {
@@ -240,12 +239,14 @@ int create_mddev(char *dev, char *name,
if (num < 0 && trustworthy == LOCAL && name) {
/* if name is numeric, use that for num
* if it is not already in use */
- char *ep;
- num = strtoul(name, &ep, 10);
- if (ep == name || *ep)
- num = -1;
- else if (mddev_busy(use_mdp ? (-1-num) : num))
- num = -1;
+ char *e = name + strlen(name);
+ while (e > name && isdigit(e[-1]))
+ e--;
+ if (e[0]) {
+ num = strtoul(e, NULL, 10);
+ if (mddev_busy(use_mdp ? (-1-num) : num))
+ num = -1;
+ }
}
if (num < 0) {
--- mdadm-3.0-devel3/config.c.foreign 2009-03-10 01:39:41.000000000 -0400
+++ mdadm-3.0-devel3/config.c 2009-03-20 17:49:20.000000000 -0400
@@ -637,7 +637,7 @@ void homehostline(char *line)
}
}
-
+int exists = 0;
int loaded = 0;
static char *conffile = NULL;
@@ -683,6 +683,7 @@ void load_conffile(void)
if (f == NULL)
return;
+ exists = 1;
loaded = 1;
while ((line=conf_line(f))) {
switch(match_keyword(line)) {
@@ -718,6 +719,13 @@ void load_conffile(void)
/* printf("got file\n"); */
}
+int conf_exists(void)
+{
+ if (!loaded)
+ load_conffile();
+ return exists;
+}
+
char *conf_get_mailaddr(void)
{
load_conffile();