[parted-devel] [PATCH 3/7] libparted: Add support for partition resize
Phillip Susi
psusi at ubuntu.com
Sun May 25 21:11:29 UTC 2014
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 | 203 +++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 175 insertions(+), 31 deletions(-)
diff --git a/NEWS b/NEWS
index 21f3e15..9e85ff0 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 f2e2abc..ac64c13 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -2521,6 +2521,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 +2843,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 +2934,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 +2947,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 = 0;
+#endif
get_partition_start_and_length = _kernel_get_partition_start_and_length;
}
@@ -2835,7 +2966,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 +2995,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;
}
@@ -2883,12 +3019,7 @@ _disk_sync_part_table (PedDisk* disk)
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 +3032,23 @@ _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
+ && length != part->geom.length)
+ {
+ /* 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.1
More information about the parted-devel
mailing list