]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
imsm: FIX: core dump during imsm metadata writing
authorAdam Kwolek <adam.kwolek@intel.com>
Mon, 29 Nov 2010 01:53:16 +0000 (12:53 +1100)
committerNeilBrown <neilb@suse.de>
Mon, 29 Nov 2010 01:53:16 +0000 (12:53 +1100)
Wrong number of disks during metadata update causes core dump.  New
disks number based on internal mdmon information has to used for
calculation (not previously read from metadata).

Signed-off-by: Adam Kwolek <adam.kwolek@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
super-intel.c

index 46d216ed8bf20c75040bb1343116f3cd11bf7eb4..eca6e3f7b2c8c952232b2e12cbb9556baa142693 100644 (file)
@@ -3484,8 +3484,9 @@ static int write_super_imsm_spares(struct intel_super *super, int doclose)
        return 0;
 }
 
-static int write_super_imsm(struct intel_super *super, int doclose)
+static int write_super_imsm(struct supertype *st, int doclose)
 {
+       struct intel_super *super = st->sb;
        struct imsm_super *mpb = super->anchor;
        struct dl *d;
        __u32 generation;
@@ -3493,6 +3494,7 @@ static int write_super_imsm(struct intel_super *super, int doclose)
        int spares = 0;
        int i;
        __u32 mpb_size = sizeof(struct imsm_super) - sizeof(struct imsm_disk);
+       int num_disks = 0;
 
        /* 'generation' is incremented everytime the metadata is written */
        generation = __le32_to_cpu(mpb->generation_num);
@@ -3505,21 +3507,28 @@ static int write_super_imsm(struct intel_super *super, int doclose)
        if (mpb->orig_family_num == 0)
                mpb->orig_family_num = mpb->family_num;
 
-       mpb_size += sizeof(struct imsm_disk) * mpb->num_disks;
        for (d = super->disks; d; d = d->next) {
                if (d->index == -1)
                        spares++;
-               else
+               else {
                        mpb->disk[d->index] = d->disk;
+                       num_disks++;
+               }
        }
-       for (d = super->missing; d; d = d->next)
+       for (d = super->missing; d; d = d->next) {
                mpb->disk[d->index] = d->disk;
+               num_disks++;
+       }
+       mpb->num_disks = num_disks;
+       mpb_size += sizeof(struct imsm_disk) * mpb->num_disks;
 
        for (i = 0; i < mpb->num_raid_devs; i++) {
                struct imsm_dev *dev = __get_imsm_dev(mpb, i);
-
-               imsm_copy_dev(dev, get_imsm_dev(super, i));
-               mpb_size += sizeof_imsm_dev(dev, 0);
+               struct imsm_dev *dev2 = get_imsm_dev(super, i);
+               if (dev && dev2) {
+                       imsm_copy_dev(dev, dev2);
+                       mpb_size += sizeof_imsm_dev(dev, 0);
+               }
        }
        mpb_size += __le32_to_cpu(mpb->bbm_log_size);
        mpb->mpb_size = __cpu_to_le32(mpb_size);
@@ -3639,7 +3648,7 @@ static int write_init_super_imsm(struct supertype *st)
                struct dl *d;
                for (d = super->disks; d; d = d->next)
                        Kill(d->devname, NULL, 0, 1, 1);
-               return write_super_imsm(st->sb, 1);
+               return write_super_imsm(st, 1);
        }
 }
 #endif
@@ -4925,7 +4934,7 @@ static void imsm_sync_metadata(struct supertype *container)
        if (!super->updates_pending)
                return;
 
-       write_super_imsm(super, 0);
+       write_super_imsm(container, 0);
 
        super->updates_pending = 0;
 }