Make it possible for the exclusive holder of a block device to mark it as about to be closed and exclusive ownership given up. Any concurrent opener trying to claim the device with the same holder ops can wait until the device is free to be reclaimed. Requiring the same holder ops makes it possible to easily define groups of openers that can wait for each other. Signed-off-by: Christian Brauner <brauner@xxxxxxxxxx> --- block/bdev.c | 20 ++++++++++++++++++++ include/linux/blk_types.h | 1 + include/linux/blkdev.h | 1 + 3 files changed, 22 insertions(+) diff --git a/block/bdev.c b/block/bdev.c index 7d19e04a8df8..943c7a188bb3 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -469,6 +469,11 @@ static bool bd_may_claim(struct block_device *bdev, void *holder, return false; return true; } + + if ((whole->bd_claim == BD_CLAIM_YIELD) && + (bdev->bd_holder_ops == hops)) + return true; + return false; } @@ -608,6 +613,7 @@ static void bd_end_claim(struct block_device *bdev, void *holder) mutex_unlock(&bdev->bd_holder_lock); if (bdev->bd_write_holder) unblock = true; + bd_clear_claiming(whole); } if (!whole->bd_holders) whole->bd_holder = NULL; @@ -954,6 +960,20 @@ void bdev_release(struct bdev_handle *handle) } EXPORT_SYMBOL(bdev_release); +void bdev_yield(struct bdev_handle *handle) +{ + struct block_device *bdev = handle->bdev; + struct block_device *whole = bdev_whole(bdev); + + mutex_lock(&bdev_lock); + WARN_ON_ONCE(bdev->bd_holders == 0); + WARN_ON_ONCE(bdev->bd_holder != handle->holder); + WARN_ON_ONCE(whole->bd_claim); + whole->bd_claim = BD_CLAIM_YIELD; + mutex_unlock(&bdev_lock); +} +EXPORT_SYMBOL(bdev_yield); + /** * lookup_bdev() - Look up a struct block_device by name. * @pathname: Name of the block device in the filesystem. diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index cbef041fd868..54cf274a436c 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -40,6 +40,7 @@ struct bio_crypt_ctx; enum bd_claim { BD_CLAIM_DEFAULT = 0, BD_CLAIM_ACQUIRE = 1, + BD_CLAIM_YIELD = 2, }; struct block_device { diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index abf71cce785c..b15129afcdbe 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1513,6 +1513,7 @@ int bd_prepare_to_claim(struct block_device *bdev, void *holder, void bd_abort_claiming(struct block_device *bdev, void *holder); void blkdev_put(struct block_device *bdev, void *holder); void bdev_release(struct bdev_handle *handle); +void bdev_yield(struct bdev_handle *handle); /* just for blk-cgroup, don't use elsewhere */ struct block_device *blkdev_get_no_open(dev_t dev); -- 2.34.1