EXPORT_SYMBOL(blkdev_compat_ptr_ioctl);
#endif
-static bool blkdev_pr_allowed(struct block_device *bdev, blk_mode_t mode)
+enum pr_direction {
+ PR_IN, /* read from device */
+ PR_OUT, /* write to device */
+};
+
+static bool blkdev_pr_allowed(struct block_device *bdev, blk_mode_t mode,
+ enum pr_direction dir)
{
/* no sense to make reservations for partitions */
if (bdev_is_partition(bdev))
if (capable(CAP_SYS_ADMIN))
return true;
+
/*
- * Only allow unprivileged reservations if the file descriptor is open
- * for writing.
+ * Only allow unprivileged reservation _out_ commands if the file
+ * descriptor is open for writing. Allow reservation _in_ commands if
+ * the file descriptor is open for reading since they do not modify the
+ * device.
*/
- return mode & BLK_OPEN_WRITE;
+ if (dir == PR_IN)
+ return mode & BLK_OPEN_READ;
+ else
+ return mode & BLK_OPEN_WRITE;
}
static int blkdev_pr_register(struct block_device *bdev, blk_mode_t mode,
const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
struct pr_registration reg;
- if (!blkdev_pr_allowed(bdev, mode))
+ if (!blkdev_pr_allowed(bdev, mode, PR_OUT))
return -EPERM;
if (!ops || !ops->pr_register)
return -EOPNOTSUPP;
const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
struct pr_reservation rsv;
- if (!blkdev_pr_allowed(bdev, mode))
+ if (!blkdev_pr_allowed(bdev, mode, PR_OUT))
return -EPERM;
if (!ops || !ops->pr_reserve)
return -EOPNOTSUPP;
const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
struct pr_reservation rsv;
- if (!blkdev_pr_allowed(bdev, mode))
+ if (!blkdev_pr_allowed(bdev, mode, PR_OUT))
return -EPERM;
if (!ops || !ops->pr_release)
return -EOPNOTSUPP;
const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
struct pr_preempt p;
- if (!blkdev_pr_allowed(bdev, mode))
+ if (!blkdev_pr_allowed(bdev, mode, PR_OUT))
return -EPERM;
if (!ops || !ops->pr_preempt)
return -EOPNOTSUPP;
const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
struct pr_clear c;
- if (!blkdev_pr_allowed(bdev, mode))
+ if (!blkdev_pr_allowed(bdev, mode, PR_OUT))
return -EPERM;
if (!ops || !ops->pr_clear)
return -EOPNOTSUPP;
size_t keys_copy_len;
int ret;
- if (!blkdev_pr_allowed(bdev, mode))
+ if (!blkdev_pr_allowed(bdev, mode, PR_IN))
return -EPERM;
if (!ops || !ops->pr_read_keys)
return -EOPNOTSUPP;
struct pr_read_reservation out = {};
int ret;
- if (!blkdev_pr_allowed(bdev, mode))
+ if (!blkdev_pr_allowed(bdev, mode, PR_IN))
return -EPERM;
if (!ops || !ops->pr_read_reservation)
return -EOPNOTSUPP;