[parted-devel] [PATCH 1/4] libparted: refactor device-mapper partition sync code

Phillip Susi phillsusi at gmail.com
Sun Jan 8 17:38:59 UTC 2012


The device-mapper partition sync code was still using the remove all
partitions, then add new partitions method.  Refactor to use the same
algorithm as regular disks: try to remove all, and ignore any that could
not be removed but have not changed.
---
 NEWS                   |    2 +
 libparted/arch/linux.c |  166 ++++++++++++++++++++----------------------------
 2 files changed, 72 insertions(+), 96 deletions(-)

diff --git a/NEWS b/NEWS
index 58a5f89..4fede6c 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,8 @@ GNU parted NEWS                                    -*- outline -*-
   parted has improved support for partitionable loopback devices
 
 ** Bug fixes
+  libparted: Don't fail to manipulate partitions on dmraid disks that
+  have other partitions in use.
 
   parted now exits nonzero for certain failures already diagnosed as "Error".
   For example, before this change, parted would exit successfully in spite
diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index e2c4139..3991adb 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -287,6 +287,14 @@ struct blkdev_ioctl_param {
 
 static char* _device_get_part_path (PedDevice* dev, int num);
 static int _partition_is_mounted_by_path (const char* path);
+static int
+_dm_add_partition (PedDisk* disk, const PedPartition* part);
+static int
+_dm_remove_partition(PedDisk* disk, int partno);
+static bool
+_dm_get_partition_start_and_length(PedPartition const *part,
+                                   unsigned long long *start,
+                                   unsigned long long *length);
 
 static int
 _read_fd (int fd, char **buf)
@@ -2558,8 +2566,23 @@ _disk_sync_part_table (PedDisk* disk)
         PED_ASSERT(disk != NULL);
         PED_ASSERT(disk->dev != NULL);
         int lpn;
-
         unsigned int part_range = _device_get_partition_range(disk->dev);
+        int (*add_partition)(PedDisk* disk, const PedPartition *part);
+        int (*remove_partition)(PedDisk* disk, int partno);
+        bool (*get_partition_start_and_length)(PedPartition const *part,
+                                               unsigned long long *start,
+                                               unsigned long long *length);
+
+
+        if (disk->dev->type == PED_DEVICE_DM) {
+                add_partition = _dm_add_partition;
+                remove_partition = _dm_remove_partition;
+                get_partition_start_and_length = _dm_get_partition_start_and_length;
+        } else {
+                add_partition = _blkpg_add_partition;
+                remove_partition = _blkpg_remove_partition;
+                get_partition_start_and_length = _kernel_get_partition_start_and_length;
+        }
 
         /* lpn = largest partition number. */
         if (ped_disk_get_max_supported_partition_count(disk, &lpn))
@@ -2594,7 +2617,7 @@ _disk_sync_part_table (PedDisk* disk)
             int j;
             for (j = 0; j < lpn; j++) {
                 if (!ok[j]) {
-                    ok[j] = _blkpg_remove_partition (disk, j + 1);
+                    ok[j] = remove_partition (disk, j + 1);
                     errnums[j] = errno;
                     if (!ok[j] && errnums[j] == EBUSY)
                         busy = true;
@@ -2611,8 +2634,8 @@ _disk_sync_part_table (PedDisk* disk)
                                 unsigned long long length;
                                 unsigned long long start;
                                 /* get start and length of existing partition */
-                                if (!_kernel_get_partition_start_and_length(part,
-                                                                &start, &length))
+                                if (!get_partition_start_and_length(part,
+                                                                    &start, &length))
                                         goto cleanup;
                                 if (start == part->geom.start
 				    && length == part->geom.length)
@@ -2625,7 +2648,7 @@ _disk_sync_part_table (PedDisk* disk)
                         }
 
                         /* add the (possibly modified or new) partition */
-                        if (!_blkpg_add_partition (disk, part)) {
+                        if (!add_partition (disk, part)) {
                                 ped_exception_throw (
                                         PED_EXCEPTION_ERROR,
                                         PED_EXCEPTION_RETRY_CANCEL,
@@ -2673,24 +2696,34 @@ _disk_sync_part_table (PedDisk* disk)
 
 #ifdef ENABLE_DEVICE_MAPPER
 static int
-_dm_remove_map_name(char *name)
+_dm_remove_partition(PedDisk* disk, int partno)
 {
         struct dm_task  *task = NULL;
         int             rc;
+        char            *part_name = _device_get_part_path (disk->dev, partno);
 
+        int fd = open (part_name, O_RDONLY | O_EXCL);
+        if (fd == -1) {
+                if (errno == ENOENT)
+                        errno = ENXIO; /* nothing to remove, device already doesn't exist */
+                free (part_name);
+                return 0;
+        }
+        close (fd);
         task = dm_task_create(DM_DEVICE_REMOVE);
-        if (!task)
-                return 1;
-
-        dm_task_set_name (task, name);
-
+        if (!task) {
+                free (part_name);
+                return 0;
+        }
+        dm_task_set_name (task, part_name);
         rc = dm_task_run(task);
         dm_task_update_nodes();
         dm_task_destroy(task);
+        free (part_name);
         if (!rc)
-                return 1;
+                return 0;
 
-        return 0;
+        return 1;
 }
 
 static int
@@ -2732,65 +2765,38 @@ err:
         return rc;
 }
 
-static int
-_dm_remove_parts (PedDevice* dev)
+static bool
+_dm_get_partition_start_and_length(PedPartition const *part,
+                                   unsigned long long *start,
+                                   unsigned long long *length)
 {
-        struct dm_task*         task = NULL;
-        struct dm_info*         info = alloca(sizeof *info);
-        struct dm_names*        names = NULL;
-        unsigned int            next = 0;
-        int                     rc;
-        LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
-
-        task = dm_task_create(DM_DEVICE_LIST);
-        if (!task)
-                goto err;
-
-        if (!dm_task_set_major_minor (task, arch_specific->major,
-                                      arch_specific->minor, 0))
-                goto err;
+        struct dm_task* task = NULL;
+        int             rc = 0;
+        char *target_type = NULL;
+        char *params;
+        char *path;
+        int major, minor;
 
+        if (!(task = dm_task_create(DM_DEVICE_TABLE)))
+                return 0;
+        path = _device_get_part_path (part->disk->dev, part->num);
+        PED_ASSERT(path);
+        dm_task_set_name(task, path);
         if (!dm_task_run(task))
                 goto err;
-
-        memset(info, '\0', sizeof *info);
-        dm_task_get_info(task, info);
-        if (!info->exists)
-                goto err;
-
-        names = dm_task_get_names(task);
-        if (!names)
+        dm_get_next_target(task, NULL, (uint64_t *)start, (uint64_t *)length, &target_type, &params);
+        if (sscanf (params, "%d:%d %Ld", &major, &minor, start) != 3)
                 goto err;
-
-        rc = 0;
-        do {
-                names = (void *) ((char *) names + next);
-
-                if (_dm_is_part(info, names->name))
-                        rc += _dm_remove_map_name(names->name);
-
-                next = names->next;
-        } while (next);
-
-        dm_task_update_nodes();
-        dm_task_destroy(task);
-        task = NULL;
-
-        if (!rc)
-                return 1;
+        rc = 1;
 err:
-        if (task)
-                dm_task_destroy(task);
-        ped_exception_throw (PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE,
-                _("parted was unable to re-read the partition "
-                  "table on %s (%s).  This means Linux won't know "
-                  "anything about the modifications you made. "),
-                dev->path, strerror (errno));
-        return 0;
+        free (path);
+        dm_task_destroy(task);
+        return rc;
 }
 
+
 static int
-_dm_add_partition (PedDisk* disk, PedPartition* part)
+_dm_add_partition (PedDisk* disk, const PedPartition* part)
 {
         char*           vol_name = NULL;
         const char*     dev_name = NULL;
@@ -2840,7 +2846,7 @@ _dm_add_partition (PedDisk* disk, PedPartition* part)
                 free(vol_name);
                 return 1;
         } else {
-                _dm_remove_map_name(vol_name);
+                _dm_remove_partition (disk, part->num);
         }
 err:
         dm_task_update_nodes();
@@ -2850,34 +2856,6 @@ err:
         free (vol_name);
         return 0;
 }
-
-static int
-_dm_reread_part_table (PedDisk* disk)
-{
-        int largest_partnum = ped_disk_get_last_partition_num (disk);
-        if (largest_partnum <= 0)
-          return 1;
-
-        int     rc = 1;
-        int     last = PED_MIN (largest_partnum, 16);
-        int     i;
-
-        sync();
-        if (!_dm_remove_parts(disk->dev))
-                rc = 0;
-
-        for (i = 1; i <= last; i++) {
-                PedPartition*      part;
-
-                part = ped_disk_get_partition (disk, i);
-                if (!part)
-                        continue;
-
-                if (!_dm_add_partition (disk, part))
-                        rc = 0;
-        }
-        return rc;
-}
 #endif
 
 static int
@@ -2897,10 +2875,6 @@ _have_blkpg ()
 static int
 linux_disk_commit (PedDisk* disk)
 {
-#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) {
 
 		/* We now require BLKPG support.  If this assertion fails,
-- 
1.7.5.4




More information about the parted-devel mailing list