diff options
author | Christoph Hellwig <hch@lst.de> | 2015-10-15 08:10:48 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2015-10-21 16:46:56 -0400 |
commit | bbd3e064362e5057cc4799ba2e4d68c7593e490b (patch) | |
tree | 94c1efd47cf05eaf940e3381bb4eb9df421ae001 /block | |
parent | d8e4bb8103df02a2c509868732dc93fb66110a12 (diff) |
block: add an API for Persistent Reservations
This commits adds a driver API and ioctls for controlling Persistent
Reservations s/genericly/generically/ at the block layer. Persistent
Reservations are supported by SCSI and NVMe and allow controlling who gets
access to a device in a shared storage setup.
Note that we add a pr_ops structure to struct block_device_operations
instead of adding the members directly to avoid bloating all instances
of devices that will never support Persistent Reservations.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block')
-rw-r--r-- | block/ioctl.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/block/ioctl.c b/block/ioctl.c index df62b47d2379..0918aed2d847 100644 --- a/block/ioctl.c +++ b/block/ioctl.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/backing-dev.h> | 7 | #include <linux/backing-dev.h> |
8 | #include <linux/fs.h> | 8 | #include <linux/fs.h> |
9 | #include <linux/blktrace_api.h> | 9 | #include <linux/blktrace_api.h> |
10 | #include <linux/pr.h> | ||
10 | #include <asm/uaccess.h> | 11 | #include <asm/uaccess.h> |
11 | 12 | ||
12 | static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg) | 13 | static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg) |
@@ -295,6 +296,96 @@ int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode, | |||
295 | */ | 296 | */ |
296 | EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl); | 297 | EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl); |
297 | 298 | ||
299 | static int blkdev_pr_register(struct block_device *bdev, | ||
300 | struct pr_registration __user *arg) | ||
301 | { | ||
302 | const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; | ||
303 | struct pr_registration reg; | ||
304 | |||
305 | if (!capable(CAP_SYS_ADMIN)) | ||
306 | return -EPERM; | ||
307 | if (!ops || !ops->pr_register) | ||
308 | return -EOPNOTSUPP; | ||
309 | if (copy_from_user(®, arg, sizeof(reg))) | ||
310 | return -EFAULT; | ||
311 | |||
312 | if (reg.flags & ~PR_FL_IGNORE_KEY) | ||
313 | return -EOPNOTSUPP; | ||
314 | return ops->pr_register(bdev, reg.old_key, reg.new_key, reg.flags); | ||
315 | } | ||
316 | |||
317 | static int blkdev_pr_reserve(struct block_device *bdev, | ||
318 | struct pr_reservation __user *arg) | ||
319 | { | ||
320 | const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; | ||
321 | struct pr_reservation rsv; | ||
322 | |||
323 | if (!capable(CAP_SYS_ADMIN)) | ||
324 | return -EPERM; | ||
325 | if (!ops || !ops->pr_reserve) | ||
326 | return -EOPNOTSUPP; | ||
327 | if (copy_from_user(&rsv, arg, sizeof(rsv))) | ||
328 | return -EFAULT; | ||
329 | |||
330 | if (rsv.flags & ~PR_FL_IGNORE_KEY) | ||
331 | return -EOPNOTSUPP; | ||
332 | return ops->pr_reserve(bdev, rsv.key, rsv.type, rsv.flags); | ||
333 | } | ||
334 | |||
335 | static int blkdev_pr_release(struct block_device *bdev, | ||
336 | struct pr_reservation __user *arg) | ||
337 | { | ||
338 | const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; | ||
339 | struct pr_reservation rsv; | ||
340 | |||
341 | if (!capable(CAP_SYS_ADMIN)) | ||
342 | return -EPERM; | ||
343 | if (!ops || !ops->pr_release) | ||
344 | return -EOPNOTSUPP; | ||
345 | if (copy_from_user(&rsv, arg, sizeof(rsv))) | ||
346 | return -EFAULT; | ||
347 | |||
348 | if (rsv.flags) | ||
349 | return -EOPNOTSUPP; | ||
350 | return ops->pr_release(bdev, rsv.key, rsv.type); | ||
351 | } | ||
352 | |||
353 | static int blkdev_pr_preempt(struct block_device *bdev, | ||
354 | struct pr_preempt __user *arg, bool abort) | ||
355 | { | ||
356 | const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; | ||
357 | struct pr_preempt p; | ||
358 | |||
359 | if (!capable(CAP_SYS_ADMIN)) | ||
360 | return -EPERM; | ||
361 | if (!ops || !ops->pr_preempt) | ||
362 | return -EOPNOTSUPP; | ||
363 | if (copy_from_user(&p, arg, sizeof(p))) | ||
364 | return -EFAULT; | ||
365 | |||
366 | if (p.flags) | ||
367 | return -EOPNOTSUPP; | ||
368 | return ops->pr_preempt(bdev, p.old_key, p.new_key, p.type, abort); | ||
369 | } | ||
370 | |||
371 | static int blkdev_pr_clear(struct block_device *bdev, | ||
372 | struct pr_clear __user *arg) | ||
373 | { | ||
374 | const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; | ||
375 | struct pr_clear c; | ||
376 | |||
377 | if (!capable(CAP_SYS_ADMIN)) | ||
378 | return -EPERM; | ||
379 | if (!ops || !ops->pr_clear) | ||
380 | return -EOPNOTSUPP; | ||
381 | if (copy_from_user(&c, arg, sizeof(c))) | ||
382 | return -EFAULT; | ||
383 | |||
384 | if (c.flags) | ||
385 | return -EOPNOTSUPP; | ||
386 | return ops->pr_clear(bdev, c.key); | ||
387 | } | ||
388 | |||
298 | /* | 389 | /* |
299 | * Is it an unrecognized ioctl? The correct returns are either | 390 | * Is it an unrecognized ioctl? The correct returns are either |
300 | * ENOTTY (final) or ENOIOCTLCMD ("I don't know this one, try a | 391 | * ENOTTY (final) or ENOIOCTLCMD ("I don't know this one, try a |
@@ -477,6 +568,18 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, | |||
477 | case BLKTRACESETUP: | 568 | case BLKTRACESETUP: |
478 | case BLKTRACETEARDOWN: | 569 | case BLKTRACETEARDOWN: |
479 | return blk_trace_ioctl(bdev, cmd, argp); | 570 | return blk_trace_ioctl(bdev, cmd, argp); |
571 | case IOC_PR_REGISTER: | ||
572 | return blkdev_pr_register(bdev, argp); | ||
573 | case IOC_PR_RESERVE: | ||
574 | return blkdev_pr_reserve(bdev, argp); | ||
575 | case IOC_PR_RELEASE: | ||
576 | return blkdev_pr_release(bdev, argp); | ||
577 | case IOC_PR_PREEMPT: | ||
578 | return blkdev_pr_preempt(bdev, argp, false); | ||
579 | case IOC_PR_PREEMPT_ABORT: | ||
580 | return blkdev_pr_preempt(bdev, argp, true); | ||
581 | case IOC_PR_CLEAR: | ||
582 | return blkdev_pr_clear(bdev, argp); | ||
480 | default: | 583 | default: |
481 | return __blkdev_driver_ioctl(bdev, mode, cmd, arg); | 584 | return __blkdev_driver_ioctl(bdev, mode, cmd, arg); |
482 | } | 585 | } |