mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-29 17:22:07 +00:00
block: refactor blkpg_ioctl
Split each sub-command out into a separate helper, and move those helpers to block/partitions/core.c instead of having a lot of partition manipulation logic open coded in block/ioctl.c. Signed-off-by: Christoph Hellwig <hch@lst.de Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
b4fd63f426
commit
fa9156ae59
@ -389,11 +389,13 @@ char *disk_name(struct gendisk *hd, int partno, char *buf);
|
||||
#define ADDPART_FLAG_NONE 0
|
||||
#define ADDPART_FLAG_RAID 1
|
||||
#define ADDPART_FLAG_WHOLEDISK 2
|
||||
struct hd_struct *__must_check add_partition(struct gendisk *disk, int partno,
|
||||
sector_t start, sector_t len, int flags,
|
||||
struct partition_meta_info *info);
|
||||
void __delete_partition(struct percpu_ref *ref);
|
||||
void delete_partition(struct gendisk *disk, int partno);
|
||||
int bdev_add_partition(struct block_device *bdev, int partno,
|
||||
sector_t start, sector_t length);
|
||||
int bdev_del_partition(struct block_device *bdev, int partno);
|
||||
int bdev_resize_partition(struct block_device *bdev, int partno,
|
||||
sector_t start, sector_t length);
|
||||
int disk_expand_part_tbl(struct gendisk *disk, int target);
|
||||
|
||||
static inline int hd_ref_init(struct hd_struct *part)
|
||||
|
144
block/ioctl.c
144
block/ioctl.c
@ -16,143 +16,45 @@
|
||||
static int blkpg_do_ioctl(struct block_device *bdev,
|
||||
struct blkpg_partition __user *upart, int op)
|
||||
{
|
||||
struct block_device *bdevp;
|
||||
struct gendisk *disk;
|
||||
struct hd_struct *part, *lpart;
|
||||
struct blkpg_partition p;
|
||||
struct disk_part_iter piter;
|
||||
long long start, length;
|
||||
int partno;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
if (copy_from_user(&p, upart, sizeof(struct blkpg_partition)))
|
||||
return -EFAULT;
|
||||
disk = bdev->bd_disk;
|
||||
if (bdev != bdev->bd_contains)
|
||||
return -EINVAL;
|
||||
partno = p.pno;
|
||||
if (partno <= 0)
|
||||
|
||||
if (p.pno <= 0)
|
||||
return -EINVAL;
|
||||
switch (op) {
|
||||
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) &&
|
||||
sizeof(long long) > sizeof(long)) {
|
||||
long pstart = start, plength = length;
|
||||
if (pstart != start || plength != length
|
||||
|| pstart < 0 || plength < 0 || partno > 65535)
|
||||
return -EINVAL;
|
||||
}
|
||||
/* check if partition is aligned to blocksize */
|
||||
if (p.start & (bdev_logical_block_size(bdev) - 1))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&bdev->bd_mutex);
|
||||
if (op == BLKPG_DEL_PARTITION)
|
||||
return bdev_del_partition(bdev, p.pno);
|
||||
|
||||
/* overlap? */
|
||||
disk_part_iter_init(&piter, disk,
|
||||
DISK_PITER_INCL_EMPTY);
|
||||
while ((part = disk_part_iter_next(&piter))) {
|
||||
if (!(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);
|
||||
start = p.start >> SECTOR_SHIFT;
|
||||
length = p.length >> SECTOR_SHIFT;
|
||||
|
||||
/* all seems OK */
|
||||
part = add_partition(disk, partno, start, length,
|
||||
ADDPART_FLAG_NONE, NULL);
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
return PTR_ERR_OR_ZERO(part);
|
||||
case BLKPG_DEL_PARTITION:
|
||||
part = disk_get_part(disk, partno);
|
||||
if (!part)
|
||||
return -ENXIO;
|
||||
/* check for fit in a hd_struct */
|
||||
if (sizeof(sector_t) < sizeof(long long)) {
|
||||
long pstart = start, plength = length;
|
||||
|
||||
bdevp = bdget(part_devt(part));
|
||||
disk_put_part(part);
|
||||
if (!bdevp)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&bdevp->bd_mutex);
|
||||
if (bdevp->bd_openers) {
|
||||
mutex_unlock(&bdevp->bd_mutex);
|
||||
bdput(bdevp);
|
||||
return -EBUSY;
|
||||
}
|
||||
/* all seems OK */
|
||||
fsync_bdev(bdevp);
|
||||
invalidate_bdev(bdevp);
|
||||
|
||||
mutex_lock_nested(&bdev->bd_mutex, 1);
|
||||
delete_partition(disk, partno);
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
mutex_unlock(&bdevp->bd_mutex);
|
||||
bdput(bdevp);
|
||||
|
||||
return 0;
|
||||
case BLKPG_RESIZE_PARTITION:
|
||||
start = p.start >> 9;
|
||||
/* new length of partition in bytes */
|
||||
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;
|
||||
}
|
||||
part = disk_get_part(disk, partno);
|
||||
if (!part)
|
||||
return -ENXIO;
|
||||
bdevp = bdget(part_devt(part));
|
||||
if (!bdevp) {
|
||||
disk_put_part(part);
|
||||
return -ENOMEM;
|
||||
}
|
||||
mutex_lock(&bdevp->bd_mutex);
|
||||
mutex_lock_nested(&bdev->bd_mutex, 1);
|
||||
if (start != part->start_sect) {
|
||||
mutex_unlock(&bdevp->bd_mutex);
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
bdput(bdevp);
|
||||
disk_put_part(part);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* overlap? */
|
||||
disk_part_iter_init(&piter, disk,
|
||||
DISK_PITER_INCL_EMPTY);
|
||||
while ((lpart = disk_part_iter_next(&piter))) {
|
||||
if (lpart->partno != partno &&
|
||||
!(start + length <= lpart->start_sect ||
|
||||
start >= lpart->start_sect + lpart->nr_sects)
|
||||
) {
|
||||
disk_part_iter_exit(&piter);
|
||||
mutex_unlock(&bdevp->bd_mutex);
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
bdput(bdevp);
|
||||
disk_put_part(part);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
disk_part_iter_exit(&piter);
|
||||
part_nr_sects_write(part, (sector_t)length);
|
||||
i_size_write(bdevp->bd_inode, p.length);
|
||||
mutex_unlock(&bdevp->bd_mutex);
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
bdput(bdevp);
|
||||
disk_put_part(part);
|
||||
return 0;
|
||||
default:
|
||||
if (pstart != start || plength != length || pstart < 0 ||
|
||||
plength < 0 || p.pno > 65535)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case BLKPG_ADD_PARTITION:
|
||||
/* check if partition is aligned to blocksize */
|
||||
if (p.start & (bdev_logical_block_size(bdev) - 1))
|
||||
return -EINVAL;
|
||||
return bdev_add_partition(bdev, p.pno, start, length);
|
||||
case BLKPG_RESIZE_PARTITION:
|
||||
return bdev_resize_partition(bdev, p.pno, start, length);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int blkpg_ioctl(struct block_device *bdev,
|
||||
|
@ -335,7 +335,7 @@ static DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL);
|
||||
* Must be called either with bd_mutex held, before a disk can be opened or
|
||||
* after all disk users are gone.
|
||||
*/
|
||||
struct hd_struct *add_partition(struct gendisk *disk, int partno,
|
||||
static struct hd_struct *add_partition(struct gendisk *disk, int partno,
|
||||
sector_t start, sector_t len, int flags,
|
||||
struct partition_meta_info *info)
|
||||
{
|
||||
@ -472,6 +472,119 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static bool partition_overlaps(struct gendisk *disk, sector_t start,
|
||||
sector_t length, int skip_partno)
|
||||
{
|
||||
struct disk_part_iter piter;
|
||||
struct hd_struct *part;
|
||||
bool overlap = false;
|
||||
|
||||
disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY);
|
||||
while ((part = disk_part_iter_next(&piter))) {
|
||||
if (part->partno == skip_partno ||
|
||||
start >= part->start_sect + part->nr_sects ||
|
||||
start + length <= part->start_sect)
|
||||
continue;
|
||||
overlap = true;
|
||||
break;
|
||||
}
|
||||
|
||||
disk_part_iter_exit(&piter);
|
||||
return overlap;
|
||||
}
|
||||
|
||||
int bdev_add_partition(struct block_device *bdev, int partno,
|
||||
sector_t start, sector_t length)
|
||||
{
|
||||
struct hd_struct *part;
|
||||
|
||||
mutex_lock(&bdev->bd_mutex);
|
||||
if (partition_overlaps(bdev->bd_disk, start, length, -1)) {
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
part = add_partition(bdev->bd_disk, partno, start, length,
|
||||
ADDPART_FLAG_NONE, NULL);
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
return PTR_ERR_OR_ZERO(part);
|
||||
}
|
||||
|
||||
int bdev_del_partition(struct block_device *bdev, int partno)
|
||||
{
|
||||
struct block_device *bdevp;
|
||||
struct hd_struct *part;
|
||||
int ret = 0;
|
||||
|
||||
part = disk_get_part(bdev->bd_disk, partno);
|
||||
if (!part)
|
||||
return -ENXIO;
|
||||
|
||||
bdevp = bdget(part_devt(part));
|
||||
disk_put_part(part);
|
||||
if (!bdevp)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&bdevp->bd_mutex);
|
||||
|
||||
ret = -EBUSY;
|
||||
if (bdevp->bd_openers)
|
||||
goto out_unlock;
|
||||
|
||||
fsync_bdev(bdevp);
|
||||
invalidate_bdev(bdevp);
|
||||
|
||||
mutex_lock_nested(&bdev->bd_mutex, 1);
|
||||
delete_partition(bdev->bd_disk, partno);
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
|
||||
ret = 0;
|
||||
out_unlock:
|
||||
mutex_unlock(&bdevp->bd_mutex);
|
||||
bdput(bdevp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bdev_resize_partition(struct block_device *bdev, int partno,
|
||||
sector_t start, sector_t length)
|
||||
{
|
||||
struct block_device *bdevp;
|
||||
struct hd_struct *part;
|
||||
int ret = 0;
|
||||
|
||||
part = disk_get_part(bdev->bd_disk, partno);
|
||||
if (!part)
|
||||
return -ENXIO;
|
||||
|
||||
ret = -ENOMEM;
|
||||
bdevp = bdget(part_devt(part));
|
||||
if (!bdevp)
|
||||
goto out_put_part;
|
||||
|
||||
mutex_lock(&bdevp->bd_mutex);
|
||||
mutex_lock_nested(&bdev->bd_mutex, 1);
|
||||
|
||||
ret = -EINVAL;
|
||||
if (start != part->start_sect)
|
||||
goto out_unlock;
|
||||
|
||||
ret = -EBUSY;
|
||||
if (partition_overlaps(bdev->bd_disk, start, length, partno))
|
||||
goto out_unlock;
|
||||
|
||||
part_nr_sects_write(part, (sector_t)length);
|
||||
i_size_write(bdevp->bd_inode, length << SECTOR_SHIFT);
|
||||
|
||||
ret = 0;
|
||||
out_unlock:
|
||||
mutex_unlock(&bdevp->bd_mutex);
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
bdput(bdevp);
|
||||
out_put_part:
|
||||
disk_put_part(part);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool disk_unlock_native_capacity(struct gendisk *disk)
|
||||
{
|
||||
const struct block_device_operations *bdops = disk->fops;
|
||||
|
Loading…
Reference in New Issue
Block a user