File retry-blkpg-ioctl-and-improve-error-handling.patch of Package parted

---
 libparted/arch/linux.c |   87 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 82 insertions(+), 5 deletions(-)

Index: parted-1.8.8/libparted/arch/linux.c
===================================================================
--- parted-1.8.8.orig/libparted/arch/linux.c	2010-04-12 13:59:13.000000000 +0200
+++ parted-1.8.8/libparted/arch/linux.c	2010-04-12 13:59:53.000000000 +0200
@@ -2192,13 +2192,27 @@ _disk_sync_part_table (PedDisk* disk)
 		last = 16;
 	else
 	 	last = PED_MAX (ped_disk_get_last_partition_num (disk), 16);
+
+        int ret = 0;
         int*    rets = ped_malloc(sizeof(int) * last);
+        if (!rets)
+            return 0;
         int*    errnums = ped_malloc(sizeof(int) * last);
-        int     ret = 1;
+        if (!errnums)
+            goto free_rets;
 
         for (i = 1; i <= last; i++) {
+                /* try to BLKPG_REMOVE the partition
+                 * retry once more after short sleep if EBUSY
+                 */
                 rets[i - 1] = _blkpg_remove_partition (disk, i);
                 errnums[i - 1] = errno;
+
+                if ( !rets[i - 1] && errnums[i - 1] == EBUSY ) {
+                        sleep(1);
+                        rets[i - 1] = _blkpg_remove_partition (disk, i);
+                        errnums[i - 1] = errno;
+                }
         }
 
         for (i = 1; i <= last; i++) {
@@ -2210,15 +2224,76 @@ _disk_sync_part_table (PedDisk* disk)
                          * doesn't matter anyway, because users shouldn't be
                          * changing mounted partitions anyway...
                          */
-                        if (!rets[i - 1] && errnums[i - 1] == EBUSY)
+                    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);
+                        free (dev_name);
+                        if (fd == -1 ||
+                            ioctl (fd, HDIO_GETGEO, &geom) ||
+                            ioctl (fd, BLKGETSIZE64, &length)) {
+                                if( fd != -1 )
+                                        close (fd);
+                                /* continue with error flag set */
                                         continue;
+                        }
+                        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 exiting
+                         * 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;
+                    }
                 }
         }
 
+        char *parts = ped_malloc (last * 5);
+        if (!parts)
+            goto free_errnums;
+        parts[0] = 0;
+        /* now warn about any errors */
+        for (i = 1; i <= last; i++)
+            if (!rets[i - 1] && errnums[i - 1] == EBUSY)
+                sprintf (parts + strlen (parts), "%i, ", i);
+        if (parts[0]) {
+            parts[strlen (parts) - 2] = 0;
+            ped_exception_throw (
+                    PED_EXCEPTION_WARNING,
+                    PED_EXCEPTION_IGNORE,
+                    _("Parted could not inform the kernel about eventual changes to "
+                      "partitions(s) %s on %s. This most likely means that the partition(s) "
+                      "is/are in use and parted could not determine whether the partition(s) "
+                      "have changed. As a result, the old partition(s) will remain in use until "
+                      "after reboot. If you know the partition(s) listed above have not changed, "
+                      "you can ignore this warning. Otherwise, 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;
 }
 
openSUSE Build Service is sponsored by