]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
imsm: fix free space calculations
[thirdparty/mdadm.git] / super-intel.c
index e249d9250428dd90cd56d77ea0b3e0f5dd09b818..824c13564a379d4697268c18f692be4813b9873c 100644 (file)
@@ -6919,8 +6919,11 @@ static unsigned long long merge_extents(struct intel_super *super, const bool ex
        int sum_extents = 0;
        unsigned long long pos = 0;
        unsigned long long start = 0;
-       unsigned long long maxsize = 0;
-       unsigned long reserve;
+       unsigned long long free_size = 0;
+
+       unsigned long pre_reservation = 0;
+       unsigned long post_reservation = IMSM_RESERVED_SECTORS;
+       unsigned long reservation_size;
 
        for (dl = super->disks; dl; dl = dl->next)
                if (dl->e)
@@ -6955,8 +6958,8 @@ static unsigned long long merge_extents(struct intel_super *super, const bool ex
        do {
                unsigned long long esize = e[i].start - pos;
 
-               if (expanding ? pos_vol_idx == super->current_vol : esize >= maxsize) {
-                       maxsize = esize;
+               if (expanding ? pos_vol_idx == super->current_vol : esize >= free_size) {
+                       free_size = esize;
                        start = pos;
                        extent_idx = i;
                }
@@ -6966,28 +6969,35 @@ static unsigned long long merge_extents(struct intel_super *super, const bool ex
 
                i++;
        } while (e[i-1].size);
-       free(e);
 
-       if (maxsize == 0)
+       if (free_size == 0) {
+               dprintf("imsm: Cannot find free size.\n");
+               free(e);
                return 0;
+       }
 
-       /* FIXME assumes volume at offset 0 is the first volume in a
-        * container
-        */
-       if (extent_idx > 0)
-               reserve = IMSM_RESERVED_SECTORS; /* gap between raid regions */
-       else
-               reserve = 0;
+       if (!expanding && extent_idx != 0)
+               /*
+                * Not a real first volume in a container is created, pre_reservation is needed.
+                */
+               pre_reservation = IMSM_RESERVED_SECTORS;
 
-       if (maxsize < reserve)
-               return 0;
+       if (e[extent_idx].size == 0)
+               /*
+                * extent_idx points to the metadata, post_reservation is allready done.
+                */
+               post_reservation = 0;
+       free(e);
 
-       super->create_offset = ~((unsigned long long) 0);
-       if (start + reserve > super->create_offset)
-               return 0; /* start overflows create_offset */
-       super->create_offset = start + reserve;
+       reservation_size = pre_reservation + post_reservation;
+
+       if (free_size < reservation_size) {
+               dprintf("imsm: Reservation size is greater than free space.\n");
+               return 0;
+       }
 
-       return maxsize - reserve;
+       super->create_offset = start + pre_reservation;
+       return free_size - reservation_size;
 }
 
 static int is_raid_level_supported(const struct imsm_orom *orom, int level, int raiddisks)