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>
This commit is contained in:
NeilBrown 2008-11-04 20:50:39 +11:00
parent 7e6c6cb267
commit ad5bc697ad
5 changed files with 68 additions and 13 deletions

View File

@ -62,6 +62,7 @@ int Build(char *mddev, int chunk, int level, int layout,
int mdfd; int mdfd;
char chosen_name[1024]; char chosen_name[1024];
int uuid[4] = {0,0,0,0}; int uuid[4] = {0,0,0,0};
struct map_ent *map = NULL;
/* scan all devices, make sure they really are block devices */ /* scan all devices, make sure they really are block devices */
for (dv = devlist; dv; dv=dv->next) { 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. */ /* We need to create the device. It can have no name. */
map_lock(&map);
mdfd = create_mddev(mddev, NULL, autof, LOCAL, mdfd = create_mddev(mddev, NULL, autof, LOCAL,
chosen_name); chosen_name);
if (mdfd < 0) if (mdfd < 0) {
map_unlock(&map);
return 1; 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); vers = md_get_version(mdfd);

View File

@ -80,6 +80,7 @@ int Create(struct supertype *st, char *mddev,
int did_default = 0; int did_default = 0;
unsigned long safe_mode_delay = 0; unsigned long safe_mode_delay = 0;
char chosen_name[1024]; char chosen_name[1024];
struct map_ent *map = NULL;
int major_num = BITMAP_MAJOR_HI; int major_num = BITMAP_MAJOR_HI;
@ -422,6 +423,7 @@ int Create(struct supertype *st, char *mddev,
} }
/* We need to create the device */ /* We need to create the device */
map_lock(&map);
mdfd = create_mddev(mddev, name, autof, LOCAL, chosen_name); mdfd = create_mddev(mddev, name, autof, LOCAL, chosen_name);
if (mdfd < 0) if (mdfd < 0)
return 1; return 1;
@ -561,8 +563,9 @@ int Create(struct supertype *st, char *mddev,
" %s metadata\n", info.text_version); " %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); info.uuid, chosen_name);
map_unlock(&map);
if (bitmap_file && vers < 9003) { if (bitmap_file && vers < 9003) {
major_num = BITMAP_MAJOR_HOSTENDIAN; major_num = BITMAP_MAJOR_HOSTENDIAN;

View File

@ -88,6 +88,7 @@ int Incremental(char *devname, int verbose, int runstop,
int active_disks; int active_disks;
int trustworthy = FOREIGN; int trustworthy = FOREIGN;
char *name_to_use; char *name_to_use;
mdu_array_info_t ainf;
struct createinfo *ci = conf_get_create_info(); 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, return Incremental_container(st, devname, verbose, runstop,
autof, trustworthy); autof, trustworthy);
} }
/* 4/ Check is array exists. /* 4/ Check if array exists.
*/ */
map_lock(&map);
mp = map_by_uuid(&map, info.uuid); mp = map_by_uuid(&map, info.uuid);
if (mp) if (mp)
mdfd = open_mddev(mp->path, 0); mdfd = open_mddev(mp->path, 0);
@ -298,6 +300,10 @@ int Incremental(char *devname, int verbose, int runstop,
} }
info.array.working_disks = 1; info.array.working_disks = 1;
sysfs_free(sra); 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 { } else {
/* 5b/ if it does */ /* 5b/ if it does */
/* - check one drive in array to make sure metadata is a reasonably */ /* - 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 ++; 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? */ /* 7/ Is there enough devices to possibly start the array? */
/* 7a/ if not, finish with success. */ /* 7a/ if not, finish with success. */
if (info.array.level == LEVEL_CONTAINER) { if (info.array.level == LEVEL_CONTAINER) {
/* Try to assemble within the container */ /* Try to assemble within the container */
close(mdfd); close(mdfd);
map_unlock(&map);
sysfs_uevent(&info, "change"); sysfs_uevent(&info, "change");
if (verbose >= 0) if (verbose >= 0)
fprintf(stderr, Name fprintf(stderr, Name
@ -394,6 +397,7 @@ int Incremental(char *devname, int verbose, int runstop,
fprintf(stderr, Name fprintf(stderr, Name
": %s attached to %s, not enough to start (%d).\n", ": %s attached to %s, not enough to start (%d).\n",
devname, chosen_name, active_disks); devname, chosen_name, active_disks);
map_unlock(&map);
close(mdfd); close(mdfd);
return 0; return 0;
} }
@ -404,18 +408,18 @@ int Incremental(char *devname, int verbose, int runstop,
/* are enough, */ /* are enough, */
/* + add any bitmap file */ /* + add any bitmap file */
/* + start the array (auto-readonly). */ /* + start the array (auto-readonly). */
{
mdu_array_info_t ainf;
if (ioctl(mdfd, GET_ARRAY_INFO, &ainf) == 0) { if (ioctl(mdfd, GET_ARRAY_INFO, &ainf) == 0) {
if (verbose >= 0) if (verbose >= 0)
fprintf(stderr, Name fprintf(stderr, Name
": %s attached to %s which is already active.\n", ": %s attached to %s which is already active.\n",
devname, chosen_name); devname, chosen_name);
close (mdfd); close(mdfd);
map_unlock(&map);
return 0; return 0;
} }
}
map_unlock(&map);
if (runstop > 0 || active_disks >= info.array.working_disks) { if (runstop > 0 || active_disks >= info.array.working_disks) {
struct mdinfo *sra; struct mdinfo *sra;
/* Let's try to start it */ /* 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 *list = st->ss->container_content(st);
struct mdinfo *ra; struct mdinfo *ra;
struct map_ent *map = NULL;
map_lock(&map);
for (ra = list ; ra ; ra = ra->next) { for (ra = list ; ra ; ra = ra->next) {
struct mdinfo *dev, *sra; struct mdinfo *dev, *sra;
int mdfd; int mdfd;
char chosen_name[1024]; char chosen_name[1024];
int working = 0, preexist = 0; int working = 0, preexist = 0;
struct map_ent *mp, *map = NULL; struct map_ent *mp;
struct mddev_ident_s *match = NULL; struct mddev_ident_s *match = NULL;
mp = map_by_uuid(&map, ra->uuid); 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); ra->uuid, chosen_name);
close(mdfd); close(mdfd);
} }
map_unlock(&map);
return 0; return 0;
} }

View File

@ -86,6 +86,43 @@ int map_write(struct map_ent *mel)
"/var/run/mdadm.map") == 0; "/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, void map_add(struct map_ent **melp,
int devnum, char *metadata, int uuid[4], char *path) int devnum, char *metadata, int uuid[4], char *path)
{ {

View File

@ -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_free(struct map_ent *map);
extern void map_add(struct map_ent **melp, extern void map_add(struct map_ent **melp,
int devnum, char *metadata, int uuid[4], char *path); 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 */ /* various details can be requested */
#define GET_LEVEL 1 #define GET_LEVEL 1