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

Jim Meyering meyering at alioth.debian.org
Fri Apr 23 18:49:36 UTC 2010


 libparted/arch/linux.c                          |  282 +++++++++++++++++++++++-
 libparted/labels/dos.c                          |   15 +
 tests/Makefile.am                               |    1 
 tests/t2310-dos-extended-2-sector-min-offset.sh |   77 ++++++
 tests/t3000-resize-fs.sh                        |    3 
 5 files changed, 371 insertions(+), 7 deletions(-)

New commits:
commit 878aabcfa3cca4bd22bb4f5497fedd6d48ddd7db
Author: Jim Meyering <meyering at redhat.com>
Date:   Fri Apr 23 20:11:23 2010 +0200

    libparted: _disk_sync_part_table: allow interactive ignore
    
    * libparted/arch/linux.c (_disk_sync_part_table): Change diagnostic
    so that it makes it clear what failed.  Let an interactive "ignore"
    cause the function to succeed.

diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index f32bd21..988fde7 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -2531,15 +2531,16 @@ _disk_sync_part_table (PedDisk* disk)
 		ret = 1;
 	else {
                 bad_part_list[strlen (bad_part_list) - 2] = 0;
-                ped_exception_throw (
+                if (ped_exception_throw (
                         PED_EXCEPTION_WARNING,
-                        PED_EXCEPTION_IGNORE,
-                        _("Partition(s) %s on %s could not be modified, probably "
-                          "because it/they are in use.  As a result, "
-                          "the old partition(s) will remain in use until after "
-                          "reboot. You should reboot "
-                          "now before making further changes."),
-                        bad_part_list, disk->dev->path);
+                        PED_EXCEPTION_IGNORE_CANCEL,
+                        _("Partition(s) %s on %s have been written, but we have "
+			  "been unable to inform the kernel of the change, "
+			  "probably because it/they are in use.  As a result, "
+                          "the old partition(s) will remain in use.  You "
+                          "should reboot now before making further changes."),
+                        bad_part_list, disk->dev->path) == PED_EXCEPTION_IGNORE)
+                        ret = 1;
 		free (bad_part_list);
         }
  free_errnums:

commit 910d134c830a81c191e15456bc2df37d6f8b2616
Author: Jim Meyering <meyering at redhat.com>
Date:   Sun Apr 18 11:15:45 2010 +0200

    tests: remove partition explicitly before mklabel, to avoid new failure
    
    * tests/t3000-resize-fs.sh: Before, mklabel was sufficient to clear
    the partition table in preparation for the next iteration in this test.
    However, with recent BLKRRPART/BLKPG changes that "mklabel" would evoke
    a warning.  Remove the sole partition to avoid that.

diff --git a/tests/t3000-resize-fs.sh b/tests/t3000-resize-fs.sh
index 4d0f5cb..5cc46d3 100755
--- a/tests/t3000-resize-fs.sh
+++ b/tests/t3000-resize-fs.sh
@@ -111,6 +111,9 @@ for fs_type in hfs+ fat32; do
   printf "1:$start:$new_end:530082s:$fs_type:primary:$ms;\n" > exp || fail=1
   compare out exp || fail=1
 
+  # Remove the partition explicitly, so that mklabel doesn't evoke a warning.
+  parted -s $dev rm 1 || fail=1
+
   # Create a clean partition table for the next iteration.
   parted -s $dev mklabel gpt > out 2>&1 || fail=1
   # expect no output

commit 76f8e829e43773778b69915b5cfff9f643701074
Author: Jim Meyering <meyering at redhat.com>
Date:   Mon Apr 12 12:08:16 2010 +0200

    libparted: linux_disk_commit: don't ignore _disk_sync_part_table failure
    
    * libparted/arch/linux.c (linux_disk_commit):
    When calling _disk_sync_part_table, always return its result.

diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index a4e4894..f32bd21 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -2799,6 +2799,7 @@ _have_blkpg ()
         return have_blkpg = kver >= KERNEL_VERSION (2,4,0) ? 1 : 0;
 }
 
+/* Return nonzero upon success, 0 if something fails.  */
 static int
 linux_disk_commit (PedDisk* disk)
 {
@@ -2817,13 +2818,15 @@ linux_disk_commit (PedDisk* disk)
                  * to re-read and grok the partition table.
                  */
                 /* Work around kernel dasd problem so we really do BLKRRPART */
-                if (disk->dev->type != PED_DEVICE_DASD &&
-                    _have_blkpg () ) {
-                        if (_disk_sync_part_table (disk))
-                                return 1;
-                }
+		int ok = 1;
+		if (disk->dev->type != PED_DEVICE_DASD && _have_blkpg ()) {
+			if (!_disk_sync_part_table (disk))
+			  ok = 0;
+		}
 
-                return _kernel_reread_part_table (disk->dev);
+		if (!_kernel_reread_part_table (disk->dev))
+			ok = 0;
+                return ok;
         }
 
         return 1;

commit 81ed7fc413375a8b8ed5bd792e7385dacaf8a3e1
Author: Jim Meyering <meyering at redhat.com>
Date:   Mon Apr 12 12:06:30 2010 +0200

    libparted: _disk_sync_part_table: always return 0 upon failure
    
    * libparted/arch/linux.c (_disk_sync_part_table):
    Return 0 (not 1) upon failure.

diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index 473a408..a4e4894 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -2527,7 +2527,9 @@ _disk_sync_part_table (PedDisk* disk)
 		}
 		sprintf (bad_part_list + strlen (bad_part_list), "%d, ", i);
 	}
