block: cleanup blkdev_ioctl
Split out helpers for all non-trivial ioctls to make this function simpler, and also start passing around a pointer version of the argument, as that's what most ioctl handlers actually need. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
parent
ef658fc2a6
commit
d8e4bb8103
173
block/ioctl.c
173
block/ioctl.c
|
@ -193,10 +193,20 @@ int blkdev_reread_part(struct block_device *bdev)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(blkdev_reread_part);
|
EXPORT_SYMBOL(blkdev_reread_part);
|
||||||
|
|
||||||
static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
|
static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
|
||||||
uint64_t len, int secure)
|
unsigned long arg, unsigned long flags)
|
||||||
{
|
{
|
||||||
unsigned long flags = 0;
|
uint64_t range[2];
|
||||||
|
uint64_t start, len;
|
||||||
|
|
||||||
|
if (!(mode & FMODE_WRITE))
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
|
if (copy_from_user(range, (void __user *)arg, sizeof(range)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
start = range[0];
|
||||||
|
len = range[1];
|
||||||
|
|
||||||
if (start & 511)
|
if (start & 511)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -207,14 +217,24 @@ static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
|
||||||
|
|
||||||
if (start + len > (i_size_read(bdev->bd_inode) >> 9))
|
if (start + len > (i_size_read(bdev->bd_inode) >> 9))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (secure)
|
|
||||||
flags |= BLKDEV_DISCARD_SECURE;
|
|
||||||
return blkdev_issue_discard(bdev, start, len, GFP_KERNEL, flags);
|
return blkdev_issue_discard(bdev, start, len, GFP_KERNEL, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int blk_ioctl_zeroout(struct block_device *bdev, uint64_t start,
|
static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
|
||||||
uint64_t len)
|
unsigned long arg)
|
||||||
{
|
{
|
||||||
|
uint64_t range[2];
|
||||||
|
uint64_t start, len;
|
||||||
|
|
||||||
|
if (!(mode & FMODE_WRITE))
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
|
if (copy_from_user(range, (void __user *)arg, sizeof(range)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
start = range[0];
|
||||||
|
len = range[1];
|
||||||
|
|
||||||
if (start & 511)
|
if (start & 511)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (len & 511)
|
if (len & 511)
|
||||||
|
@ -295,20 +315,11 @@ static inline int is_unrecognized_ioctl(int ret)
|
||||||
ret == -ENOIOCTLCMD;
|
ret == -ENOIOCTLCMD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int blkdev_flushbuf(struct block_device *bdev, fmode_t mode,
|
||||||
* always keep this in sync with compat_blkdev_ioctl()
|
unsigned cmd, unsigned long arg)
|
||||||
*/
|
|
||||||
int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
|
||||||
unsigned long arg)
|
|
||||||
{
|
{
|
||||||
struct gendisk *disk = bdev->bd_disk;
|
int ret;
|
||||||
struct backing_dev_info *bdi;
|
|
||||||
loff_t size;
|
|
||||||
int ret, n;
|
|
||||||
unsigned int max_sectors;
|
|
||||||
|
|
||||||
switch(cmd) {
|
|
||||||
case BLKFLSBUF:
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
|
@ -319,47 +330,32 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
||||||
fsync_bdev(bdev);
|
fsync_bdev(bdev);
|
||||||
invalidate_bdev(bdev);
|
invalidate_bdev(bdev);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int blkdev_roset(struct block_device *bdev, fmode_t mode,
|
||||||
|
unsigned cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
int ret, n;
|
||||||
|
|
||||||
case BLKROSET:
|
|
||||||
ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
||||||
if (!is_unrecognized_ioctl(ret))
|
if (!is_unrecognized_ioctl(ret))
|
||||||
return ret;
|
return ret;
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
if (get_user(n, (int __user *)(arg)))
|
if (get_user(n, (int __user *)arg))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
set_device_ro(bdev, n);
|
set_device_ro(bdev, n);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case BLKDISCARD:
|
|
||||||
case BLKSECDISCARD: {
|
|
||||||
uint64_t range[2];
|
|
||||||
|
|
||||||
if (!(mode & FMODE_WRITE))
|
|
||||||
return -EBADF;
|
|
||||||
|
|
||||||
if (copy_from_user(range, (void __user *)arg, sizeof(range)))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
return blk_ioctl_discard(bdev, range[0], range[1],
|
|
||||||
cmd == BLKSECDISCARD);
|
|
||||||
}
|
|
||||||
case BLKZEROOUT: {
|
|
||||||
uint64_t range[2];
|
|
||||||
|
|
||||||
if (!(mode & FMODE_WRITE))
|
|
||||||
return -EBADF;
|
|
||||||
|
|
||||||
if (copy_from_user(range, (void __user *)arg, sizeof(range)))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
return blk_ioctl_zeroout(bdev, range[0], range[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case HDIO_GETGEO: {
|
static int blkdev_getgeo(struct block_device *bdev,
|
||||||
|
struct hd_geometry __user *argp)
|
||||||
|
{
|
||||||
|
struct gendisk *disk = bdev->bd_disk;
|
||||||
struct hd_geometry geo;
|
struct hd_geometry geo;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!arg)
|
if (!argp)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!disk->fops->getgeo)
|
if (!disk->fops->getgeo)
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
|
@ -373,11 +369,61 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
||||||
ret = disk->fops->getgeo(bdev, &geo);
|
ret = disk->fops->getgeo(bdev, &geo);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
if (copy_to_user((struct hd_geometry __user *)arg, &geo,
|
if (copy_to_user(argp, &geo, sizeof(geo)))
|
||||||
sizeof(geo)))
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set the logical block size */
|
||||||
|
static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
|
||||||
|
int __user *argp)
|
||||||
|
{
|
||||||
|
int ret, n;
|
||||||
|
|
||||||
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
|
return -EACCES;
|
||||||
|
if (!argp)
|
||||||
|
return -EINVAL;
|
||||||
|
if (get_user(n, argp))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (!(mode & FMODE_EXCL)) {
|
||||||
|
bdgrab(bdev);
|
||||||
|
if (blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0)
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = set_blocksize(bdev, n);
|
||||||
|
if (!(mode & FMODE_EXCL))
|
||||||
|
blkdev_put(bdev, mode | FMODE_EXCL);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* always keep this in sync with compat_blkdev_ioctl()
|
||||||
|
*/
|
||||||
|
int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
||||||
|
unsigned long arg)
|
||||||
|
{
|
||||||
|
struct backing_dev_info *bdi;
|
||||||
|
void __user *argp = (void __user *)arg;
|
||||||
|
loff_t size;
|
||||||
|
unsigned int max_sectors;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case BLKFLSBUF:
|
||||||
|
return blkdev_flushbuf(bdev, mode, cmd, arg);
|
||||||
|
case BLKROSET:
|
||||||
|
return blkdev_roset(bdev, mode, cmd, arg);
|
||||||
|
case BLKDISCARD:
|
||||||
|
return blk_ioctl_discard(bdev, mode, arg, 0);
|
||||||
|
case BLKSECDISCARD:
|
||||||
|
return blk_ioctl_discard(bdev, mode, arg,
|
||||||
|
BLKDEV_DISCARD_SECURE);
|
||||||
|
case BLKZEROOUT:
|
||||||
|
return blk_ioctl_zeroout(bdev, mode, arg);
|
||||||
|
case HDIO_GETGEO:
|
||||||
|
return blkdev_getgeo(bdev, argp);
|
||||||
case BLKRAGET:
|
case BLKRAGET:
|
||||||
case BLKFRAGET:
|
case BLKFRAGET:
|
||||||
if (!arg)
|
if (!arg)
|
||||||
|
@ -414,28 +460,11 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
||||||
bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
|
bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
|
||||||
return 0;
|
return 0;
|
||||||
case BLKBSZSET:
|
case BLKBSZSET:
|
||||||
/* set the logical block size */
|
return blkdev_bszset(bdev, mode, argp);
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
|
||||||
return -EACCES;
|
|
||||||
if (!arg)
|
|
||||||
return -EINVAL;
|
|
||||||
if (get_user(n, (int __user *) arg))
|
|
||||||
return -EFAULT;
|
|
||||||
if (!(mode & FMODE_EXCL)) {
|
|
||||||
bdgrab(bdev);
|
|
||||||
if (blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0)
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
ret = set_blocksize(bdev, n);
|
|
||||||
if (!(mode & FMODE_EXCL))
|
|
||||||
blkdev_put(bdev, mode | FMODE_EXCL);
|
|
||||||
return ret;
|
|
||||||
case BLKPG:
|
case BLKPG:
|
||||||
ret = blkpg_ioctl(bdev, (struct blkpg_ioctl_arg __user *) arg);
|
return blkpg_ioctl(bdev, argp);
|
||||||
break;
|
|
||||||
case BLKRRPART:
|
case BLKRRPART:
|
||||||
ret = blkdev_reread_part(bdev);
|
return blkdev_reread_part(bdev);
|
||||||
break;
|
|
||||||
case BLKGETSIZE:
|
case BLKGETSIZE:
|
||||||
size = i_size_read(bdev->bd_inode);
|
size = i_size_read(bdev->bd_inode);
|
||||||
if ((size >> 9) > ~0UL)
|
if ((size >> 9) > ~0UL)
|
||||||
|
@ -447,11 +476,9 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
||||||
case BLKTRACESTOP:
|
case BLKTRACESTOP:
|
||||||
case BLKTRACESETUP:
|
case BLKTRACESETUP:
|
||||||
case BLKTRACETEARDOWN:
|
case BLKTRACETEARDOWN:
|
||||||
ret = blk_trace_ioctl(bdev, cmd, (char __user *) arg);
|
return blk_trace_ioctl(bdev, cmd, argp);
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(blkdev_ioctl);
|
EXPORT_SYMBOL_GPL(blkdev_ioctl);
|
||||||
|
|
Loading…
Reference in a new issue