[parted-devel] [PATCH] Properly sync partitions with operating system

Joel Granados Moreno jgranado at redhat.com
Wed Feb 25 22:59:33 UTC 2009


* include/parted/disk.h : Added headers for new function.
* libparted/disk.c (ped_disk_get_max_supported_partition_count):  New
  function that calls the label specific function.
* libparted/arch/linux.c (_disk_sync_part_table):  To sync the table in
  disk with the kernel we remove all partitions from the kernel table
  and then add the ones that are in disk.  For this to happen we need to
  calculate the maximum number of supported partitions in the label.
* libparted/labels/gpt.c (gpt_get_max_supported_partition_count):  We
  read the gpt header from disk and calculate the maximum amount of
  partitions that the label can hold.
* libparted/labels/aix.c: new get_max_supported_partition_count function.
* libparted/labels/bsd.c: likewise
* libparted/labels/dasd.c: likewise
* libparted/labels/dos.c: likewise
* libparted/labels/dvh.c: likewise
* libparted/labels/gpt.c: likewise
* libparted/labels/loop.c: likewise
* libparted/labels/mac.c: likewise
* libparted/labels/pc98.c: likewise
* libparted/labels/rdb.c: likewise
* libparted/labels/sun.c: likewise
---
 include/parted/disk.h   |    5 +++
 libparted/arch/linux.c  |   75 ++++++++++++++++++++++++++++++++++++++++------
 libparted/disk.c        |   17 ++++++++++-
 libparted/labels/aix.c  |   10 ++++++
 libparted/labels/bsd.c  |   11 ++++++-
 libparted/labels/dasd.c |    8 +++++
 libparted/labels/dos.c  |   11 ++++++-
 libparted/labels/dvh.c  |   11 +++++-
 libparted/labels/gpt.c  |   49 ++++++++++++++++++++++++++++++-
 libparted/labels/loop.c |   11 ++++++-
 libparted/labels/mac.c  |   11 ++++++-
 libparted/labels/pc98.c |   10 +++++-
 libparted/labels/rdb.c  |   10 +++++-
 libparted/labels/sun.c  |    8 +++++
 14 files changed, 227 insertions(+), 20 deletions(-)

diff --git a/include/parted/disk.h b/include/parted/disk.h
index dfcf39e..ec6044d 100644
--- a/include/parted/disk.h
+++ b/include/parted/disk.h
@@ -84,6 +84,7 @@ typedef const struct _PedDiskArchOps    PedDiskArchOps;
 #include <parted/filesys.h>
 #include <parted/natmath.h>
 #include <parted/geom.h>
+#include <stdbool.h>
 
 /** @} */
 
@@ -210,6 +211,8 @@ struct _PedDiskOps {
         /* other */
         int (*alloc_metadata) (PedDisk* disk);
         int (*get_max_primary_partition_count) (const PedDisk* disk);
+        bool (*get_max_supported_partition_count) (const PedDisk* disk,
+                                                   int* supported);
 };
 
 struct _PedDiskType {
@@ -257,6 +260,8 @@ extern void ped_disk_print (const PedDisk* disk);
 extern int ped_disk_get_primary_partition_count (const PedDisk* disk);
 extern int ped_disk_get_last_partition_num (const PedDisk* disk);
 extern int ped_disk_get_max_primary_partition_count (const PedDisk* disk);
+extern bool ped_disk_get_max_supported_partition_count(const PedDisk* disk,
+                                                       int* supported);
 
 /** @} */
 
diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index 4a8c9e7..6a90ee2 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -279,6 +279,9 @@ struct blkdev_ioctl_param {
                 || (M) == SCSI_CDROM_MAJOR                              \
                 || ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR))
 
+/* Maximum number of partitions supported by linux. */
+#define MAX_NUM_PARTS		64
+
 static char* _device_get_part_path (PedDevice* dev, int num);
 static int _partition_is_mounted_by_path (const char* path);
 
@@ -2261,25 +2264,77 @@ _blkpg_remove_partition (PedDisk* disk, int n)
                                     BLKPG_DEL_PARTITION);
 }
 
