OSDN Git Service

libparted: improve support for partitions on loopback devices
authorPetr Uzel <petr.uzel@suse.cz>
Thu, 29 Sep 2011 13:14:23 +0000 (15:14 +0200)
committerJim Meyering <meyering@redhat.com>
Thu, 29 Sep 2011 14:18:58 +0000 (16:18 +0200)
Since linux-2.6.26, the kernel allows partitions on loopback devices.
Implement support for this feature in parted.
* libparted/arch/linux.c (_sysfs_int_entry_from_dev): New function.
(_loop_get_partition_range): New function.
(_device_get_partition_range): Add special handling for loop devices.
* NEWS: Mention this change.

NEWS
libparted/arch/linux.c

diff --git a/NEWS b/NEWS
index 6c55ec9..293dad8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,10 @@ GNU parted NEWS                                    -*- outline -*-
 
 * Noteworthy changes in release ?.? (????-??-??) [?]
 
+** New features
+
+  parted has improved support for partitionable loopback devices
+
 ** Bug fixes
 
   libparted: no longer aborts (failed assertion) due to a nilfs2_probe bug
index 5452f30..b1c12b5 100644 (file)
@@ -2428,32 +2428,75 @@ _blkpg_remove_partition (PedDisk* disk, int n)
                                     BLKPG_DEL_PARTITION);
 }
 
+/* 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. */
+static bool
+_sysfs_int_entry_from_dev(PedDevice const* dev, const char *entry, int *val)
+{
+        char        path[128];
+        int r = snprintf(path, sizeof(path), "/sys/block/%s/%s",
+                        last_component(dev->path), entry);
+        if (r < 0 || r >= sizeof(path))
+                return false;
+
+        FILE *fp = fopen(path, "r");
+        if (!fp)
+                return false;
+
+        bool ok = fscanf(fp, "%d", val) == 1;
+        fclose(fp);
+
+        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/range, we will use our own
  * value.
  */
 static unsigned int
-_device_get_partition_range(PedDevice* dev)
+_device_get_partition_range(PedDevice const* dev)
 {
-        int         range, r;
-        char        path[128];
-        FILE*       fp;
-        bool        ok;
-
-        r = snprintf(path, sizeof(path), "/sys/block/%s/range",
-                     last_component(dev->path));
-        if (r < 0 || r >= sizeof(path))
-                return MAX_NUM_PARTS;
+        /* loop handling is special */
+        if (dev->type == PED_DEVICE_LOOP)
+                return _loop_get_partition_range(dev);
 
-        fp = fopen(path, "r");
-        if (!fp)
-                return MAX_NUM_PARTS;
-
-        ok = fscanf(fp, "%d", &range) == 1;
-        fclose(fp);
+        int range;
+        bool ok = _sysfs_int_entry_from_dev(dev, "range", &range);
 
-        /* (range <= 0) is none sense.*/
         return ok && range > 0 ? range : MAX_NUM_PARTS;
 }