Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

block: add IOC_PR_READ_KEYS ioctl

Add a Persistent Reservations ioctl to read the list of currently
registered reservation keys. This calls the pr_ops->read_keys() 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_KEYS 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: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Stefan Hajnoczi and committed by
Jens Axboe
22a1ffea 38ec8469

+63
+56
block/ioctl.c
··· 423 423 return ops->pr_clear(bdev, c.key); 424 424 } 425 425 426 + static int blkdev_pr_read_keys(struct block_device *bdev, blk_mode_t mode, 427 + struct pr_read_keys __user *arg) 428 + { 429 + const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; 430 + struct pr_keys *keys_info; 431 + struct pr_read_keys read_keys; 432 + u64 __user *keys_ptr; 433 + size_t keys_info_len; 434 + size_t keys_copy_len; 435 + int ret; 436 + 437 + if (!blkdev_pr_allowed(bdev, mode)) 438 + return -EPERM; 439 + if (!ops || !ops->pr_read_keys) 440 + return -EOPNOTSUPP; 441 + 442 + if (copy_from_user(&read_keys, arg, sizeof(read_keys))) 443 + return -EFAULT; 444 + 445 + keys_info_len = struct_size(keys_info, keys, read_keys.num_keys); 446 + if (keys_info_len == SIZE_MAX) 447 + return -EINVAL; 448 + 449 + keys_info = kzalloc(keys_info_len, GFP_KERNEL); 450 + if (!keys_info) 451 + return -ENOMEM; 452 + 453 + keys_info->num_keys = read_keys.num_keys; 454 + 455 + ret = ops->pr_read_keys(bdev, keys_info); 456 + if (ret) 457 + goto out; 458 + 459 + /* Copy out individual keys */ 460 + keys_ptr = u64_to_user_ptr(read_keys.keys_ptr); 461 + keys_copy_len = min(read_keys.num_keys, keys_info->num_keys) * 462 + sizeof(keys_info->keys[0]); 463 + 464 + if (copy_to_user(keys_ptr, keys_info->keys, keys_copy_len)) { 465 + ret = -EFAULT; 466 + goto out; 467 + } 468 + 469 + /* Copy out the arg struct */ 470 + read_keys.generation = keys_info->generation; 471 + read_keys.num_keys = keys_info->num_keys; 472 + 473 + if (copy_to_user(arg, &read_keys, sizeof(read_keys))) 474 + ret = -EFAULT; 475 + out: 476 + kfree(keys_info); 477 + return ret; 478 + } 479 + 426 480 static int blkdev_flushbuf(struct block_device *bdev, unsigned cmd, 427 481 unsigned long arg) 428 482 { ··· 699 645 return blkdev_pr_preempt(bdev, mode, argp, true); 700 646 case IOC_PR_CLEAR: 701 647 return blkdev_pr_clear(bdev, mode, argp); 648 + case IOC_PR_READ_KEYS: 649 + return blkdev_pr_read_keys(bdev, mode, argp); 702 650 default: 703 651 return blk_get_meta_cap(bdev, cmd, argp); 704 652 }
+7
include/uapi/linux/pr.h
··· 56 56 __u32 __pad; 57 57 }; 58 58 59 + struct pr_read_keys { 60 + __u32 generation; 61 + __u32 num_keys; 62 + __u64 keys_ptr; 63 + }; 64 + 59 65 #define PR_FL_IGNORE_KEY (1 << 0) /* ignore existing key */ 60 66 61 67 #define IOC_PR_REGISTER _IOW('p', 200, struct pr_registration) ··· 70 64 #define IOC_PR_PREEMPT _IOW('p', 203, struct pr_preempt) 71 65 #define IOC_PR_PREEMPT_ABORT _IOW('p', 204, struct pr_preempt) 72 66 #define IOC_PR_CLEAR _IOW('p', 205, struct pr_clear) 67 + #define IOC_PR_READ_KEYS _IOWR('p', 206, struct pr_read_keys) 73 68 74 69 #endif /* _UAPI_PR_H */