Blame SOURCES/0046-libparted-Backport-partition-resize-code.patch

fc4a62
From 31ab97cfe0233191a73a1dd9cb7cd193451491da Mon Sep 17 00:00:00 2001
fc4a62
From: "Brian C. Lane" <bcl@redhat.com>
fc4a62
Date: Fri, 11 Aug 2017 08:37:11 -0700
fc4a62
Subject: [PATCH 46/48] libparted: Backport partition resize code
fc4a62
fc4a62
This adds _blkpg_resize_partition, _dm_resize_partition, and adjust the
fc4a62
current code to support it. Changes are somewhat extensive, since they
fc4a62
also touch _disk_sync_part_table.
fc4a62
fc4a62
This is based on code from commit f09ca967a0bc443b869a6fad5b5ffe8e95c3fe9a
fc4a62
fc4a62
Related: rhbz#1423357
fc4a62
---
fc4a62
 libparted/arch/linux.c | 673 +++++++++++++++++++++++++++++--------------------
fc4a62
 1 file changed, 403 insertions(+), 270 deletions(-)
fc4a62
fc4a62
diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
fc4a62
index fa329f4..6e78faf 100644
fc4a62
--- a/libparted/arch/linux.c
fc4a62
+++ b/libparted/arch/linux.c
fc4a62
@@ -288,6 +288,7 @@ struct blkdev_ioctl_param {
fc4a62
 
fc4a62
 static char* _device_get_part_path (PedDevice* dev, int num);
fc4a62
 static int _partition_is_mounted_by_path (const char* path);
fc4a62
+static unsigned int _device_get_partition_range(PedDevice const* dev);
fc4a62
 static int _device_open (PedDevice* dev, int flags);
fc4a62
 static int _device_open_ro (PedDevice* dev);
fc4a62
 static int _device_close (PedDevice* dev);
fc4a62
@@ -446,6 +447,17 @@ _is_blkext_major (int major)
fc4a62
 
fc4a62
 #ifdef ENABLE_DEVICE_MAPPER
fc4a62
 static int
fc4a62
+_dm_task_run_wait (struct dm_task *task, uint32_t cookie)
fc4a62
+{
fc4a62
+        int rc = 0;
fc4a62
+
fc4a62
+        rc = dm_task_run (task);
fc4a62
+        dm_udev_wait (cookie);
fc4a62
+
fc4a62
+        return rc;
fc4a62
+}
fc4a62
+
fc4a62
+static int
fc4a62
 _is_dm_major (int major)
fc4a62
 {
fc4a62
         return _major_type_in_devices (major, "device-mapper");
fc4a62
@@ -1521,6 +1533,7 @@ _flush_cache (PedDevice* dev)
fc4a62
 {
fc4a62
         LinuxSpecific*  arch_specific = LINUX_SPECIFIC (dev);
fc4a62
         int             i;
fc4a62
+        int             lpn = _device_get_partition_range(dev);
fc4a62
 
fc4a62
         if (dev->read_only)
fc4a62
                 return;
fc4a62
@@ -1532,7 +1545,7 @@ _flush_cache (PedDevice* dev)
fc4a62
         if (_have_kern26())
fc4a62
                 return;
fc4a62
 
fc4a62
-        for (i = 1; i < 16; i++) {
fc4a62
+        for (i = 1; i < lpn; i++) {
fc4a62
                 char*           name;
fc4a62
                 int             fd;
fc4a62
 
fc4a62
@@ -2268,28 +2281,63 @@ zasprintf (const char *format, ...)
fc4a62
   return r < 0 ? NULL : resultp;
fc4a62
 }
fc4a62
 
fc4a62
+#ifdef ENABLE_DEVICE_MAPPER
fc4a62
+static char *
fc4a62
+dm_canonical_path (PedDevice const *dev)
fc4a62
+{
fc4a62
+        LinuxSpecific const *arch_specific = LINUX_SPECIFIC (dev);
fc4a62
+
fc4a62
+        /* Get map name from devicemapper */
fc4a62
+        struct dm_task *task = dm_task_create (DM_DEVICE_INFO);
fc4a62
+        if (!task)
fc4a62
+                goto err;
fc4a62
+        if (!dm_task_set_major_minor (task, arch_specific->major,
fc4a62
+                                      arch_specific->minor, 0))
fc4a62
+                goto err;
fc4a62
+        if (!dm_task_run(task))
fc4a62
+                goto err;
fc4a62
+        char *dev_name = zasprintf ("/dev/mapper/%s", dm_task_get_name (task));
fc4a62
+        if (dev_name == NULL)
fc4a62
+                goto err;
fc4a62
+        dm_task_destroy (task);
fc4a62
+        return dev_name;
fc4a62
+err:
fc4a62
+        return NULL;
fc4a62
+}
fc4a62
+#endif
fc4a62
+
fc4a62
 static char*
fc4a62
 _device_get_part_path (PedDevice *dev, int num)
fc4a62
 {
fc4a62
-        size_t path_len = strlen (dev->path);
fc4a62
-
fc4a62
+        char *devpath;
fc4a62
+        size_t path_len;
fc4a62
         char *result;
fc4a62
+#ifdef ENABLE_DEVICE_MAPPER
fc4a62
+        devpath = (dev->type == PED_DEVICE_DM
fc4a62
+                         ? dm_canonical_path (dev) : dev->path);
fc4a62
+#else
fc4a62
+        devpath = dev->path;
fc4a62
+#endif
fc4a62
+        path_len = strlen (devpath);
fc4a62
         /* Check for devfs-style /disc => /partN transformation
fc4a62
            unconditionally; the system might be using udev with devfs rules,
fc4a62
            and if not the test is harmless. */
fc4a62
-        if (5 < path_len && !strcmp (dev->path + path_len - 5, "/disc")) {
fc4a62
+        if (5 < path_len && !strcmp (devpath + path_len - 5, "/disc")) {
fc4a62
                 /* replace /disc with /part%d */
fc4a62
                 result = zasprintf ("%.*s/part%d",
fc4a62
-                                    (int) (path_len - 5), dev->path, num);
fc4a62
+                                    (int) (path_len - 5), devpath, num);
fc4a62
         } else {
fc4a62
                 char const *p = (dev->type == PED_DEVICE_DAC960
fc4a62
                                  || dev->type == PED_DEVICE_CPQARRAY
fc4a62
                                  || dev->type == PED_DEVICE_ATARAID
fc4a62
                                  || isdigit (dev->path[path_len - 1])
fc4a62
                                  ? "p" : "");
fc4a62
-                result = zasprintf ("%s%s%d", dev->path, p, num);
fc4a62
+                result = zasprintf ("%s%s%d", devpath, p, num);
fc4a62
         }
fc4a62
-
fc4a62
+#ifdef ENABLE_DEVICE_MAPPER
fc4a62
+        if (dev->type == PED_DEVICE_DM)
fc4a62
+                free (devpath);
fc4a62
+#endif
fc4a62
         return result;
fc4a62
 }
fc4a62
 
fc4a62
@@ -2438,6 +2486,62 @@ _blkpg_add_partition (PedDisk* disk, const PedPartition *part)
fc4a62
 
fc4a62
         if (!_blkpg_part_command (disk->dev, &linux_part,
fc4a62
                                   BLKPG_ADD_PARTITION)) {
fc4a62
+            return 0;
fc4a62
+        }
fc4a62
+
fc4a62
+        return 1;
fc4a62
+}
fc4a62
+
fc4a62
+static int
fc4a62
+_blkpg_remove_partition (PedDisk* disk, int n)
fc4a62
+{
fc4a62
+        struct blkpg_partition  linux_part;
fc4a62
+
fc4a62
+        memset (&linux_part, 0, sizeof (linux_part));
fc4a62
+        linux_part.pno = n;
fc4a62
+        return _blkpg_part_command (disk->dev, &linux_part,
fc4a62
+                                    BLKPG_DEL_PARTITION);
fc4a62
+}
fc4a62
+
fc4a62
+#ifdef BLKPG_RESIZE_PARTITION
fc4a62
+static int _blkpg_resize_partition (PedDisk* disk, const PedPartition *part)
fc4a62
+{
fc4a62
+        struct blkpg_partition  linux_part;
fc4a62
+        char*                   dev_name;
fc4a62
+
fc4a62
+        PED_ASSERT(disk != NULL);
fc4a62
+        PED_ASSERT(disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
fc4a62
+
fc4a62
+        dev_name = _device_get_part_path (disk->dev, part->num);
fc4a62
+        if (!dev_name)
fc4a62
+                return 0;
fc4a62
+        memset (&linux_part, 0, sizeof (linux_part));
fc4a62
+        linux_part.start = part->geom.start * disk->dev->sector_size;
fc4a62
+        /* see fs/partitions/msdos.c:msdos_partition(): "leave room for LILO" */
fc4a62
+        if (part->type & PED_PARTITION_EXTENDED) {
fc4a62
+                if (disk->dev->sector_size == 512) {
fc4a62
+                        linux_part.length = 2;
fc4a62
+                        PedPartition *walk;
fc4a62
+                        /* if the second sector is claimed by a logical partition,
fc4a62
+                           then there's just no room for lilo, so don't try to use it */
fc4a62
+                        for (walk = part->part_list; walk; walk = walk->next) {
fc4a62
+                                if (walk->geom.start == part->geom.start+1)
fc4a62
+                                        linux_part.length = 1;
fc4a62
+                        }
fc4a62
+                } else {
fc4a62
+                        linux_part.length = 1;
fc4a62
+                }
fc4a62
+                linux_part.length *= disk->dev->sector_size;
fc4a62
+        }
fc4a62
+        else
fc4a62
+                linux_part.length = part->geom.length * disk->dev->sector_size;
fc4a62
+        linux_part.pno = part->num;
fc4a62
+        strncpy (linux_part.devname, dev_name, BLKPG_DEVNAMELTH);
fc4a62
+
fc4a62
+        free (dev_name);
fc4a62
+
fc4a62
+        if (!_blkpg_part_command (disk->dev, &linux_part,
fc4a62
+                                  BLKPG_RESIZE_PARTITION)) {
fc4a62
                 return ped_exception_throw (
fc4a62
                         PED_EXCEPTION_ERROR,
fc4a62
                         PED_EXCEPTION_IGNORE_CANCEL,
fc4a62
@@ -2454,17 +2558,7 @@ _blkpg_add_partition (PedDisk* disk, const PedPartition *part)
fc4a62
 
fc4a62
         return 1;
fc4a62
 }
fc4a62
-
fc4a62
-static int
fc4a62
-_blkpg_remove_partition (PedDisk* disk, int n)
fc4a62
-{
fc4a62
-        struct blkpg_partition  linux_part;
fc4a62
-
fc4a62
-        memset (&linux_part, 0, sizeof (linux_part));
fc4a62
-        linux_part.pno = n;
fc4a62
-        return _blkpg_part_command (disk->dev, &linux_part,
fc4a62
-                                    BLKPG_DEL_PARTITION);
fc4a62
-}
fc4a62
+#endif
fc4a62
 
fc4a62
 /* Read the integer from /sys/block/DEV_BASE/ENTRY and set *VAL
fc4a62
    to that value, where DEV_BASE is the last component of DEV->path.
fc4a62
@@ -2586,6 +2680,8 @@ static unsigned int
fc4a62
 _device_get_partition_range(PedDevice const* dev)
fc4a62
 {
fc4a62
         int range;
fc4a62
+        if (dev->type == PED_DEVICE_DM)
fc4a62
+                return MAX_NUM_PARTS;
fc4a62
         bool ok = _sysfs_int_entry_from_dev(dev, "ext_range", &range);
fc4a62
 
fc4a62
         if (!ok)
fc4a62
@@ -2594,264 +2690,78 @@ _device_get_partition_range(PedDevice const* dev)
fc4a62
         return range > 1 ? range : 0;
fc4a62
 }
fc4a62
 
fc4a62
-/*
fc4a62
- * Sync the partition table in two step process:
fc4a62
- * 1. Remove all of the partitions from the kernel's tables, but do not attempt
fc4a62
- *    removal of any partition for which the corresponding ioctl call fails.
fc4a62
- * 2. Add all the partitions that we hold in disk, throwing a warning
fc4a62
- *    if we cannot because step 1 failed to remove it and it is not being
fc4a62
- *    added back with the same start and length.
fc4a62
- *
fc4a62
- * To achieve this two step process we must calculate the minimum number of
fc4a62
- * maximum possible partitions between what linux supports and what the label
fc4a62
- * type supports. EX:
fc4a62
- *
fc4a62
- * number=MIN(max_parts_supported_in_linux,max_parts_supported_in_msdos_tables)
fc4a62
- */
fc4a62
-static int
fc4a62
-_disk_sync_part_table (PedDisk* disk)
fc4a62
-{
fc4a62
-        PED_ASSERT(disk != NULL);
fc4a62
-        PED_ASSERT(disk->dev != NULL);
fc4a62
-        int lpn;
fc4a62
-
fc4a62
-        unsigned int part_range = _device_get_partition_range(disk->dev);
fc4a62
-
fc4a62
-        /* lpn = largest partition number. */
fc4a62
-        if (ped_disk_get_max_supported_partition_count(disk, &lpn))
fc4a62
-                lpn = PED_MIN(lpn, part_range);
fc4a62
-        else
fc4a62
-                lpn = part_range;
fc4a62
-
fc4a62
-        /* Its not possible to support largest_partnum < 0.
fc4a62
-         * largest_partnum == 0 would mean does not support partitions.
fc4a62
-         * */
fc4a62
-        if (lpn < 1)
fc4a62
-                return 0;
fc4a62
-        int ret = 0;
fc4a62
-        int *ok = calloc (lpn, sizeof *ok);
fc4a62
-        if (!ok)
fc4a62
-                return 0;
fc4a62
-        int *errnums = ped_malloc(sizeof(int) * lpn);
fc4a62
-        if (!errnums)
fc4a62
-                goto cleanup;
fc4a62
-
fc4a62
-        /* Attempt to remove each and every partition, retrying for
fc4a62
-           up to max_sleep_seconds upon any failure due to EBUSY. */
fc4a62
-        unsigned int sleep_microseconds = 10000;
fc4a62
-        unsigned int max_sleep_seconds = 1;
fc4a62
-        unsigned int n_sleep = (max_sleep_seconds
fc4a62
-                                * 1000000 / sleep_microseconds);
fc4a62
-        int i;
fc4a62
-        for (i = 0; i < n_sleep; i++) {
fc4a62
-	    if (i)
fc4a62
-		usleep (sleep_microseconds);
fc4a62
-            bool busy = false;
fc4a62
-            int j;
fc4a62
-            for (j = 0; j < lpn; j++) {
fc4a62
-                if (!ok[j]) {
fc4a62
-                    ok[j] = _blkpg_remove_partition (disk, j + 1);
fc4a62
-                    errnums[j] = errno;
fc4a62
-                    if (!ok[j] && errnums[j] == EBUSY)
fc4a62
-                        busy = true;
fc4a62
-                }
fc4a62
-            }
fc4a62
-            if (!busy)
fc4a62
-                break;
fc4a62
-        }
fc4a62
-
fc4a62
-        for (i = 1; i <= lpn; i++) {
fc4a62
-                PedPartition *part = ped_disk_get_partition (disk, i);
fc4a62
-                if (part) {
fc4a62
-                        if (!ok[i - 1] && errnums[i - 1] == EBUSY) {
fc4a62
-                                unsigned long long length;
fc4a62
-                                unsigned long long start;
fc4a62
-                                /* get start and length of existing partition */
fc4a62
-                                if (!_kernel_get_partition_start_and_length(part,
fc4a62
-                                                                &start, &length))
fc4a62
-                                        goto cleanup;
fc4a62
-                                if (start == part->geom.start
fc4a62
-				    && length == part->geom.length)
fc4a62
-                                        ok[i - 1] = 1;
fc4a62
-                                /* If the new partition is unchanged and the
fc4a62
-				   existing one was not removed because it was
fc4a62
-				   in use, then reset the error flag and do not
fc4a62
-				   try to add it since it is already there.  */
fc4a62
-                                continue;
fc4a62
-                        }
fc4a62
-
fc4a62
-                        /* add the (possibly modified or new) partition */
fc4a62
-                        if (!_blkpg_add_partition (disk, part)) {
fc4a62
-                                ped_exception_throw (
fc4a62
-                                        PED_EXCEPTION_ERROR,
fc4a62
-                                        PED_EXCEPTION_RETRY_CANCEL,
fc4a62
-                                        _("Failed to add partition %d (%s)"),
fc4a62
-                                        i, strerror (errno));
fc4a62
-                                goto cleanup;
fc4a62
-                        }
fc4a62
-                }
fc4a62
-        }
fc4a62
-
fc4a62
-        char *bad_part_list = NULL;
fc4a62
-        /* now warn about any errors */
fc4a62
-        for (i = 1; i <= lpn; i++) {
fc4a62
-		if (ok[i - 1] || errnums[i - 1] == ENXIO)
fc4a62
-			continue;
fc4a62
-		if (bad_part_list == NULL) {
fc4a62
-			  bad_part_list = malloc (lpn * 5);
fc4a62
-			  if (!bad_part_list)
fc4a62
-				  goto cleanup;
fc4a62
-			  bad_part_list[0] = 0;
fc4a62
-		}
fc4a62
-		sprintf (bad_part_list + strlen (bad_part_list), "%d, ", i);
fc4a62
-	}
fc4a62
-        if (bad_part_list == NULL)
fc4a62
-		ret = 1;
fc4a62
-	else {
fc4a62
-                bad_part_list[strlen (bad_part_list) - 2] = 0;
fc4a62
-                if (ped_exception_throw (
fc4a62
-                        PED_EXCEPTION_ERROR,
fc4a62
-                        PED_EXCEPTION_IGNORE_CANCEL,
fc4a62
-                        _("Partition(s) %s on %s have been written, but we have "
fc4a62
-			  "been unable to inform the kernel of the change, "
fc4a62
-			  "probably because it/they are in use.  As a result, "
fc4a62
-                          "the old partition(s) will remain in use.  You "
fc4a62
-                          "should reboot now before making further changes."),
fc4a62
-                        bad_part_list, disk->dev->path) == PED_EXCEPTION_IGNORE)
fc4a62
-                        ret = 1;
fc4a62
-		free (bad_part_list);
fc4a62
-        }
fc4a62
- cleanup:
fc4a62
-        free (errnums);
fc4a62
-        free (ok);
fc4a62
-        return ret;
fc4a62
-}
fc4a62
-
fc4a62
 #ifdef ENABLE_DEVICE_MAPPER
fc4a62
 static int
fc4a62
-_dm_remove_map_name(char *name)
fc4a62
+_dm_remove_partition(PedDisk* disk, int partno)
fc4a62
 {
fc4a62
-        struct dm_task  *task = NULL;
fc4a62
         int             rc = 0;
fc4a62
         uint32_t        cookie = 0;
fc4a62
+        char            *part_name = _device_get_part_path (disk->dev, partno);
fc4a62
 
fc4a62
-        task = dm_task_create(DM_DEVICE_REMOVE);
fc4a62
+        int fd = open (part_name, O_RDONLY | O_EXCL);
fc4a62
+        if (fd == -1) {
fc4a62
+                if (errno == ENOENT)
fc4a62
+                        errno = ENXIO; /* nothing to remove, device already doesn't exist */
fc4a62
+                goto err;
fc4a62
+        }
fc4a62
+        close (fd);
fc4a62
+        struct dm_task *task = dm_task_create(DM_DEVICE_REMOVE);
fc4a62
         if (!task)
fc4a62
-                return 1;
fc4a62
-
fc4a62
-        dm_task_set_name (task, name);
fc4a62
-        if (!dm_task_set_cookie(task, &cookie, 0))
fc4a62
-            goto err;
fc4a62
-
fc4a62
-        rc = dm_task_run(task);
fc4a62
-        dm_udev_wait(cookie);
fc4a62
+                goto err;
fc4a62
+        dm_task_set_name (task, part_name);
fc4a62
+        if (!dm_task_set_cookie (task, &cookie, 0))
fc4a62
+                goto err;
fc4a62
+        rc = _dm_task_run_wait (task, cookie);
fc4a62
         dm_task_update_nodes();
fc4a62
-err:
fc4a62
         dm_task_destroy(task);
fc4a62
-        if (!rc)
fc4a62
-                return 1;
fc4a62
-
fc4a62
-        return 0;
fc4a62
+err:
fc4a62
+        free (part_name);
fc4a62
+        return rc;
fc4a62
 }
fc4a62
 
fc4a62
-static int
fc4a62
-_dm_is_part (struct dm_info *this, char *name)
fc4a62
+static bool
fc4a62
+_dm_get_partition_start_and_length(PedPartition const *part,
fc4a62
+                                   unsigned long long *start,
fc4a62
+                                   unsigned long long *length)
fc4a62
 {
fc4a62
         struct dm_task* task = NULL;
fc4a62
-        struct dm_info* info = alloca(sizeof *info);
fc4a62
-        struct dm_deps* deps = NULL;
fc4a62
         int             rc = 0;
fc4a62
-        unsigned int    i;
fc4a62
 
fc4a62
-        task = dm_task_create(DM_DEVICE_DEPS);
fc4a62
-        if (!task)
fc4a62
+        if (!(task = dm_task_create(DM_DEVICE_TABLE)))
fc4a62
                 return 0;
fc4a62
-
fc4a62
-        dm_task_set_name(task, name);
fc4a62
-        if (!dm_task_run(task))
fc4a62
+        char *path = _device_get_part_path (part->disk->dev, part->num);
fc4a62
+        PED_ASSERT(path);
fc4a62
+        /* libdevmapper likes to complain on stderr instead of quietly
fc4a62
+           returning ENOENT or ENXIO, so try to stat first */
fc4a62
+        struct stat st;
fc4a62
+        if (stat(path, &st))
fc4a62
                 goto err;
fc4a62
-
fc4a62
-        memset(info, '\0', sizeof *info);
fc4a62
-        dm_task_get_info(task, info);
fc4a62
-        if (!info->exists)
fc4a62
+        dm_task_set_name(task, path);
fc4a62
+        if (!dm_task_run(task))
fc4a62
                 goto err;
fc4a62
 
fc4a62
-        deps = dm_task_get_deps(task);
fc4a62
-        if (!deps)
fc4a62
+        int major, minor;
fc4a62
+        char *params;
fc4a62
+        char *target_type;
fc4a62
+        dm_get_next_target(task, NULL, (uint64_t *)start, (uint64_t *)length, &target_type, &params);
fc4a62
+        if (sscanf (params, "%d:%d %Ld", &major, &minor, start) != 3)
fc4a62
                 goto err;
fc4a62
+        rc = 1;
fc4a62
 
fc4a62
-        for (i = 0; i < deps->count; i++) {
fc4a62
-                unsigned int ma = major(deps->device[i]),
fc4a62
-                             mi = minor(deps->device[i]);
fc4a62
-
fc4a62
-                if (ma == this->major && mi == this->minor)
fc4a62
-                        rc = 1;
fc4a62
-        }
fc4a62
-
fc4a62
+        /* device-mapper uses 512b units, make sure we return length and start in terms of the device's
fc4a62
+         * sector size.
fc4a62
+         */
fc4a62
+        *start /= (part->disk->dev->sector_size / PED_SECTOR_SIZE_DEFAULT);
fc4a62
+        *length /= (part->disk->dev->sector_size / PED_SECTOR_SIZE_DEFAULT);
fc4a62
 err:
fc4a62
+        free (path);
fc4a62
         dm_task_destroy(task);
fc4a62
         return rc;
fc4a62
 }
fc4a62
 
fc4a62
-static int
fc4a62
-_dm_remove_parts (PedDevice* dev)
fc4a62
-{
fc4a62
-        struct dm_task*         task = NULL;
fc4a62
-        struct dm_info*         info = alloca(sizeof *info);
fc4a62
-        struct dm_names*        names = NULL;
fc4a62
-        unsigned int            next = 0;
fc4a62
-        int                     rc;
fc4a62
-        LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
fc4a62
-
fc4a62
-        task = dm_task_create(DM_DEVICE_LIST);
fc4a62
-        if (!task)
fc4a62
-                goto err;
fc4a62
-
fc4a62
-        if (!dm_task_set_major_minor (task, arch_specific->major,
fc4a62
-                                      arch_specific->minor, 0))
fc4a62
-                goto err;
fc4a62
-
fc4a62
-        if (!dm_task_run(task))
fc4a62
-                goto err;
fc4a62
-
fc4a62
-        memset(info, '\0', sizeof *info);
fc4a62
-        dm_task_get_info(task, info);
fc4a62
-        if (!info->exists)
fc4a62
-                goto err;
fc4a62
-
fc4a62
-        names = dm_task_get_names(task);
fc4a62
-        if (!names)
fc4a62
-                goto err;
fc4a62
-
fc4a62
-        rc = 0;
fc4a62
-        do {
fc4a62
-                names = (void *) ((char *) names + next);
fc4a62
-
fc4a62
-                if (_dm_is_part(info, names->name))
fc4a62
-                        rc += _dm_remove_map_name(names->name);
fc4a62
-
fc4a62
-                next = names->next;
fc4a62
-        } while (next);
fc4a62
-
fc4a62
-        dm_task_update_nodes();
fc4a62
-        dm_task_destroy(task);
fc4a62
-        task = NULL;
fc4a62
-
fc4a62
-        if (!rc)
fc4a62
-                return 1;
fc4a62
-err:
fc4a62
-        if (task)
fc4a62
-                dm_task_destroy(task);
fc4a62
-        ped_exception_throw (PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE,
fc4a62
-                _("parted was unable to re-read the partition "
fc4a62
-                  "table on %s (%s).  This means Linux won't know "
fc4a62
-                  "anything about the modifications you made. "),
fc4a62
-                dev->path, strerror (errno));
fc4a62
-        return 0;
fc4a62
-}
fc4a62
 
fc4a62
 static int
fc4a62
-_dm_add_partition (PedDisk* disk, PedPartition* part)
fc4a62
+_dm_add_partition (PedDisk* disk, const PedPartition* part)
fc4a62
 {
fc4a62
         char*           vol_name = NULL;
fc4a62
         const char*     dev_name = NULL;
fc4a62
@@ -2908,9 +2818,8 @@ _dm_add_partition (PedDisk* disk, PedPartition* part)
fc4a62
                 "linear", params);
fc4a62
         if (!dm_task_set_cookie(task, &cookie, 0))
fc4a62
             goto err;
fc4a62
-        if (dm_task_run (task)) {
fc4a62
+        if (_dm_task_run_wait (task, cookie)) {
fc4a62
                 //printf("0 %ld linear %s\n", part->geom.length, params);
fc4a62
-                dm_udev_wait(cookie);
fc4a62
                 dm_task_update_nodes();
fc4a62
                 dm_task_destroy(task);
fc4a62
                 free(params);
fc4a62
@@ -2918,8 +2827,7 @@ _dm_add_partition (PedDisk* disk, PedPartition* part)
fc4a62
                 free(vol_name);
fc4a62
                 return 1;
fc4a62
         } else {
fc4a62
-                dm_udev_wait(cookie);
fc4a62
-                _dm_remove_map_name(vol_name);
fc4a62
+                _dm_remove_partition (disk, part->num);
fc4a62
         }
fc4a62
 err:
fc4a62
         dm_task_update_nodes();
fc4a62
@@ -2932,30 +2840,259 @@ err:
fc4a62
 }
fc4a62
 
fc4a62
 static int
fc4a62
-_dm_reread_part_table (PedDisk* disk)
fc4a62
+_dm_resize_partition (PedDisk* disk, const PedPartition* part)
fc4a62
 {
fc4a62
-        int largest_partnum = ped_disk_get_last_partition_num (disk);
fc4a62
-        int     rc = 1;
fc4a62
-        int     i;
fc4a62
+        LinuxSpecific*  arch_specific = LINUX_SPECIFIC (disk->dev);
fc4a62
+        char*           params = NULL;
fc4a62
+        char*           vol_name = NULL;
fc4a62
+        const char*     dev_name = NULL;
fc4a62
+        uint32_t        cookie = 0;
fc4a62
+        int             rc = 0;
fc4a62
 
fc4a62
-        sync();
fc4a62
-        if (!_dm_remove_parts(disk->dev))
fc4a62
-                rc = 0;
fc4a62
+        /* Get map name from devicemapper */
fc4a62
+        struct dm_task *task = dm_task_create (DM_DEVICE_INFO);
fc4a62
+        if (!task)
fc4a62
+                goto err;
fc4a62
 
fc4a62
-        for (i = 1; i <= largest_partnum; i++) {
fc4a62
-                PedPartition*      part;
fc4a62
+        if (!dm_task_set_major_minor (task, arch_specific->major,
fc4a62
+                                      arch_specific->minor, 0))
fc4a62
+                goto err;
fc4a62
 
fc4a62
-                part = ped_disk_get_partition (disk, i);
fc4a62
-                if (!part)
fc4a62
-                        continue;
fc4a62
+        if (!dm_task_run(task))
fc4a62
+                goto err;
fc4a62
+
fc4a62
+        dev_name = dm_task_get_name (task);
fc4a62
+        size_t name_len = strlen (dev_name);
fc4a62
+        vol_name = zasprintf ("%s%s%d",
fc4a62
+                              dev_name,
fc4a62
+                              isdigit (dev_name[name_len - 1]) ? "p" : "",
fc4a62
+                              part->num);
fc4a62
+        if (vol_name == NULL)
fc4a62
+                goto err;
fc4a62
+
fc4a62
+        /* Caution: dm_task_destroy frees dev_name.  */
fc4a62
+        dm_task_destroy (task);
fc4a62
+        task = NULL;
fc4a62
+
fc4a62
+        /* device-mapper uses 512b units, not the device's sector size */
fc4a62
+        if ( ! (params = zasprintf ("%d:%d %lld", arch_specific->major,
fc4a62
+                                    arch_specific->minor,
fc4a62
+                                    part->geom.start * (disk->dev->sector_size / PED_SECTOR_SIZE_DEFAULT))))
fc4a62
+                goto err;
fc4a62
+
fc4a62
+        task = dm_task_create (DM_DEVICE_RELOAD);
fc4a62
+        if (!task)
fc4a62
+                goto err;
fc4a62
 
fc4a62
-                if (!_dm_add_partition (disk, part))
fc4a62
-                        rc = 0;
fc4a62
+        dm_task_set_name (task, vol_name);
fc4a62
+        /* device-mapper uses 512b units, not the device's sector size */
fc4a62
+        dm_task_add_target (task, 0, part->geom.length * (disk->dev->sector_size / PED_SECTOR_SIZE_DEFAULT),
fc4a62
+                "linear", params);
fc4a62
+        /* NOTE: DM_DEVICE_RELOAD doesn't generate udev events, so no cookie is needed (it will freeze).
fc4a62
+         *       DM_DEVICE_RESUME does, so get a cookie and synchronize with udev.
fc4a62
+         */
fc4a62
+        if (dm_task_run (task)) {
fc4a62
+                dm_task_destroy (task);
fc4a62
+                task = dm_task_create (DM_DEVICE_RESUME);
fc4a62
+                if (!task)
fc4a62
+                        goto err;
fc4a62
+                dm_task_set_name (task, vol_name);
fc4a62
+                if (!dm_task_set_cookie (task, &cookie, 0))
fc4a62
+                        goto err;
fc4a62
+                if (_dm_task_run_wait (task, cookie)) {
fc4a62
+                        rc = 1;
fc4a62
+                }
fc4a62
         }
fc4a62
+err:
fc4a62
+        dm_task_update_nodes();
fc4a62
+        if (task)
fc4a62
+                dm_task_destroy (task);
fc4a62
+        free (params);
fc4a62
+        free (vol_name);
fc4a62
         return rc;
fc4a62
 }
fc4a62
+
fc4a62
 #endif
fc4a62
 
fc4a62
+/*
fc4a62
+ * Sync the partition table in two step process:
fc4a62
+ * 1. Remove all of the partitions from the kernel's tables, but do not attempt
fc4a62
+ *    removal of any partition for which the corresponding ioctl call fails.
fc4a62
+ * 2. Add all the partitions that we hold in disk, throwing a warning
fc4a62
+ *    if we cannot because step 1 failed to remove it and it is not being
fc4a62
+ *    added back with the same start and length.
fc4a62
+ *
fc4a62
+ * To achieve this two step process we must calculate the minimum number of
fc4a62
+ * maximum possible partitions between what linux supports and what the label
fc4a62
+ * type supports. EX:
fc4a62
+ *
fc4a62
+ * number=MIN(max_parts_supported_in_linux,max_parts_supported_in_msdos_tables)
fc4a62
+ */
fc4a62
+static int
fc4a62
+_disk_sync_part_table (PedDisk* disk)
fc4a62
+{
fc4a62
+        PED_ASSERT(disk != NULL);
fc4a62
+        PED_ASSERT(disk->dev != NULL);
fc4a62
+        int lpn, lpn2;
fc4a62
+        unsigned int part_range = _device_get_partition_range(disk->dev);
fc4a62
+        int (*add_partition)(PedDisk* disk, const PedPartition *part);
fc4a62
+        int (*resize_partition)(PedDisk* disk, const PedPartition *part);
fc4a62
+        int (*remove_partition)(PedDisk* disk, int partno);
fc4a62
+        bool (*get_partition_start_and_length)(PedPartition const *part,
fc4a62
+                                               unsigned long long *start,
fc4a62
+                                               unsigned long long *length);
fc4a62
+
fc4a62
+
fc4a62
+#ifdef ENABLE_DEVICE_MAPPER
fc4a62
+        if (disk->dev->type == PED_DEVICE_DM) {
fc4a62
+                add_partition = _dm_add_partition;
fc4a62
+                remove_partition = _dm_remove_partition;
fc4a62
+                resize_partition = _dm_resize_partition;
fc4a62
+                get_partition_start_and_length = _dm_get_partition_start_and_length;
fc4a62
+        } else
fc4a62
+#endif
fc4a62
+        {
fc4a62
+                add_partition = _blkpg_add_partition;
fc4a62
+                remove_partition = _blkpg_remove_partition;
fc4a62
+#ifdef BLKPG_RESIZE_PARTITION
fc4a62
+                resize_partition = _blkpg_resize_partition;
fc4a62
+#else
fc4a62
+                resize_partition = NULL;
fc4a62
+#endif
fc4a62
+                get_partition_start_and_length = _kernel_get_partition_start_and_length;
fc4a62
+        }
fc4a62
+
fc4a62
+        /* lpn = largest partition number.
fc4a62
+         * for remove pass, use greater of device or label limit */
fc4a62
+        if (ped_disk_get_max_supported_partition_count(disk, &lpn))
fc4a62
+                lpn = PED_MAX(lpn, part_range);
fc4a62
+        else
fc4a62
+                lpn = part_range;
fc4a62
+        /* for add pass, use lesser of device or label limit */
fc4a62
+        if (ped_disk_get_max_supported_partition_count(disk, &lpn2))
fc4a62
+                lpn2 = PED_MIN(lpn2, part_range);
fc4a62
+        else
fc4a62
+                lpn2 = part_range;
fc4a62
+        /* Its not possible to support largest_partnum < 0.
fc4a62
+         * largest_partnum == 0 would mean does not support partitions.
fc4a62
+         * */
fc4a62
+        if (lpn < 1)
fc4a62
+                return 0;
fc4a62
+        int ret = 0;
fc4a62
+        int *ok = calloc (lpn, sizeof *ok);
fc4a62
+        if (!ok)
fc4a62
+                return 0;
fc4a62
+        int *errnums = ped_malloc(sizeof(int) * lpn);
fc4a62
+        if (!errnums)
fc4a62
+                goto cleanup;
fc4a62
+
fc4a62
+        int i;
fc4a62
+        /* remove old partitions first */
fc4a62
+        for (i = 1; i <= lpn; i++) {
fc4a62
+                PedPartition *part = ped_disk_get_partition (disk, i);
fc4a62
+                if (part) {
fc4a62
+                        unsigned long long length;
fc4a62
+                        unsigned long long start;
fc4a62
+                        /* get start and length of existing partition */
fc4a62
+                        if (get_partition_start_and_length(part,
fc4a62
+                                                           &start, &length)
fc4a62
+                            && start == part->geom.start
fc4a62
+                            && (length == part->geom.length
fc4a62
+                                || (resize_partition && part->num < lpn2)))
fc4a62
+                        {
fc4a62
+                                /* partition is unchanged, or will be resized so nothing to do */
fc4a62
+                                ok[i - 1] = 1;
fc4a62
+                                continue;
fc4a62
+                        }
fc4a62
+                }
fc4a62
+                /* Attempt to remove the partition, retrying for
fc4a62
+                   up to max_sleep_seconds upon any failure due to EBUSY. */
fc4a62
+                unsigned int sleep_microseconds = 10000;
fc4a62
+                unsigned int max_sleep_seconds = 1;
fc4a62
+                unsigned int n_sleep = (max_sleep_seconds
fc4a62
+                                        * 1000000 / sleep_microseconds);
fc4a62
+                do {
fc4a62
+                        ok[i - 1] = remove_partition (disk, i);
fc4a62
+                        errnums[i - 1] = errno;
fc4a62
+                        if (ok[i - 1] || errnums[i - 1] != EBUSY)
fc4a62
+                                break;
fc4a62
+                        usleep (sleep_microseconds);
fc4a62
+                } while (n_sleep--);
fc4a62
+                if (!ok[i - 1] && errnums[i - 1] == ENXIO)
fc4a62
+                        ok[i - 1] = 1; /* it already doesn't exist */
fc4a62
+        }
fc4a62
+        lpn = lpn2;
fc4a62
+        /* don't actually add partitions for loop */
fc4a62
+        if (strcmp (disk->type->name, "loop") == 0)
fc4a62
+                lpn = 0;
fc4a62
+        for (i = 1; i <= lpn; i++) {
fc4a62
+                PedPartition *part = ped_disk_get_partition (disk, i);
fc4a62
+                if (!part)
fc4a62
+                        continue;
fc4a62
+                unsigned long long length;
fc4a62
+                unsigned long long start;
fc4a62
+                /* get start and length of existing partition */
fc4a62
+                if (get_partition_start_and_length(part,
fc4a62
+                                                   &start, &length)
fc4a62
+                    && start == part->geom.start)
fc4a62
+                {
fc4a62
+                        if (length == part->geom.length) {
fc4a62
+                                ok[i - 1] = 1;
fc4a62
+                                /* partition is unchanged, so nothing to do */
fc4a62
+                                continue;
fc4a62
+                        }
fc4a62
+                        if (resize_partition
fc4a62
+                            && start == part->geom.start)
fc4a62
+                        {
fc4a62
+                                /* try to resize */
fc4a62
+                                if (resize_partition (disk, part)) {
fc4a62
+                                        ok[i - 1] = 1;
fc4a62
+                                        continue;
fc4a62
+                                }
fc4a62
+                        }
fc4a62
+                }
fc4a62
+                /* add the (possibly modified or new) partition */
fc4a62
+                if (!add_partition (disk, part)) {
fc4a62
+                        ok[i - 1] = 0;
fc4a62
+                        errnums[i - 1] = errno;
fc4a62
+                }
fc4a62
+        }
fc4a62
+
fc4a62
+        char *bad_part_list = NULL;
fc4a62
+        /* now warn about any errors */
fc4a62
+        for (i = 1; i <= lpn; i++) {
fc4a62
+                if (ok[i - 1] || errnums[i - 1] == ENXIO)
fc4a62
+                        continue;
fc4a62
+                if (bad_part_list == NULL) {
fc4a62
+                        bad_part_list = malloc (lpn * 5);
fc4a62
+                        if (!bad_part_list)
fc4a62
+                                goto cleanup;
fc4a62
+                        bad_part_list[0] = 0;
fc4a62
+                }
fc4a62
+                sprintf (bad_part_list + strlen (bad_part_list), "%d, ", i);
fc4a62
+        }
fc4a62
+        if (bad_part_list == NULL)
fc4a62
+                ret = 1;
fc4a62
+        else {
fc4a62
+                bad_part_list[strlen (bad_part_list) - 2] = 0;
fc4a62
+                if (ped_exception_throw (
fc4a62
+                        PED_EXCEPTION_ERROR,
fc4a62
+                        PED_EXCEPTION_IGNORE_CANCEL,
fc4a62
+                        _("Partition(s) %s on %s have been written, but we have "
fc4a62
+                          "been unable to inform the kernel of the change, "
fc4a62
+                          "probably because it/they are in use.  As a result, "
fc4a62
+                          "the old partition(s) will remain in use.  You "
fc4a62
+                          "should reboot now before making further changes."),
fc4a62
+                        bad_part_list, disk->dev->path) == PED_EXCEPTION_IGNORE)
fc4a62
+                        ret = 1;
fc4a62
+                free (bad_part_list);
fc4a62
+        }
fc4a62
+ cleanup:
fc4a62
+        free (errnums);
fc4a62
+        free (ok);
fc4a62
+        return ret;
fc4a62
+}
fc4a62
+
fc4a62
 static int
fc4a62
 _have_blkpg ()
fc4a62
 {
fc4a62
@@ -2973,10 +3110,6 @@ _have_blkpg ()
fc4a62
 static int
fc4a62
 linux_disk_commit (PedDisk* disk)
fc4a62
 {
fc4a62
-#ifdef ENABLE_DEVICE_MAPPER
fc4a62
-        if (disk->dev->type == PED_DEVICE_DM)
fc4a62
-                return _dm_reread_part_table (disk);
fc4a62
-#endif
fc4a62
         if (disk->dev->type != PED_DEVICE_FILE) {
fc4a62
 
fc4a62
 		/* We now require BLKPG support.  If this assertion fails,
fc4a62
-- 
fc4a62
2.9.4
fc4a62