[Parted-commits] GNU Parted Official Repository: Changes to 'master'

Jim Meyering meyering at alioth.debian.org
Thu Jan 5 18:40:20 UTC 2012


 libparted/arch/linux.c |  193 +++++++++++++++++++++++++++++--------------------
 1 file changed, 116 insertions(+), 77 deletions(-)

New commits:
commit 9b9913a315fb739fb8b886e84c8dd137539faacf
Author: Phillip Susi <psusi at cfl.rr.com>
Date:   Fri Dec 16 23:05:40 2011 -0500

    libparted: avoid the HDIO_GETGEO ioctl when possible
    
    We were using the long depreciated HDIO_GETGEO ioctl on the
    partition to get its start sector.  Use the new BLKPG_GET_PARTITION
    ioctl instead.  This allows for disks > 2TB and partitioned loop
    devices, which don't support HDIO_GETGEO.  As a fallback when
    BLKPG_GET_PARTITION fails or is not availible, try getting the
    values from sysfs, and finally use BLKGETSIZE64 and HDIO_GETGEO
    as a last resort.

diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index 0e12ab0..6d7fc56 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -2410,6 +2410,24 @@ _blkpg_remove_partition (PedDisk* disk, int n)
                                     BLKPG_DEL_PARTITION);
 }
 
+#ifdef BLKPG_GET_PARTITION
+static int
+_blkpg_get_partition (PedPartition *part, long long *start, long long *length)
+{
+        struct blkpg_partition  linux_part;
+
+        memset (&linux_part, 0, sizeof (linux_part));
+        linux_part.pno = part->num;
+        if (_blkpg_part_command (part->disk->dev, &linux_part,
+                                 BLKPG_GET_PARTITION)) {
+                *start = linux_part.start;
+                *length = linux_part.length;
+                return 1;
+        } else
+                return 0;
+}
+#endif
+
 /* Read the integer from /sys/block/DEV_BASE/ENTRY and set *VAL
    to that value, where DEV_BASE is the last component of DEV->path.
    Upon success, return true.  Otherwise, return false. */
@@ -2432,6 +2450,101 @@ _sysfs_int_entry_from_dev(PedDevice const* dev, const char *entry, int *val)
         return ok;
 }
 
+/* Read the unsigned long long from /sys/block/DEV_BASE/PART_BASE/ENTRY
+   and set *VAL to that value, where DEV_BASE is the last component of path to
+   block device corresponding to PART and PART_BASE is the sysfs name of PART.
+   Upon success, return true. Otherwise, return false. */
+static bool
+_sysfs_ull_entry_from_part(PedPartition const* part, const char *entry,
+			   unsigned long long *val)
+{
+        char path[128];
+        char *part_name = linux_partition_get_path(part);
+        if (!part_name)
+                return false;
+
+        int r = snprintf(path, sizeof(path), "/sys/block/%s/%s/%s",
+                last_component(part->disk->dev->path),
+                last_component(part_name), entry);
+        free(part_name);
+        if (r < 0 || r >= sizeof(path))
+                return false;
+
+        FILE *fp = fopen(path, "r");
+        if (!fp)
+                return false;
+
+        bool ok = fscanf(fp, "%llu", val) == 1;
+        fclose(fp);
+
+        return ok;
+}
+
+
+/* Get the starting sector and length of a partition PART within a block device
+   Use blkpg if available, then check sysfs and then use HDIO_GETGEO and
+   BLKGETSIZE64 ioctls as fallback.  Upon success, return true.  Otherwise,
+   return false. */
+static bool
+_kernel_get_partition_start_and_length(PedPartition const *part,
+				       unsigned long long *start,
+                                      unsigned long long *length)
+{
+        int fd = -1;
+        int ok;
+        PED_ASSERT(part);
+        PED_ASSERT(start);
+        PED_ASSERT(length);
+
+#ifdef BLKPG_GET_PARTITION
+        ok = _blkpg_get_partition (part, start, length);
+        if (ok) {
+                *length = (*length * 512) / part->disk->dev->sector_size;
+                *start = (*start * 512) / part->disk->dev->sector_size;
+                return ok;
+        }
+#endif
+        char *dev_name = linux_partition_get_path (part);
+        if (!dev_name)
+                return false;
+
+        ok = _sysfs_ull_entry_from_part (part, "start", start);
+        if (!ok) {
+                struct hd_geometry geom;
+                int dev_fd = open (dev_name, O_RDONLY);
+                if (dev_fd != -1 && ioctl (dev_fd, HDIO_GETGEO, &geom)) {
+                        *start = geom.start;
+                        ok = true;
+                } else {
+                        if (dev_fd != -1)
+                                close(dev_fd);
+                        free (dev_name);
+                        return false;
+                }
+        }
+        *start = (*start * 512) / part->disk->dev->sector_size;
+        ok = _sysfs_ull_entry_from_part (part, "size", length);
+        if (!ok) {
+                if (fd == -1)
+                        fd = open (dev_name, O_RDONLY);
+                if (fd != -1 && ioctl (fd, BLKGETSIZE64, length))
+                        ok = true;
+        } else *length *= 512;
+        *length /= part->disk->dev->sector_size;
+        if (fd != -1)
+                close (fd);
+
+        if (!ok)
+                ped_exception_throw (
+                        PED_EXCEPTION_BUG,
+                        PED_EXCEPTION_CANCEL,
+                        _("Unable to determine the size and length of %s."),
+                        dev_name);
+        free (dev_name);
+        return ok;
+}
+
+
 /*
  * The number of partitions that a device can have depends on the kernel.
  * If we don't find this value in /sys/block/DEV/ext_range, we will use our own
@@ -2516,33 +2629,16 @@ _disk_sync_part_table (PedDisk* disk)
         }
 
         for (i = 1; i <= lpn; i++) {
-                const PedPartition *part = ped_disk_get_partition (disk, i);
+                PedPartition *part = ped_disk_get_partition (disk, i);
                 if (part) {
                         if (!ok[i - 1] && errnums[i - 1] == EBUSY) {
-                                struct hd_geometry geom;
-                                unsigned long long length = 0;
+                                unsigned long long length;
+                                unsigned long long start;
                                 /* get start and length of existing partition */
