From 03018d188d911fddb248018c3440f43b2c958ba9 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 4 Nov 2008 20:50:39 +1100 Subject: [PATCH 12/19] Incremental: lock against multiple concurrent additions to an array. In two devices are added via -I to one array at the same time, mdadm can get badly confused. Signed-off-by: NeilBrown Signed-off-by: Surbhi Palande --- Incremental.c | 76 +++++++++++++++++++++++++++++++++++--------------------- mapfile.c | 37 +++++++++++++++++++++++++++ mdadm.h | 2 + 3 files changed, 86 insertions(+), 29 deletions(-) diff --git a/Incremental.c b/Incremental.c index 870914d..0ab8dfe 100644 --- a/Incremental.c +++ b/Incremental.c @@ -222,40 +222,46 @@ int Incremental(char *devname, int verbose, int runstop, /* - Choose a free, high number. */ /* - Use a partitioned device unless strong suggestion not to. */ /* e.g. auto=md */ + + map_lock(&map); if (match && is_standard(match->devname, &devnum)) /* We have devnum now */; - else if ((mp = map_by_uuid(&map, info.uuid)) != NULL) - devnum = mp->devnum; else { - /* Have to guess a bit. */ - int use_partitions = 1; - char *np, *ep; - if ((autof&7) == 3 || (autof&7) == 5) - use_partitions = 0; - np = strchr(info.name, ':'); - if (np) - np++; - else - np = info.name; - devnum = strtoul(np, &ep, 10); - if (ep > np && *ep == 0) { - /* This is a number. Let check that it is unused. */ - if (mddev_busy(use_partitions ? (-1-devnum) : devnum)) + mp = map_by_uuid(&map, info.uuid); + if (mp != NULL) + devnum = mp->devnum; + else { + /* Have to guess a bit. */ + int use_partitions = 1; + char *np, *ep; + if ((autof&7) == 3 || (autof&7) == 5) + use_partitions = 0; + np = strchr(info.name, ':'); + if (np) + np++; + else + np = info.name; + devnum = strtoul(np, &ep, 10); + if (ep > np && *ep == 0) { + /* This is a number. Let check that it is unused. */ + if (mddev_busy(use_partitions ? (-1-devnum) : devnum)) + devnum = -1; + } else devnum = -1; - } else - devnum = -1; - if (devnum < 0) { - /* Haven't found anything yet, choose something free */ - devnum = find_free_devnum(use_partitions); + if (devnum < 0) { + /* Haven't found anything yet, choose something free */ + devnum = find_free_devnum(use_partitions); - if (devnum == NoMdDev) { - fprintf(stderr, Name - ": No spare md devices!!\n"); - return 2; - } - } else - devnum = use_partitions ? (-1-devnum) : devnum; + if (devnum == NoMdDev) { + fprintf(stderr, Name + ": No spare md devices!!\n"); + map_unlock(&map); + return 2; + } + } else + devnum = use_partitions ? (-1-devnum) : devnum; + } } mdfd = create_mddev_devnum(match ? match->devname : NULL, devnum, @@ -264,6 +270,7 @@ int Incremental(char *devname, int verbose, int runstop, if (mdfd < 0) { fprintf(stderr, Name ": failed to open %s: %s.\n", chosen_name, strerror(errno)); + map_unlock(&map); return 2; } /* 5/ Find out if array already exists */ @@ -285,6 +292,7 @@ int Incremental(char *devname, int verbose, int runstop, ": SET_ARRAY_INFO failed for %s: %s\b", chosen_name, strerror(errno)); close(mdfd); + map_unlock(&map); return 2; } sprintf(md, "%d.%d\n", st->ss->major, st->minor_version); @@ -299,6 +307,7 @@ int Incremental(char *devname, int verbose, int runstop, devname, chosen_name, strerror(errno)); ioctl(mdfd, STOP_ARRAY, 0); close(mdfd); + map_unlock(&map); return 2; } sra = sysfs_read(mdfd, devnum, GET_DEVS); @@ -313,6 +322,7 @@ int Incremental(char *devname, int verbose, int runstop, " --incremental reliably. Aborting.\n"); close(mdfd); sysfs_free(sra); + map_unlock(&map); return 2; } } else { @@ -339,6 +349,7 @@ int Incremental(char *devname, int verbose, int runstop, sra->array.minor_version, st->ss->major, st->minor_version); close(mdfd); + map_unlock(&map); return 1; } sprintf(dn, "%d:%d", sra->devs->disk.major, @@ -351,6 +362,7 @@ int Incremental(char *devname, int verbose, int runstop, chosen_name); close(mdfd); close(dfd2); + map_unlock(&map); return 2; } close(dfd2); @@ -363,6 +375,7 @@ int Incremental(char *devname, int verbose, int runstop, ": unexpected difference between %s and %s.\n", chosen_name, devname); close(mdfd); + map_unlock(&map); return 2; } memset(&disk, 0, sizeof(disk)); @@ -381,6 +394,7 @@ int Incremental(char *devname, int verbose, int runstop, fprintf(stderr, Name ": failed to add %s to %s: %s.\n", devname, chosen_name, strerror(errno)); close(mdfd); + map_unlock(&map); return 2; } } @@ -390,6 +404,8 @@ int Incremental(char *devname, int verbose, int runstop, info.array.minor_version, info.uuid, chosen_name); + map_unlock(&map); + /* 7/ Is there enough devices to possibly start the array? */ /* 7a/ if not, finish with success. */ avail = NULL; @@ -424,6 +440,7 @@ int Incremental(char *devname, int verbose, int runstop, return 0; } } + if (runstop > 0 || active_disks >= info.array.working_disks) { struct mdinfo *sra; /* Let's try to start it */ @@ -675,7 +692,8 @@ int IncrementalScan(int verbose) mddev_ident_t devs, mddev; int rv = 0; - map_read(&mapl); + map_lock(&mapl); + map_unlock(&mapl); devs = conf_get_ident(NULL); for (me = mapl ; me ; me = me->next) { diff --git a/mapfile.c b/mapfile.c index a13dd3b..0229e56 100644 --- a/mapfile.c +++ b/mapfile.c @@ -86,6 +86,43 @@ int map_write(struct map_ent *mel) "/var/run/mdadm.map") == 0; } + +static int lfd = -1; +static int lsubdir = 0; +int map_lock(struct map_ent **melp) +{ + if (lfd < 0) { + lfd = open("/var/run/mdadm/map.lock", O_CREAT|O_RDWR, 0600); + if (lfd < 0) { + lfd = open("/var/run/mdadm.map.lock", O_CREAT|O_RDWR, 0600); + lsubdir = 0; + } else + lsubdir = 1; + if (lfd < 0) + return -1; + if (lockf(lfd, F_LOCK, 0) != 0) { + close(lfd); + lfd = -1; + return -1; + } + } + if (*melp) + map_free(*melp); + map_read(melp); + return 0; +} + +void map_unlock(struct map_ent **melp) +{ + if (lfd >= 0) + close(lfd); + if (lsubdir) + unlink("/var/run/mdadm/map.lock"); + else + unlink("/var/run/mdadm.map.lock"); + lfd = -1; +} + void map_add(struct map_ent **melp, int devnum, int major, int minor, int uuid[4], char *path) { diff --git a/mdadm.h b/mdadm.h index ee713fd..ca621a3 100644 --- a/mdadm.h +++ b/mdadm.h @@ -276,6 +276,8 @@ extern void map_delete(struct map_ent **mapp, int devnum); extern void map_free(struct map_ent *map); extern void map_add(struct map_ent **melp, int devnum, int major, int minor, int uuid[4], char *path); +extern int map_lock(struct map_ent **melp); +extern void map_unlock(struct map_ent **melp); /* various details can be requested */ #define GET_LEVEL 1 -- 1.7.0.4