]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
block: add IOC_PR_READ_RESERVATION ioctl
authorStefan Hajnoczi <stefanha@redhat.com>
Mon, 1 Dec 2025 21:43:29 +0000 (16:43 -0500)
committerJens Axboe <axboe@kernel.dk>
Thu, 4 Dec 2025 14:19:26 +0000 (07:19 -0700)
Add a Persistent Reservations ioctl to read the current reservation.
This calls the pr_ops->read_reservation() function that was previously
added in commit c787f1baa503 ("block: Add PR callouts for read keys and
reservation") but was only used by the in-kernel SCSI target so far.

The IOC_PR_READ_RESERVATION ioctl is necessary so that userspace
applications that rely on Persistent Reservations ioctls have a way of
inspecting the current state. Cluster managers and validation tests need
this functionality.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/ioctl.c
include/uapi/linux/pr.h

index c0802ebf54a635bd2f9f6c9096d2e23d3bc5e647..61feed686418a6f3c228a50b516cc1b1c01f0db5 100644 (file)
@@ -477,6 +477,32 @@ out:
        return ret;
 }
 
+static int blkdev_pr_read_reservation(struct block_device *bdev,
+               blk_mode_t mode, struct pr_read_reservation __user *arg)
+{
+       const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
+       struct pr_held_reservation rsv = {};
+       struct pr_read_reservation out = {};
+       int ret;
+
+       if (!blkdev_pr_allowed(bdev, mode))
+               return -EPERM;
+       if (!ops || !ops->pr_read_reservation)
+               return -EOPNOTSUPP;
+
+       ret = ops->pr_read_reservation(bdev, &rsv);
+       if (ret)
+               return ret;
+
+       out.key = rsv.key;
+       out.generation = rsv.generation;
+       out.type = rsv.type;
+
+       if (copy_to_user(arg, &out, sizeof(out)))
+               return -EFAULT;
+       return 0;
+}
+
 static int blkdev_flushbuf(struct block_device *bdev, unsigned cmd,
                unsigned long arg)
 {
@@ -701,6 +727,8 @@ static int blkdev_common_ioctl(struct block_device *bdev, blk_mode_t mode,
                return blkdev_pr_clear(bdev, mode, argp);
        case IOC_PR_READ_KEYS:
                return blkdev_pr_read_keys(bdev, mode, argp);
+       case IOC_PR_READ_RESERVATION:
+               return blkdev_pr_read_reservation(bdev, mode, argp);
        default:
                return blk_get_meta_cap(bdev, cmd, argp);
        }
index fcb74eab92c80c2a4603fb01120359de64ddc52b..847f3051057af733718edb9fd39a791df6fc23d3 100644 (file)
@@ -62,6 +62,12 @@ struct pr_read_keys {
        __u64   keys_ptr;
 };
 
+struct pr_read_reservation {
+       __u64   key;
+       __u32   generation;
+       __u32   type;
+};
+
 #define PR_FL_IGNORE_KEY       (1 << 0)        /* ignore existing key */
 
 #define IOC_PR_REGISTER                _IOW('p', 200, struct pr_registration)
@@ -71,5 +77,6 @@ struct pr_read_keys {
 #define IOC_PR_PREEMPT_ABORT   _IOW('p', 204, struct pr_preempt)
 #define IOC_PR_CLEAR           _IOW('p', 205, struct pr_clear)
 #define IOC_PR_READ_KEYS       _IOWR('p', 206, struct pr_read_keys)
+#define IOC_PR_READ_RESERVATION        _IOR('p', 207, struct pr_read_reservation)
 
 #endif /* _UAPI_PR_H */