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

---
 libparted/arch/linux.c |   88 +++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 81 insertions(+), 7 deletions(-)

Index: parted-1.9.0/libparted/arch/linux.c
===================================================================
--- parted-1.9.0.orig/libparted/arch/linux.c	2010-04-12 09:33:46.000000000 +0200
+++ parted-1.9.0/libparted/arch/linux.c	2010-04-12 09:51:13.000000000 +0200
@@ -2110,7 +2110,9 @@ _device_get_part_path (PedDevice* dev, i
                 /* replace /disc with /path%d */
                 strcpy (result, dev->path);
                 snprintf (result + path_len - 5, 16, "/part%d", num);
-        } else if (dev->type == PED_DEVICE_DAC960
+        } else if (!strncmp (dev->path, "/dev/md", 7 ))
+                snprintf (result, result_len, "%sp%d", dev->path, num);
+        else if (dev->type == PED_DEVICE_DAC960
                         || dev->type == PED_DEVICE_CPQARRAY
                         || dev->type == PED_DEVICE_ATARAID
                         || dev->type == PED_DEVICE_DM
@@ -2352,15 +2354,28 @@ _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++) {
+                /* 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 <= lpn; i++) {
                 const PedPartition *part = ped_disk_get_partition (disk, i);
@@ -2369,17 +2384,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;
+                    }
+                    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;
+                    }
 
-                        /* add the (possibly modified or new) partition */
-                        if (!_blkpg_add_partition (disk, part))
-                                ret = 0;
                 }
         }
 
-        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] == 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