]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-ddf.c
raid6check.c: move manual repair code to separate function
[thirdparty/mdadm.git] / super-ddf.c
index 002b2717fc581f2b3c7f305ffe7bbcd5cdc68d05..c83960ab2f0be2b40670011f7d9d0d242c0cec09 100644 (file)
@@ -511,6 +511,8 @@ static void pr_state(const struct ddf_super *ddf, const char *msg) {}
 
 static void _ddf_set_updates_pending(struct ddf_super *ddf, const char *func)
 {
+       if (ddf->updates_pending)
+               return;
        ddf->updates_pending = 1;
        ddf->active->seq = cpu_to_be32((be32_to_cpu(ddf->active->seq)+1));
        pr_state(ddf, func);
@@ -1126,7 +1128,7 @@ static int load_super_ddf(struct supertype *st, int fd,
        if (get_dev_size(fd, devname, &dsize) == 0)
                return 1;
 
-       if (!st->ignore_hw_compat && test_partition(fd))
+       if (test_partition(fd))
                /* DDF is not allowed on partitions */
                return 1;
 
@@ -1913,6 +1915,7 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *m
        info->disk.major = 0;
        info->disk.minor = 0;
        if (ddf->dlist) {
+               struct phys_disk_entry *pde = NULL;
                info->disk.number = be32_to_cpu(ddf->dlist->disk.refnum);
                info->disk.raid_disk = find_phys(ddf, ddf->dlist->disk.refnum);
 
@@ -1920,12 +1923,21 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *m
                                                  entries[info->disk.raid_disk].
                                                  config_size);
                info->component_size = ddf->dlist->size - info->data_offset;
+               if (info->disk.raid_disk >= 0)
+                       pde = ddf->phys->entries + info->disk.raid_disk;
+               if (pde &&
+                   !(be16_to_cpu(pde->state) & DDF_Failed))
+                       info->disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE);
+               else
+                       info->disk.state = 1 << MD_DISK_FAULTY;
+
+               info->events = be32_to_cpu(ddf->active->seq);
        } else {
                info->disk.number = -1;
                info->disk.raid_disk = -1;
 //             info->disk.raid_disk = find refnum in the table and use index;
+               info->disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE);
        }
-       info->disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE);
 
        info->recovery_start = MaxSector;
        info->reshape_active = 0;
@@ -1943,8 +1955,6 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *m
                int i;
                for (i = 0 ; i < map_disks; i++) {
                        if (i < info->array.raid_disks &&
-                           (be16_to_cpu(ddf->phys->entries[i].state)
-                            & DDF_Online) &&
                            !(be16_to_cpu(ddf->phys->entries[i].state)
                              & DDF_Failed))
                                map[i] = 1;
@@ -2017,7 +2027,12 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info, cha
                info->disk.raid_disk = cd + conf->sec_elmnt_seq
                        * be16_to_cpu(conf->prim_elmnt_count);
                info->disk.number = dl->pdnum;
-               info->disk.state = (1<<MD_DISK_SYNC)|(1<<MD_DISK_ACTIVE);
+               info->disk.state = 0;
+               if (info->disk.number >= 0 &&
+                   (be16_to_cpu(ddf->phys->entries[info->disk.number].state) & DDF_Online) &&
+                   !(be16_to_cpu(ddf->phys->entries[info->disk.number].state) & DDF_Failed))
+                       info->disk.state = (1<<MD_DISK_SYNC)|(1<<MD_DISK_ACTIVE);
+               info->events = be32_to_cpu(ddf->active->seq);
        }
 
        info->container_member = ddf->currentconf->vcnum;
@@ -2703,6 +2718,31 @@ static unsigned int find_unused_pde(const struct ddf_super *ddf)
        return DDF_NOTFOUND;
 }
 