-        if (bad_part_list) {
+        if (bad_part_list == NULL)
+		ret = 1;
+	else {
                 bad_part_list[strlen (bad_part_list) - 2] = 0;
                 ped_exception_throw (
                         PED_EXCEPTION_WARNING,
@@ -2540,7 +2542,6 @@ _disk_sync_part_table (PedDisk* disk)
                         bad_part_list, disk->dev->path);
 		free (bad_part_list);
         }
-        ret = 1;
  free_errnums:
         free (errnums);
  free_rets:

commit 713322fa88e097b5bcaae36ad5b6a41d1acc6db3
Author: Colin Watson <cjwatson at ubuntu.com>
Date:   Mon Mar 29 14:40:54 2010 +0100

    dos: always allow at least two sectors for extended boot record
    
    Unless specifically told otherwise, the Linux kernel considers extended
    boot records to be two sectors long, in order to "leave room for LILO".
    When using anything other than cylinder alignment, libparted was only
    allowing one sector in the minimum extended partition geometry, which in
    some situations (e.g. following Phillip Susi's patch to reintroduce
    BLKPG) could confuse the kernel into thinking that the EBR and the first
    logical partition overlapped.
    
    * libparted/labels/dos.c (_get_min_extended_part_geom): Allow at least
    two sectors for the extended boot record.

diff --git a/libparted/labels/dos.c b/libparted/labels/dos.c
index 8679c49..9cbfd74 100644
--- a/libparted/labels/dos.c
+++ b/libparted/labels/dos.c
@@ -1754,7 +1754,11 @@ _get_min_extended_part_geom (const PedPartition* ext_part,
 	min_geom = ped_geometry_duplicate (&walk->geom);
 	if (!min_geom)
 		return NULL;
-	ped_geometry_set_start (min_geom, walk->geom.start - 1 * head_size);
+	/* We must always allow at least two sectors at the start, to leave
+	 * room for LILO.  See linux/fs/partitions/msdos.c.
+	 */
+	ped_geometry_set_start (min_geom,
+				walk->geom.start - PED_MAX (1 * head_size, 2));
 
 	for (walk = ext_part->part_list; walk; walk = walk->next) {
 		if (!ped_partition_is_active (walk) || walk->num == 5)

commit 83a11dc7619838c2492b57c4a3837fc2e73023c6
Author: Jim Meyering <meyering at redhat.com>
Date:   Tue Mar 30 11:57:35 2010 +0200

    tests: test for new 2-sector minimum ext-logical-separation
    
    * tests/t2310-dos-extended-2-sector-min-offset.sh: New file.
    * tests/Makefile.am (TESTS): Add it.

diff --git a/tests/Makefile.am b/tests/Makefile.am
index c2d826c..6f7730d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -22,6 +22,7 @@ TESTS = \
   t2100-mkswap.sh \
   t2200-dos-label-recog.sh \
   t2300-dos-label-extended-bootcode.sh \
+  t2310-dos-extended-2-sector-min-offset.sh \
   t2400-dos-hfs-partition-type.sh \
   t3000-resize-fs.sh \
   t3200-type-change.sh \
diff --git a/tests/t2310-dos-extended-2-sector-min-offset.sh b/tests/t2310-dos-extended-2-sector-min-offset.sh
new file mode 100644
index 0000000..550ded4
--- /dev/null
+++ b/tests/t2310-dos-extended-2-sector-min-offset.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+# Ensure that parted leaves at least 2 sectors between the beginning
+# of an extended partition and the first logical partition.
+# Before parted-2.3, it could be made to leave just one, and that
+# would cause trouble with the Linux kernel.
+
+# Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+  set -x
+  parted --version
+fi
+
+: ${srcdir=.}
+. $srcdir/t-lib.sh
+
+require_root_
+require_scsi_debug_module_
+
+# check for scsi_debug module
+modprobe -n scsi_debug ||
+  skip_test_ "you lack the scsi_debug kernel module"
+
+# create memory-backed device
+scsi_debug_setup_ dev_size_mb=1 > dev-name ||
+  skip_test_ 'failed to create scsi_debug device'
+scsi_dev=$(cat dev-name)
+p1=${scsi_dev}1
+
+cat <<EOF > exp || framework_failure
+BYT;
+$scsi_dev:2048s:scsi:512:512:msdos:Linux scsi_debug;
+1:64s:128s:65s:::lba;
+5:66s:128s:63s:::;
+EOF
+
+cat <<EOF > err.exp || framework_failure
+Error: Error informing the kernel about modifications to partition /dev/sdd5 -- Device or resource busy.  This means Linux won't know about any changes you made to /dev/sdd5 until you reboot -- so you shouldn't mount it or use it in any way before rebooting.
+Error: Failed to add partition 5 (Device or resource busy)
+EOF
+
+fail=0
+
+# Create a DOS label with an extended partition starting at sector 64.
+parted -s $scsi_dev mklabel msdos || fail=1
+parted --align=min -s $scsi_dev mkpart extended 64s 128s> out 2>&1 || fail=1
+parted -m -s $scsi_dev u s print
+compare out /dev/null || fail=1
+
+# Provoke a failure by trying to create a partition that starts just
+# one sector after the start of the extended partition.
+parted --align=min -s $scsi_dev mkpart logical 65s 128s > err 2>&1 && fail=1
+compare err err.exp || fail=1
+
+# The above failed, but created the partition nonetheless.  Remove it.
+parted -s $scsi_dev rm 5 || fail=1
+
+parted --align=min -s $scsi_dev mkpart logical 66s 128s > out 2>&1 || fail=1
+compare out /dev/null || fail=1
+
+parted -m -s $scsi_dev u s print > out 2>&1
+compare out exp || fail=1
+
+Exit $fail

commit c79d91ec71882a1673daae0482aa90c514c63cc1
Author: Jim Meyering <meyering at redhat.com>
Date:   Tue Mar 30 16:50:59 2010 +0200

    dos: accommodate very small devices (useful for testing)
    
    * libparted/labels/dos.c (_primary_constraint): Don't pass a negative
    "device_length" to ped_geometry_init when the underlying device
    has fewer sectors than a "cylinder".

diff --git a/libparted/labels/dos.c b/libparted/labels/dos.c
index 752f186..8679c49 100644
--- a/libparted/labels/dos.c
+++ b/libparted/labels/dos.c
@@ -1616,8 +1616,13 @@ _primary_constraint (const PedDisk* disk, const PedCHSGeometry* bios_geom,
 			       		dev->length - min_geom->end))
 			return NULL;
 	} else {
-		if (!ped_geometry_init (&start_geom, dev, cylinder_size,
-			       		dev->length - cylinder_size))
+		/* Do not assume that length is larger than 1 cylinder's
+		   worth of sectors.  This is useful when testing with
+		   a memory-mapped "disk" (a la scsi_debug) that is say,
+		   2048 sectors long.  */
+		if (cylinder_size < dev->length
+		    && !ped_geometry_init (&start_geom, dev, cylinder_size,
+					   dev->length - cylinder_size))
 			return NULL;
 		if (!ped_geometry_init (&end_geom, dev, 0, dev->length))
 			return NULL;

commit c7c7d440a9d7e3549aaba4f8ff3a0324ae803999
Author: Jim Meyering <meyering at redhat.com>
Date:   Mon Apr 12 10:13:18 2010 +0200

    libparted: allocate storage for diagnostic only when needed
    
    * libparted/arch/linux.c (_disk_sync_part_table): Rename local:
    s/parts/bad_part_list/
    Allocate space for it only if needed.
    Use malloc rather than ped_malloc.
    Move decl of FD down to first use.

diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index 79cea46..473a408 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -2470,13 +2470,12 @@ _disk_sync_part_table (PedDisk* disk)
                 if (part) {
                         if (!rets[i - 1] && errnums[i - 1] == EBUSY) {
                                 struct hd_geometry geom;
-                                int fd;
                                 unsigned long long length = 0;
                                 /* get start and length of existing partition */
                                 char *dev_name = _device_get_part_path (disk->dev, i);
                                 if (!dev_name)
                                         goto free_errnums;
-                                fd = open (dev_name, O_RDONLY);
+                                int fd = open (dev_name, O_RDONLY);
                                 if (fd == -1
 				    || ioctl (fd, HDIO_GETGEO, &geom)
 				    || ioctl (fd, BLKGETSIZE64, &length)) {
@@ -2515,16 +2514,21 @@ _disk_sync_part_table (PedDisk* disk)
                 }
         }
 
-        char *parts = ped_malloc (lpn * 5);
-        if (!parts)
-                goto free_errnums;
-        parts[0] = 0;
+        char *bad_part_list = NULL;
         /* now warn about any errors */
-        for (i = 1; i <= lpn; i++)
-                if (!rets[i - 1] && errnums[i - 1] != ENXIO)
-                        sprintf (parts + strlen (parts), "%d, ", i);
-        if (parts[0]) {
-                parts[strlen (parts) - 2] = 0;
+        for (i = 1; i <= lpn; i++) {
+		if (rets[i - 1] || errnums[i - 1] == ENXIO)
+			continue;
+		if (bad_part_list == NULL) {
+			  bad_part_list = malloc (lpn * 5);
+			  if (!bad_part_list)
+				  goto free_errnums;
+			  bad_part_list[0] = 0;
+		}
+		sprintf (bad_part_list + strlen (bad_part_list), "%d, ", i);
+	}
+        if (bad_part_list) {
+                bad_part_list[strlen (bad_part_list) - 2] = 0;
                 ped_exception_throw (
                         PED_EXCEPTION_WARNING,
                         PED_EXCEPTION_IGNORE,
@@ -2533,9 +2537,9 @@ _disk_sync_part_table (PedDisk* disk)
                           "the old partition(s) will remain in use until after "
                           "reboot. You should reboot "
                           "now before making further changes."),
-                        parts, disk->dev->path);
+                        bad_part_list, disk->dev->path);
+		free (bad_part_list);
         }
-        free (parts);
         ret = 1;
  free_errnums:
         free (errnums);

commit 18bda4aa38083f12afa6e3f24deb6ad853b90f91
Author: Jim Meyering <meyering at redhat.com>
Date:   Mon Apr 12 09:55:38 2010 +0200

    libparted: adjust code formatting

diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index 198441d..79cea46 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -2405,11 +2405,11 @@ _device_get_partition_range(PedDevice* dev)
 
         r = snprintf(path, sizeof(path), "/sys/block/%s/range",
                      last_component(dev->path));
-        if(r < 0 || r >= sizeof(path))
+        if (r < 0 || r >= sizeof(path))
                 return MAX_NUM_PARTS;
 
         fp = fopen(path, "r");
-        if(!fp)
+        if (!fp)
                 return MAX_NUM_PARTS;
 
         ok = fscanf(fp, "%d", &range) == 1;
@@ -2441,7 +2441,7 @@ _disk_sync_part_table (PedDisk* disk)
         int lpn;
 
         /* lpn = largest partition number. */
-        if(ped_disk_get_max_supported_partition_count(disk, &lpn))
+        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);
@@ -2449,7 +2449,7 @@ _disk_sync_part_table (PedDisk* disk)
         /* Its not possible to support largest_partnum < 0.
          * largest_partnum == 0 would mean does not support partitions.
          * */
-        if(lpn < 0)
+        if (lpn < 0)
                 return 0;
         int ret = 0;
         int *rets = ped_malloc(sizeof(int) * lpn);
@@ -2477,15 +2477,15 @@ _disk_sync_part_table (PedDisk* disk)
                                 if (!dev_name)
                                         goto free_errnums;
                                 fd = open (dev_name, O_RDONLY);
-                                if (fd == -1 ||
-                                    ioctl (fd, HDIO_GETGEO, &geom) ||
-                                    ioctl (fd, BLKGETSIZE64, &length)) {
+                                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."),
+			    _("Unable to determine the size and length of %s."),
                                                              dev_name);
-                                        if( fd != -1 )
+                                        if (fd != -1)
                                                 close (fd);
                                         free (dev_name);
                                         goto free_errnums;
@@ -2493,13 +2493,13 @@ _disk_sync_part_table (PedDisk* disk)
                                 free (dev_name);
                                 length /= disk->dev->sector_size;
                                 close (fd);
-                                if (geom.start == part->geom.start &&
-                                    length == part->geom.length)
+                                if (geom.start == part->geom.start
+				    && length == part->geom.length)
                                         rets[i - 1] = 1;
-                                /* if the new partition is unchanged and the existing
-                                   one was not removed because it was in use, then
-                                   reset the error flag and skip adding it
-                                   since it is already there */
+                                /* If the new partition is unchanged and the
+				   existing one was not removed because it was
+				   in use, then reset the error flag and do not
+				   try to add it since it is already there.  */
                                 continue;
                         }
 
