Blob Blame History Raw
From e4bf9b823452c0b98b394b8abcc67f887b6991b3 Mon Sep 17 00:00:00 2001
From: Petr Uzel <petr.uzel@suse.cz>
Date: Thu, 21 Jul 2016 16:46:46 +0200
Subject: [PATCH 44/53] libparted: only IEC units are treated as exact

If the user specifies start/end of the partition as a unit,
whose size happens to be power of two, we treat that as
exact address with exact placement.

Recently, commit 01900e056ec25083 added an exception for
percent units.

This logic however can fail also for cylinders, e.g. on DASD FBA disks,
which report CHS=(*, 128, 16) geometry, hence once cylinder is 1 MiB.
With cylinders as units, exact placement is not what the user wants.

Instead of adding cylinders to the blacklist, let's instead
whitelist units which should trigger exact placement.

* libparted/unit.c (is_power_of_2): Remove now unused function.
(ped_unit_parse_custom): Specify which units trigger exact placement.
* NEWS (Bug Fixes): Mention this.

(cherry picked from commit f4f38082fc4dbf0c28ccc7613c672fe279d3032e)
---
 libparted/unit.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/libparted/unit.c b/libparted/unit.c
index dddb5db..e47e868 100644
--- a/libparted/unit.c
+++ b/libparted/unit.c
@@ -481,12 +481,6 @@ parse_unit_suffix (const char* suffix, PedUnit suggested_unit)
 	return suggested_unit;
 }
 
-static bool
-is_power_of_2 (long long n)
-{
-  return (n & (n - 1)) == 0;
-}
-
 /**
  * If \p str contains a valid description of a location on \p dev, then
  * \p *sector is modified to describe the location and a geometry is created
@@ -540,16 +534,23 @@ ped_unit_parse_custom (const char* str, const PedDevice* dev, PedUnit unit,
         }
 
 	unit_size = ped_unit_get_size (dev, unit);
-	radius = (ped_div_round_up (unit_size, dev->sector_size) / 2) - 1;
-	if (radius < 0)
-		radius = 0;
-	/* If the user specifies units in a power of 2, e.g., 4MiB, as in
-	       parted -s -- $dev mklabel gpt mkpart P-NAME 4MiB -34s
-	   do not use 4MiB as the range.  Rather, presume that they
-	   are specifying precisely the starting or ending number,
-	   and treat "4MiB" just as we would treat "4194304B".  */
-	if (is_power_of_2 (unit_size) && unit != PED_UNIT_PERCENT)
-		radius = 0;
+	switch (unit) {
+		/* If the user specifies the address using IEC units e.g., 4MiB, as in
+		   parted -s -- $dev mklabel gpt mkpart P-NAME 4MiB -34s
+		   do not use size of the unit as the range.  Rather, presume that they
+		   are specifying precisely the starting or ending number,
+		   and treat "4MiB" just as we would treat "4194304B".  */
+		case PED_UNIT_KIBIBYTE:
+		case PED_UNIT_MEBIBYTE:
+		case PED_UNIT_GIBIBYTE:
+		case PED_UNIT_TEBIBYTE:
+			radius = 0;
+			break;
+		default:
+			radius = (ped_div_round_up (unit_size, dev->sector_size) / 2) - 1;
+			if (radius < 0)
+				radius = 0;
+	}
 
 	*sector = num * unit_size / dev->sector_size;
 	/* negative numbers count from the end */
-- 
2.7.4