OSDN Git Service

block: refactor blkpg_ioctl
authorChristoph Hellwig <hch@lst.de>
Tue, 14 Apr 2020 07:28:53 +0000 (09:28 +0200)
committerJens Axboe <axboe@kernel.dk>
Mon, 20 Apr 2020 17:32:59 +0000 (11:32 -0600)
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>
block/blk.h
block/ioctl.c
block/partitions/core.c

index 0a94ec6..305e0ac 100644 (file)
@@ -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)
index 6e827de..75c6481 100644 (file)
 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;
+
+       if (op == BLKPG_DEL_PARTITION)
+               return bdev_del_partition(bdev, p.pno);
+
+       start = p.start >> SECTOR_SHIFT;
+       length = p.length >> SECTOR_SHIFT;
+
+       /* check for fit in a hd_struct */
+       if (sizeof(sector_t) < sizeof(long long)) {
+               long pstart = start, plength = length;
+
+               if (pstart != start || plength != length || pstart < 0 ||
+                   plength < 0 || p.pno > 65535)
+                       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);
-
-                       /* 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);
-
-                       /* 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;
-
-                       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:
+       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;
        }
 }
 
index bc1ded1..7e2f408 100644 (file)
@@ -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 @@ out_put:
        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;