Fix efi_use_whole_disk() when efi_nparts == 128.
authorEtienne Dechamps <etienne.dechamps@ovh.net>
Wed, 11 Jul 2012 15:47:10 +0000 (17:47 +0200)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 12 Jul 2012 15:59:22 +0000 (08:59 -0700)
Commit e5dc681a changed EFI_NUMPAR from 9 to 128. This means that the
on-disk EFI label has efi_nparts = 128 instead of 9. The index of the
reserved partition, however, is still 8. This breaks
efi_use_whole_disk(), which uses efi_nparts-1 as the index of the
reserved partition.

This commit fixes efi_use_whole_disk() when the index of the reserved
partition is not efi_nparts-1. It rewrites the algorithm and makes it
more robust by using the order of the partitions instead of their
numbering. It assumes that the last non-empty partition is the reserved
partition, and that the non-empty partition before that is the data
partition.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Issue #808

lib/libefi/rdwr_efi.c

index 0600a95..474f78a 100644 (file)
@@ -1028,24 +1028,15 @@ efi_use_whole_disk(int fd)
        struct dk_gpt           *efi_label;
        int                     rval;
        int                     i;
-       uint_t                  phy_last_slice = 0;
-       diskaddr_t              pl_start = 0;
-       diskaddr_t              pl_size;
+       uint_t                  resv_index = 0, data_index = 0;
+       diskaddr_t              resv_start = 0, data_start = 0;
+       diskaddr_t              difference;
 
        rval = efi_alloc_and_read(fd, &efi_label);
        if (rval < 0) {
                return (rval);
        }
 
-       /* find the last physically non-zero partition */
-       for (i = 0; i < efi_label->efi_nparts - 2; i ++) {
-               if (pl_start < efi_label->efi_parts[i].p_start) {
-                       pl_start = efi_label->efi_parts[i].p_start;
-                       phy_last_slice = i;
-               }
-       }
-       pl_size = efi_label->efi_parts[phy_last_slice].p_size;
-
        /*
         * If alter_lba is 1, we are using the backup label.
         * Since we can locate the backup label by disk capacity,
@@ -1061,16 +1052,28 @@ efi_use_whole_disk(int fd)
                return (VT_ENOSPC);
        }
 
+       difference = efi_label->efi_last_lba - efi_label->efi_altern_lba;
+
+       /*
+        * Find the last physically non-zero partition.
+        * This is the reserved partition.
+        */
+       for (i = 0; i < efi_label->efi_nparts; i ++) {
+               if (resv_start < efi_label->efi_parts[i].p_start) {
+                       resv_start = efi_label->efi_parts[i].p_start;
+                       resv_index = i;
+               }
+       }
+
        /*
-        * If there is space between the last physically non-zero partition
-        * and the reserved partition, just add the unallocated space to this
-        * area. Otherwise, the unallocated space is added to the last
-        * physically non-zero partition.
+        * Find the last physically non-zero partition before that.
+        * This is the data partition.
         */
-       if (pl_start + pl_size - 1 == efi_label->efi_last_u_lba -
-           EFI_MIN_RESV_SIZE) {
-               efi_label->efi_parts[phy_last_slice].p_size +=
-                   efi_label->efi_last_lba - efi_label->efi_altern_lba;
+       for (i = 0; i < resv_index; i ++) {
+               if (data_start < efi_label->efi_parts[i].p_start) {
+                       data_start = efi_label->efi_parts[i].p_start;
+                       data_index = i;
+               }
        }
 
        /*
@@ -1078,10 +1081,9 @@ efi_use_whole_disk(int fd)
         * here except fabricated devids (which get generated via
         * efi_write()). So there is no need to copy data.
         */
-       efi_label->efi_parts[efi_label->efi_nparts - 1].p_start +=
-           efi_label->efi_last_lba - efi_label->efi_altern_lba;
-       efi_label->efi_last_u_lba += efi_label->efi_last_lba
-           - efi_label->efi_altern_lba;
+       efi_label->efi_parts[data_index].p_size += difference;
+       efi_label->efi_parts[resv_index].p_start += difference;
+       efi_label->efi_last_u_lba += difference;
 
        rval = efi_write(fd, efi_label);
        if (rval < 0) {