@@ -2508,7 +2508,7 @@ _disk_sync_part_table (PedDisk* disk)
                                 ped_exception_throw (
                                         PED_EXCEPTION_ERROR,
                                         PED_EXCEPTION_RETRY_CANCEL,
-                                        _("Failed to add partition %i (%s)"),
+                                        _("Failed to add partition %d (%s)"),
                                         i, strerror (errno));
                                 goto free_errnums;
                         }
@@ -2522,7 +2522,7 @@ _disk_sync_part_table (PedDisk* disk)
         /* now warn about any errors */
         for (i = 1; i <= lpn; i++)
                 if (!rets[i - 1] && errnums[i - 1] != ENXIO)
-                        sprintf (parts + strlen (parts), "%i, ", i);
+                        sprintf (parts + strlen (parts), "%d, ", i);
         if (parts[0]) {
                 parts[strlen (parts) - 2] = 0;
                 ped_exception_throw (

commit 1745f05df3e7f3c9681ae4d39430b43dad40bc45
Author: Jim Meyering <meyering at redhat.com>
Date:   Thu Apr 15 13:45:44 2010 +0200

    libparted: reword a diagnostic

diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index 8e7d185..198441d 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -2529,8 +2529,9 @@ _disk_sync_part_table (PedDisk* disk)
                         PED_EXCEPTION_WARNING,
                         PED_EXCEPTION_IGNORE,
                         _("Partition(s) %s on %s could not be modified, probably "
-                          "because it/they is/are in use.  As a result, the old partition(s) "
-                          "will remain in use until after reboot. You should reboot "
+                          "because it/they are in use.  As a result, "
+                          "the old partition(s) will remain in use until after "
+                          "reboot. You should reboot "
                           "now before making further changes."),
                         parts, disk->dev->path);
         }

