]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-ddf.c
imsm: enforce "all member disks must be members of all arrays"
[thirdparty/mdadm.git] / super-ddf.c
index 3c97bb678b70161ca34eebc5228b0d4e80677058..f621f4df3922ac43b5932a16a7e40cc982006538 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;
 };
@@ -1022,6 +1026,7 @@ static void examine_vd(int n, struct ddf_super *sb, char *guid)
        struct vcl *vcl;
 
        for (vcl = sb->conflist ; vcl ; vcl = vcl->next) {
+               int i;
                struct vd_config *vc = &vcl->conf;
 
                if (calc_crc(vc, crl*512) != vc->crc)
@@ -1030,8 +1035,22 @@ static void examine_vd(int n, struct ddf_super *sb, char *guid)
                        continue;
 
                /* Ok, we know about this VD, let's give more details */
-               printf(" Raid Devices[%d] : %d\n", n,
+               printf(" Raid Devices[%d] : %d (", n,
                       __be16_to_cpu(vc->prim_elmnt_count));
+               for (i=0; i<__be16_to_cpu(vc->prim_elmnt_count); i++) {
+                       int j;
+                       int cnt = __be16_to_cpu(sb->phys->used_pdes);
+                       for (j=0; j<cnt; j++)
+                               if (vc->phys_refnum[i] == sb->phys->entries[j].refnum)
+                                       break;
+                       if (i) printf(" ");
+                       if (j < cnt)
+                               printf("%d", j);
+                       else
+                               printf("--");
+               }
+               printf(")\n");
+               if (vc->chunk_shift != 255)
                printf("   Chunk Size[%d] : %d sectors\n", n,
                       1 << vc->chunk_shift);
                printf("   Raid Level[%d] : %s\n", n,
@@ -1057,6 +1076,7 @@ static void examine_vds(struct ddf_super *sb)
 
        for (i=0; i<cnt; i++) {
                struct virtual_entry *ve = &sb->virt->entries[i];
+               printf("\n");
                printf("      VD GUID[%d] : ", i); print_guid(ve->guid, 1);
                printf("\n");
                printf("         unit[%d] : %d\n", i, __be16_to_cpu(ve->unit));
@@ -1080,40 +1100,43 @@ static void examine_pds(struct ddf_super *sb)
        int i;
        struct dl *dl;
        printf(" Physical Disks : %d\n", cnt);
+       printf("      Number    RefNo    Size       Device    Type/State\n");
 
        for (i=0 ; i<cnt ; i++) {
                struct phys_disk_entry *pd = &sb->phys->entries[i];
                int type = __be16_to_cpu(pd->type);
                int state = __be16_to_cpu(pd->state);
 
-               printf("      PD GUID[%d] : ", i); print_guid(pd->guid, 0);
-               printf("\n");
-               printf("          ref[%d] : %08x\n", i,
+               //printf("      PD GUID[%d] : ", i); print_guid(pd->guid, 0);
+               //printf("\n");
+               printf("       %3d    %08x  ", i,
                       __be32_to_cpu(pd->refnum));
-               printf("         mode[%d] : %s%s%s%s%s\n", i,
+               printf("%lluK ",  __be64_to_cpu(pd->config_size)>>1);
+               for (dl = sb->dlist; dl ; dl = dl->next) {
+                       if (dl->disk.refnum == pd->refnum) {
+                               char *dv = map_dev(dl->major, dl->minor, 0);
+                               if (dv) {
+                                       printf("%-10s", dv);
+                                       break;
+                               }
+                       }
+               }
+               if (!dl)
+                       printf("%10s","");
+               printf(" %s%s%s%s%s",
                       (type&2) ? "active":"",
-                      (type&4) ? "Global Spare":"",
+                      (type&4) ? "Global-Spare":"",
                       (type&8) ? "spare" : "",
                       (type&16)? ", foreign" : "",
                       (type&32)? "pass-through" : "");
-               printf("        state[%d] : %s%s%s%s%s%s%s\n", i,
+               printf("/%s%s%s%s%s%s%s",
                       (state&1)? "Online": "Offline",
                       (state&2)? ", Failed": "",
                       (state&4)? ", Rebuilding": "",
                       (state&8)? ", in-transition": "",
-                      (state&16)? ", SMART errors": "",
-                      (state&32)? ", Unrecovered Read Errors": "",
+                      (state&16)? ", SMART-errors": "",
+                      (state&32)? ", Unrecovered-Read-Errors": "",
                       (state&64)? ", Missing" : "");
-               printf("   Avail Size[%d] : %llu K\n", i,
-                      __be64_to_cpu(pd->config_size)>>1);
-               for (dl = sb->dlist; dl ; dl = dl->next) {
-                       if (dl->disk.refnum == pd->refnum) {
-                               char *dv = map_dev(dl->major, dl->minor, 0);
-                               if (dv)
-                                       printf("       Device[%d] : %s\n",
-                                              i, dv);
-                       }
-               }
                printf("\n");
        }
 }
@@ -1325,6 +1348,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 +1370,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 +1996,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 +2009,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 +2057,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 +2373,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 +2501,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 +2510,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.
@@ -3426,4 +3569,5 @@ struct superswitch super_ddf = {
        .prepare_update = ddf_prepare_update,
        .activate_spare = ddf_activate_spare,
 #endif
+       .name = "ddf",
 };