]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Create: support autolayout when creating in a DDF
authorNeilBrown <neilb@suse.de>
Thu, 4 Dec 2008 05:08:33 +0000 (16:08 +1100)
committerNeilBrown <neilb@suse.de>
Thu, 4 Dec 2008 05:08:33 +0000 (16:08 +1100)
If, when creating an array, a signal target device is given which
is a container, then allow the metadata handler to choose which
devices to use.
This is currently only supported for DDF.

Signed-off-by: NeilBrown <neilb@suse.de>
Create.c
mdadm.h
super-ddf.c
super-intel.c

index 7ea39c4f6fd8e7a2181890ff924381537d3576da..422b46df1e371ae8480423edd0f791ab309fad87 100644 (file)
--- a/Create.c
+++ b/Create.c
@@ -81,6 +81,7 @@ int Create(struct supertype *st, char *mddev,
        unsigned long safe_mode_delay = 0;
        char chosen_name[1024];
        struct map_ent *map = NULL;
+       unsigned long long newsize;
 
        int major_num = BITMAP_MAJOR_HI;
 
@@ -147,13 +148,11 @@ int Create(struct supertype *st, char *mddev,
                                else
                                        st = NULL;
                        }
+                       if (have_container)
+                               subdevs = raiddisks;
                }
                if (fd >= 0)
                        close(fd);
-               if (have_container) {
-                       subdevs = 0;
-                       devlist = NULL;
-               }
        }
        if (st && st->ss->external && sparedisks) {
                fprintf(stderr,
@@ -238,16 +237,23 @@ int Create(struct supertype *st, char *mddev,
                fprintf(stderr, Name ": unknown level %d\n", level);
                return 1;
        }
-
+       
+       newsize = size * 2;
        if (st && ! st->ss->validate_geometry(st, level, layout, raiddisks,
-                                             chunk, size*2, NULL, NULL, verbose>=0))
+                                             chunk, size*2, NULL, &newsize, verbose>=0))
                return 1;
+       if (size == 0) {
+               size = newsize / 2;
+               if (size && verbose > 0)
+                       fprintf(stderr, Name ": setting size to %lluK\n",
+                               (unsigned long long)size);
+       }
 
        /* now look at the subdevs */
        info.array.active_disks = 0;
        info.array.working_disks = 0;
        dnum = 0;
