summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2009-05-11 15:58:42 +1000
committerNeilBrown <neilb@suse.de>2009-05-11 15:58:42 +1000
commit360b463696e89593645c0f094f0c39ba0fa65944 (patch)
tree9d1e369adfa0f5f9b89c1d4a86c0da88e4767d39
parent2400e6eb21af93368824110d087708dc9c48f744 (diff)
downloadmdadm-360b463696e89593645c0f094f0c39ba0fa65944.tar.gz
mdadm-360b463696e89593645c0f094f0c39ba0fa65944.tar.xz
mdadm-360b463696e89593645c0f094f0c39ba0fa65944.zip
mapfile - when rebuilding, choose an appropriate name is none is found.
When rebuilding the mapfile (mdadm -Ir), if not appropriate name is found in /dev/md/, try to find an appropriate name, either by looking in mdadm.conf or by using the name in the metadata. Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r--config.c70
-rw-r--r--mapfile.c85
-rw-r--r--mdadm.h1
3 files changed, 155 insertions, 1 deletions
diff --git a/config.c b/config.c
index d171b1e..275ca21 100644
--- a/config.c
+++ b/config.c
@@ -1013,3 +1013,73 @@ int conf_name_is_free(char *name)
}
return 1;
}
+
+struct mddev_ident_s *conf_match(struct mdinfo *info, struct supertype *st)
+{
+ struct mddev_ident_s *array_list, *match;
+ int verbose = 0;
+ char *devname = NULL;
+ array_list = conf_get_ident(NULL);
+ match = NULL;
+ for (; array_list; array_list = array_list->next) {
+ if (array_list->uuid_set &&
+ same_uuid(array_list->uuid, info->uuid, st->ss->swapuuid)
+ == 0) {
+ if (verbose >= 2 && array_list->devname)
+ fprintf(stderr, Name
+ ": UUID differs from %s.\n",
+ array_list->devname);
+ continue;
+ }
+ if (array_list->name[0] &&
+ strcasecmp(array_list->name, info->name) != 0) {
+ if (verbose >= 2 && array_list->devname)
+ fprintf(stderr, Name
+ ": Name differs from %s.\n",
+ array_list->devname);
+ continue;
+ }
+ if (array_list->devices && devname &&
+ !match_oneof(array_list->devices, devname)) {
+ if (verbose >= 2 && array_list->devname)
+ fprintf(stderr, Name
+ ": Not a listed device for %s.\n",
+ array_list->devname);
+ continue;
+ }
+ if (array_list->super_minor != UnSet &&
+ array_list->super_minor != info->array.md_minor) {
+ if (verbose >= 2 && array_list->devname)
+ fprintf(stderr, Name
+ ": Different super-minor to %s.\n",
+ array_list->devname);
+ continue;
+ }
+ if (!array_list->uuid_set &&
+ !array_list->name[0] &&
+ !array_list->devices &&
+ array_list->super_minor == UnSet) {
+ if (verbose >= 2 && array_list->devname)
+ fprintf(stderr, Name
+ ": %s doesn't have any identifying information.\n",
+ array_list->devname);
+ continue;
+ }
+ /* FIXME, should I check raid_disks and level too?? */
+
+ if (match) {
+ if (verbose >= 0) {
+ if (match->devname && array_list->devname)
+ fprintf(stderr, Name
+ ": we match both %s and %s - cannot decide which to use.\n",
+ match->devname, array_list->devname);
+ else
+ fprintf(stderr, Name
+ ": multiple lines in mdadm.conf match\n");
+ }
+ return NULL;
+ }
+ match = array_list;
+ }
+ return match;
+}
diff --git a/mapfile.c b/mapfile.c
index 112d385..601c4cc 100644
--- a/mapfile.c
+++ b/mapfile.c
@@ -47,7 +47,8 @@
* We read from the first one that exists and write to the first
* one that we can.
*/
-#include "mdadm.h"
+#include "mdadm.h"
+#include <ctype.h>
#define mapnames(base) { #base, #base ".new", #base ".lock"}
char *mapname[3][3] = {
@@ -302,6 +303,16 @@ void RebuildMap(void)
struct mdstat_ent *md;
struct map_ent *map = NULL;
int mdp = get_mdp_major();
+ int require_homehost;
+ char sys_hostname[256];
+ char *homehost = conf_get_homehost(&require_homehost);
+
+ if (homehost == NULL || strcmp(homehost, "<system>")==0) {
+ if (gethostname(sys_hostname, sizeof(sys_hostname)) == 0) {
+ sys_hostname[sizeof(sys_hostname)-1] = 0;
+ homehost = sys_hostname;
+ }
+ }
for (md = mdstat ; md ; md = md->next) {
struct mdinfo *sra = sysfs_read(-1, md->devnum, GET_DEVS|SKIP_GONE_DEVS);
@@ -311,6 +322,7 @@ void RebuildMap(void)
continue;
for (sd = sra->devs ; sd ; sd = sd->next) {
+ char namebuf[100];
char dn[30];
int dfd;
int ok;
@@ -335,6 +347,77 @@ void RebuildMap(void)
path = map_dev(MD_MAJOR, md->devnum, 0);
else
path = map_dev(mdp, (-1-md->devnum)<< 6, 0);
+ if (path == NULL ||
+ strncmp(path, "/dev/md/", 8) != 0) {
+ /* We would really like a name that provides
+ * an MD_DEVNAME for udev.
+ * The name needs to be unique both in /dev/md/
+ * and in this mapfile.
+ * It needs to match watch -I or -As would come
+ * up with.
+ * That means:
+ * Check if array is in mdadm.conf
+ * - if so use that.
+ * determine trustworthy from homehost etc
+ * find a unique name based on metadata name.
+ *
+ */
+ struct mddev_ident_s *match = conf_match(&info, st);
+ struct stat stb;
+ if (match && match->devname && match->devname[0] == '/') {
+ path = match->devname;
+ if (path[0] != '/') {
+ strcpy(namebuf, "/dev/md/");
+ strcat(namebuf, path);
+ path = namebuf;
+ }
+ } else {
+ int unum = 0;
+ char *sep = "_";
+ const char *name;
+ int conflict = 1;
+ if ((homehost == NULL ||
+ st->ss->match_home(st, homehost) != 1) &&
+ st->ss->match_home(st, "any") != 1 &&
+ (require_homehost
+ || ! conf_name_is_free(info.name)))
+ /* require a numeric suffix */
+ unum = 0;
+ else
+ /* allow name to be used as-is if no conflict */
+ unum = -1;
+ name = info.name;
+ if (!*name) {
+ name = st->ss->name;
+ if (!isdigit(name[strlen(name)-1]) &&
+ unum == -1) {
+ unum = 0;
+ sep = "";
+ }
+ }
+ if (strchr(name, ':'))
+ /* probably a uniquifying
+ * hostname prefix. Allow
+ * without a suffix
+ */
+ unum = -1;
+
+ while (conflict) {
+ if (unum >= 0)
+ sprintf(namebuf, "/dev/md/%s%s%d",
+ name, sep, unum);
+ else
+ sprintf(namebuf, "/dev/md/%s",
+ name);
+ unum++;
+ if (lstat(namebuf, &stb) != 0 &&
+ (map == NULL ||
+ !map_by_name(&map, namebuf+8)))
+ conflict = 0;
+ }
+ path = namebuf;
+ }
+ }
map_add(&map, md->devnum,
info.text_version,
info.uuid, path);
diff --git a/mdadm.h b/mdadm.h
index 645cf58..8aa38c5 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -801,6 +801,7 @@ extern char *conf_line(FILE *file);
extern char *conf_word(FILE *file, int allow_key);
extern int conf_name_is_free(char *name);
extern int devname_matches(char *name, char *match);
+extern struct mddev_ident_s *conf_match(struct mdinfo *info, struct supertype *st);
extern void free_line(char *line);
extern int match_oneof(char *devices, char *devname);