Commit d8e4bb81 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jens Axboe

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: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent ef658fc2
...@@ -193,10 +193,20 @@ int blkdev_reread_part(struct block_device *bdev) ...@@ -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, ...@@ -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,89 +315,115 @@ static inline int is_unrecognized_ioctl(int ret) ...@@ -295,89 +315,115 @@ 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) { if (!capable(CAP_SYS_ADMIN))
case BLKFLSBUF: return -EACCES;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
if (!is_unrecognized_ioctl(ret))
return ret;
fsync_bdev(bdev); ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
invalidate_bdev(bdev); if (!is_unrecognized_ioctl(ret))
return 0; return ret;
case BLKROSET: fsync_bdev(bdev);
ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg); invalidate_bdev(bdev);
if (!is_unrecognized_ioctl(ret)) return 0;
return ret; }
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (get_user(n, (int __user *)(arg)))
return -EFAULT;
set_device_ro(bdev, n);
return 0;
case BLKDISCARD: static int blkdev_roset(struct block_device *bdev, fmode_t mode,
case BLKSECDISCARD: { unsigned cmd, unsigned long arg)
uint64_t range[2]; {
int ret, n;
if (!(mode & FMODE_WRITE)) ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
return -EBADF; if (!is_unrecognized_ioctl(ret))
return ret;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (get_user(n, (int __user *)arg))
return -EFAULT;
set_device_ro(bdev, n);
return 0;
}
if (copy_from_user(range, (void __user *)arg, sizeof(range))) static int blkdev_getgeo(struct block_device *bdev,
return -EFAULT; struct hd_geometry __user *argp)
{
struct gendisk *disk = bdev->bd_disk;
struct hd_geometry geo;
int ret;
return blk_ioctl_discard(bdev, range[0], range[1], if (!argp)
cmd == BLKSECDISCARD); return -EINVAL;
} if (!disk->fops->getgeo)
case BLKZEROOUT: { return -ENOTTY;
uint64_t range[2];
/*
* We need to set the startsect first, the driver may
* want to override it.
*/
memset(&geo, 0, sizeof(geo));
geo.start = get_start_sect(bdev);
ret = disk->fops->getgeo(bdev, &geo);
if (ret)
return ret;
if (copy_to_user(argp, &geo, sizeof(geo)))
return -EFAULT;
return 0;
}
if (!(mode & FMODE_WRITE)) /* set the logical block size */
return -EBADF; static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
int __user *argp)
{
int ret, n;
if (copy_from_user(range, (void __user *)arg, sizeof(range))) if (!capable(CAP_SYS_ADMIN))
return -EFAULT; return -EACCES;
if (!argp)
return -EINVAL;
if (get_user(n, argp))
return -EFAULT;
return blk_ioctl_zeroout(bdev, range[0], range[1]); if (!(mode & FMODE_EXCL)) {
bdgrab(bdev);
if (blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0)
return -EBUSY;
} }
case HDIO_GETGEO: { ret = set_blocksize(bdev, n);
struct hd_geometry geo; if (!(mode & FMODE_EXCL))
blkdev_put(bdev, mode | FMODE_EXCL);
return ret;
}
if (!arg) /*
return -EINVAL; * always keep this in sync with compat_blkdev_ioctl()
if (!disk->fops->getgeo) */
return -ENOTTY; int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
unsigned long arg)
/* {
* We need to set the startsect first, the driver may struct backing_dev_info *bdi;
* want to override it. void __user *argp = (void __user *)arg;
*/ loff_t size;
memset(&geo, 0, sizeof(geo)); unsigned int max_sectors;
geo.start = get_start_sect(bdev);
ret = disk->fops->getgeo(bdev, &geo); switch (cmd) {
if (ret) case BLKFLSBUF:
return ret; return blkdev_flushbuf(bdev, mode, cmd, arg);
if (copy_to_user((struct hd_geometry __user *)arg, &geo, case BLKROSET:
sizeof(geo))) return blkdev_roset(bdev, mode, cmd, arg);
return -EFAULT; case BLKDISCARD:
return 0; 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, ...@@ -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, ...@@ -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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment