]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-ddf.c
Incremental: support replacement devices.
[thirdparty/mdadm.git] / super-ddf.c
index d006a04d2c3dc41223ee4d8eb912060ba40fb72a..3b3c1f0ff8aac8205d10565894fc9dacf25c2f84 100644 (file)
@@ -439,7 +439,6 @@ struct ddf_super {
 #define offsetof(t,f) ((size_t)&(((t*)0)->f))
 #endif
 
-
 static unsigned int calc_crc(void *buf, int len)
 {
        /* crcs are always at the same place as in the ddf_header */
@@ -707,7 +706,7 @@ static int load_ddf_local(int fd, struct ddf_super *super,
                                       __func__);
                                return 1;
                        }
-                               
+
                        memcpy(dl->spare, vd, super->conf_rec_len*512);
                        continue;
                }
@@ -893,7 +892,6 @@ static struct supertype *match_metadata_desc_ddf(char *arg)
        return st;
 }
 
-
 #ifndef MDASSEMBLE
 
 static mapping_t ddf_state[] = {
@@ -1050,8 +1048,8 @@ static void examine_vd(int n, struct ddf_super *sb, char *guid)
                }
                printf(")\n");
                if (vc->chunk_shift != 255)
-               printf("   Chunk Size[%d] : %d sectors\n", n,
-                      1 << vc->chunk_shift);
+                       printf("   Chunk Size[%d] : %d sectors\n", n,
+                              1 << vc->chunk_shift);
                printf("   Raid Level[%d] : %s\n", n,
                       map_num(ddf_level, vc->prl)?:"-unknown-");
                if (vc->sec_elmnt_count != 1) {
@@ -1110,7 +1108,7 @@ static void examine_pds(struct ddf_super *sb)
                //printf("\n");
                printf("       %3d    %08x  ", i,
                       __be32_to_cpu(pd->refnum));
-               printf("%8lluK ", 
+               printf("%8lluK ",
                       (unsigned long long)__be64_to_cpu(pd->config_size)>>1);
                for (dl = sb->dlist; dl ; dl = dl->next) {
                        if (dl->disk.refnum == pd->refnum) {
@@ -1213,7 +1211,6 @@ static void export_examine_super_ddf(struct supertype *st)
        printf("MD_LEVEL=container\n");
        printf("MD_UUID=%s\n", nbuf+5);
 }
-       
 
 static void detail_super_ddf(struct supertype *st, char *homehost)
 {
@@ -1292,7 +1289,7 @@ static void uuid_from_super_ddf(struct supertype *st, int uuid[4])
         *    not the device-set.
         *  uuid to recognise same set when adding a missing device back
         *    to an array.   This is a uuid for the device-set.
-        *  
+        *
         * For each of these we can make do with a truncated
         * or hashed uuid rather than the original, as long as
         * everyone agrees.
@@ -1345,7 +1342,6 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *m
        info->array.chunk_size    = 0;
        info->container_enough    = 1;
 
-
        info->disk.major = 0;
        info->disk.minor = 0;
        if (ddf->dlist) {
@@ -1353,8 +1349,8 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *m
                info->disk.raid_disk = find_phys(ddf, ddf->dlist->disk.refnum);
 
                info->data_offset = __be64_to_cpu(ddf->phys->
-                                         entries[info->disk.raid_disk].
-                                         config_size);
+                                                 entries[info->disk.raid_disk].
+                                                 config_size);
                info->component_size = ddf->dlist->size - info->data_offset;
        } else {
                info->disk.number = -1;
@@ -1363,7 +1359,6 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *m
        }
        info->disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE);
 
-
        info->recovery_start = MaxSector;
        info->reshape_active = 0;
        info->recovery_blocked = 0;
@@ -1471,7 +1466,7 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info, cha
                        map[j] = 0;
                        if (j <  info->array.raid_disks) {
                                int i = find_phys(ddf, vc->conf.phys_refnum[j]);
-                               if (i >= 0 && 
+                               if (i >= 0 &&
                                    (__be16_to_cpu(ddf->phys->entries[i].state) & DDF_Online) &&
                                    !(__be16_to_cpu(ddf->phys->entries[i].state) & DDF_Failed))
                                        map[i] = 1;
@@ -1479,7 +1474,6 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info, cha
                }
 }
 
-
 static int update_super_ddf(struct supertype *st, struct mdinfo *info,
                            char *update,
                            char *devname, int verbose,
@@ -1574,12 +1568,12 @@ static int init_super_ddf_bvd(struct supertype *st,
                              mdu_array_info_t *info,
                              unsigned long long size,
                              char *name, char *homehost,
-                             int *uuid);
+                             int *uuid, unsigned long long data_offset);
 
 static int init_super_ddf(struct supertype *st,
                          mdu_array_info_t *info,
                          unsigned long long size, char *name, char *homehost,
-                         int *uuid)
+                         int *uuid, unsigned long long data_offset)
 {
        /* This is primarily called by Create when creating a new array.
         * We will then get add_to_super called for each component, and then
@@ -1615,8 +1609,14 @@ static int init_super_ddf(struct supertype *st,
        struct phys_disk *pd;
        struct virtual_disk *vd;
 
+       if (data_offset != INVALID_SECTORS) {
+               fprintf(stderr, Name ": data-offset not supported by DDF\n");
+               return 0;
+       }
+
        if (st->sb)
-               return init_super_ddf_bvd(st, info, size, name, homehost, uuid);
+               return init_super_ddf_bvd(st, info, size, name, homehost, uuid,
+                                         data_offset);
 
        if (posix_memalign((void**)&ddf, 512, sizeof(*ddf)) != 0) {
                pr_err("%s could not allocate superblock\n", __func__);
@@ -1807,6 +1807,7 @@ static int level_to_prl(int level)
        default: return -1;
        }
 }
+
 static int layout_to_rlq(int level, int layout, int raiddisks)
 {
        switch(level) {
@@ -1910,7 +1911,7 @@ static struct extent *get_extents(struct ddf_super *ddf, struct dl *dl)
         * (dnum) of the given ddf.
         * Return a malloced array of 'struct extent'
 
-FIXME ignore DDF_Legacy devices?
+        * FIXME ignore DDF_Legacy devices?
 
         */
        struct extent *rv;
@@ -1944,7 +1945,7 @@ static int init_super_ddf_bvd(struct supertype *st,
                              mdu_array_info_t *info,
                              unsigned long long size,
                              char *name, char *homehost,
-                             int *uuid)
+                             int *uuid, unsigned long long data_offset)
 {
        /* We are creating a BVD inside a pre-existing container.
         * so st->sb is already set.
@@ -1982,7 +1983,7 @@ static int init_super_ddf_bvd(struct supertype *st,
                        break;
        if (venum == __be16_to_cpu(ddf->virt->max_vdes)) {
                pr_err("Cannot find spare slot for "
-                       "virtual disk - DDF is corrupt\n");
+                      "virtual disk - DDF is corrupt\n");
                return 0;
        }
        ve = &ddf->virt->entries[venum];
@@ -2173,7 +2174,8 @@ static void add_to_super_ddf_bvd(struct supertype *st,
  * expanding a pre-existing container
  */
 static int add_to_super_ddf(struct supertype *st,
-                            mdu_disk_info_t *dk, int fd, char *devname)
+                           mdu_disk_info_t *dk, int fd, char *devname,
+                           unsigned long long data_offset)
 {
        struct ddf_super *ddf = st->sb;
        struct dl *dd;
@@ -2474,7 +2476,7 @@ static int write_init_super_ddf(struct supertype *st)
 
                /* FIXME I need to close the fds! */
                return 0;
-       } else {        
+       } else {
                struct dl *d;
                for (d = ddf->dlist; d; d=d->next)
                        while (Kill(d->devname, NULL, 0, -1, 1) == 0);
@@ -2484,7 +2486,8 @@ static int write_init_super_ddf(struct supertype *st)
 
 #endif
 
-static __u64 avail_size_ddf(struct supertype *st, __u64 devsize)
+static __u64 avail_size_ddf(struct supertype *st, __u64 devsize,
+                           unsigned long long data_offset)
 {
        /* We must reserve the last 32Meg */
        if (devsize <= 32*1024*2)
@@ -2508,7 +2511,7 @@ static int reserve_space(struct supertype *st, int raiddisks,
        int cnt = 0;
 
        for (dl = ddf->dlist; dl ; dl=dl->next) {
-               dl->raiddisk = -1;      
+               dl->raiddisk = -1;
                dl->esize = 0;
        }
        /* Now find largest extent on each device */
@@ -2574,31 +2577,32 @@ static int reserve_space(struct supertype *st, int raiddisks,
        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,
                                int chunk, unsigned long long size,
+                               unsigned long long data_offset,
                                char *dev, unsigned long long *freesize,
                                int verbose);
 
 static int validate_geometry_ddf_bvd(struct supertype *st,
                                     int level, int layout, int raiddisks,
                                     int *chunk, unsigned long long size,
+                                    unsigned long long data_offset,
                                     char *dev, unsigned long long *freesize,
                                     int verbose);
 
 static int validate_geometry_ddf(struct supertype *st,
                                 int level, int layout, int raiddisks,
                                 int *chunk, unsigned long long size,
+                                unsigned long long data_offset,
                                 char *dev, unsigned long long *freesize,
                                 int verbose)
 {
@@ -2616,12 +2620,13 @@ static int validate_geometry_ddf(struct supertype *st,
        if (chunk && *chunk == UnSet)
                *chunk = DEFAULT_CHUNK;
 
-
+       if (level == -1000000) level = LEVEL_CONTAINER;
        if (level == LEVEL_CONTAINER) {
                /* Must be a fresh device to add to a container */
                return validate_geometry_ddf_container(st, level, layout,
                                                       raiddisks, chunk?*chunk:0,
-                                                      size, dev, freesize,
+                                                      size, data_offset, dev,
+                                                      freesize,
                                                       verbose);
        }
 
@@ -2634,7 +2639,7 @@ static int validate_geometry_ddf(struct supertype *st,
                if (ddf_level_num[i].num1 == MAXINT) {
                        if (verbose)
                                pr_err("DDF does not support level %d arrays\n",
-                                       level);
+                                      level);
                        return 0;
                }
                /* Should check layout? etc */
@@ -2658,7 +2663,8 @@ static int validate_geometry_ddf(struct supertype *st,
                 * Should make a distinction one day.
                 */
                return validate_geometry_ddf_bvd(st, level, layout, raiddisks,
-                                                chunk, size, dev, freesize,
+                                                chunk, size, data_offset, dev,
+                                                freesize,
                                                 verbose);
        }
        /* This is the first device for the array.
@@ -2690,7 +2696,7 @@ static int validate_geometry_ddf(struct supertype *st,
        if (errno != EBUSY || (fd = open(dev, O_RDONLY, 0)) < 0) {
                if (verbose)
                        pr_err("ddf: Cannot open %s: %s\n",
-                               dev, strerror(errno));
+                              dev, strerror(errno));
                return 0;
        }
        /* Well, it is in use by someone, maybe a 'ddf' container. */
@@ -2699,7 +2705,7 @@ static int validate_geometry_ddf(struct supertype *st,
                close(fd);
                if (verbose)
                        pr_err("ddf: Cannot use %s: %s\n",
-                               dev, strerror(EBUSY));
+                              dev, strerror(EBUSY));
                return 0;
        }
        sra = sysfs_read(cfd, 0, GET_VERSION);
@@ -2716,6 +2722,7 @@ static int validate_geometry_ddf(struct supertype *st,
                        close(cfd);
                        return validate_geometry_ddf_bvd(st, level, layout,
                                                         raiddisks, chunk, size,
+                                                        data_offset,
                                                         dev, freesize,
                                                         verbose);
                }
@@ -2730,6 +2737,7 @@ static int
 validate_geometry_ddf_container(struct supertype *st,
                                int level, int layout, int raiddisks,
                                int chunk, unsigned long long size,
+                               unsigned long long data_offset,
                                char *dev, unsigned long long *freesize,
                                int verbose)
 {
@@ -2745,7 +2753,7 @@ validate_geometry_ddf_container(struct supertype *st,
        if (fd < 0) {
                if (verbose)
                        pr_err("ddf: Cannot open %s: %s\n",
-                               dev, strerror(errno));
+                              dev, strerror(errno));
                return 0;
        }
        if (!get_dev_size(fd, dev, &ldsize)) {
@@ -2754,7 +2762,7 @@ validate_geometry_ddf_container(struct supertype *st,
        }
        close(fd);
 
-       *freesize = avail_size_ddf(st, ldsize >> 9);
+       *freesize = avail_size_ddf(st, ldsize >> 9, INVALID_SECTORS);
        if (*freesize == 0)
                return 0;
 
@@ -2764,6 +2772,7 @@ validate_geometry_ddf_container(struct supertype *st,
 static int validate_geometry_ddf_bvd(struct supertype *st,
                                     int level, int layout, int raiddisks,
                                     int *chunk, unsigned long long size,
+                                    unsigned long long data_offset,
                                     char *dev, unsigned long long *freesize,
                                     int verbose)
 {
@@ -2834,21 +2843,21 @@ static int validate_geometry_ddf_bvd(struct supertype *st,
        if (!dl) {
                if (verbose)
                        pr_err("ddf: %s is not in the "
-                               "same DDF set\n",
-                               dev);
+                              "same DDF set\n",
+                              dev);
                return 0;
        }
        e = get_extents(ddf, dl);
        maxsize = 0;
        i = 0;
        if (e) do {
-               unsigned long long esize;
-               esize = e[i].start - pos;
-               if (esize >= maxsize)
-                       maxsize = esize;
-               pos = e[i].start + e[i].size;
-               i++;
-       } while (e[i-1].size);
+                       unsigned long long esize;
+                       esize = e[i].start - pos;
+                       if (esize >= maxsize)
+                               maxsize = esize;
+                       pos = e[i].start + e[i].size;
+                       i++;
+               } while (e[i-1].size);
        *freesize = maxsize;
        // FIXME here I am
 
@@ -3180,8 +3189,8 @@ static int ddf_set_array_state(struct active_array *a, int consistent)
 }
 
 #define container_of(ptr, type, member) ({                      \
-        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
-        (type *)( (char *)__mptr - offsetof(type,member) );})
+       const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+       (type *)( (char *)__mptr - offsetof(type,member) );})
 /*
  * The state of each disk is stored in the global phys_disk structure
  * in phys_disk.entries[n].state.
@@ -3274,29 +3283,29 @@ static void ddf_set_disk(struct active_array *a, int n, int state)
        if (working == a->info.array.raid_disks)
                state = DDF_state_optimal;
        else switch(vc->prl) {
-       case DDF_RAID0:
-       case DDF_CONCAT:
-       case DDF_JBOD:
-               state = DDF_state_failed;
-               break;
-       case DDF_RAID1:
-               if (working == 0)
+               case DDF_RAID0:
+               case DDF_CONCAT:
+               case DDF_JBOD:
                        state = DDF_state_failed;
-               else if (working == 2 && state == DDF_state_degraded)
-                       state = DDF_state_part_optimal;
-               break;
-       case DDF_RAID4:
-       case DDF_RAID5:
-               if (working < a->info.array.raid_disks-1)
-                       state = DDF_state_failed;
-               break;
-       case DDF_RAID6:
-               if (working < a->info.array.raid_disks-2)
-                       state = DDF_state_failed;
-               else if (working == a->info.array.raid_disks-1)
-                       state = DDF_state_part_optimal;
-               break;
-       }
+                       break;
+               case DDF_RAID1:
+                       if (working == 0)
+                               state = DDF_state_failed;
+                       else if (working == 2 && state == DDF_state_degraded)
+                               state = DDF_state_part_optimal;
+                       break;
+               case DDF_RAID4:
+               case DDF_RAID5:
+                       if (working < a->info.array.raid_disks-1)
+                               state = DDF_state_failed;
+                       break;
+               case DDF_RAID6:
+                       if (working < a->info.array.raid_disks-2)
+                               state = DDF_state_failed;
+                       else if (working == a->info.array.raid_disks-1)
+                               state = DDF_state_part_optimal;
+                       break;
+               }
 
        if (ddf->virt->entries[inst].state !=
            ((ddf->virt->entries[inst].state & ~DDF_state_mask)
@@ -3405,7 +3414,7 @@ static void ddf_process_update(struct supertype *st,
                        return;
                ddf->phys->entries[ent] = pd->entries[0];
                ddf->phys->used_pdes = __cpu_to_be16(1 +
-                                          __be16_to_cpu(ddf->phys->used_pdes));
+                                                    __be16_to_cpu(ddf->phys->used_pdes));
                ddf->updates_pending = 1;
                if (ddf->add_list) {
                        struct active_array *a;
@@ -3437,7 +3446,7 @@ static void ddf_process_update(struct supertype *st,
                        return;
                ddf->virt->entries[ent] = vd->entries[0];
                ddf->virt->populated_vdes = __cpu_to_be16(1 +
-                             __be16_to_cpu(ddf->virt->populated_vdes));
+                                                         __be16_to_cpu(ddf->virt->populated_vdes));
                ddf->updates_pending = 1;
                break;
 
@@ -3519,12 +3528,12 @@ static void ddf_process_update(struct supertype *st,
                                        ~__cpu_to_be16(DDF_Global_Spare);
                                if (!(ddf->phys->entries[dl->pdnum].type &
                                      __cpu_to_be16(DDF_Active_in_VD))) {
-                                           ddf->phys->entries[dl->pdnum].type |=
-                                                   __cpu_to_be16(DDF_Active_in_VD);
-                                           if (in_degraded)
-                                                   ddf->phys->entries[dl->pdnum].state |=
-                                                           __cpu_to_be16(DDF_Rebuilding);
-                                   }
+                                       ddf->phys->entries[dl->pdnum].type |=
+                                               __cpu_to_be16(DDF_Active_in_VD);
+                                       if (in_degraded)
+                                               ddf->phys->entries[dl->pdnum].state |=
+                                                       __cpu_to_be16(DDF_Rebuilding);
+                               }
                        }
                        if (dl->spare) {
                                ddf->phys->entries[dl->pdnum].type &=
@@ -3585,8 +3594,8 @@ static void ddf_prepare_update(struct supertype *st,
        __u32 *magic = (__u32*)update->buf;
        if (*magic == DDF_VD_CONF_MAGIC)
                if (posix_memalign(&update->space, 512,
-                              offsetof(struct vcl, conf)
-                              + ddf->conf_rec_len * 512) != 0)
+                                  offsetof(struct vcl, conf)
+                                  + ddf->conf_rec_len * 512) != 0)
                        update->space = NULL;
 }
 
@@ -3622,7 +3631,7 @@ static struct mdinfo *ddf_activate_spare(struct active_array *a,
 
        for (d = a->info.devs ; d ; d = d->next) {
                if ((d->curr_state & DS_FAULTY) &&
-                       d->state_fd >= 0)
+                   d->state_fd >= 0)
                        /* wait for Removal to happen */
                        return NULL;
                if (d->state_fd >= 0)
@@ -3701,11 +3710,15 @@ static struct mdinfo *ddf_activate_spare(struct active_array *a,
                        } else if (ddf->phys->entries[dl->pdnum].type &
                                   __cpu_to_be16(DDF_Global_Spare)) {
                                is_global = 1;
+                       } else if (!(ddf->phys->entries[dl->pdnum].state &
+                                    __cpu_to_be16(DDF_Failed))) {
+                               /* we can possibly use some of this */
+                               is_global = 1;
                        }
                        if ( ! (is_dedicated ||
                                (is_global && global_ok))) {
                                dprintf("%x:%x not suitable: %d %d\n", dl->major, dl->minor,
-                                      is_dedicated, is_global);
+                                       is_dedicated, is_global);
                                continue;
                        }