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
signature.asc
Description: OpenPGP digital signature