commit 7165951dfb584aae2901ac3f1a28fe3624667f19
Author: Phillip Susi <psusi at cfl.rr.com>
Date:   Fri Apr 9 15:22:20 2010 -0400

    libparted: improve BLKPG error checking
    
    This patch cleans up the BLKPG code that the previous patch put back
    to perform proper error checking and in the event that some partitions
    are in use, they can not be modified in the running kernel using BLKPG.
    Warn the user that this is the case and advise them to reboot, just like
    we do when BLKRRPART fails for the same reason, unless the partition in
    question is unchanged.

diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index 65043d3..8e7d185 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -2423,7 +2423,9 @@ _device_get_partition_range(PedDevice* dev)
  * Sync the partition table in two step process:
  * 1. Remove all of the partitions from the kernel's tables, but do not attempt
  *    removal of any partition for which the corresponding ioctl call fails.
- * 2. Add all the partitions that we hold in disk.
+ * 2. Add all the partitions that we hold in disk, throwing a warning
+ *    if we cannot because step 1 failed to remove it and it is not being
+ *    added back with the same start and length.
  *
  * To achieve this two step process we must calculate the minimum number of
  * maximum possible partitions between what linux supports and what the label
@@ -2449,10 +2451,13 @@ _disk_sync_part_table (PedDisk* disk)
          * */
         if(lpn < 0)
                 return 0;
