X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=mapfile.c;h=9e2c89368c9cc2a0f997cbbc35e6165fa2dafe0d;hb=308340aa585aed1f3703e03768d2973ffff83b12;hp=ffe8e16f1ef582023467844d7bdbb1c44462b99e;hpb=1538aca5cbbd99be47657e0ca0b7e2186426a1b1;p=thirdparty%2Fmdadm.git diff --git a/mapfile.c b/mapfile.c index ffe8e16f..9e2c8936 100644 --- a/mapfile.c +++ b/mapfile.c @@ -1,8 +1,8 @@ /* - * mapfile - manage /var/run/mdadm.map. Part of: + * mapfile - keep track of uuid <-> array mapping. Part of: * mdadm - manage Linux "md" devices aka RAID arrays. * - * Copyright (C) 2006-2009 Neil Brown + * Copyright (C) 2006-2010 Neil Brown * * * This program is free software; you can redistribute it and/or modify @@ -28,7 +28,7 @@ * Australia */ -/* /var/run/mdadm.map is used to track arrays being created in --incremental +/* The mapfile is used to track arrays being created in --incremental * mode. It particularly allows lookup from UUID to array device, but * also allows the array device name to be easily found. * @@ -38,48 +38,49 @@ * UUID - uuid of the array * path - path where device created: /dev/md/home * - * The preferred location for the map file is /var/run/mdadm.map. - * However /var/run may not exist or be writable in early boot. And if - * no-one has created /var/run/mdadm, we still want to survive. - * So possible locations are: - * /var/run/mdadm/map /var/run/mdadm.map /lib/initrw/madam/map - * The last can easily be change at compile to e.g. somewhere in /dev. - * We read from the first one that exists and write to the first - * one that we can. + * The best place for the mapfile wold be /var/run/mdadm/map. However + * it is needed during initramfs early-boot, and /var/run doesn't exist there + * and certainly doesn't persist through to normal boot. + * So we store it in /dev/.mdadm/map but allow this to be changed at + * compile time. via MAP_DIR and MAP_FILE + * */ #include "mdadm.h" #include #include -#define mapnames(base) { base, base ".new", base ".lock"} -char *mapname[3][3] = { - mapnames(VAR_RUN "/map"), - mapnames("/var/run/mdadm.map"), - mapnames(ALT_RUN "/" ALT_MAPFILE) +#ifndef MAP_DIR +#define MAP_DIR "/dev/.mdadm" +#define MAP_FILE "map" +#endif + +#define MAP_READ 0 +#define MAP_NEW 1 +#define MAP_LOCK 2 +#define MAP_DIRNAME 3 +#define mapnames(dir, base) { \ + +char *mapname[4] = { + MAP_DIR "/" MAP_FILE, + MAP_DIR "/" MAP_FILE ".new", + MAP_DIR "/" MAP_FILE ".lock", + MAP_DIR }; -char *mapdir[3] = { VAR_RUN, NULL, ALT_RUN }; -int mapmode[3] = { O_RDONLY, O_RDWR|O_CREAT, O_RDWR|O_CREAT | O_TRUNC }; +int mapmode[3] = { O_RDONLY, O_RDWR|O_CREAT, O_RDWR|O_CREAT|O_TRUNC }; char *mapsmode[3] = { "r", "w", "w"}; -FILE *open_map(int modenum, int *choice) +FILE *open_map(int modenum) { - int i; - - for (i = 0 ; i < 3 ; i++) { - int fd; - if ((mapmode[modenum] & O_CREAT) && - mapdir[modenum]) - /* Attempt to create directory, don't worry about - * failure. - */ - mkdir(mapdir[modenum], 0755); - fd = open(mapname[i][modenum], mapmode[modenum], 0600); - if (fd >= 0) { - *choice = i; - return fdopen(fd, mapsmode[modenum]); - } - } + int fd; + if ((mapmode[modenum] & O_CREAT)) + /* Attempt to create directory, don't worry about + * failure. + */ + (void)mkdir(mapname[MAP_DIRNAME], 0755); + fd = open(mapname[modenum], mapmode[modenum], 0600); + if (fd >= 0) + return fdopen(fd, mapsmode[modenum]); return NULL; } @@ -87,9 +88,8 @@ int map_write(struct map_ent *mel) { FILE *f; int err; - int which; - f = open_map(1, &which); + f = open_map(MAP_NEW); if (!f) return 0; @@ -109,20 +109,20 @@ int map_write(struct map_ent *mel) err = ferror(f); fclose(f); if (err) { - unlink(mapname[which][1]); + unlink(mapname[1]); return 0; } - return rename(mapname[which][1], - mapname[which][0]) == 0; + return rename(mapname[1], + mapname[0]) == 0; } static FILE *lf = NULL; -static int lwhich = 0; int map_lock(struct map_ent **melp) { - if (lf == NULL) { - lf = open_map(2, &lwhich); + while (lf == NULL) { + struct stat buf; + lf = open_map(MAP_LOCK); if (lf == NULL) return -1; if (flock(fileno(lf), LOCK_EX) != 0) { @@ -130,6 +130,15 @@ int map_lock(struct map_ent **melp) lf = NULL; return -1; } + if (fstat(fileno(lf), &buf) != 0 || + buf.st_nlink == 0) { + /* The owner of the lock unlinked it, + * so we have a lock on a stale file, + * try again + */ + fclose(lf); + lf = NULL; + } } if (*melp) map_free(*melp); @@ -140,13 +149,28 @@ int map_lock(struct map_ent **melp) void map_unlock(struct map_ent **melp) { if (lf) { - flock(fileno(lf), LOCK_UN); + /* must unlink before closing the file, + * as only the owner of the lock may + * unlink the file + */ + unlink(mapname[2]); fclose(lf); } - unlink(mapname[lwhich][2]); lf = NULL; } +void map_fork(void) +{ + /* We are forking, so must close the lock file. + * Don't risk flushing anything though. + */ + if (lf) { + close(fileno(lf)); + fclose(lf); + lf = NULL; + } +} + void map_add(struct map_ent **melp, int devnum, char *metadata, int uuid[4], char *path) { @@ -169,14 +193,13 @@ void map_read(struct map_ent **melp) int devnum, uuid[4]; char metadata[30]; char nam[4]; - int which; *melp = NULL; - f = open_map(0, &which); + f = open_map(MAP_READ); if (!f) { RebuildMap(); - f = open_map(0, &which); + f = open_map(MAP_READ); } if (!f) return; @@ -223,6 +246,7 @@ int map_update(struct map_ent **mpp, int devnum, char *metadata, memcpy(mp->uuid, uuid, 16); free(mp->path); mp->path = path ? strdup(path) : NULL; + mp->bad = 0; break; } if (!mp) @@ -323,31 +347,20 @@ struct map_ent *map_by_name(struct map_ent **map, char *name) * version super_by_fd does this automatically, this routine is meant as * a supplement for guess_super() */ -static void set_member_info(struct supertype *st, struct mdstat_ent *ent) +static char *get_member_info(struct mdstat_ent *ent) { - st->subarray[0] = '\0'; - if (ent->metadata_version == NULL || strncmp(ent->metadata_version, "external:", 9) != 0) - return; + return NULL; if (is_subarray(&ent->metadata_version[9])) { - char version[strlen(ent->metadata_version)+1]; char *subarray; - char *name = &version[10]; - - strcpy(version, ent->metadata_version); - subarray = strrchr(version, '/'); - name = &version[10]; - - if (!subarray) - return; - *subarray++ = '\0'; - st->container_dev = devname2devnum(name); - strncpy(st->subarray, subarray, sizeof(st->subarray)); + subarray = strrchr(ent->metadata_version, '/'); + return subarray + 1; } + return NULL; } void RebuildMap(void) @@ -380,8 +393,9 @@ void RebuildMap(void) int dfd; int ok; struct supertype *st; + char *subarray = NULL; char *path; - struct mdinfo info; + struct mdinfo *info; sprintf(dn, "%d:%d", sd->disk.major, sd->disk.minor); dfd = dev_open(dn, O_RDONLY); @@ -391,13 +405,14 @@ void RebuildMap(void) if ( st == NULL) ok = -1; else { - set_member_info(st, md); + subarray = get_member_info(md); ok = st->ss->load_super(st, dfd, NULL); } close(dfd); if (ok != 0) continue; - st->ss->getinfo_super(st, &info); + info = st->ss->container_content(st, subarray); + if (md->devnum >= 0) path = map_dev(MD_MAJOR, md->devnum, 0); else @@ -417,7 +432,9 @@ void RebuildMap(void) * find a unique name based on metadata name. * */ - struct mddev_ident_s *match = conf_match(&info, st); + struct mddev_ident *match = conf_match(st, info, + NULL, 0, + NULL); struct stat stb; if (match && match->devname && match->devname[0] == '/') { path = match->devname; @@ -435,13 +452,13 @@ void RebuildMap(void) st->ss->match_home(st, homehost) != 1) && st->ss->match_home(st, "any") != 1 && (require_homehost - || ! conf_name_is_free(info.name))) + || ! 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; + name = info->name; if (!*name) { name = st->ss->name; if (!isdigit(name[strlen(name)-1]) && @@ -474,9 +491,10 @@ void RebuildMap(void) } } map_add(&map, md->devnum, - info.text_version, - info.uuid, path); + info->text_version, + info->uuid, path); st->ss->free_super(st); + free(info); break; } sysfs_free(sra);