13386670d0
- libparted: Add support for partition resize - parted: add resizepart command
332 lines
13 KiB
Diff
332 lines
13 KiB
Diff
From f09ca967a0bc443b869a6fad5b5ffe8e95c3fe9a Mon Sep 17 00:00:00 2001
|
|
From: Phillip Susi <psusi@ubuntu.com>
|
|
Date: Tue, 29 Nov 2011 14:05:48 -0500
|
|
Subject: [PATCH 128/134] libparted: Add support for partition resize
|
|
|
|
When resizing a partition ( same partition number, same
|
|
start sector, different end sector ), try to use the
|
|
new BLKPG_RES_PARTITION request to update the kernel
|
|
partition table with the new size. Also handle resizing
|
|
devmapper targets.
|
|
---
|
|
NEWS | 3 +-
|
|
libparted/arch/linux.c | 207 +++++++++++++++++++++++++++++++++++++++++--------
|
|
2 files changed, 177 insertions(+), 33 deletions(-)
|
|
|
|
diff --git a/NEWS b/NEWS
|
|
index 7069020..ad2fea1 100644
|
|
--- a/NEWS
|
|
+++ b/NEWS
|
|
@@ -4,7 +4,8 @@ GNU parted NEWS -*- outline -*-
|
|
|
|
** New Features
|
|
|
|
- Add resizepart command to resize a partition
|
|
+ Add resizepart command to resize a partition. This works even on
|
|
+ mounted partitions.
|
|
|
|
Add support for EAV DASD partitions, which are ECKD's with more than
|
|
65520 cylinders.
|
|
diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
|
|
index cdb8a26..0f18904 100644
|
|
--- a/libparted/arch/linux.c
|
|
+++ b/libparted/arch/linux.c
|
|
@@ -2493,8 +2493,9 @@ _blkpg_add_partition (PedDisk* disk, const PedPartition *part)
|
|
}
|
|
linux_part.length *= disk->dev->sector_size;
|
|
}
|
|
- else
|
|
+ else {
|
|
linux_part.length = part->geom.length * disk->dev->sector_size;
|
|
+ }
|
|
linux_part.pno = part->num;
|
|
strncpy (linux_part.devname, dev_name, BLKPG_DEVNAMELTH);
|
|
if (vol_name)
|
|
@@ -2521,6 +2522,60 @@ _blkpg_remove_partition (PedDisk* disk, int n)
|
|
BLKPG_DEL_PARTITION);
|
|
}
|
|
|
|
+#ifdef BLKPG_RESIZE_PARTITION
|
|
+static int _blkpg_resize_partition (PedDisk* disk, const PedPartition *part)
|
|
+{
|
|
+ struct blkpg_partition linux_part;
|
|
+ char* dev_name;
|
|
+
|
|
+ PED_ASSERT(disk != NULL);
|
|
+ PED_ASSERT(disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
|
|
+
|
|
+ dev_name = _device_get_part_path (disk->dev, part->num);
|
|
+ if (!dev_name)
|
|
+ return 0;
|
|
+ memset (&linux_part, 0, sizeof (linux_part));
|
|
+ linux_part.start = part->geom.start * disk->dev->sector_size;
|
|
+ /* see fs/partitions/msdos.c:msdos_partition(): "leave room for LILO" */
|
|
+ if (part->type & PED_PARTITION_EXTENDED) {
|
|
+ if (disk->dev->sector_size == 512) {
|
|
+ linux_part.length = 2;
|
|
+ PedPartition *walk;
|
|
+ /* if the second sector is claimed by a logical partition,
|
|
+ then there's just no room for lilo, so don't try to use it */
|
|
+ for (walk = part->part_list; walk; walk = walk->next) {
|
|
+ if (walk->geom.start == part->geom.start+1)
|
|
+ linux_part.length = 1;
|
|
+ }
|
|
+ } else linux_part.length = 1;
|
|
+ }
|
|
+ else
|
|
+ linux_part.length = part->geom.length * disk->dev->sector_size;
|
|
+ linux_part.pno = part->num;
|
|
+ strncpy (linux_part.devname, dev_name, BLKPG_DEVNAMELTH);
|
|
+
|
|
+ free (dev_name);
|
|
+
|
|
+ if (!_blkpg_part_command (disk->dev, &linux_part,
|
|
+ BLKPG_RESIZE_PARTITION)) {
|
|
+ return ped_exception_throw (
|
|
+ PED_EXCEPTION_ERROR,
|
|
+ PED_EXCEPTION_IGNORE_CANCEL,
|
|
+ _("Error informing the kernel about modifications to "
|
|
+ "partition %s -- %s. This means Linux won't know "
|
|
+ "about any changes you made to %s until you reboot "
|
|
+ "-- so you shouldn't mount it or use it in any way "
|
|
+ "before rebooting."),
|
|
+ linux_part.devname,
|
|
+ strerror (errno),
|
|
+ linux_part.devname)
|
|
+ == PED_EXCEPTION_IGNORE;
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+#endif
|
|
+
|
|
/* Read the integer from /sys/block/DEV_BASE/ENTRY and set *VAL
|
|
to that value, where DEV_BASE is the last component of DEV->path.
|
|
Upon success, return true. Otherwise, return false. */
|
|
@@ -2789,6 +2844,76 @@ err:
|
|
free (vol_name);
|
|
return 0;
|
|
}
|
|
+
|
|
+static int
|
|
+_dm_resize_partition (PedDisk* disk, const PedPartition* part)
|
|
+{
|
|
+ LinuxSpecific* arch_specific = LINUX_SPECIFIC (disk->dev);
|
|
+ char* params = NULL;
|
|
+ char* vol_name = NULL;
|
|
+ const char* dev_name = NULL;
|
|
+ uint32_t cookie = 0;
|
|
+
|
|
+ /* Get map name from devicemapper */
|
|
+ struct dm_task *task = dm_task_create (DM_DEVICE_INFO);
|
|
+ if (!task)
|
|
+ goto err;
|
|
+
|
|
+ if (!dm_task_set_major_minor (task, arch_specific->major,
|
|
+ arch_specific->minor, 0))
|
|
+ goto err;
|
|
+
|
|
+ if (!dm_task_run(task))
|
|
+ goto err;
|
|
+
|
|
+ dev_name = dm_task_get_name (task);
|
|
+ size_t name_len = strlen (dev_name);
|
|
+ vol_name = zasprintf ("%s%s%d",
|
|
+ dev_name,
|
|
+ isdigit (dev_name[name_len - 1]) ? "p" : "",
|
|
+ part->num);
|
|
+ if (vol_name == NULL)
|
|
+ goto err;
|
|
+
|
|
+ /* Caution: dm_task_destroy frees dev_name. */
|
|
+ dm_task_destroy (task);
|
|
+ task = NULL;
|
|
+ if ( ! (params = zasprintf ("%d:%d %lld", arch_specific->major,
|
|
+ arch_specific->minor, part->geom.start)))
|
|
+ goto err;
|
|
+
|
|
+ task = dm_task_create (DM_DEVICE_RELOAD);
|
|
+ if (!task)
|
|
+ goto err;
|
|
+
|
|
+ dm_task_set_name (task, vol_name);
|
|
+ dm_task_add_target (task, 0, part->geom.length,
|
|
+ "linear", params);
|
|
+ if (!dm_task_set_cookie (task, &cookie, 0))
|
|
+ goto err;
|
|
+ if (dm_task_run (task)) {
|
|
+ dm_task_destroy (task);
|
|
+ task = dm_task_create (DM_DEVICE_RESUME);
|
|
+ if (!task)
|
|
+ goto err;
|
|
+ dm_task_set_name (task, vol_name);
|
|
+ if (!dm_task_set_cookie (task, &cookie, 0))
|
|
+ goto err;
|
|
+ if (dm_task_run (task)) {
|
|
+ free (params);
|
|
+ free (vol_name);
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+err:
|
|
+ dm_task_update_nodes();
|
|
+ if (task)
|
|
+ dm_task_destroy (task);
|
|
+ free (params);
|
|
+ free (vol_name);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
#endif
|
|
|
|
/*
|
|
@@ -2810,9 +2935,10 @@ _disk_sync_part_table (PedDisk* disk)
|
|
{
|
|
PED_ASSERT(disk != NULL);
|
|
PED_ASSERT(disk->dev != NULL);
|
|
- int lpn;
|
|
+ int lpn, lpn2;
|
|
unsigned int part_range = _device_get_partition_range(disk->dev);
|
|
int (*add_partition)(PedDisk* disk, const PedPartition *part);
|
|
+ int (*resize_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,
|
|
@@ -2822,10 +2948,16 @@ _disk_sync_part_table (PedDisk* disk)
|
|
if (disk->dev->type == PED_DEVICE_DM) {
|
|
add_partition = _dm_add_partition;
|
|
remove_partition = _dm_remove_partition;
|
|
+ resize_partition = _dm_resize_partition;
|
|
get_partition_start_and_length = _dm_get_partition_start_and_length;
|
|
} else {
|
|
add_partition = _blkpg_add_partition;
|
|
remove_partition = _blkpg_remove_partition;
|
|
+#ifdef BLKPG_RESIZE_PARTITION
|
|
+ resize_partition = _blkpg_resize_partition;
|
|
+#else
|
|
+ resize_partition = NULL;
|
|
+#endif
|
|
get_partition_start_and_length = _kernel_get_partition_start_and_length;
|
|
}
|
|
|
|
@@ -2835,7 +2967,11 @@ _disk_sync_part_table (PedDisk* disk)
|
|
lpn = PED_MAX(lpn, part_range);
|
|
else
|
|
lpn = part_range;
|
|
-
|
|
+ /* for add pass, use lesser of device or label limit */
|
|
+ if (ped_disk_get_max_supported_partition_count(disk, &lpn2))
|
|
+ lpn2 = PED_MIN(lpn2, part_range);
|
|
+ else
|
|
+ lpn2 = part_range;
|
|
/* Its not possible to support largest_partnum < 0.
|
|
* largest_partnum == 0 would mean does not support partitions.
|
|
* */
|
|
@@ -2860,9 +2996,10 @@ _disk_sync_part_table (PedDisk* disk)
|
|
if (get_partition_start_and_length(part,
|
|
&start, &length)
|
|
&& start == part->geom.start
|
|
- && length == part->geom.length)
|
|
+ && (length == part->geom.length
|
|
+ || (resize_partition && part->num < lpn2)))
|
|
{
|
|
- /* partition is unchanged, so nothing to do */
|
|
+ /* partition is unchanged, or will be resized so nothing to do */
|
|
ok[i - 1] = 1;
|
|
continue;
|
|
}
|
|
@@ -2882,13 +3019,8 @@ _disk_sync_part_table (PedDisk* disk)
|
|
} while (n_sleep--);
|
|
if (!ok[i - 1] && errnums[i - 1] == ENXIO)
|
|
ok[i - 1] = 1; /* it already doesn't exist */
|
|
- }
|
|
- /* lpn = largest partition number.
|
|
- * for add pass, use lesser of device or label limit */
|
|
- if (ped_disk_get_max_supported_partition_count(disk, &lpn))
|
|
- lpn = PED_MIN(lpn, part_range);
|
|
- else
|
|
- lpn = part_range;
|
|
+ }
|
|
+ lpn = lpn2;
|
|
/* don't actually add partitions for loop */
|
|
if (strcmp (disk->type->name, "loop") == 0)
|
|
lpn = 0;
|
|
@@ -2901,11 +3033,22 @@ _disk_sync_part_table (PedDisk* disk)
|
|
/* get start and length of existing partition */
|
|
if (get_partition_start_and_length(part,
|
|
&start, &length)
|
|
- && start == part->geom.start
|
|
- && length == part->geom.length) {
|
|
- ok[i - 1] = 1;
|
|
- /* partition is unchanged, so nothing to do */
|
|
- continue;
|
|
+ && start == part->geom.start)
|
|
+ {
|
|
+ if (length == part->geom.length) {
|
|
+ ok[i - 1] = 1;
|
|
+ /* partition is unchanged, so nothing to do */
|
|
+ continue;
|
|
+ }
|
|
+ if (resize_partition
|
|
+ && start == part->geom.start)
|
|
+ {
|
|
+ /* try to resize */
|
|
+ if (resize_partition (disk, part)) {
|
|
+ ok[i - 1] = 1;
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
}
|
|
/* add the (possibly modified or new) partition */
|
|
if (!add_partition (disk, part)) {
|
|
@@ -2917,31 +3060,31 @@ _disk_sync_part_table (PedDisk* disk)
|
|
char *bad_part_list = NULL;
|
|
/* now warn about any errors */
|
|
for (i = 1; i <= lpn; i++) {
|
|
- if (ok[i - 1] || errnums[i - 1] == ENXIO)
|
|
- continue;
|
|
- if (bad_part_list == NULL) {
|
|
- bad_part_list = malloc (lpn * 5);
|
|
- if (!bad_part_list)
|
|
- goto cleanup;
|
|
- bad_part_list[0] = 0;
|
|
- }
|
|
- sprintf (bad_part_list + strlen (bad_part_list), "%d, ", i);
|
|
- }
|
|
+ if (ok[i - 1] || errnums[i - 1] == ENXIO)
|
|
+ continue;
|
|
+ if (bad_part_list == NULL) {
|
|
+ bad_part_list = malloc (lpn * 5);
|
|
+ if (!bad_part_list)
|
|
+ goto cleanup;
|
|
+ bad_part_list[0] = 0;
|
|
+ }
|
|
+ sprintf (bad_part_list + strlen (bad_part_list), "%d, ", i);
|
|
+ }
|
|
if (bad_part_list == NULL)
|
|
- ret = 1;
|
|
- else {
|
|
+ ret = 1;
|
|
+ else {
|
|
bad_part_list[strlen (bad_part_list) - 2] = 0;
|
|
if (ped_exception_throw (
|
|
PED_EXCEPTION_ERROR,
|
|
PED_EXCEPTION_IGNORE_CANCEL,
|
|
_("Partition(s) %s on %s have been written, but we have "
|
|
- "been unable to inform the kernel of the change, "
|
|
- "probably because it/they are in use. As a result, "
|
|
+ "been unable to inform the kernel of the change, "
|
|
+ "probably because it/they are in use. As a result, "
|
|
"the old partition(s) will remain in use. You "
|
|
"should reboot now before making further changes."),
|
|
bad_part_list, disk->dev->path) == PED_EXCEPTION_IGNORE)
|
|
ret = 1;
|
|
- free (bad_part_list);
|
|
+ free (bad_part_list);
|
|
}
|
|
cleanup:
|
|
free (errnums);
|
|
--
|
|
1.9.3
|
|
|