Add support for persistent reservations. Effectively all that is done here is that a multipath version of pr_ops is created which calls into the driver version of the callbacks for the mpath_device selected.
Structure mpath_pr_ops is introduced, which must be set by the driver for PR callbacks. Signed-off-by: John Garry <[email protected]> --- include/linux/multipath.h | 18 +++++ lib/multipath.c | 146 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) diff --git a/include/linux/multipath.h b/include/linux/multipath.h index 9122560f71778..454826c385923 100644 --- a/include/linux/multipath.h +++ b/include/linux/multipath.h @@ -5,6 +5,7 @@ #include <linux/blkdev.h> #include <linux/blk-mq.h> #include <linux/cdev.h> +#include <linux/pr.h> #include <linux/srcu.h> #include <linux/io_uring/cmd.h> @@ -48,6 +49,22 @@ struct mpath_device { int numa_node; }; +struct mpath_pr_ops { + int (*pr_register)(struct mpath_device *mpath_device, u64 old_key, + u64 new_key, u32 flags); + int (*pr_reserve)(struct mpath_device *mpath_device, u64 key, + enum pr_type type, u32 flags); + int (*pr_release)(struct mpath_device *mpath_device, u64 key, + enum pr_type type); + int (*pr_preempt)(struct mpath_device *mpath_device, u64 old_key, + u64 new_key, enum pr_type type, bool abort); + int (*pr_clear)(struct mpath_device *mpath_device, u64 key); + int (*pr_read_keys)(struct mpath_device *mpath_device, + struct pr_keys *keys_info); + int (*pr_read_reservation)(struct mpath_device *mpath_device, + struct pr_held_reservation *rsv); +}; + struct mpath_head_template { bool (*available_path)(struct mpath_device *, bool *); int (*add_cdev)(struct mpath_head *); @@ -64,6 +81,7 @@ struct mpath_head_template { unsigned int poll_flags); enum mpath_iopolicy_e (*get_iopolicy)(struct mpath_head *); struct bio *(*clone_bio)(struct bio *); + const struct mpath_pr_ops *pr_ops; const struct attribute_group **device_groups; }; diff --git a/lib/multipath.c b/lib/multipath.c index c05b4d25ca223..8ee2d12600035 100644 --- a/lib/multipath.c +++ b/lib/multipath.c @@ -472,11 +472,157 @@ static void mpath_bdev_release(struct gendisk *disk) mpath_put_disk(mpath_disk); } +static int mpath_pr_register(struct block_device *bdev, u64 old_key, + u64 new_key, unsigned int flags) +{ + struct mpath_disk *mpath_disk = dev_get_drvdata(&bdev->bd_device); + struct mpath_head *mpath_head = mpath_disk->mpath_head; + struct mpath_device *mpath_device; + int srcu_idx, ret = -EWOULDBLOCK; + + srcu_idx = srcu_read_lock(&mpath_head->srcu); + mpath_device = mpath_find_path(mpath_head); + if (mpath_device) + ret = mpath_head->mpdt->pr_ops->pr_register(mpath_device, + old_key, new_key, flags); + srcu_read_unlock(&mpath_head->srcu, srcu_idx); + + return ret; +} + +static int mpath_pr_reserve(struct block_device *bdev, u64 key, + enum pr_type type, unsigned flags) +{ + struct mpath_disk *mpath_disk = dev_get_drvdata(&bdev->bd_device); + struct mpath_head *mpath_head = mpath_disk->mpath_head; + struct mpath_device *mpath_device; + int srcu_idx, ret = -EWOULDBLOCK; + + srcu_idx = srcu_read_lock(&mpath_head->srcu); + mpath_device = mpath_find_path(mpath_head); + + if (mpath_device) + ret = mpath_head->mpdt->pr_ops->pr_reserve(mpath_device, key, + type, flags); + + srcu_read_unlock(&mpath_head->srcu, srcu_idx); + + return ret; +} + +static int mpath_pr_release(struct block_device *bdev, u64 key, enum pr_type type) +{ + struct mpath_disk *mpath_disk = dev_get_drvdata(&bdev->bd_device); + struct mpath_head *mpath_head = mpath_disk->mpath_head; + struct mpath_device *mpath_device; + int srcu_idx, ret = -EWOULDBLOCK; + + srcu_idx = srcu_read_lock(&mpath_head->srcu); + mpath_device = mpath_find_path(mpath_head); + + if (mpath_device) + ret = mpath_head->mpdt->pr_ops->pr_release(mpath_device, key, + type); + + srcu_read_unlock(&mpath_head->srcu, srcu_idx); + + return ret; +} + +static int mpath_pr_preempt(struct block_device *bdev, u64 old, u64 new, + enum pr_type type, bool abort) +{ + struct mpath_disk *mpath_disk = dev_get_drvdata(&bdev->bd_device); + struct mpath_head *mpath_head = mpath_disk->mpath_head; + struct mpath_device *mpath_device; + int srcu_idx, ret = -EWOULDBLOCK; + + srcu_idx = srcu_read_lock(&mpath_head->srcu); + mpath_device = mpath_find_path(mpath_head); + + if (mpath_device) + ret = mpath_head->mpdt->pr_ops->pr_preempt(mpath_device, old, + new, type, abort); + + srcu_read_unlock(&mpath_head->srcu, srcu_idx); + + return ret; +} + +static int mpath_pr_clear(struct block_device *bdev, u64 key) +{ + struct mpath_disk *mpath_disk = dev_get_drvdata(&bdev->bd_device); + struct mpath_head *mpath_head = mpath_disk->mpath_head; + struct mpath_device *mpath_device; + int srcu_idx, ret = -EWOULDBLOCK; + + srcu_idx = srcu_read_lock(&mpath_head->srcu); + mpath_device = mpath_find_path(mpath_head); + + if (mpath_device) + ret = mpath_head->mpdt->pr_ops->pr_clear(mpath_device, key); + + srcu_read_unlock(&mpath_head->srcu, srcu_idx); + + return ret; +} + +static int mpath_pr_read_keys(struct block_device *bdev, + struct pr_keys *keys_info) +{ + struct mpath_disk *mpath_disk = dev_get_drvdata(&bdev->bd_device); + struct mpath_head *mpath_head = mpath_disk->mpath_head; + struct mpath_device *mpath_device; + int srcu_idx, ret = -EWOULDBLOCK; + + srcu_idx = srcu_read_lock(&mpath_head->srcu); + mpath_device = mpath_find_path(mpath_head); + + if (mpath_device) + ret = mpath_head->mpdt->pr_ops->pr_read_keys(mpath_device, + keys_info); + + srcu_read_unlock(&mpath_head->srcu, srcu_idx); + + return ret; +} + +static int mpath_pr_read_reservation(struct block_device *bdev, + struct pr_held_reservation *resv) +{ + struct mpath_disk *mpath_disk = dev_get_drvdata(&bdev->bd_device); + struct mpath_head *mpath_head = mpath_disk->mpath_head; + struct mpath_device *mpath_device; + int srcu_idx, ret = -EWOULDBLOCK; + + srcu_idx = srcu_read_lock(&mpath_head->srcu); + mpath_device = mpath_find_path(mpath_head); + + if (mpath_device) + ret = mpath_head->mpdt->pr_ops->pr_read_reservation( + mpath_device, resv); + + srcu_read_unlock(&mpath_head->srcu, srcu_idx); + + return ret; +} + +static const struct pr_ops mpath_pr_ops = { + .pr_register = mpath_pr_register, + .pr_reserve = mpath_pr_reserve, + .pr_release = mpath_pr_release, + .pr_preempt = mpath_pr_preempt, + .pr_clear = mpath_pr_clear, + .pr_read_keys = mpath_pr_read_keys, + .pr_read_reservation = mpath_pr_read_reservation, +}; + const struct block_device_operations mpath_ops = { .owner = THIS_MODULE, .open = mpath_bdev_open, .release = mpath_bdev_release, .submit_bio = mpath_bdev_submit_bio, + .pr_ops = &mpath_pr_ops, }; EXPORT_SYMBOL_GPL(mpath_ops); -- 2.43.5

