]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Incremental: lock against multiple concurrent additions to an array.
authorNeilBrown <neilb@suse.de>
Tue, 4 Nov 2008 09:50:39 +0000 (20:50 +1100)
committerNeilBrown <neilb@suse.de>
Tue, 4 Nov 2008 09:50:39 +0000 (20:50 +1100)
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>
Build.c
Create.c
Incremental.c
mapfile.c
mdadm.h

diff --git a/Build.c b/Build.c
index d831e555fdb44fd506d19fb089a47032db97ecc3..c92c6a985b947d819e11572dc8cd9053405546fe 100644 (file)
--- a/Build.c
+++ b/Build.c
@@ -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);
 
index a66ed0ce2f01e50dd61ff94ee43bd866917f2df7..7492c67efaff3724bbc58792d9941ed4e8636001 100644 (file)
--- a/Create.c
+++ b/Create.c
@@ -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;
index f0f0c00c30072c0b9598ea48960d2b0985b3b2cc..37a762a1b1a900ef61f297c06bceda11e1776243 100644 (file)
@@ -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;
 }
index a59ea4dd9dfbc5eb929ddabfb9b2d6471ca4949c..1c2dc52b31f742d2bf6e160b0638c4fe4523d104 100644 (file)
--- 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, char *metadata, int uuid[4], char *path)
 {
diff --git a/mdadm.h b/mdadm.h
index dd33116cafcfdc46d803ff5b1786018f96e10207..bc12d68bca03aac40ab70a269c1e19ff6aca43b3 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -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