block: make the block holder code optional

Move the block holder code into a separate file as it is not in any way
related to the other block_dev.c code, and add a new selectable config
option for it so that we don't have to build it without any remapped
drivers selected.

The Kconfig symbol contains a _DEPRECATED suffix to match the comments
added in commit 49731baa41
("block: restore multiple bd_link_disk_holder() support").

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Mike Snitzer <snitzer@redhat.com>
Link: https://lore.kernel.org/r/20210804094147.459763-2-hch@lst.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Christoph Hellwig 2021-08-04 11:41:40 +02:00 committed by Jens Axboe
parent 2112f5c133
commit c66fd01971
8 changed files with 151 additions and 146 deletions

View File

@ -241,4 +241,8 @@ config BLK_MQ_RDMA
config BLK_PM config BLK_PM
def_bool BLOCK && PM def_bool BLOCK && PM
# do not use in new code
config BLOCK_HOLDER_DEPRECATED
bool
source "block/Kconfig.iosched" source "block/Kconfig.iosched"

View File

@ -41,3 +41,4 @@ obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o
obj-$(CONFIG_BLK_PM) += blk-pm.o obj-$(CONFIG_BLK_PM) += blk-pm.o
obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += keyslot-manager.o blk-crypto.o obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += keyslot-manager.o blk-crypto.o
obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o
obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED) += holder.o

139
block/holder.c Normal file
View File

@ -0,0 +1,139 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/genhd.h>
struct bd_holder_disk {
struct list_head list;
struct gendisk *disk;
int refcnt;
};
static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev,
struct gendisk *disk)
{
struct bd_holder_disk *holder;
list_for_each_entry(holder, &bdev->bd_holder_disks, list)
if (holder->disk == disk)
return holder;
return NULL;
}
static int add_symlink(struct kobject *from, struct kobject *to)
{
return sysfs_create_link(from, to, kobject_name(to));
}
static void del_symlink(struct kobject *from, struct kobject *to)
{
sysfs_remove_link(from, kobject_name(to));
}
/**
* bd_link_disk_holder - create symlinks between holding disk and slave bdev
* @bdev: the claimed slave bdev
* @disk: the holding disk
*
* DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
*
* This functions creates the following sysfs symlinks.
*
* - from "slaves" directory of the holder @disk to the claimed @bdev
* - from "holders" directory of the @bdev to the holder @disk
*
* For example, if /dev/dm-0 maps to /dev/sda and disk for dm-0 is
* passed to bd_link_disk_holder(), then:
*
* /sys/block/dm-0/slaves/sda --> /sys/block/sda
* /sys/block/sda/holders/dm-0 --> /sys/block/dm-0
*
* The caller must have claimed @bdev before calling this function and
* ensure that both @bdev and @disk are valid during the creation and
* lifetime of these symlinks.
*
* CONTEXT:
* Might sleep.
*
* RETURNS:
* 0 on success, -errno on failure.
*/
int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
{
struct bd_holder_disk *holder;
int ret = 0;
mutex_lock(&bdev->bd_disk->open_mutex);
WARN_ON_ONCE(!bdev->bd_holder);
/* FIXME: remove the following once add_disk() handles errors */
if (WARN_ON(!disk->slave_dir || !bdev->bd_holder_dir))
goto out_unlock;
holder = bd_find_holder_disk(bdev, disk);
if (holder) {
holder->refcnt++;
goto out_unlock;
}
holder = kzalloc(sizeof(*holder), GFP_KERNEL);
if (!holder) {
ret = -ENOMEM;
goto out_unlock;
}
INIT_LIST_HEAD(&holder->list);
holder->disk = disk;
holder->refcnt = 1;
ret = add_symlink(disk->slave_dir, bdev_kobj(bdev));
if (ret)
goto out_free;
ret = add_symlink(bdev->bd_holder_dir, &disk_to_dev(disk)->kobj);
if (ret)
goto out_del;
/*
* bdev could be deleted beneath us which would implicitly destroy
* the holder directory. Hold on to it.
*/
kobject_get(bdev->bd_holder_dir);
list_add(&holder->list, &bdev->bd_holder_disks);
goto out_unlock;
out_del:
del_symlink(disk->slave_dir, bdev_kobj(bdev));
out_free:
kfree(holder);
out_unlock:
mutex_unlock(&bdev->bd_disk->open_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(bd_link_disk_holder);
/**
* bd_unlink_disk_holder - destroy symlinks created by bd_link_disk_holder()
* @bdev: the calimed slave bdev
* @disk: the holding disk
*
* DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
*
* CONTEXT:
* Might sleep.
*/
void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
{
struct bd_holder_disk *holder;
mutex_lock(&bdev->bd_disk->open_mutex);
holder = bd_find_holder_disk(bdev, disk);
if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) {
del_symlink(disk->slave_dir, bdev_kobj(bdev));
del_symlink(bdev->bd_holder_dir, &disk_to_dev(disk)->kobj);
kobject_put(bdev->bd_holder_dir);
list_del_init(&holder->list);
kfree(holder);
}
mutex_unlock(&bdev->bd_disk->open_mutex);
}
EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);

