aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2015-10-15 08:10:48 -0400
committerJens Axboe <axboe@fb.com>2015-10-21 16:46:56 -0400
commitbbd3e064362e5057cc4799ba2e4d68c7593e490b (patch)
tree94c1efd47cf05eaf940e3381bb4eb9df421ae001 /block
parentd8e4bb8103df02a2c509868732dc93fb66110a12 (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.c103
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
12static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg) 13static 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 */
296EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl); 297EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl);
297 298
299static 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(&reg, 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
317static 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
335static 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
353static 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
371static 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 }