Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+127 −100
Original line number Diff line number Diff line
@@ -193,10 +193,20 @@ int blkdev_reread_part(struct block_device *bdev)
}
EXPORT_SYMBOL(blkdev_reread_part);

static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
			     uint64_t len, int secure)
static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
		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)
		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))
		return -EINVAL;
	if (secure)
		flags |= BLKDEV_DISCARD_SECURE;
	return blkdev_issue_discard(bdev, start, len, GFP_KERNEL, flags);
}

static int blk_ioctl_zeroout(struct block_device *bdev, uint64_t start,
			     uint64_t len)
static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
		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)
		return -EINVAL;
	if (len & 511)
@@ -295,20 +315,11 @@ static inline int is_unrecognized_ioctl(int ret)
		ret == -ENOIOCTLCMD;
}

/*
 * always keep this in sync with compat_blkdev_ioctl()
 */
int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
			unsigned long arg)
static int blkdev_flushbuf(struct block_device *bdev, fmode_t mode,
		unsigned cmd, unsigned long arg)
{
	struct gendisk *disk = bdev->bd_disk;
	struct backing_dev_info *bdi;
	loff_t size;
	int ret, n;
	unsigned int max_sectors;
	int ret;

	switch(cmd) {
	case BLKFLSBUF:
	if (!capable(CAP_SYS_ADMIN))
		return -EACCES;

@@ -319,47 +330,32 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
	fsync_bdev(bdev);
	invalidate_bdev(bdev);
	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);
	if (!is_unrecognized_ioctl(ret))
		return ret;
	if (!capable(CAP_SYS_ADMIN))
		return -EACCES;
		if (get_user(n, (int __user *)(arg)))
	if (get_user(n, (int __user *)arg))
		return -EFAULT;
	set_device_ro(bdev, n);
	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;
	int ret;

		if (!arg)
	if (!argp)
		return -EINVAL;
	if (!disk->fops->getgeo)
		return -ENOTTY;
@@ -373,11 +369,61 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
	ret = disk->fops->getgeo(bdev, &geo);
	if (ret)
		return ret;
		if (copy_to_user((struct hd_geometry __user *)arg, &geo,
					sizeof(geo)))
	if (copy_to_user(argp, &geo, sizeof(geo)))
		return -EFAULT;
	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 BLKFRAGET:
		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;
		return 0;
	case BLKBSZSET:
		/* set the logical block size */
		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;
		return blkdev_bszset(bdev, mode, argp);
	case BLKPG:
		ret = blkpg_ioctl(bdev, (struct blkpg_ioctl_arg __user *) arg);
		break;
		return blkpg_ioctl(bdev, argp);
	case BLKRRPART:
		ret = blkdev_reread_part(bdev);
		break;
		return blkdev_reread_part(bdev);
	case BLKGETSIZE:
		size = i_size_read(bdev->bd_inode);
		if ((size >> 9) > ~0UL)
@@ -447,11 +476,9 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
	case BLKTRACESTOP:
	case BLKTRACESETUP:
	case BLKTRACETEARDOWN:
		ret = blk_trace_ioctl(bdev, cmd, (char __user *) arg);
		break;
		return blk_trace_ioctl(bdev, cmd, argp);
	default:
		ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
		return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
	}
	return ret;
}
EXPORT_SYMBOL_GPL(blkdev_ioctl);