On 11/29/2011 04:09 PM, Phillip Susi wrote:
> On 11/29/2011 11:02 AM, Petr Uzel wrote:
>> I was also thinking about some new BLKPG-like ioctl()s. Could you
>> please elaborate more on your new ioctl() proposal? Perhaps we could
>> combine the ideas...
> 
> I just added one to update the length of the partition.  Attaching the patch 
> so far ( untested ).

Slightly updated and tested version.  I was able to successfully extend an ext4 
partition while it was mounted multiple times.  I also tried both online extend 
and shrink of a btrfs partition and this seemed to work well.  Also attaching 
my patches to parted to allow the online resize.

From 015092754e5accddb83ccbb5ee60838eafede96f Mon Sep 17 00:00:00 2001
From: Phillip Susi <[email protected]>
Date: Wed, 30 Nov 2011 13:07:40 -0500
Subject: [PATCH] Add partition resize function to BLKPG ioctl

Add a new operation code ( BLKPG_RES_PARTITION ) to the
BLKPG ioctl that allows altering the size of an existing
partition, even if it is currently in use.
---
 block/ioctl.c         |   51 +++++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/blkpg.h |    1 +
 2 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/block/ioctl.c b/block/ioctl.c
index ca939fc..e49cc41 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -36,8 +36,8 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
 		case BLKPG_ADD_PARTITION:
 			start = p.start >> 9;
 			length = p.length >> 9;
