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;
}