A lot of block drivers need only a trivial .compat_ioctl callback.
Add a helper function that can be set as the callback pointer to only convert the argument using the compat_ptr() conversion and otherwise assume all input and output data is compatible, or handled using in_compat_syscall() checks.
This mirrors the compat_ptr_ioctl() helper function used in character devices.
Signed-off-by: Arnd Bergmann arnd@arndb.de --- block/ioctl.c | 21 +++++++++++++++++++++ include/linux/blkdev.h | 7 +++++++ 2 files changed, 28 insertions(+)
diff --git a/block/ioctl.c b/block/ioctl.c index 5de98b97af2a..e728331d1a5b 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/capability.h> +#include <linux/compat.h> #include <linux/blkdev.h> #include <linux/export.h> #include <linux/gfp.h> @@ -285,6 +286,26 @@ int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode, */ EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl);
+#ifdef CONFIG_COMPAT +/* + * This is the equivalent of compat_ptr_ioctl(), to be used by block + * drivers that implement only commands that are completely compatible + * between 32-bit and 64-bit user space + */ +int blkdev_compat_ptr_ioctl(struct block_device *bdev, fmode_t mode, + unsigned cmd, unsigned long arg) +{ + struct gendisk *disk = bdev->bd_disk; + + if (disk->fops->ioctl) + return disk->fops->ioctl(bdev, mode, cmd, + (unsigned long)compat_ptr(arg)); + + return -ENOIOCTLCMD; +} +EXPORT_SYMBOL(blkdev_compat_ptr_ioctl); +#endif + static int blkdev_pr_register(struct block_device *bdev, struct pr_registration __user *arg) { diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 47eb22a3b7f9..3e0408618da7 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1711,6 +1711,13 @@ struct block_device_operations { const struct pr_ops *pr_ops; };
+#ifdef CONFIG_COMPAT +extern int blkdev_compat_ptr_ioctl(struct block_device *, fmode_t, + unsigned int, unsigned long); +#else +#define blkdev_compat_ptr_ioctl NULL +#endif + extern int __blkdev_driver_ioctl(struct block_device *, fmode_t, unsigned int, unsigned long); extern int bdev_read_page(struct block_device *, sector_t, struct page *);