-			/* check for fit in a hd_struct */ 
-			if (sizeof(sector_t) == sizeof(long) && 
+			/* check for fit in a hd_struct */
+			if (sizeof(sector_t) == sizeof(long) &&
 			    sizeof(long long) > sizeof(long)) {
 				long pstart = start, plength = length;
 				if (pstart != start || plength != length
@@ -92,6 +92,53 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
 			bdput(bdevp);
 
 			return 0;
+		case BLKPG_RES_PARTITION:
+			start = p.start >> 9;
+			length = p.length >> 9;
+			/* check for fit in a hd_struct */ 
+			if (sizeof(sector_t) == sizeof(long) && 
+			    sizeof(long long) > sizeof(long)) {
+				long pstart = start, plength = length;
+				if (pstart != start || plength != length
+				    || pstart < 0 || plength < 0)
+					return -EINVAL;
+			}
+
+			mutex_lock(&bdev->bd_mutex);
+
+			/* overlap? */
+			disk_part_iter_init(&piter, disk,
+					    DISK_PITER_INCL_EMPTY);
+			while ((part = disk_part_iter_next(&piter))) {
+				if (part->partno != partno && !(start + length <= part->start_sect ||
+				      start >= part->start_sect + part->nr_sects)) {
+					disk_part_iter_exit(&piter);
+					mutex_unlock(&bdev->bd_mutex);
+					return -EBUSY;
+				}
+			}
+			disk_part_iter_exit(&piter);
+			part = disk_get_part(disk, partno);
+			if (!part)
+			{
+				mutex_unlock(&bdev->bd_mutex);
+				return -ENXIO;
+			}
+			if (start != part->start_sect)
+			{
+				mutex_unlock(&bdev->bd_mutex);
+				disk_put_part(part);
+				return -EINVAL;
+			}
+			part->nr_sects = length;
+			bdevp = bdget(part_devt(part));
+			mutex_lock(&bdevp->bd_mutex);
+			i_size_write(bdevp->bd_inode, p.length);
+			mutex_unlock(&bdevp->bd_mutex);
+			bdput(bdevp);
+			disk_put_part(part);
+			mutex_unlock(&bdev->bd_mutex);
+			return 0;
 		default:
 			return -EINVAL;
 	}
diff --git a/include/linux/blkpg.h b/include/linux/blkpg.h
index faf8a45..103da38 100644
--- a/include/linux/blkpg.h
+++ b/include/linux/blkpg.h
@@ -40,6 +40,7 @@ struct blkpg_ioctl_arg {
 /* The subfunctions (for the op field) */
 #define BLKPG_ADD_PARTITION	1
 #define BLKPG_DEL_PARTITION	2
+#define BLKPG_RES_PARTITION	3
 
 /* Sizes of name fields. Unused at present. */
 #define BLKPG_DEVNAMELTH	64
-- 
1.7.5.4

From d52312f0e413d31338b5198474d99aec4e74551b Mon Sep 17 00:00:00 2001
From: Phillip Susi <[email protected]>
Date: Tue, 29 Nov 2011 14:05:48 -0500
Subject: [PATCH 1/4] Add support for BLKPG ioctl partition resize

When resizing a partition ( same partition number, same
start sector, different end sector ), if removing the old
partition fails because it is in use, try to use the
new BLKPG_RES_PARTITION request to update the kernel
partition table with the new size.
---
 libparted/arch/linux.c |   58 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 58 insertions(+), 0 deletions(-)

diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
index 1da3343..5b128f9 100644
--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -2428,6 +2428,55 @@ _blkpg_remove_partition (PedDisk* disk, int n)
                                     BLKPG_DEL_PARTITION);
 }
 
+#ifdef BLKPG_RES_PARTITION
+static int _blkpg_resize_partition (PedDisk* disk, const PedPartition *part)
+{
+        struct blkpg_partition  linux_part;
+        const char*             vol_name;
+        char*                   dev_name;
+
+        PED_ASSERT(disk != NULL);
+        PED_ASSERT(disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
+
+        if (!_has_partitions (disk))
+                return 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)
+                linux_part.length = part->geom.length == 1 ? 512 : 1024;
+        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)
+                strncpy (linux_part.volname, vol_name, BLKPG_VOLNAMELTH);
+
+        free (dev_name);
+
+        if (!_blkpg_part_command (disk->dev, &linux_part,
+                                  BLKPG_RES_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. */
@@ -2596,6 +2645,15 @@ _disk_sync_part_table (PedDisk* disk)
                                 if (geom.start == part->geom.start
 				    && length == part->geom.length)
                                         ok[i - 1] = 1;
+#ifdef BLKPG_RES_PARTITION
+				if (geom.start == part->geom.start
+				    && length != part->geom.length)
+				{
+					/* try to resize */
+					if (_blkpg_resize_partition (disk, part))
+						ok[i - 1] = 1;
+				}
+#endif
                                 /* If the new partition is unchanged and the
 				   existing one was not removed because it was
 				   in use, then reset the error flag and do not
-- 
1.7.5.4

From f15440e30a67458ba119f34b3c7c36e40de95198 Mon Sep 17 00:00:00 2001
From: Phillip Susi <[email protected]>
Date: Wed, 30 Nov 2011 13:13:58 -0500
Subject: [PATCH 4/4] Make _partition_warn_busy actually a warning instead of
 an error

This function was throwing a PED_EXCEPTION_ERROR with only the
PED_EXCEPTION_CANCEL option.  Converted to a PED_EXCEPTION_WARNING.
---
 parted/parted.c |   18 ++++++++++--------
 1 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/parted/parted.c b/parted/parted.c
index d582f10..a517ff8 100644
--- a/parted/parted.c
+++ b/parted/parted.c
@@ -222,14 +222,16 @@ _partition_warn_busy (PedPartition* part)
 
         if (ped_partition_is_busy (part)) {
                 path = ped_partition_get_path (part);
-                ped_exception_throw (
-                        PED_EXCEPTION_ERROR,
-                        PED_EXCEPTION_CANCEL,
-                        _("Partition %s is being used. You must unmount it "
-                          "before you modify it with Parted."),
-                        path);
-                free (path);
-                return 0;
+                if (ped_exception_throw (
+			    PED_EXCEPTION_WARNING,
+			    PED_EXCEPTION_OK_CANCEL,
+			    _("Partition %s is being used. Are you sure you " \
+			      "want to continue?"),
+			    path) == PED_EXCEPTION_CANCEL)
+			{
+				free (path);
+				return 0;
+			}
         }
         return 1;
 }
-- 
1.7.5.4

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to