-
+        int ret = 0;
         int *rets = ped_malloc(sizeof(int) * lpn);
+        if (!rets)
+                return 0;
         int *errnums = ped_malloc(sizeof(int) * lpn);
-        int ret = 1;
+        if (!errnums)
+                goto free_rets;
         int i;
 
         for (i = 1; i <= lpn; i++) {
@@ -2463,21 +2468,78 @@ _disk_sync_part_table (PedDisk* disk)
         for (i = 1; i <= lpn; i++) {
                 const PedPartition *part = ped_disk_get_partition (disk, i);
                 if (part) {
-                        /* busy... so we won't (can't!) disturb ;)  Prolly
-                         * doesn't matter anyway, because users shouldn't be
-                         * changing mounted partitions anyway...
-                         */
-                        if (!rets[i - 1] && errnums[i - 1] == EBUSY)
-                                        continue;
+                        if (!rets[i - 1] && errnums[i - 1] == EBUSY) {
+                                struct hd_geometry geom;
+                                int fd;
+                                unsigned long long length = 0;
+                                /* get start and length of existing partition */
+                                char *dev_name = _device_get_part_path (disk->dev, i);
+                                if (!dev_name)
+                                        goto free_errnums;
+                                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);
+                                        goto free_errnums;
+                                }
+                                free (dev_name);
+                                length /= disk->dev->sector_size;
+                                close (fd);
+                                if (geom.start == part->geom.start &&
+                                    length == part->geom.length)
+                                        rets[i - 1] = 1;
+                                /* if the new partition is unchanged and the existing
+                                   one was not removed because it was in use, then
+                                   reset the error flag and skip adding it
+                                   since it is already there */
+                                continue;
+                        }
 
                         /* add the (possibly modified or new) partition */
-                        if (!_blkpg_add_partition (disk, part))
-                                ret = 0;
+                        if (!_blkpg_add_partition (disk, part)) {
+                                ped_exception_throw (
+                                        PED_EXCEPTION_ERROR,
+                                        PED_EXCEPTION_RETRY_CANCEL,
+                                        _("Failed to add partition %i (%s)"),
+                                        i, strerror (errno));
+                                goto free_errnums;
+                        }
                 }
         }
 