+/*
+ * The number of partitions that a device can have depends on the kernel.
+ * If we don't find this value in /sys/block/DEV/range, we will use our own
+ * value.
+ */
+static unsigned int
+_device_get_partition_range(PedDevice* dev)
+{
+        int         range, r;
+        char        path[128];
+        FILE*       fp;
+        bool        ok;
+
+        r = snprintf(path, sizeof(path), "/sys/block/%s/range",
+                        basename(dev->path));
+        if(r < 0 || r > sizeof(path))
+                return MAX_NUM_PARTS;
+
+        fp = fopen(path, "r");
+        if(!fp)
+                return MAX_NUM_PARTS;
+
+        ok = fscanf(fp, "%d", &range) == 1;
+        fclose(fp);
+
+        /* (range <= 0) is none sense.*/
+        return ok && range > 0 ? range : MAX_NUM_PARTS;
+}
+
+/*
+ * We sync the partition table in two step process:
+ * 1. We remove all the partitions from the kernel's tables.  The partitions
+ *    will not be removed if the ioctl call fails.
+ * 2. We add all the partitions that we hold in disk.
+ *
+ * To achieve this two step process we must calculate the minimum number of
+ * maximum possible partitions between what linux supports and what the label
+ * type supports. EX:
+ *
+ * number=MIN(max_parts_supported_in_linux,max_parts_supported_in_msdos_tables)
+ */
 static int
 _disk_sync_part_table (PedDisk* disk)
 {
-        int largest_partnum = ped_disk_get_last_partition_num (disk);
-        if (largest_partnum <= 0)
-          return 1;
+        PED_ASSERT(disk != NULL, return 0);
+        PED_ASSERT(disk->dev != NULL, return 0);
+        int lpn;
 
-        int     last = 16;
-        int*    rets = ped_malloc(sizeof(int) * last);
-        int*    errnums = ped_malloc(sizeof(int) * last);
-        int     ret = 1;
-        int     i;
+        /* lpn = largest partition number. */
+        if(ped_disk_get_max_supported_partition_count(disk, &lpn))
+                lpn = PED_MIN(lpn, _device_get_partition_range(disk->dev));
+        else
+                lpn = _device_get_partition_range(disk->dev);
 
-        for (i = 1; i <= last; i++) {
+        /* Its not possible to support largest_partnum < 0.
+         * largest_partnum == 0 would mean does not support partitions.
+         * */
+        if(lpn < 0)
+                return 0;
+
+        int*        rets = ped_malloc(sizeof(int) * lpn);
+        int*        errnums = ped_malloc(sizeof(int) * lpn);
+        int                 ret = 1;
+        int                 i;
+
+        for (i = 1; i <= lpn; i++) {
                 rets[i - 1] = _blkpg_remove_partition (disk, i);
                 errnums[i - 1] = errno;
         }
 
-        for (i = 1; i <= last; i++) {
+        for (i = 1; i <= lpn; i++) {
                 const PedPartition *part;
 
                 part = ped_disk_get_partition (disk, i);
diff --git a/libparted/disk.c b/libparted/disk.c
index 93929b2..4003618 100644
--- a/libparted/disk.c
+++ b/libparted/disk.c
@@ -36,6 +36,7 @@
 
 #include <parted/parted.h>
 #include <parted/debug.h>
+#include <stdbool.h>
 
 #include "architecture.h"
 #include "intprops.h"
@@ -628,7 +629,7 @@ ped_disk_get_primary_partition_count (const PedDisk* disk)
 }
 
 /**
- * Get the highest partition number on \p disk.
+ * Get the highest available partition number on \p disk.
  */
 int
 ped_disk_get_last_partition_num (const PedDisk* disk)
@@ -648,6 +649,20 @@ ped_disk_get_last_partition_num (const PedDisk* disk)
 }
 
 /**
+ * Get the highest supported partition number on \p disk.
+ *
+ * \return 0 if call fails. 1 otherwise.
+ */
+bool
+ped_disk_get_max_supported_partition_count(const PedDisk* disk, int* supported)
+{
+	PED_ASSERT(disk != NULL, return -1);
+	PED_ASSERT(disk->type->ops->get_max_supported_partition_count != NULL, return -1);
+
+	return disk->type->ops->get_max_supported_partition_count(disk, supported);
+}
+
+/**
  * Get the maximum number of (primary) partitions the disk label supports.
  * 
  * For example, MacIntosh partition maps can have different sizes,
diff --git a/libparted/labels/aix.c b/libparted/labels/aix.c
index b3dd176..2d8a40c 100644
--- a/libparted/labels/aix.c
+++ b/libparted/labels/aix.c
@@ -24,6 +24,7 @@
 #include <parted/parted.h>
 #include <parted/debug.h>
 #include <parted/endian.h>
+#include <stdbool.h>
 
 #if ENABLE_NLS
 #  include <libintl.h>
@@ -33,6 +34,7 @@
 #endif /* ENABLE_NLS */
 
 #define	AIX_LABEL_MAGIC		0xc9c2d4c1
+#define	MAX_TOTAL_PART		16
 
 static PedDiskType aix_disk_type;
 
@@ -221,6 +223,12 @@ aix_get_max_primary_partition_count (const PedDisk* disk)
 	return 4;
 }
 
+static bool
+aix_get_max_supported_partition_count (const PedDisk* disk, int *supported)
+{
+	return *supported = MAX_TOTAL_PART;
+}
+
 static int
 aix_partition_align (PedPartition* part, const PedConstraint* constraint)
 {
@@ -270,6 +278,8 @@ static PedDiskOps aix_disk_ops = {
 	alloc_metadata:		aix_alloc_metadata,
 	get_max_primary_partition_count:
 				aix_get_max_primary_partition_count,
+	get_max_supported_partition_count:
+				aix_get_max_supported_partition_count,
 
 	partition_set_name:		NULL,
 	partition_get_name:		NULL,
diff --git a/libparted/labels/bsd.c b/libparted/labels/bsd.c
index 3eb5363..55af468 100644
--- a/libparted/labels/bsd.c
+++ b/libparted/labels/bsd.c
@@ -24,6 +24,7 @@
 #include <parted/parted.h>
 #include <parted/debug.h>
 #include <parted/endian.h>
+#include <stdbool.h>
 
 #if ENABLE_NLS
 #  include <libintl.h>
@@ -547,6 +548,12 @@ bsd_get_max_primary_partition_count (const PedDisk* disk)
 	return BSD_MAXPARTITIONS;
 }
 
+static bool
+bsd_get_max_supported_partition_count(const PedDisk* disk, int* supported)
+{
+	return *supported = BSD_MAXPARTITIONS;
+}
+
 static PedConstraint*
 _get_constraint (const PedDevice* dev)
 {
@@ -656,7 +663,9 @@ static PedDiskOps bsd_disk_ops = {
 
 	alloc_metadata:		bsd_alloc_metadata,
 	get_max_primary_partition_count:
-				bsd_get_max_primary_partition_count
+				bsd_get_max_primary_partition_count,
+	get_max_supported_partition_count:
+				bsd_get_max_supported_partition_count
 };
 
 static PedDiskType bsd_disk_type = {
diff --git a/libparted/labels/dasd.c b/libparted/labels/dasd.c
index b1cd937..35cfbb3 100644
--- a/libparted/labels/dasd.c
+++ b/libparted/labels/dasd.c
@@ -28,6 +28,7 @@
 #include <time.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <stdbool.h>
 
 #include <sys/stat.h>
 #include <sys/ioctl.h>
@@ -128,6 +129,7 @@ static PedDiskOps dasd_disk_ops = {
 
 	alloc_metadata: dasd_alloc_metadata,
 	get_max_primary_partition_count: dasd_get_max_primary_partition_count,
+	get_max_supported_partition_count: dasd_get_max_supported_partition_count,
 
 	partition_duplicate: NULL
 };
@@ -713,6 +715,12 @@ dasd_get_max_primary_partition_count (const PedDisk* disk)
 	return USABLE_PARTITIONS;
 }
 
+static bool
+dasd_get_max_supported_partition_count (const PedDisk* disk, int* supported)
+{
+	return *supported = dasd_get_max_primary_partition_count(disk);
+}
+
 static PedConstraint*
 _primary_constraint (PedDisk* disk)
 {
diff --git a/libparted/labels/dos.c b/libparted/labels/dos.c
index cb7e45e..92b728d 100644
--- a/libparted/labels/dos.c
+++ b/libparted/labels/dos.c
@@ -97,6 +97,7 @@ static const char MBR_BOOT_CODE[] = {
  * (i.e. 1022 is sometimes used to indicate "use LBA").
  */
 #define MAX_CHS_CYLINDER	1021
+#define MAX_TOTAL_PART		16
 
 typedef struct _DosRawPartition		DosRawPartition;
 typedef struct _DosRawTable		DosRawTable;
@@ -2213,6 +2214,12 @@ msdos_get_max_primary_partition_count (const PedDisk* disk)
 	return 4;
 }
 
+static bool
+msdos_get_max_supported_partition_count(const PedDisk* disk, int* supported)
+{
+	return *supported = MAX_TOTAL_PART;
+}
+
 static PedDiskOps msdos_disk_ops = {
 	probe:			msdos_probe,
 #ifndef DISCOVER_ONLY
@@ -2244,7 +2251,9 @@ static PedDiskOps msdos_disk_ops = {
 
 	alloc_metadata:		msdos_alloc_metadata,
 	get_max_primary_partition_count:
-				msdos_get_max_primary_partition_count
+				msdos_get_max_primary_partition_count,
+	get_max_supported_partition_count:
+				msdos_get_max_supported_partition_count
 };
 
 static PedDiskType msdos_disk_type = {
diff --git a/libparted/labels/dvh.c b/libparted/labels/dvh.c
index 8d8ba76..3814824 100644
--- a/libparted/labels/dvh.c
+++ b/libparted/labels/dvh.c
@@ -822,6 +822,13 @@ dvh_get_max_primary_partition_count (const PedDisk* disk)
 	return NPARTAB;
 }
 
+static bool
+dvh_get_max_supported_partition_count (const PedDisk* disk, int* supported)
+{
+	return *supported = NPARTAB;
+}
+
+
 static int
 dvh_alloc_metadata (PedDisk* disk)
 {
@@ -887,8 +894,8 @@ static PedDiskOps dvh_disk_ops = {
 	partition_enumerate:	dvh_partition_enumerate,
 
 	alloc_metadata:		dvh_alloc_metadata,
-	get_max_primary_partition_count:
-				dvh_get_max_primary_partition_count
+	get_max_primary_partition_count: dvh_get_max_primary_partition_count,
+	get_max_supported_partition_count: dvh_get_max_supported_partition_count
 };
 
 static PedDiskType dvh_disk_type = {
diff --git a/libparted/labels/gpt.c b/libparted/labels/gpt.c
index 90e5068..aeaee8a 100644
--- a/libparted/labels/gpt.c
+++ b/libparted/labels/gpt.c
@@ -1475,6 +1475,52 @@ gpt_get_max_primary_partition_count (const PedDisk *disk)
 	return gpt_disk_data->entry_count;
 }
 
+/*
+ * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
+ * According to the specs the first LBA (LBA0) is not relevant (it exists
+ * to maintain compatibility).  on the second LBA(LBA1) gpt places the
+ * header.  The header is as big as the block size.  After the header we
+ * find the Entry array.  Each element of said array, describes each
+ * partition.  One can have as much elements as can fit between the end of
+ * the second LBA (where the header ends) and the FirstUsableLBA.
+ * FirstUsableLBA is the first logical block that is used for contents
+ * and is defined in header.
+ *
+ * /---------------------------------------------------\
+ * | BLOCK0 | HEADER | Entry Array | First Usable LBA  |
+ * |        | BLOCK1 |             |                   |
+ * \---------------------------------------------------/
+ *                  /              \
+ *     /----------/                  \----------\
+ *     /-----------------------------------------\
+ *     |  E1  |  E2  |  E3  |...............| EN |
+ *     \-----------------------------------------/
+ *
+ * The number of possible partitions or supported partitions is:
+ * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
+ * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
+ */
+static bool
+gpt_get_max_supported_partition_count (const PedDisk *disk, int *supported)
+{
+	GuidPartitionTableHeader_t *pth = NULL;
+	uint8_t *pth_raw = ped_malloc (pth_get_size(disk->dev));
+
+	if(ped_device_read(disk->dev, pth_raw, 1, GPT_HEADER_SECTORS) ||
+			ped_device_read(disk->dev, pth_raw, disk->dev->length, GPT_HEADER_SECTORS))
+		pth = pth_new_from_raw(disk->dev, pth_raw);
+	free(pth_raw);
+
+	if(pth){
+		*supported = (disk->dev->sector_size*(pth->FirstUsableLBA - 2) /
+				pth->SizeOfPartitionEntry);
+		pth_free(pth);
+		return true;
+	}
+
+	return false;
+}
+
 static PedConstraint*
 _non_metadata_constraint (const PedDisk* disk)
 {
@@ -1529,7 +1575,8 @@ static PedDiskOps gpt_disk_ops = {
 	partition_align:		gpt_partition_align,
 	partition_enumerate:		gpt_partition_enumerate,
 	alloc_metadata:			gpt_alloc_metadata,
-	get_max_primary_partition_count: gpt_get_max_primary_partition_count
+	get_max_primary_partition_count: gpt_get_max_primary_partition_count,
+	get_max_supported_partition_count: gpt_get_max_supported_partition_count
 };
 
 static PedDiskType gpt_disk_type = {
diff --git a/libparted/labels/loop.c b/libparted/labels/loop.c
index a6a2057..23e0d3c 100644
--- a/libparted/labels/loop.c
+++ b/libparted/labels/loop.c
@@ -21,6 +21,7 @@
 #include <parted/parted.h>
 #include <parted/debug.h>
 #include <parted/endian.h>
+#include <stdbool.h>
 
 #if ENABLE_NLS
 #  include <libintl.h>
@@ -280,6 +281,12 @@ loop_get_max_primary_partition_count (const PedDisk* disk)
 	return 1;
 }
 
+static bool
+loop_get_max_supported_partition_count (const PedDisk* disk, int* supported)
+{
+	return *supported = 1;
+}
+
 static PedDiskOps loop_disk_ops = {
 	probe:			loop_probe,
 #ifndef DISCOVER_ONLY
@@ -311,7 +318,9 @@ static PedDiskOps loop_disk_ops = {
 
 	alloc_metadata:		loop_alloc_metadata,
 	get_max_primary_partition_count:
-				loop_get_max_primary_partition_count
+				loop_get_max_primary_partition_count,
+	get_max_supported_partition_count:
+				loop_get_max_supported_partition_count
 };
 
 static PedDiskType loop_disk_type = {
diff --git a/libparted/labels/mac.c b/libparted/labels/mac.c
index 3ec8390..db22aa8 100644
--- a/libparted/labels/mac.c
+++ b/libparted/labels/mac.c
@@ -21,6 +21,7 @@
 #include <parted/parted.h>
 #include <parted/debug.h>
 #include <parted/endian.h>
+#include <stdbool.h>
 
 #if ENABLE_NLS
 #  include <libintl.h>
@@ -1563,6 +1564,12 @@ mac_get_max_primary_partition_count (const PedDisk* disk)
 		- mac_disk_data->free_part_entry_count + 1;
 }
 
+static bool
+mac_get_max_supported_partition_count (const PedDisk* disk, int* supported)
+{
+	return *supported = 65536;
+}
+
 static PedDiskOps mac_disk_ops = {
 	probe:			mac_probe,
 #ifndef DISCOVER_ONLY
@@ -1596,7 +1603,9 @@ static PedDiskOps mac_disk_ops = {
 
 	alloc_metadata:		mac_alloc_metadata,
 	get_max_primary_partition_count:
-				mac_get_max_primary_partition_count
+				mac_get_max_primary_partition_count,
+	get_max_supported_partition_count:
+				mac_get_max_supported_partition_count
 };
 
 static PedDiskType mac_disk_type = {
diff --git a/libparted/labels/pc98.c b/libparted/labels/pc98.c
index a7b7e57..ff21750 100644
--- a/libparted/labels/pc98.c
+++ b/libparted/labels/pc98.c
@@ -832,6 +832,12 @@ pc98_get_max_primary_partition_count (const PedDisk* disk)
 	return MAX_PART_COUNT;
 }
 
+static bool
+pc98_get_max_supported_partition_count (const PedDisk* disk, int* supported)
+{
+	return *supported = MAX_PART_COUNT;
+}
+
 static PedDiskOps pc98_disk_ops = {
 	probe:			pc98_probe,
 #ifndef DISCOVER_ONLY
@@ -863,7 +869,9 @@ static PedDiskOps pc98_disk_ops = {
 
 	alloc_metadata:		pc98_alloc_metadata,
 	get_max_primary_partition_count:
-				pc98_get_max_primary_partition_count
+				pc98_get_max_primary_partition_count,
+	get_max_supported_partition_count:
+				pc98_get_max_supported_partition_count
 };
 
 static PedDiskType pc98_disk_type = {
diff --git a/libparted/labels/rdb.c b/libparted/labels/rdb.c
index 386b2bd..43496dc 100644
--- a/libparted/labels/rdb.c
+++ b/libparted/labels/rdb.c
@@ -1124,6 +1124,12 @@ amiga_get_max_primary_partition_count (const PedDisk* disk)
 	return AMIGA_MAX_PARTITIONS;
 }
 
+static bool
+amiga_get_max_supported_partition_count (const PedDisk* disk, int* supported)
+{
+	return *supported = AMIGA_MAX_PARTITIONS;
+}
+
 static PedDiskOps amiga_disk_ops = {
 	probe:			amiga_probe,
 #ifndef DISCOVER_ONLY
@@ -1157,7 +1163,9 @@ static PedDiskOps amiga_disk_ops = {
 
 	alloc_metadata:		amiga_alloc_metadata,
 	get_max_primary_partition_count:
-				amiga_get_max_primary_partition_count
+				amiga_get_max_primary_partition_count,
+	get_max_supported_partition_count:
+				amiga_get_max_supported_partition_count
 };
 
 static PedDiskType amiga_disk_type = {
diff --git a/libparted/labels/sun.c b/libparted/labels/sun.c
index 76f2b78..7c43240 100644
--- a/libparted/labels/sun.c
+++ b/libparted/labels/sun.c
@@ -24,6 +24,7 @@
 #include <parted/parted.h>
 #include <parted/debug.h>
 #include <parted/endian.h>
+#include <stdbool.h>
 
 #if ENABLE_NLS
 #  include <libintl.h>
@@ -663,6 +664,11 @@ sun_partition_is_flag_available (const PedPartition* part,
 	}
 }
 
+static bool
+sun_get_max_supported_partition_count (const PedDisk* disk, int* supported)
+{
+	return *supported = SUN_DISK_MAXPARTITIONS;
+}
 
 static int
 sun_get_max_primary_partition_count (const PedDisk* disk)
@@ -858,6 +864,8 @@ static PedDiskOps sun_disk_ops = {
 	alloc_metadata:		sun_alloc_metadata,
 	get_max_primary_partition_count:
 				sun_get_max_primary_partition_count,
+	get_max_supported_partition_count:
+				sun_get_max_supported_partition_count,
 
 	partition_set_name:		NULL,
 	partition_get_name:		NULL,
-- 
1.6.0.6




More information about the parted-devel mailing list