Improve the logic for autosizing partitions.
authorSascha Wildner <saw@online.de>
Mon, 29 Dec 2008 18:33:17 +0000 (19:33 +0100)
committerSascha Wildner <saw@online.de>
Mon, 29 Dec 2008 18:33:28 +0000 (19:33 +0100)
This fixes the error with '*' for offset and size when the first
partition didn't start at 0.

Taken-from: FreeBSD

sbin/disklabel/disklabel.c

index d29cbc8..52fa108 100644 (file)
@@ -1217,7 +1217,8 @@ checklabel(struct disklabel32 *lp)
        struct partition32 *pp;
        int i, errors = 0;
        char part;
-       u_long total_size, total_percent, current_offset;
+       u_long base_offset, needed, total_size, total_percent, current_offset;
+       long free_space;
        int seen_default_offset;
        int hog_part;
        int j;
@@ -1328,9 +1329,25 @@ checklabel(struct disklabel32 *lp)
                        }
                }
        }
+
+       /* Find out the total free space, excluding the boot block area. */
+       base_offset = BBSIZE / lp->d_secsize;
+       free_space = 0;
+       for (i = 0; i < lp->d_npartitions; i++) {
+               pp = &lp->d_partitions[i];
+               if (!part_set[i] || i == RAW_PART ||
+                   part_size_type[i] == '%' || part_size_type[i] == '*')
+                       continue;
+               if (pp->p_offset > base_offset)
+                       free_space += pp->p_offset - base_offset;
+               if (pp->p_offset + pp->p_size > base_offset)
+                       base_offset = pp->p_offset + pp->p_size;
+       }
+       if (base_offset < lp->d_secperunit)
+               free_space += lp->d_secperunit - base_offset;
+
        /* handle % partitions - note %'s don't need to add up to 100! */
        if (total_percent != 0) {
-               long free_space = lp->d_secperunit - total_size;
                if (total_percent > 100) {
                        fprintf(stderr,"total percentage %lu is greater than 100\n",
                            total_percent);
@@ -1359,12 +1376,52 @@ checklabel(struct disklabel32 *lp)
        }
        /* give anything remaining to the hog partition */
        if (hog_part != -1) {
-               lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size;
-               total_size = lp->d_secperunit;
+               /*
+                * Find the range of offsets usable by '*' partitions around
+                * the hog partition and how much space they need.
+                */
+               needed = 0;
+               base_offset = BBSIZE / lp->d_secsize;
+               for (i = hog_part - 1; i >= 0; i--) {
+                       pp = &lp->d_partitions[i];
+                       if (!part_set[i] || i == RAW_PART)
+                               continue;
+                       if (part_offset_type[i] == '*') {
+                               needed += pp->p_size;
+                               continue;
+                       }
+                       base_offset = pp->p_offset + pp->p_size;
+                       break;
+               }
+               current_offset = lp->d_secperunit;
+               for (i = lp->d_npartitions - 1; i > hog_part; i--) {
+                       pp = &lp->d_partitions[i];
+                       if (!part_set[i] || i == RAW_PART)
+                               continue;
+                       if (part_offset_type[i] == '*') {
+                               needed += pp->p_size;
+                               continue;
+                       }
+                       current_offset = pp->p_offset;
+               }
+
+               if (current_offset - base_offset <= needed) {
+                       fprintf(stderr, "Cannot find space for partition %c\n",
+                           hog_part + 'a');
+                       fprintf(stderr,
+                           "Need more than %lu sectors between %lu and %lu\n",
+                           needed, base_offset, current_offset);
+                       errors++;
+                       lp->d_partitions[hog_part].p_size = 0;
+               } else {
+                       lp->d_partitions[hog_part].p_size = current_offset -
+                           base_offset - needed;
+                       total_size += lp->d_partitions[hog_part].p_size;
+               }
        }
 
        /* Now set the offsets for each partition */
-       current_offset = 0; /* in sectors */
+       current_offset = BBSIZE / lp->d_secsize; /* in sectors */
        seen_default_offset = 0;
        for (i = 0; i < lp->d_npartitions; i++) {
                part = 'a' + i;