View File

@ -15,6 +15,7 @@ if MD
config BLK_DEV_MD config BLK_DEV_MD
tristate "RAID support" tristate "RAID support"
select BLOCK_HOLDER_DEPRECATED if SYSFS
help help
This driver lets you combine several hard disk partitions into one This driver lets you combine several hard disk partitions into one
logical block device. This can be used to simply append one logical block device. This can be used to simply append one
@ -201,6 +202,7 @@ config BLK_DEV_DM_BUILTIN
config BLK_DEV_DM config BLK_DEV_DM
tristate "Device mapper support" tristate "Device mapper support"
select BLOCK_HOLDER_DEPRECATED if SYSFS
select BLK_DEV_DM_BUILTIN select BLK_DEV_DM_BUILTIN
depends on DAX || DAX=n depends on DAX || DAX=n
help help

View File

@ -2,6 +2,7 @@
config BCACHE config BCACHE
tristate "Block device as cache" tristate "Block device as cache"
select BLOCK_HOLDER_DEPRECATED if SYSFS
select CRC64 select CRC64
help help
Allows a block device to be used as cache for other devices; uses Allows a block device to be used as cache for other devices; uses

View File

@ -902,7 +902,7 @@ struct block_device *bdev_alloc(struct gendisk *disk, u8 partno)
bdev->bd_disk = disk; bdev->bd_disk = disk;
bdev->bd_partno = partno; bdev->bd_partno = partno;
bdev->bd_inode = inode; bdev->bd_inode = inode;
#ifdef CONFIG_SYSFS #ifdef CONFIG_BLOCK_HOLDER_DEPRECATED
INIT_LIST_HEAD(&bdev->bd_holder_disks); INIT_LIST_HEAD(&bdev->bd_holder_disks);
#endif #endif
bdev->bd_stats = alloc_percpu(struct disk_stats); bdev->bd_stats = alloc_percpu(struct disk_stats);
@ -1063,148 +1063,6 @@ void bd_abort_claiming(struct block_device *bdev, void *holder)
} }
EXPORT_SYMBOL(bd_abort_claiming); EXPORT_SYMBOL(bd_abort_claiming);
#ifdef CONFIG_SYSFS
struct bd_holder_disk {
struct list_head list;
struct gendisk *disk;
int refcnt;
};
static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev,
struct gendisk *disk)
{
struct bd_holder_disk *holder;
list_for_each_entry(holder, &bdev->bd_holder_disks, list)
if (holder->disk == disk)
return holder;
return NULL;
}
static int add_symlink(struct kobject *from, struct kobject *to)
{
return sysfs_create_link(from, to, kobject_name(to));
}
static void del_symlink(struct kobject *from, struct kobject *to)
{
sysfs_remove_link(from, kobject_name(to));
}
/**
* bd_link_disk_holder - create symlinks between holding disk and slave bdev
* @bdev: the claimed slave bdev
* @disk: the holding disk
*
* DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
*
* This functions creates the following sysfs symlinks.
*
* - from "slaves" directory of the holder @disk to the claimed @bdev
* - from "holders" directory of the @bdev to the holder @disk
*
* For example, if /dev/dm-0 maps to /dev/sda and disk for dm-0 is
* passed to bd_link_disk_holder(), then:
*
* /sys/block/dm-0/slaves/sda --> /sys/block/sda
* /sys/block/sda/holders/dm-0 --> /sys/block/dm-0
*
* The caller must have claimed @bdev before calling this function and
* ensure that both @bdev and @disk are valid during the creation and
* lifetime of these symlinks.
*
* CONTEXT:
* Might sleep.
*
* RETURNS:
* 0 on success, -errno on failure.
*/
int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
{
struct bd_holder_disk *holder;
int ret = 0;
mutex_lock(&bdev->bd_disk->open_mutex);
WARN_ON_ONCE(!bdev->bd_holder);
/* FIXME: remove the following once add_disk() handles errors */
if (WARN_ON(!disk->slave_dir || !bdev->bd_holder_dir))
goto out_unlock;
holder = bd_find_holder_disk(bdev, disk);
if (holder) {
holder->refcnt++;
goto out_unlock;
}
holder = kzalloc(sizeof(*holder), GFP_KERNEL);
if (!holder) {
ret = -ENOMEM;
goto out_unlock;
}
INIT_LIST_HEAD(&holder->list);
holder->disk = disk;
holder->refcnt = 1;
ret = add_symlink(disk->slave_dir, bdev_kobj(bdev));
if (ret)
goto out_free;
ret = add_symlink(bdev->bd_holder_dir, &disk_to_dev(disk)->kobj);
if (ret)
goto out_del;
/*
* bdev could be deleted beneath us which would implicitly destroy
* the holder directory. Hold on to it.
*/
kobject_get(bdev->bd_holder_dir);
list_add(&holder->list, &bdev->bd_holder_disks);
goto out_unlock;
out_del:
del_symlink(disk->slave_dir, bdev_kobj(bdev));
out_free:
kfree(holder);
out_unlock:
mutex_unlock(&bdev->bd_disk->open_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(bd_link_disk_holder);
/**
* bd_unlink_disk_holder - destroy symlinks created by bd_link_disk_holder()
* @bdev: the calimed slave bdev
* @disk: the holding disk
*
* DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
*
* CONTEXT:
* Might sleep.
*/
void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
{
struct bd_holder_disk *holder;
mutex_lock(&bdev->bd_disk->open_mutex);
holder = bd_find_holder_disk(bdev, disk);
if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) {
del_symlink(disk->slave_dir, bdev_kobj(bdev));
del_symlink(bdev->bd_holder_dir, &disk_to_dev(disk)->kobj);
kobject_put(bdev->bd_holder_dir);
list_del_init(&holder->list);
kfree(holder);
}
mutex_unlock(&bdev->bd_disk->open_mutex);
}
EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
#endif
static void blkdev_flush_mapping(struct block_device *bdev) static void blkdev_flush_mapping(struct block_device *bdev)
{ {
WARN_ON_ONCE(bdev->bd_holders); WARN_ON_ONCE(bdev->bd_holders);

View File

@ -34,7 +34,7 @@ struct block_device {
void * bd_holder; void * bd_holder;
int bd_holders; int bd_holders;
bool bd_write_holder; bool bd_write_holder;
#ifdef CONFIG_SYSFS #ifdef CONFIG_BLOCK_HOLDER_DEPRECATED
struct list_head bd_holder_disks; struct list_head bd_holder_disks;
#endif #endif
struct kobject *bd_holder_dir; struct kobject *bd_holder_dir;

View File

@ -318,7 +318,7 @@ void set_capacity(struct gendisk *disk, sector_t size);
int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long); int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long);
long compat_blkdev_ioctl(struct file *, unsigned, unsigned long); long compat_blkdev_ioctl(struct file *, unsigned, unsigned long);
#ifdef CONFIG_SYSFS #ifdef CONFIG_BLOCK_HOLDER_DEPRECATED
int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk); int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk);
void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk); void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk);
#else #else
@ -331,7 +331,7 @@ static inline void bd_unlink_disk_holder(struct block_device *bdev,
struct gendisk *disk) struct gendisk *disk)
{ {
} }
#endif /* CONFIG_SYSFS */ #endif /* CONFIG_BLOCK_HOLDER_DEPRECATED */
dev_t part_devt(struct gendisk *disk, u8 partno); dev_t part_devt(struct gendisk *disk, u8 partno);
void inc_diskseq(struct gendisk *disk); void inc_diskseq(struct gendisk *disk);