|
@@ -179,6 +179,26 @@ int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
|
|
*/
|
|
*/
|
|
EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl);
|
|
EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl);
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Is it an unrecognized ioctl? The correct returns are either
|
|
|
|
+ * ENOTTY (final) or ENOIOCTLCMD ("I don't know this one, try a
|
|
|
|
+ * fallback"). ENOIOCTLCMD gets turned into ENOTTY by the ioctl
|
|
|
|
+ * code before returning.
|
|
|
|
+ *
|
|
|
|
+ * Confused drivers sometimes return EINVAL, which is wrong. It
|
|
|
|
+ * means "I understood the ioctl command, but the parameters to
|
|
|
|
+ * it were wrong".
|
|
|
|
+ *
|
|
|
|
+ * We should aim to just fix the broken drivers, the EINVAL case
|
|
|
|
+ * should go away.
|
|
|
|
+ */
|
|
|
|
+static inline int is_unrecognized_ioctl(int ret)
|
|
|
|
+{
|
|
|
|
+ return ret == -EINVAL ||
|
|
|
|
+ ret == -ENOTTY ||
|
|
|
|
+ ret == -ENOIOCTLCMD;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* always keep this in sync with compat_blkdev_ioctl()
|
|
* always keep this in sync with compat_blkdev_ioctl()
|
|
*/
|
|
*/
|
|
@@ -196,8 +216,7 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
|
return -EACCES;
|
|
return -EACCES;
|
|
|
|
|
|
ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
|
ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
|
- /* -EINVAL to handle old uncorrected drivers */
|
|
|
|
- if (ret != -EINVAL && ret != -ENOTTY)
|
|
|
|
|
|
+ if (!is_unrecognized_ioctl(ret))
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
fsync_bdev(bdev);
|
|
fsync_bdev(bdev);
|
|
@@ -206,8 +225,7 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
|
|
|
|
|
case BLKROSET:
|
|
case BLKROSET:
|
|
ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
|
ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
|
- /* -EINVAL to handle old uncorrected drivers */
|
|
|
|
- if (ret != -EINVAL && ret != -ENOTTY)
|
|
|
|
|
|
+ if (!is_unrecognized_ioctl(ret))
|
|
return ret;
|
|
return ret;
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
return -EACCES;
|
|
return -EACCES;
|