diff options
author | NeilBrown <neilb@suse.de> | 2008-11-04 20:50:39 +1100 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2008-11-04 20:50:39 +1100 |
commit | ad5bc697ad9bb52616c34b022fb014e890be6a2d (patch) | |
tree | c8c8905f29d993f4b3bcf7f449c249c4d9f21337 | |
parent | 7e6c6cb26790e4b0de2e8694cca655db26bee11a (diff) | |
download | mdadm-ad5bc697ad9bb52616c34b022fb014e890be6a2d.tar.gz mdadm-ad5bc697ad9bb52616c34b022fb014e890be6a2d.tar.xz mdadm-ad5bc697ad9bb52616c34b022fb014e890be6a2d.zip |
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 <neilb@suse.de>
-rw-r--r-- | Build.c | 9 | ||||
-rw-r--r-- | Create.c | 5 | ||||
-rw-r--r-- | Incremental.c | 28 | ||||
-rw-r--r-- | mapfile.c | 37 | ||||
-rw-r--r-- | mdadm.h | 2 |
5 files changed, 68 insertions, 13 deletions
@@ -62,6 +62,7 @@ int Build(char *mddev, int chunk, int level, int layout, int mdfd; char chosen_name[1024]; int uuid[4] = {0,0,0,0}; + struct map_ent *map = NULL; /* scan all devices, make sure they really are block devices */ for (dv = devlist; dv; dv=dv->next) { @@ -116,12 +117,16 @@ int Build(char *mddev, int chunk, int level, int layout, } /* We need to create the device. It can have no name. */ + map_lock(&map); mdfd = create_mddev(mddev, NULL, autof, LOCAL, chosen_name); - if (mdfd < 0) + if (mdfd < 0) { + map_unlock(&map); return 1; + } - map_update(NULL, fd2devnum(mdfd), "none", uuid, chosen_name); + map_update(&map, fd2devnum(mdfd), "none", uuid, chosen_name); + map_unlock(&map); vers = md_get_version(mdfd); @@ -80,6 +80,7 @@ int Create(struct supertype *st, char *mddev, int did_default = 0; unsigned long safe_mode_delay = 0; char chosen_name[1024]; + struct map_ent *map = NULL; int major_num = BITMAP_MAJOR_HI; @@ -422,6 +423,7 @@ int Create(struct supertype *st, char *mddev, } /* We need to create the device */ + map_lock(&map); mdfd = create_mddev(mddev, name, autof, LOCAL, chosen_name); if (mdfd < 0) return 1; @@ -561,8 +563,9 @@ int Create(struct supertype *st, char *mddev, " %s metadata\n", info.text_version); } - map_update(NULL, fd2devnum(mdfd), info.text_version, + map_update(&map, fd2devnum(mdfd), info.text_version, info.uuid, chosen_name); + map_unlock(&map); if (bitmap_file && vers < 9003) { major_num = BITMAP_MAJOR_HOSTENDIAN; diff --git a/Incremental.c b/Incremental.c index f0f0c00..37a762a 100644 --- a/Incremental.c +++ b/Incremental.c @@ -88,6 +88,7 @@ int Incremental(char *devname, int verbose, int runstop, int active_disks; int trustworthy = FOREIGN; char *name_to_use; + mdu_array_info_t ainf; struct createinfo *ci = conf_get_create_info(); @@ -243,8 +244,9 @@ int Incremental(char *devname, int verbose, int runstop, return Incremental_container(st, devname, verbose, runstop, autof, trustworthy); } - /* 4/ Check is array exists. + /* 4/ Check if array exists. */ + map_lock(&map); mp = map_by_uuid(&map, info.uuid); if (mp) mdfd = open_mddev(mp->path, 0); @@ -298,6 +300,10 @@ int Incremental(char *devname, int verbose, int runstop, } info.array.working_disks = 1; sysfs_free(sra); + /* 6/ Make sure /var/run/mdadm.map contains this array. */ + map_update(&map, fd2devnum(mdfd), + info.text_version, + info.uuid, chosen_name); } else { /* 5b/ if it does */ /* - check one drive in array to make sure metadata is a reasonably */ @@ -366,16 +372,13 @@ int Incremental(char *devname, int verbose, int runstop, info.array.working_disks ++; } - /* 6/ Make sure /var/run/mdadm.map contains this array. */ - map_update(&map, fd2devnum(mdfd), - info.text_version, - info.uuid, chosen_name); /* 7/ Is there enough devices to possibly start the array? */ /* 7a/ if not, finish with success. */ if (info.array.level == LEVEL_CONTAINER) { /* Try to assemble within the container */ close(mdfd); + map_unlock(&map); sysfs_uevent(&info, "change"); if (verbose >= 0) fprintf(stderr, Name @@ -394,6 +397,7 @@ int Incremental(char *devname, int verbose, int runstop, fprintf(stderr, Name ": %s attached to %s, not enough to start (%d).\n", devname, chosen_name, active_disks); + map_unlock(&map); close(mdfd); return 0; } @@ -404,18 +408,18 @@ int Incremental(char *devname, int verbose, int runstop, /* are enough, */ /* + add any bitmap file */ /* + start the array (auto-readonly). */ -{ - mdu_array_info_t ainf; if (ioctl(mdfd, GET_ARRAY_INFO, &ainf) == 0) { if (verbose >= 0) fprintf(stderr, Name ": %s attached to %s which is already active.\n", devname, chosen_name); - close (mdfd); + close(mdfd); + map_unlock(&map); return 0; } -} + + map_unlock(&map); if (runstop > 0 || active_disks >= info.array.working_disks) { struct mdinfo *sra; /* Let's try to start it */ @@ -749,13 +753,16 @@ int Incremental_container(struct supertype *st, char *devname, int verbose, struct mdinfo *list = st->ss->container_content(st); struct mdinfo *ra; + struct map_ent *map = NULL; + + map_lock(&map); for (ra = list ; ra ; ra = ra->next) { struct mdinfo *dev, *sra; int mdfd; char chosen_name[1024]; int working = 0, preexist = 0; - struct map_ent *mp, *map = NULL; + struct map_ent *mp; struct mddev_ident_s *match = NULL; mp = map_by_uuid(&map, ra->uuid); @@ -869,5 +876,6 @@ int Incremental_container(struct supertype *st, char *devname, int verbose, ra->uuid, chosen_name); close(mdfd); } + map_unlock(&map); return 0; } @@ -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, char *metadata, int uuid[4], char *path) { @@ -325,6 +325,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, char *metadata, 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 |