-                                char *dev_name = _device_get_part_path (disk->dev, i);
-                                if (!dev_name)
-                                        goto cleanup;
-                                int fd = open (dev_name, O_RDONLY);
-                                if (fd == -1
-				    || ioctl (fd, HDIO_GETGEO, &geom)
-				    || ioctl (fd, BLKGETSIZE64, &length)) {
-                                        ped_exception_throw (
-                                                             PED_EXCEPTION_BUG,
-                                                             PED_EXCEPTION_CANCEL,
-			    _("Unable to determine the size and length of %s."),
-                                                             dev_name);
-                                        if (fd != -1)
-                                                close (fd);
-                                        free (dev_name);
+                                if (!_kernel_get_partition_start_and_length(part,
+                                                                &start, &length))
                                         goto cleanup;
-                                }
-                                free (dev_name);
-                                length /= disk->dev->sector_size;
-                                close (fd);
-                                if (geom.start == part->geom.start
+                                if (start == part->geom.start
 				    && length == part->geom.length)
                                         ok[i - 1] = 1;
                                 /* If the new partition is unchanged and the

commit f5c909c0cd50ed52a48dae6d35907dc08b137e88
Author: Phillip Susi <psusi at cfl.rr.com>
Date:   Fri Dec 16 23:05:39 2011 -0500

    libparted: remove has_partitions check to allow loopback partitions
    
    Commit 1b766b69 added the _has_partitions function to check if a device
    was a loop device and if so, skip updating the kernel partition table
    because loop devices did not support partitions.  This function never
    worked anyway, and loop devices now (since linux 3.2) support
    partitions, so remove this crufty code.
    * libparted/arch/linux.c (_has_partitions): Remove function and
    all uses.

diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index 5c22276..0e12ab0 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -2314,18 +2314,6 @@ _partition_is_mounted (const PedPartition *part)
 	return !!status;
 }
 
-static int _GL_ATTRIBUTE_PURE
-_has_partitions (const PedDisk* disk)
-{
-        PED_ASSERT(disk != NULL);
-
-        /* Some devices can't be partitioned. */
-        if (!strcmp (disk->type->name, "loop"))
-                return 0;
-
-        return 1;
-}
-
 static int
 linux_partition_is_busy (const PedPartition* part)
 {
@@ -2368,9 +2356,6 @@ _blkpg_add_partition (PedDisk* disk, const PedPartition *part)
         PED_ASSERT(disk != NULL);
         PED_ASSERT(disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
 
-        if (!_has_partitions (disk))
-                return 0;
-
         if (ped_disk_type_check_feature (disk->type,
                                          PED_DISK_TYPE_PARTITION_NAME))
                 vol_name = ped_partition_get_name (part);
@@ -2419,9 +2404,6 @@ _blkpg_remove_partition (PedDisk* disk, int n)
 {
         struct blkpg_partition  linux_part;
 
-        if (!_has_partitions (disk))
-                return 0;
-
         memset (&linux_part, 0, sizeof (linux_part));
         linux_part.pno = n;
         return _blkpg_part_command (disk->dev, &linux_part,
@@ -2743,9 +2725,6 @@ _dm_add_partition (PedDisk* disk, PedPartition* part)
         char*           params = NULL;
         LinuxSpecific*  arch_specific = LINUX_SPECIFIC (disk->dev);
 
-        if (!_has_partitions(disk))
-                return 0;
-
         /* Get map name from devicemapper */
         struct dm_task *task = dm_task_create (DM_DEVICE_INFO);
         if (!task)
@@ -2846,9 +2825,6 @@ _have_blkpg ()
 static int
 linux_disk_commit (PedDisk* disk)
 {
-        if (!_has_partitions (disk))
-                return 1;
-
 #ifdef ENABLE_DEVICE_MAPPER
         if (disk->dev->type == PED_DEVICE_DM)
                 return _dm_reread_part_table (disk);

commit 11316315f99e61e875eef2964ae3b227a6088db1
Author: Phillip Susi <psusi at cfl.rr.com>
Date:   Fri Dec 16 22:40:04 2011 -0500

    libparted: remove _loop_get_partition_range
    
    Commit 1eb0cc30 added support for loop devices to be partitioned,
    but it only enabled that support if the kernel parameter max_part
    was non zero.  This parameter just reserves minor numbers for
    partitions in the traditional sequence that hard disks used.
    When it is zero, it is still possible to add partitions, they
    just will get minor numbers from another pool.  Removing this
    check allows partitions to be used on loop devices even when the
    loop module was not loaded with the max_part argument.
    * libparted/arch/linux.c (_loop_get_partition_range): Remove function
    and all uses.

diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index 07fc97c..5c22276 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -2450,38 +2450,6 @@ _sysfs_int_entry_from_dev(PedDevice const* dev, const char *entry, int *val)
         return ok;
 }
 
-/* Return the maximum number of partitions that the loopback device can hold.
-   First, check the loop-module-exported max_part parameter (since linux-3.0).
-   If that is not available, fall back to checking ext_range, which seems to
-   have (for some reason) different semantics compared to other devices;
-   specifically, ext_range <= 1 means that the loopback device does
-   not support partitions.  */
-static unsigned int
-_loop_get_partition_range(PedDevice const* dev)
-{
-        int         max_part;
-        bool        ok = false;
-
-        /* max_part module param is exported since kernel 3.0 */
-        FILE *fp = fopen("/sys/module/loop/parameters/max_part", "r");
-        if (fp) {
-                ok = fscanf(fp, "%d", &max_part) == 1;
-                fclose(fp);
-        }
-
-        if (ok)
-                return max_part > 0 ? max_part : 0;
-
-        /*
-         * max_part is not exported - check ext_range;
-         * device supports partitions if ext_range > 1
-         */
-        int range;
-        ok = _sysfs_int_entry_from_dev(dev, "range", &range);
-
-        return ok && range > 1 ? range : 0;
-}
-
 /*
  * The number of partitions that a device can have depends on the kernel.
  * If we don't find this value in /sys/block/DEV/ext_range, we will use our own
@@ -2490,14 +2458,13 @@ _loop_get_partition_range(PedDevice const* dev)
 static unsigned int
 _device_get_partition_range(PedDevice const* dev)
 {
-        /* loop handling is special */
-        if (dev->type == PED_DEVICE_LOOP)
-                return _loop_get_partition_range(dev);
-
         int range;
         bool ok = _sysfs_int_entry_from_dev(dev, "ext_range", &range);
 
-        return ok && range > 0 ? range : MAX_NUM_PARTS;
+        if (!ok)
+                return MAX_NUM_PARTS;
+        /* both 0 and 1 mean no partitions */
+        return range > 1 ? range : 0;
 }
 
 /*



More information about the Parted-commits mailing list