+static void _set_config_size(struct phys_disk_entry *pde, const struct dl *dl)
+{
+       __u64 cfs, t;
+       cfs = min(dl->size - 32*1024*2ULL, be64_to_cpu(dl->primary_lba));
+       t = be64_to_cpu(dl->secondary_lba);
+       if (t != ~(__u64)0)
+               cfs = min(cfs, t);
+       /*
+        * Some vendor DDF structures interpret workspace_lba
+        * very differently then us. Make a sanity check on the value.
+        */
+       t = be64_to_cpu(dl->workspace_lba);
+       if (t < cfs) {
+               __u64 wsp = cfs - t;
+               if (wsp > 1024*1024*2ULL && wsp > dl->size / 16) {
+                       pr_err("%s: %x:%x: workspace size 0x%llx too big, ignoring\n",
+                              __func__, dl->major, dl->minor, wsp);
+               } else
+                       cfs = t;
+       }
+       pde->config_size = cpu_to_be64(cfs);
+       dprintf("%s: %x:%x config_size %llx, DDF structure is %llx blocks\n",
+               __func__, dl->major, dl->minor, cfs, dl->size-cfs);
+}
+
 /* add a device to a container, either while creating it or while
  * expanding a pre-existing container
  */
@@ -2825,7 +2865,7 @@ static int add_to_super_ddf(struct supertype *st,
        if (ddf->dlist == NULL ||
            be64_to_cpu(ddf->dlist->secondary_lba) != ~(__u64)0)
                __calc_lba(dd, ddf->dlist, secondary_lba, 32);
-       pde->config_size = dd->workspace_lba;
+       _set_config_size(pde, dd);
 
        sprintf(pde->path, "%17.17s","Information: nil") ;
        memset(pde->pad, 0xff, 6);
@@ -3805,7 +3845,7 @@ static struct mdinfo *container_content_ddf(struct supertype *st, char *subarray
                        dev->disk.state = (1<<MD_DISK_SYNC)|(1<<MD_DISK_ACTIVE);
                        dev->recovery_start = MaxSector;
 
-                       dev->events = be32_to_cpu(ddf->primary.seq);
+                       dev->events = be32_to_cpu(ddf->active->seq);
                        dev->data_offset =
                                be64_to_cpu(LBA_OFFSET(ddf, bvd)[iphys]);
                        dev->component_size = be64_to_cpu(bvd->blocks);
@@ -3892,12 +3932,6 @@ static int compare_super_ddf(struct supertype *st, struct supertype *tst)
        if (memcmp(first->anchor.guid, second->anchor.guid, DDF_GUID_LEN) != 0)
                return 2;
 
-       if (!be32_eq(first->active->seq, second->active->seq)) {
-               dprintf("%s: sequence number mismatch %u<->%u\n", __func__,
-                       be32_to_cpu(first->active->seq),
-                       be32_to_cpu(second->active->seq));
-               return 3;
-       }
        if (first->max_part != second->max_part ||
            !be16_eq(first->phys->used_pdes, second->phys->used_pdes) ||
            !be16_eq(first->virt->populated_vdes,
@@ -4082,6 +4116,31 @@ static int ddf_open_new(struct supertype *c, struct active_array *a, char *inst)
        return 0;
 }
 
+static void handle_missing(struct ddf_super *ddf, int inst)
+{
+       /* This member array is being activated.  If any devices
+        * are missing they must now be marked as failed.
+        */
+       struct vd_config *vc;
+       unsigned int n_bvd;
+       struct vcl *vcl;
+       struct dl *dl;
+       int n;
+
+       for (n = 0; ; n++) {
+               vc = find_vdcr(ddf, inst, n, &n_bvd, &vcl);
+               if (!vc)
+                       break;
+               for (dl = ddf->dlist; dl; dl = dl->next)
+                       if (be32_eq(dl->disk.refnum, vc->phys_refnum[n_bvd]))
+                               break;
+               if (dl)
+                       /* Found this disk, so not missing */
+                       continue;
+               vc->phys_refnum[n_bvd] = cpu_to_be32(0);
+       }
+}
+
 /*
  * The array 'a' is to be marked clean in the metadata.
  * If '->resync_start' is not ~(unsigned long long)0, then the array is only
@@ -4097,6 +4156,7 @@ static int ddf_set_array_state(struct active_array *a, int consistent)
        int inst = a->info.container_member;
        int old = ddf->virt->entries[inst].state;
        if (consistent == 2) {
+               handle_missing(ddf, inst);
                /* Should check if a recovery should be started FIXME */
                consistent = 1;
                if (!is_resync_complete(&a->info))