Message ID | 20210525022539.119661-7-damien.lemoal@wdc.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | dm: Improve zoned block device support | expand |
On 5/24/21 9:25 PM, Damien Le Moal wrote: > Move core and table code used for zoned targets and conditionally > defined with #ifdef CONFIG_BLK_DEV_ZONED to the new file dm-zone.c. > This file is conditionally compiled depending on CONFIG_BLK_DEV_ZONED. > The small helper dm_set_zones_restrictions() is introduced to > initialize a mapped device request queue zone attributes in > dm_table_set_restrictions(). > > Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> > Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> > Reviewed-by: Hannes Reinecke <hare@suse.de> > --- > drivers/md/Makefile | 4 ++ > drivers/md/dm-table.c | 14 ++---- > drivers/md/dm-zone.c | 102 ++++++++++++++++++++++++++++++++++++++++++ > drivers/md/dm.c | 78 -------------------------------- > drivers/md/dm.h | 11 +++++ > 5 files changed, 120 insertions(+), 89 deletions(-) > create mode 100644 drivers/md/dm-zone.c > > diff --git a/drivers/md/Makefile b/drivers/md/Makefile > index ef7ddc27685c..a74aaf8b1445 100644 > --- a/drivers/md/Makefile > +++ b/drivers/md/Makefile > @@ -92,6 +92,10 @@ ifeq ($(CONFIG_DM_UEVENT),y) > dm-mod-objs += dm-uevent.o > endif > > +ifeq ($(CONFIG_BLK_DEV_ZONED),y) > +dm-mod-objs += dm-zone.o > +endif > + > ifeq ($(CONFIG_DM_VERITY_FEC),y) > dm-verity-objs += dm-verity-fec.o > endif > diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c > index 21fd9cd4da32..dd9f648ab598 100644 > --- a/drivers/md/dm-table.c > +++ b/drivers/md/dm-table.c > @@ -2064,17 +2064,9 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, > dm_table_any_dev_attr(t, device_is_not_random, NULL)) > blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q); > > - /* > - * For a zoned target, the number of zones should be updated for the > - * correct value to be exposed in sysfs queue/nr_zones. For a BIO based > - * target, this is all that is needed. > - */ > -#ifdef CONFIG_BLK_DEV_ZONED > - if (blk_queue_is_zoned(q)) { > - WARN_ON_ONCE(queue_is_mq(q)); > - q->nr_zones = blkdev_nr_zones(t->md->disk); > - } > -#endif > + /* For a zoned target, setup the zones related queue attributes */ > + if (blk_queue_is_zoned(q)) > + dm_set_zones_restrictions(t, q); > > dm_update_keyslot_manager(q, t); > blk_queue_update_readahead(q); > diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c > new file mode 100644 > index 000000000000..3243c42b7951 > --- /dev/null > +++ b/drivers/md/dm-zone.c > @@ -0,0 +1,102 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (C) 2021 Western Digital Corporation or its affiliates. > + */ > + > +#include <linux/blkdev.h> > + > +#include "dm-core.h" > + > +/* > + * User facing dm device block device report zone operation. This calls the > + * report_zones operation for each target of a device table. This operation is > + * generally implemented by targets using dm_report_zones(). > + */ > +int dm_blk_report_zones(struct gendisk *disk, sector_t sector, > + unsigned int nr_zones, report_zones_cb cb, void *data) > +{ > + struct mapped_device *md = disk->private_data; > + struct dm_table *map; > + int srcu_idx, ret; > + struct dm_report_zones_args args = { > + .next_sector = sector, > + .orig_data = data, > + .orig_cb = cb, > + }; > + > + if (dm_suspended_md(md)) > + return -EAGAIN; > + > + map = dm_get_live_table(md, &srcu_idx); > + if (!map) { > + ret = -EIO; > + goto out; > + } > + > + do { > + struct dm_target *tgt; > + > + tgt = dm_table_find_target(map, args.next_sector); > + if (WARN_ON_ONCE(!tgt->type->report_zones)) { > + ret = -EIO; > + goto out; > + } > + > + args.tgt = tgt; > + ret = tgt->type->report_zones(tgt, &args, > + nr_zones - args.zone_idx); > + if (ret < 0) > + goto out; > + } while (args.zone_idx < nr_zones && > + args.next_sector < get_capacity(disk)); > + > + ret = args.zone_idx; > +out: > + dm_put_live_table(md, srcu_idx); > + return ret; > +} > + > +int dm_report_zones_cb(struct blk_zone *zone, unsigned int idx, void *data) > +{ > + struct dm_report_zones_args *args = data; > + sector_t sector_diff = args->tgt->begin - args->start; > + > + /* > + * Ignore zones beyond the target range. > + */ > + if (zone->start >= args->start + args->tgt->len) > + return 0; > + > + /* > + * Remap the start sector and write pointer position of the zone > + * to match its position in the target range. > + */ > + zone->start += sector_diff; > + if (zone->type != BLK_ZONE_TYPE_CONVENTIONAL) { > + if (zone->cond == BLK_ZONE_COND_FULL) > + zone->wp = zone->start + zone->len; > + else if (zone->cond == BLK_ZONE_COND_EMPTY) > + zone->wp = zone->start; > + else > + zone->wp += sector_diff; > + } > + > + args->next_sector = zone->start + zone->len; > + return args->orig_cb(zone, args->zone_idx++, args->orig_data); > +} > +EXPORT_SYMBOL_GPL(dm_report_zones_cb); > + > +void dm_set_zones_restrictions(struct dm_table *t, struct request_queue *q) > +{ > + if (!blk_queue_is_zoned(q)) > + return; > + > + /* > + * For a zoned target, the number of zones should be updated for the > + * correct value to be exposed in sysfs queue/nr_zones. For a BIO based > + * target, this is all that is needed. > + */ > + WARN_ON_ONCE(queue_is_mq(q)); > + q->nr_zones = blkdev_nr_zones(t->md->disk); > +} > + > diff --git a/drivers/md/dm.c b/drivers/md/dm.c > index a9211575bfed..45d2dc2ee844 100644 > --- a/drivers/md/dm.c > +++ b/drivers/md/dm.c > @@ -444,84 +444,6 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) > return dm_get_geometry(md, geo); > } > > -#ifdef CONFIG_BLK_DEV_ZONED > -int dm_report_zones_cb(struct blk_zone *zone, unsigned int idx, void *data) > -{ > - struct dm_report_zones_args *args = data; > - sector_t sector_diff = args->tgt->begin - args->start; > - > - /* > - * Ignore zones beyond the target range. > - */ > - if (zone->start >= args->start + args->tgt->len) > - return 0; > - > - /* > - * Remap the start sector and write pointer position of the zone > - * to match its position in the target range. > - */ > - zone->start += sector_diff; > - if (zone->type != BLK_ZONE_TYPE_CONVENTIONAL) { > - if (zone->cond == BLK_ZONE_COND_FULL) > - zone->wp = zone->start + zone->len; > - else if (zone->cond == BLK_ZONE_COND_EMPTY) > - zone->wp = zone->start; > - else > - zone->wp += sector_diff; > - } > - > - args->next_sector = zone->start + zone->len; > - return args->orig_cb(zone, args->zone_idx++, args->orig_data); > -} > -EXPORT_SYMBOL_GPL(dm_report_zones_cb); > - > -static int dm_blk_report_zones(struct gendisk *disk, sector_t sector, > - unsigned int nr_zones, report_zones_cb cb, void *data) > -{ > - struct mapped_device *md = disk->private_data; > - struct dm_table *map; > - int srcu_idx, ret; > - struct dm_report_zones_args args = { > - .next_sector = sector, > - .orig_data = data, > - .orig_cb = cb, > - }; > - > - if (dm_suspended_md(md)) > - return -EAGAIN; > - > - map = dm_get_live_table(md, &srcu_idx); > - if (!map) { > - ret = -EIO; > - goto out; > - } > - > - do { > - struct dm_target *tgt; > - > - tgt = dm_table_find_target(map, args.next_sector); > - if (WARN_ON_ONCE(!tgt->type->report_zones)) { > - ret = -EIO; > - goto out; > - } > - > - args.tgt = tgt; > - ret = tgt->type->report_zones(tgt, &args, > - nr_zones - args.zone_idx); > - if (ret < 0) > - goto out; > - } while (args.zone_idx < nr_zones && > - args.next_sector < get_capacity(disk)); > - > - ret = args.zone_idx; > -out: > - dm_put_live_table(md, srcu_idx); > - return ret; > -} > -#else > -#define dm_blk_report_zones NULL > -#endif /* CONFIG_BLK_DEV_ZONED */ > - > static int dm_prepare_ioctl(struct mapped_device *md, int *srcu_idx, > struct block_device **bdev) > { > diff --git a/drivers/md/dm.h b/drivers/md/dm.h > index b441ad772c18..fdf1536a4b62 100644 > --- a/drivers/md/dm.h > +++ b/drivers/md/dm.h > @@ -100,6 +100,17 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t); > */ > #define dm_target_hybrid(t) (dm_target_bio_based(t) && dm_target_request_based(t)) > > +/* > + * Zoned targets related functions. > + */ > +void dm_set_zones_restrictions(struct dm_table *t, struct request_queue *q); > +#ifdef CONFIG_BLK_DEV_ZONED > +int dm_blk_report_zones(struct gendisk *disk, sector_t sector, > + unsigned int nr_zones, report_zones_cb cb, void *data); > +#else > +#define dm_blk_report_zones NULL > +#endif > + > /*----------------------------------------------------------------- > * A registry of target types. > *---------------------------------------------------------------*/ > Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
diff --git a/drivers/md/Makefile b/drivers/md/Makefile index ef7ddc27685c..a74aaf8b1445 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -92,6 +92,10 @@ ifeq ($(CONFIG_DM_UEVENT),y) dm-mod-objs += dm-uevent.o endif +ifeq ($(CONFIG_BLK_DEV_ZONED),y) +dm-mod-objs += dm-zone.o +endif + ifeq ($(CONFIG_DM_VERITY_FEC),y) dm-verity-objs += dm-verity-fec.o endif diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 21fd9cd4da32..dd9f648ab598 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -2064,17 +2064,9 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, dm_table_any_dev_attr(t, device_is_not_random, NULL)) blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q); - /* - * For a zoned target, the number of zones should be updated for the - * correct value to be exposed in sysfs queue/nr_zones. For a BIO based - * target, this is all that is needed. - */ -#ifdef CONFIG_BLK_DEV_ZONED - if (blk_queue_is_zoned(q)) { - WARN_ON_ONCE(queue_is_mq(q)); - q->nr_zones = blkdev_nr_zones(t->md->disk); - } -#endif + /* For a zoned target, setup the zones related queue attributes */ + if (blk_queue_is_zoned(q)) + dm_set_zones_restrictions(t, q); dm_update_keyslot_manager(q, t); blk_queue_update_readahead(q); diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c new file mode 100644 index 000000000000..3243c42b7951 --- /dev/null +++ b/drivers/md/dm-zone.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Western Digital Corporation or its affiliates. + */ + +#include <linux/blkdev.h> + +#include "dm-core.h" + +/* + * User facing dm device block device report zone operation. This calls the + * report_zones operation for each target of a device table. This operation is + * generally implemented by targets using dm_report_zones(). + */ +int dm_blk_report_zones(struct gendisk *disk, sector_t sector, + unsigned int nr_zones, report_zones_cb cb, void *data) +{ + struct mapped_device *md = disk->private_data; + struct dm_table *map; + int srcu_idx, ret; + struct dm_report_zones_args args = { + .next_sector = sector, + .orig_data = data, + .orig_cb = cb, + }; + + if (dm_suspended_md(md)) + return -EAGAIN; + + map = dm_get_live_table(md, &srcu_idx); + if (!map) { + ret = -EIO; + goto out; + } + + do { + struct dm_target *tgt; + + tgt = dm_table_find_target(map, args.next_sector); + if (WARN_ON_ONCE(!tgt->type->report_zones)) { + ret = -EIO; + goto out; + } + + args.tgt = tgt; + ret = tgt->type->report_zones(tgt, &args, + nr_zones - args.zone_idx); + if (ret < 0) + goto out; + } while (args.zone_idx < nr_zones && + args.next_sector < get_capacity(disk)); + + ret = args.zone_idx; +out: + dm_put_live_table(md, srcu_idx); + return ret; +} + +int dm_report_zones_cb(struct blk_zone *zone, unsigned int idx, void *data) +{ + struct dm_report_zones_args *args = data; + sector_t sector_diff = args->tgt->begin - args->start; + + /* + * Ignore zones beyond the target range. + */ + if (zone->start >= args->start + args->tgt->len) + return 0; + + /* + * Remap the start sector and write pointer position of the zone + * to match its position in the target range. + */ + zone->start += sector_diff; + if (zone->type != BLK_ZONE_TYPE_CONVENTIONAL) { + if (zone->cond == BLK_ZONE_COND_FULL) + zone->wp = zone->start + zone->len; + else if (zone->cond == BLK_ZONE_COND_EMPTY) + zone->wp = zone->start; + else + zone->wp += sector_diff; + } + + args->next_sector = zone->start + zone->len; + return args->orig_cb(zone, args->zone_idx++, args->orig_data); +} +EXPORT_SYMBOL_GPL(dm_report_zones_cb); + +void dm_set_zones_restrictions(struct dm_table *t, struct request_queue *q) +{ + if (!blk_queue_is_zoned(q)) + return; + + /* + * For a zoned target, the number of zones should be updated for the + * correct value to be exposed in sysfs queue/nr_zones. For a BIO based + * target, this is all that is needed. + */ + WARN_ON_ONCE(queue_is_mq(q)); + q->nr_zones = blkdev_nr_zones(t->md->disk); +} + diff --git a/drivers/md/dm.c b/drivers/md/dm.c index a9211575bfed..45d2dc2ee844 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -444,84 +444,6 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) return dm_get_geometry(md, geo); } -#ifdef CONFIG_BLK_DEV_ZONED -int dm_report_zones_cb(struct blk_zone *zone, unsigned int idx, void *data) -{ - struct dm_report_zones_args *args = data; - sector_t sector_diff = args->tgt->begin - args->start; - - /* - * Ignore zones beyond the target range. - */ - if (zone->start >= args->start + args->tgt->len) - return 0; - - /* - * Remap the start sector and write pointer position of the zone - * to match its position in the target range. - */ - zone->start += sector_diff; - if (zone->type != BLK_ZONE_TYPE_CONVENTIONAL) { - if (zone->cond == BLK_ZONE_COND_FULL) - zone->wp = zone->start + zone->len; - else if (zone->cond == BLK_ZONE_COND_EMPTY) - zone->wp = zone->start; - else - zone->wp += sector_diff; - } - - args->next_sector = zone->start + zone->len; - return args->orig_cb(zone, args->zone_idx++, args->orig_data); -} -EXPORT_SYMBOL_GPL(dm_report_zones_cb); - -static int dm_blk_report_zones(struct gendisk *disk, sector_t sector, - unsigned int nr_zones, report_zones_cb cb, void *data) -{ - struct mapped_device *md = disk->private_data; - struct dm_table *map; - int srcu_idx, ret; - struct dm_report_zones_args args = { - .next_sector = sector, - .orig_data = data, - .orig_cb = cb, - }; - - if (dm_suspended_md(md)) - return -EAGAIN; - - map = dm_get_live_table(md, &srcu_idx); - if (!map) { - ret = -EIO; - goto out; - } - - do { - struct dm_target *tgt; - - tgt = dm_table_find_target(map, args.next_sector); - if (WARN_ON_ONCE(!tgt->type->report_zones)) { - ret = -EIO; - goto out; - } - - args.tgt = tgt; - ret = tgt->type->report_zones(tgt, &args, - nr_zones - args.zone_idx); - if (ret < 0) - goto out; - } while (args.zone_idx < nr_zones && - args.next_sector < get_capacity(disk)); - - ret = args.zone_idx; -out: - dm_put_live_table(md, srcu_idx); - return ret; -} -#else -#define dm_blk_report_zones NULL -#endif /* CONFIG_BLK_DEV_ZONED */ - static int dm_prepare_ioctl(struct mapped_device *md, int *srcu_idx, struct block_device **bdev) { diff --git a/drivers/md/dm.h b/drivers/md/dm.h index b441ad772c18..fdf1536a4b62 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -100,6 +100,17 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t); */ #define dm_target_hybrid(t) (dm_target_bio_based(t) && dm_target_request_based(t)) +/* + * Zoned targets related functions. + */ +void dm_set_zones_restrictions(struct dm_table *t, struct request_queue *q); +#ifdef CONFIG_BLK_DEV_ZONED +int dm_blk_report_zones(struct gendisk *disk, sector_t sector, + unsigned int nr_zones, report_zones_cb cb, void *data); +#else +#define dm_blk_report_zones NULL +#endif + /*----------------------------------------------------------------- * A registry of target types. *---------------------------------------------------------------*/