-        free (rets);
+        char *parts = ped_malloc (lpn * 5);
+        if (!parts)
+                goto free_errnums;
+        parts[0] = 0;
+        /* now warn about any errors */
+        for (i = 1; i <= lpn; i++)
+                if (!rets[i - 1] && errnums[i - 1] != ENXIO)
+                        sprintf (parts + strlen (parts), "%i, ", i);
+        if (parts[0]) {
+                parts[strlen (parts) - 2] = 0;
+                ped_exception_throw (
+                        PED_EXCEPTION_WARNING,
+                        PED_EXCEPTION_IGNORE,
+                        _("Partition(s) %s on %s could not be modified, probably "
+                          "because it/they is/are in use.  As a result, the old partition(s) "
+                          "will remain in use until after reboot. You should reboot "
+                          "now before making further changes."),
+                        parts, disk->dev->path);
+        }
+        free (parts);
+        ret = 1;
+ free_errnums:
         free (errnums);
+ free_rets:
+        free (rets);
         return ret;
 }
 

commit 0e04d17386274fc218a9e6f9ae17d75510e632a3
Author: Phillip Susi <psusi at cfl.rr.com>
Date:   Tue Mar 30 15:04:43 2010 -0400

    libparted: reenable use of BLKPG ioctls
    
    This patch effectively reverses commit 1d8f9bec which removed the code
    using the new BLKPG ioctls instead of the old BLKRRPART ioctl to update
    the in-kernel partition table.  The reason for this is because BLKRRPART
    fails if any partition on the disk is in use, but the BLKPG ioctls allow
    you to manipulate the other partitions on the disk without requiring a
    reboot.  Also BLKRRPART requires that the kernel understand the
    partition table on the disk, which may not always be the case.

diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index d7ec2e4..65043d3 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -19,7 +19,7 @@
 
 #include <config.h>
 #include <arch/linux.h>
-
+#include <linux/blkpg.h>
 #include <parted/parted.h>
 #include <parted/debug.h>
 #if defined __s390__ || defined __s390x__
@@ -2305,6 +2305,182 @@ linux_partition_is_busy (const PedPartition* part)
         return 0;
 }
 