-       for (dv=devlist; dv; dv=dv->next, dnum++) {
+       for (dv=devlist; dv && !have_container; dv=dv->next, dnum++) {
                char *dname = dv->devname;
                unsigned long long freesize;
                if (strcasecmp(dname, "missing")==0) {
@@ -341,6 +347,8 @@ int Create(struct supertype *st, char *mddev,
                        close(fd);
                }
        }
+       if (have_container)
+               info.array.working_disks = raiddisks;
        if (fail) {
                fprintf(stderr, Name ": create aborted\n");
                return 1;
@@ -366,9 +374,9 @@ int Create(struct supertype *st, char *mddev,
                                fprintf(stderr, Name ": size set to %lluK\n", size);
                }
        }
-       if (level > 0 && ((maxsize-size)*100 > maxsize)) {
+       if (!have_container && level > 0 && ((maxsize-size)*100 > maxsize)) {
                if (runstop != 1 || verbose >= 0)
-                       fprintf(stderr, Name ": largest drive (%s) exceed size (%lluK) by more than 1%%\n",
+                       fprintf(stderr, Name ": largest drive (%s) exceeds size (%lluK) by more than 1%%\n",
                                maxdisc, size);
                warn = 1;
        }
@@ -669,10 +677,15 @@ int Create(struct supertype *st, char *mddev,
                                abort();
                        if (dnum == insert_point) {
                                moved_disk = dv;
+                               continue;
                        }
-                       if (dnum == insert_point ||
-                           strcasecmp(dv->devname, "missing")==0)
+                       if (strcasecmp(dv->devname, "missing")==0)
                                continue;
+                       if (have_container)
+                               moved_disk = NULL;
+                       if (have_container && dnum < info.array.raid_disks - 1)
+                               /* repeatedly use the container */
+                               moved_disk = dv;
 
                        switch(pass) {
                        case 1:
@@ -689,31 +702,43 @@ int Create(struct supertype *st, char *mddev,
                                if (dv->writemostly == 1)
                                        inf->disk.state |= (1<<MD_DISK_WRITEMOSTLY);
 
-                               if (st->ss->external && st->subarray[0])
-                                       fd = open(dv->devname, O_RDWR);
-                               else
-                                       fd = open(dv->devname, O_RDWR|O_EXCL);
-
-                               if (fd < 0) {
-                                       fprintf(stderr, Name ": failed to open %s "
-                                               "after earlier success - aborting\n",
-                                               dv->devname);
-                                       goto abort;
+                               if (have_container)
+                                       fd = -1;
+                               else {
+                                       if (st->ss->external && st->subarray[0])
+                                               fd = open(dv->devname, O_RDWR);
+                                       else
+                                               fd = open(dv->devname, O_RDWR|O_EXCL);
+
+                                       if (fd < 0) {
+                                               fprintf(stderr, Name ": failed to open %s "
+                                                       "after earlier success - aborting\n",
+                                                       dv->devname);
+                                               goto abort;
+                                       }
+                                       fstat(fd, &stb);
+                                       inf->disk.major = major(stb.st_rdev);
+                                       inf->disk.minor = minor(stb.st_rdev);
                                }
-                               fstat(fd, &stb);
-                               inf->disk.major = major(stb.st_rdev);
-                               inf->disk.minor = minor(stb.st_rdev);
-
-                               remove_partitions(fd);
+                               if (fd >= 0)
+                                       remove_partitions(fd);
                                if (st->ss->add_to_super(st, &inf->disk,
                                                         fd, dv->devname))
                                        goto abort;
                                st->ss->getinfo_super(st, inf);
                                safe_mode_delay = inf->safe_mode_delay;
 
-                               /* getinfo_super might have lost these ... */
-                               inf->disk.major = major(stb.st_rdev);
-                               inf->disk.minor = minor(stb.st_rdev);
+                               if (have_container && verbose > 0)
+                                       fprintf(stderr, Name ": Using %s for device %d\n",
+                                               map_dev(inf->disk.major,
+                                                       inf->disk.minor,
+                                                       0), dnum);
+
+                               if (!have_container) {
+                                       /* getinfo_super might have lost these ... */
+                                       inf->disk.major = major(stb.st_rdev);
+                                       inf->disk.minor = minor(stb.st_rdev);
+                               }
                                break;
                        case 2:
                                inf->errors = 0;
@@ -731,7 +756,8 @@ int Create(struct supertype *st, char *mddev,
                                }
                                break;
                        }
-                       if (dv == moved_disk && dnum != insert_point) break;
+                       if (!have_container &&
+                           dv == moved_disk && dnum != insert_point) break;
                }
                if (pass == 1) {
                        st->ss->write_init_super(st);
diff --git a/mdadm.h b/mdadm.h
index b0966e6f9f9fa9c2b310605d843160ac1ff0dbeb..610e1d1b88914e55a8125e40360696a190e35282 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -448,7 +448,7 @@ extern struct superswitch {
         */
        void (*uuid_from_super)(struct supertype *st, int uuid[4]);
 
-       /* Extra generic details from metadata.  This could be details about
+       /* Extract generic details from metadata.  This could be details about
         * the container, or about an individual array within the container.
         * The determination is made either by:
         *   load_super being given a 'component' string.
index 3c97bb678b70161ca34eebc5228b0d4e80677058..3b3cac0551b56c713dc3b241c1ff051adaa7d994 100644 (file)
@@ -423,10 +423,14 @@ struct ddf_super {
                                unsigned long long size; /* sectors */
                                int pdnum;      /* index in ->phys */
                                struct spare_assign *spare;
+                               void *mdupdate; /* hold metadata update */
+
+                               /* These fields used by auto-layout */
+                               int raiddisk; /* slot to fill in autolayout */
+                               __u64 esize;
                        };
                };
                struct disk_data disk;
-               void *mdupdate; /* hold metadata update */
                struct vcl *vlist[0]; /* max_part in size */
        } *dlist, *add_list;
 };
@@ -1325,6 +1329,7 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info)
        struct vcl *vc = ddf->currentconf;
        int cd = ddf->currentdev;
        int j;
+       struct dl *dl;
 
        /* FIXME this returns BVD info - what if we want SVD ?? */
 
@@ -1346,8 +1351,15 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info)
                        info->component_size = __be64_to_cpu(vc->conf.blocks);
        }
 
+       for (dl = ddf->dlist; dl ; dl = dl->next)
+               if (dl->raiddisk == info->disk.raid_disk)
+                       break;
        info->disk.major = 0;
        info->disk.minor = 0;
+       if (dl) {
+               info->disk.major = dl->major;
+               info->disk.minor = dl->minor;
+       }
 //     info->disk.number = __be32_to_cpu(ddf->disk.refnum);
 //     info->disk.raid_disk = find refnum in the table and use index;
 //     info->disk.state = ???;
@@ -1965,6 +1977,9 @@ static void add_to_super_ddf_bvd(struct supertype *st,
         * the phys_refnum and lba_offset for the newly created vd_config.
         * We might also want to update the type in the phys_disk
         * section.
+        *
+        * Alternately: fd == -1 and we have already chosen which device to
+        * use and recorded in dlist->raid_disk;
         */
        struct dl *dl;
        struct ddf_super *ddf = st->sb;
@@ -1975,10 +1990,16 @@ static void add_to_super_ddf_bvd(struct supertype *st,
        unsigned long long blocks, pos, esize;
        struct extent *ex;
 
-       for (dl = ddf->dlist; dl ; dl = dl->next)
-               if (dl->major == dk->major &&
-                   dl->minor == dk->minor)
-                       break;
+       if (fd == -1) {
+               for (dl = ddf->dlist; dl ; dl = dl->next)
+                       if (dl->raiddisk == dk->raid_disk)
+                               break;
+       } else {
+               for (dl = ddf->dlist; dl ; dl = dl->next)
+                       if (dl->major == dk->major &&
+                           dl->minor == dk->minor)
+                               break;
+       }
        if (!dl || ! (dk->state & (1<<MD_DISK_SYNC)))
                return;
 
@@ -2017,8 +2038,10 @@ static void add_to_super_ddf_bvd(struct supertype *st,
                return;
        dl->vlist[i] = ddf->currentconf;
 
-       dl->fd = fd;
-       dl->devname = devname;
+       if (fd >= 0)
+               dl->fd = fd;
+       if (devname)
+               dl->devname = devname;
 
        /* Check how many working raid_disks, and if we can mark
         * array as optimal yet
@@ -2331,6 +2354,96 @@ static __u64 avail_size_ddf(struct supertype *st, __u64 devsize)
 }
 
 #ifndef MDASSEMBLE
+
+static int reserve_space(struct supertype *st, int raiddisks,
+                        unsigned long long size, int chunk,
+                        unsigned long long *freesize)
+{
+       /* Find 'raiddisks' spare extents at least 'size' big (but
+        * only caring about multiples of 'chunk') and remember
+        * them.
+        * If the cannot be found, fail.
+        */
+       struct dl *dl;
+       struct ddf_super *ddf = st->sb;
+       int cnt = 0;
+
+       for (dl = ddf->dlist; dl ; dl=dl->next) {
+               dl->raiddisk = -1;      
+               dl->esize = 0;
+       }
+       /* Now find largest extent on each device */
+       for (dl = ddf->dlist ; dl ; dl=dl->next) {
+               struct extent *e = get_extents(ddf, dl);
+               unsigned long long pos = 0;
+               int i = 0;
+               int found = 0;
+               unsigned long long minsize = size;
+
+               if (size == 0)
+                       minsize = chunk;
+
+               if (!e)
+                       continue;
+               do {
+                       unsigned long long esize;
+                       esize = e[i].start - pos;
+                       if (esize >= minsize) {
+                               found = 1;
+                               minsize = esize;
+                       }
+                       pos = e[i].start + e[i].size;
+                       i++;
+               } while (e[i-1].size);
+               if (found) {
+                       cnt++;
+                       dl->esize = minsize;
+               }
+               free(e);
+       }
+       if (cnt < raiddisks) {
+               fprintf(stderr, Name ": not enough devices with space to create array.\n");
+               return 0; /* No enough free spaces large enough */
+       }
+       if (size == 0) {
+               /* choose the largest size of which there are at least 'raiddisk' */
+               for (dl = ddf->dlist ; dl ; dl=dl->next) {
+                       struct dl *dl2;
+                       if (dl->esize <= size)
+                               continue;
+                       /* This is bigger than 'size', see if there are enough */
+                       cnt = 0;
+                       for (dl2 = dl; dl2 ; dl2=dl2->next)
+                               if (dl2->esize >= dl->esize)
+                                       cnt++;
+                       if (cnt >= raiddisks)
+                               size = dl->esize;
+               }
+               if (chunk) {
+                       size = size / chunk;
+                       size *= chunk;
+               }
+               *freesize = size;
+               if (size < 32) {
+                       fprintf(stderr, Name ": not enough spare devices to create array.\n");
+                       return 0;
+               }
+       }
+       /* We have a 'size' of which there are enough spaces.
+        * We simply do a first-fit */
+       cnt = 0;
+       for (dl = ddf->dlist ; dl && cnt < raiddisks ; dl=dl->next) {
+               if (dl->esize < size)
+                       continue;
+               
+               dl->raiddisk = cnt;
+               cnt++;
+       }
+       return 1;
+}
+
+
+
 static int
 validate_geometry_ddf_container(struct supertype *st,
                                int level, int layout, int raiddisks,
@@ -2369,15 +2482,6 @@ static int validate_geometry_ddf(struct supertype *st,
                                                       verbose);
        }
 
-       if (st->sb) {
-               /* A container has already been opened, so we are
-                * creating in there.  Maybe a BVD, maybe an SVD.
-                * Should make a distinction one day.
-                */
-               return validate_geometry_ddf_bvd(st, level, layout, raiddisks,
-                                                chunk, size, dev, freesize,
-                                                verbose);
-       }
        if (!dev) {
                /* Initial sanity check.  Exclude illegal levels. */
                int i;
@@ -2387,9 +2491,29 @@ static int validate_geometry_ddf(struct supertype *st,
                if (ddf_level_num[i].num1 == MAXINT)
                        return 0;
                /* Should check layout? etc */
+
+               if (st->sb && freesize) {
+                       /* --create was given a container to create in.
+                        * So we need to check that there are enough
+                        * free spaces and return the amount of space.
+                        * We may as well remember which drives were
+                        * chosen so that add_to_super/getinfo_super
+                        * can return them.
+                        */
+                       return reserve_space(st, raiddisks, size, chunk, freesize);
+               }
                return 1;
        }
 
+       if (st->sb) {
+               /* A container has already been opened, so we are
+                * creating in there.  Maybe a BVD, maybe an SVD.
+                * Should make a distinction one day.
+                */
+               return validate_geometry_ddf_bvd(st, level, layout, raiddisks,
+                                                chunk, size, dev, freesize,
+                                                verbose);
+       }
        /* This is the first device for the array.
         * If it is a container, we read it in and do automagic allocations,
         * no other devices should be given.
index f78957f13549325932cb22d7c45c89a21b154a82..b908375df0430cf875cb898ea0e44e05899e80ed 100644 (file)
@@ -2387,6 +2387,14 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                                        verbose);
        }
        
+       if (!dev) {
+               if (st->sb && freesize) {
+                       /* Should do auto-layout here */
+                       fprintf(stderr, Name ": IMSM does not support auto-layout yet\n");
+                       return 0;
+               }
+               return 1;
+       }
        if (st->sb) {
                /* creating in a given container */
                return validate_geometry_imsm_volume(st, level, layout,