+static int
+_blkpg_part_command (PedDevice* dev, struct blkpg_partition* part, int op)
+{
+        LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
+        struct blkpg_ioctl_arg  ioctl_arg;
+
+        ioctl_arg.op = op;
+        ioctl_arg.flags = 0;
+        ioctl_arg.datalen = sizeof (struct blkpg_partition);
+        ioctl_arg.data = (void*) part;
+
+        return ioctl (arch_specific->fd, BLKPG, &ioctl_arg) == 0;
+}
+
+static int
+_blkpg_add_partition (PedDisk* disk, const PedPartition *part)
+{
+        struct blkpg_partition  linux_part;
+        const char*             vol_name;
+        char*                   dev_name;
+
+        PED_ASSERT(disk != NULL, return 0);
+        PED_ASSERT(disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0,
+                   return 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);
+        else
+                vol_name = NULL;
+
+        dev_name = _device_get_part_path (disk->dev, part->num);
+        if (!dev_name)
+                return 0;
+
+        memset (&linux_part, 0, sizeof (linux_part));
+        linux_part.start = part->geom.start * disk->dev->sector_size;
+        /* see fs/partitions/msdos.c:msdos_partition(): "leave room for LILO" */
+        if (part->type & PED_PARTITION_EXTENDED)
+                linux_part.length = part->geom.length == 1 ? 512 : 1024;
+        else
+                linux_part.length = part->geom.length * disk->dev->sector_size;
+        linux_part.pno = part->num;
+        strncpy (linux_part.devname, dev_name, BLKPG_DEVNAMELTH);
+        if (vol_name)
+                strncpy (linux_part.volname, vol_name, BLKPG_VOLNAMELTH);
+
+        free (dev_name);
+
+        if (!_blkpg_part_command (disk->dev, &linux_part,
+                                  BLKPG_ADD_PARTITION)) {
+                return ped_exception_throw (
+                        PED_EXCEPTION_ERROR,
+                        PED_EXCEPTION_IGNORE_CANCEL,
+                        _("Error informing the kernel about modifications to "
+                          "partition %s -- %s.  This means Linux won't know "
+                          "about any changes you made to %s until you reboot "
+                          "-- so you shouldn't mount it or use it in any way "
+                          "before rebooting."),
+                        linux_part.devname,
+                        strerror (errno),
+                        linux_part.devname)
+                                == PED_EXCEPTION_IGNORE;
+        }
+
+        return 1;
+}
+
+static int
+_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,
+                                    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",
+                     last_component(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;
+}
+
+/*
+ * Sync the partition table in two step process:
+ * 1. Remove all of the partitions from the kernel's tables, but do not attempt
+ *    removal of any partition for which the corresponding ioctl call fails.
+ * 2. 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)
+{
+        PED_ASSERT(disk != NULL, return 0);
+        PED_ASSERT(disk->dev != NULL, return 0);
+        int lpn;
+
+        /* 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);
+
+        /* 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 <= lpn; i++) {
+                const PedPartition *part = ped_disk_get_partition (disk, i);
+                if (part) {
+                        /* busy... so we won't (can't!) disturb ;)  Prolly
+                         * doesn't matter anyway, because users shouldn't be
+                         * changing mounted partitions anyway...
+                         */
+                        if (!rets[i - 1] && errnums[i - 1] == EBUSY)
+                                        continue;
+
+                        /* add the (possibly modified or new) partition */
+                        if (!_blkpg_add_partition (disk, part))
+                                ret = 0;
+                }
+        }
+
+        free (rets);
+        free (errnums);
+        return ret;
+}
+
 #ifdef ENABLE_DEVICE_MAPPER
 static int
 _dm_remove_map_name(char *name)
@@ -2543,16 +2719,42 @@ _kernel_reread_part_table (PedDevice* dev)
 }
 
 static int
+_have_blkpg ()
+{
+        static int have_blkpg = -1;
+        int kver;
+
+        if (have_blkpg != -1)
+                return have_blkpg;
+
+        kver = _get_linux_version();
+        return have_blkpg = kver >= KERNEL_VERSION (2,4,0) ? 1 : 0;
+}
+
+static int
 linux_disk_commit (PedDisk* disk)
 {
-       if (!_has_partitions (disk))
-               return 1;
+        if (!_has_partitions (disk))
+                return 1;
 
 #ifdef ENABLE_DEVICE_MAPPER
         if (disk->dev->type == PED_DEVICE_DM)
                 return _dm_reread_part_table (disk);
 #endif
         if (disk->dev->type != PED_DEVICE_FILE) {
+                /* The ioctl() command BLKPG_ADD_PARTITION does not notify
+                 * the devfs system; consequently, /proc/partitions will not
+                 * be up to date, and the proper links in /dev are not
+                 * created.  Therefore, if using DevFS, we must get the kernel
+                 * to re-read and grok the partition table.
+                 */
+                /* Work around kernel dasd problem so we really do BLKRRPART */
+                if (disk->dev->type != PED_DEVICE_DASD &&
+                    _have_blkpg () ) {
+                        if (_disk_sync_part_table (disk))
+                                return 1;
+                }
+
                 return _kernel_reread_part_table (disk->dev);
         }
 



More information about the Parted-commits mailing list