Commit 464a47f4 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-5.5/zoned-20191122' of git://git.kernel.dk/linux-block

Pull zoned block device update from Jens Axboe:
 "Enhancements and improvements to the zoned device support"

* tag 'for-5.5/zoned-20191122' of git://git.kernel.dk/linux-block:
  scsi: sd_zbc: Remove set but not used variable 'buflen'
  block: rework zone reporting
  scsi: sd_zbc: Cleanup sd_zbc_alloc_report_buffer()
  null_blk: Add zone_nr_conv to features
  null_blk: clean up report zones
  null_blk: clean up the block device operations
  block: Remove partition support for zoned block devices
  block: Simplify report zones execution
  block: cleanup the !zoned case in blk_revalidate_disk_zones
  block: Enhance blk_revalidate_disk_zones()
parents 323264ee a4681681
...@@ -851,11 +851,7 @@ static inline int blk_partition_remap(struct bio *bio) ...@@ -851,11 +851,7 @@ static inline int blk_partition_remap(struct bio *bio)
if (unlikely(bio_check_ro(bio, p))) if (unlikely(bio_check_ro(bio, p)))
goto out; goto out;
/* if (bio_sectors(bio)) {
* Zone management bios do not have a sector count but they do have
* a start sector filled out and need to be remapped.
*/
if (bio_sectors(bio) || op_is_zone_mgmt(bio_op(bio))) {
if (bio_check_eod(bio, part_nr_sects_read(p))) if (bio_check_eod(bio, part_nr_sects_read(p)))
goto out; goto out;
bio->bi_iter.bi_sector += p->start_sect; bio->bi_iter.bi_sector += p->start_sect;
......
This diff is collapsed.
...@@ -462,56 +462,6 @@ static int drop_partitions(struct gendisk *disk, struct block_device *bdev) ...@@ -462,56 +462,6 @@ static int drop_partitions(struct gendisk *disk, struct block_device *bdev)
return 0; return 0;
} }
static bool part_zone_aligned(struct gendisk *disk,
struct block_device *bdev,
sector_t from, sector_t size)
{
unsigned int zone_sectors = bdev_zone_sectors(bdev);
/*
* If this function is called, then the disk is a zoned block device
* (host-aware or host-managed). This can be detected even if the
* zoned block device support is disabled (CONFIG_BLK_DEV_ZONED not
* set). In this case, however, only host-aware devices will be seen
* as a block device is not created for host-managed devices. Without
* zoned block device support, host-aware drives can still be used as
* regular block devices (no zone operation) and their zone size will
* be reported as 0. Allow this case.
*/
if (!zone_sectors)
return true;
/*
* Check partition start and size alignement. If the drive has a
* smaller last runt zone, ignore it and allow the partition to
* use it. Check the zone size too: it should be a power of 2 number
* of sectors.
*/
if (WARN_ON_ONCE(!is_power_of_2(zone_sectors))) {
u32 rem;
div_u64_rem(from, zone_sectors, &rem);
if (rem)
return false;
if ((from + size) < get_capacity(disk)) {
div_u64_rem(size, zone_sectors, &rem);
if (rem)
return false;
}
} else {
if (from & (zone_sectors - 1))
return false;
if ((from + size) < get_capacity(disk) &&
(size & (zone_sectors - 1)))
return false;
}
return true;
}
int rescan_partitions(struct gendisk *disk, struct block_device *bdev) int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
{ {
struct parsed_partitions *state = NULL; struct parsed_partitions *state = NULL;
...@@ -547,6 +497,14 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) ...@@ -547,6 +497,14 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
} }
return -EIO; return -EIO;
} }
/* Partitions are not supported on zoned block devices */
if (bdev_is_zoned(bdev)) {
pr_warn("%s: ignoring partition table on zoned block device\n",
disk->disk_name);
goto out;
}
/* /*
* If any partition code tried to read beyond EOD, try * If any partition code tried to read beyond EOD, try
* unlocking native capacity even if partition table is * unlocking native capacity even if partition table is
...@@ -610,21 +568,6 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) ...@@ -610,21 +568,6 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
} }
} }
/*
* On a zoned block device, partitions should be aligned on the
* device zone size (i.e. zone boundary crossing not allowed).
* Otherwise, resetting the write pointer of the last zone of
* one partition may impact the following partition.
*/
if (bdev_is_zoned(bdev) &&
!part_zone_aligned(disk, bdev, from, size)) {
printk(KERN_WARNING
"%s: p%d start %llu+%llu is not zone aligned\n",
disk->disk_name, p, (unsigned long long) from,
(unsigned long long) size);
continue;
}
part = add_partition(disk, p, from, size, part = add_partition(disk, p, from, size,
state->parts[p].flags, state->parts[p].flags,
&state->parts[p].info); &state->parts[p].info);
...@@ -638,6 +581,7 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) ...@@ -638,6 +581,7 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
md_autodetect_dev(part_to_dev(part)->devt); md_autodetect_dev(part_to_dev(part)->devt);
#endif #endif
} }
out:
free_partitions(state); free_partitions(state);
return 0; return 0;
} }
......
...@@ -91,8 +91,8 @@ struct nullb { ...@@ -91,8 +91,8 @@ struct nullb {
#ifdef CONFIG_BLK_DEV_ZONED #ifdef CONFIG_BLK_DEV_ZONED
int null_zone_init(struct nullb_device *dev); int null_zone_init(struct nullb_device *dev);
void null_zone_exit(struct nullb_device *dev); void null_zone_exit(struct nullb_device *dev);
int null_zone_report(struct gendisk *disk, sector_t sector, int null_report_zones(struct gendisk *disk, sector_t sector,
struct blk_zone *zones, unsigned int *nr_zones); unsigned int nr_zones, report_zones_cb cb, void *data);
blk_status_t null_handle_zoned(struct nullb_cmd *cmd, blk_status_t null_handle_zoned(struct nullb_cmd *cmd,
enum req_opf op, sector_t sector, enum req_opf op, sector_t sector,
sector_t nr_sectors); sector_t nr_sectors);
...@@ -105,12 +105,6 @@ static inline int null_zone_init(struct nullb_device *dev) ...@@ -105,12 +105,6 @@ static inline int null_zone_init(struct nullb_device *dev)
return -EINVAL; return -EINVAL;
} }
static inline void null_zone_exit(struct nullb_device *dev) {} static inline void null_zone_exit(struct nullb_device *dev) {}
static inline int null_zone_report(struct gendisk *disk, sector_t sector,
struct blk_zone *zones,
unsigned int *nr_zones)
{
return -EOPNOTSUPP;
}
static inline blk_status_t null_handle_zoned(struct nullb_cmd *cmd, static inline blk_status_t null_handle_zoned(struct nullb_cmd *cmd,
enum req_opf op, sector_t sector, enum req_opf op, sector_t sector,
sector_t nr_sectors) sector_t nr_sectors)
...@@ -123,5 +117,6 @@ static inline size_t null_zone_valid_read_len(struct nullb *nullb, ...@@ -123,5 +117,6 @@ static inline size_t null_zone_valid_read_len(struct nullb *nullb,
{ {
return len; return len;
} }
#define null_report_zones NULL
#endif /* CONFIG_BLK_DEV_ZONED */ #endif /* CONFIG_BLK_DEV_ZONED */
#endif /* __NULL_BLK_H */ #endif /* __NULL_BLK_H */
...@@ -493,7 +493,7 @@ nullb_group_drop_item(struct config_group *group, struct config_item *item) ...@@ -493,7 +493,7 @@ nullb_group_drop_item(struct config_group *group, struct config_item *item)
static ssize_t memb_group_features_show(struct config_item *item, char *page) static ssize_t memb_group_features_show(struct config_item *item, char *page)
{ {
return snprintf(page, PAGE_SIZE, "memory_backed,discard,bandwidth,cache,badblocks,zoned,zone_size\n"); return snprintf(page, PAGE_SIZE, "memory_backed,discard,bandwidth,cache,badblocks,zoned,zone_size,zone_nr_conv\n");
} }
CONFIGFS_ATTR_RO(memb_group_, features); CONFIGFS_ATTR_RO(memb_group_, features);
...@@ -1468,20 +1468,9 @@ static void null_config_discard(struct nullb *nullb) ...@@ -1468,20 +1468,9 @@ static void null_config_discard(struct nullb *nullb)
blk_queue_flag_set(QUEUE_FLAG_DISCARD, nullb->q); blk_queue_flag_set(QUEUE_FLAG_DISCARD, nullb->q);
} }
static int null_open(struct block_device *bdev, fmode_t mode) static const struct block_device_operations null_ops = {
{
return 0;
}
static void null_release(struct gendisk *disk, fmode_t mode)
{
}
static const struct block_device_operations null_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = null_open, .report_zones = null_report_zones,
.release = null_release,
.report_zones = null_zone_report,
}; };
static void null_init_queue(struct nullb *nullb, struct nullb_queue *nq) static void null_init_queue(struct nullb *nullb, struct nullb_queue *nq)
...@@ -1582,7 +1571,7 @@ static int null_gendisk_register(struct nullb *nullb) ...@@ -1582,7 +1571,7 @@ static int null_gendisk_register(struct nullb *nullb)
disk->flags |= GENHD_FL_EXT_DEVT | GENHD_FL_SUPPRESS_PARTITION_INFO; disk->flags |= GENHD_FL_EXT_DEVT | GENHD_FL_SUPPRESS_PARTITION_INFO;
disk->major = null_major; disk->major = null_major;
disk->first_minor = nullb->index; disk->first_minor = nullb->index;
disk->fops = &null_fops; disk->fops = &null_ops;
disk->private_data = nullb; disk->private_data = nullb;
disk->queue = nullb->q; disk->queue = nullb->q;
strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN); strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN);
......
...@@ -66,22 +66,35 @@ void null_zone_exit(struct nullb_device *dev) ...@@ -66,22 +66,35 @@ void null_zone_exit(struct nullb_device *dev)
kvfree(dev->zones); kvfree(dev->zones);
} }
int null_zone_report(struct gendisk *disk, sector_t sector, int null_report_zones(struct gendisk *disk, sector_t sector,
struct blk_zone *zones, unsigned int *nr_zones) unsigned int nr_zones, report_zones_cb cb, void *data)
{ {
struct nullb *nullb = disk->private_data; struct nullb *nullb = disk->private_data;
struct nullb_device *dev = nullb->dev; struct nullb_device *dev = nullb->dev;
unsigned int zno, nrz = 0; unsigned int first_zone, i;
struct blk_zone zone;
int error;
zno = null_zone_no(dev, sector); first_zone = null_zone_no(dev, sector);
if (zno < dev->nr_zones) { if (first_zone >= dev->nr_zones)
nrz = min_t(unsigned int, *nr_zones, dev->nr_zones - zno); return 0;
memcpy(zones, &dev->zones[zno], nrz * sizeof(struct blk_zone));
}
*nr_zones = nrz; nr_zones = min(nr_zones, dev->nr_zones - first_zone);
for (i = 0; i < nr_zones; i++) {
/*
* Stacked DM target drivers will remap the zone information by
* modifying the zone information passed to the report callback.
* So use a local copy to avoid corruption of the device zone
* array.
*/
memcpy(&zone, &dev->zones[first_zone + i],
sizeof(struct blk_zone));
error = cb(&zone, i, data);
if (error)
return error;
}
return 0; return nr_zones;
} }
size_t null_zone_valid_read_len(struct nullb *nullb, size_t null_zone_valid_read_len(struct nullb *nullb,
......
...@@ -459,21 +459,15 @@ static int flakey_prepare_ioctl(struct dm_target *ti, struct block_device **bdev ...@@ -459,21 +459,15 @@ static int flakey_prepare_ioctl(struct dm_target *ti, struct block_device **bdev
} }
#ifdef CONFIG_BLK_DEV_ZONED #ifdef CONFIG_BLK_DEV_ZONED
static int flakey_report_zones(struct dm_target *ti, sector_t sector, static int flakey_report_zones(struct dm_target *ti,
struct blk_zone *zones, unsigned int *nr_zones) struct dm_report_zones_args *args, unsigned int nr_zones)
{ {
struct flakey_c *fc = ti->private; struct flakey_c *fc = ti->private;
int ret; sector_t sector = flakey_map_sector(ti, args->next_sector);
/* Do report and remap it */ args->start = fc->start;
ret = blkdev_report_zones(fc->dev->bdev, flakey_map_sector(ti, sector), return blkdev_report_zones(fc->dev->bdev, sector, nr_zones,
zones, nr_zones); dm_report_zones_cb, args);
if (ret != 0)
return ret;
if (*nr_zones)
dm_remap_zone_report(ti, fc->start, zones, nr_zones);
return 0;
} }
#endif #endif
......
...@@ -136,21 +136,15 @@ static int linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev ...@@ -136,21 +136,15 @@ static int linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev
} }
#ifdef CONFIG_BLK_DEV_ZONED #ifdef CONFIG_BLK_DEV_ZONED
static int linear_report_zones(struct dm_target *ti, sector_t sector, static int linear_report_zones(struct dm_target *ti,
struct blk_zone *zones, unsigned int *nr_zones) struct dm_report_zones_args *args, unsigned int nr_zones)
{ {
struct linear_c *lc = (struct linear_c *) ti->private; struct linear_c *lc = ti->private;
int ret; sector_t sector = linear_map_sector(ti, args->next_sector);
/* Do report and remap it */
ret = blkdev_report_zones(lc->dev->bdev, linear_map_sector(ti, sector),
zones, nr_zones);
if (ret != 0)
return ret;
if (*nr_zones) args->start = lc->start;
dm_remap_zone_report(ti, lc->start, zones, nr_zones); return blkdev_report_zones(lc->dev->bdev, sector, nr_zones,
return 0; dm_report_zones_cb, args);
} }
#endif #endif
......
...@@ -1080,9 +1080,10 @@ static int dmz_load_sb(struct dmz_metadata *zmd) ...@@ -1080,9 +1080,10 @@ static int dmz_load_sb(struct dmz_metadata *zmd)
/* /*
* Initialize a zone descriptor. * Initialize a zone descriptor.
*/ */
static int dmz_init_zone(struct dmz_metadata *zmd, struct dm_zone *zone, static int dmz_init_zone(struct blk_zone *blkz, unsigned int idx, void *data)
struct blk_zone *blkz)
{ {
struct dmz_metadata *zmd = data;
struct dm_zone *zone = &zmd->zones[idx];
struct dmz_dev *dev = zmd->dev; struct dmz_dev *dev = zmd->dev;
/* Ignore the eventual last runt (smaller) zone */ /* Ignore the eventual last runt (smaller) zone */
...@@ -1096,26 +1097,29 @@ static int dmz_init_zone(struct dmz_metadata *zmd, struct dm_zone *zone, ...@@ -1096,26 +1097,29 @@ static int dmz_init_zone(struct dmz_metadata *zmd, struct dm_zone *zone,
atomic_set(&zone->refcount, 0); atomic_set(&zone->refcount, 0);
zone->chunk = DMZ_MAP_UNMAPPED; zone->chunk = DMZ_MAP_UNMAPPED;
if (blkz->type == BLK_ZONE_TYPE_CONVENTIONAL) { switch (blkz->type) {
case BLK_ZONE_TYPE_CONVENTIONAL:
set_bit(DMZ_RND, &zone->flags); set_bit(DMZ_RND, &zone->flags);
zmd->nr_rnd_zones++; zmd->nr_rnd_zones++;
} else if (blkz->type == BLK_ZONE_TYPE_SEQWRITE_REQ || break;
blkz->type == BLK_ZONE_TYPE_SEQWRITE_PREF) { case BLK_ZONE_TYPE_SEQWRITE_REQ:
case BLK_ZONE_TYPE_SEQWRITE_PREF:
set_bit(DMZ_SEQ, &zone->flags); set_bit(DMZ_SEQ, &zone->flags);
} else break;
default:
return -ENXIO; return -ENXIO;
}
if (blkz->cond == BLK_ZONE_COND_OFFLINE)
set_bit(DMZ_OFFLINE, &zone->flags);
else if (blkz->cond == BLK_ZONE_COND_READONLY)
set_bit(DMZ_READ_ONLY, &zone->flags);
if (dmz_is_rnd(zone)) if (dmz_is_rnd(zone))
zone->wp_block = 0; zone->wp_block = 0;
else else
zone->wp_block = dmz_sect2blk(blkz->wp - blkz->start); zone->wp_block = dmz_sect2blk(blkz->wp - blkz->start);
if (!dmz_is_offline(zone) && !dmz_is_readonly(zone)) { if (blkz->cond == BLK_ZONE_COND_OFFLINE)
set_bit(DMZ_OFFLINE, &zone->flags);
else if (blkz->cond == BLK_ZONE_COND_READONLY)
set_bit(DMZ_READ_ONLY, &zone->flags);
else {
zmd->nr_useable_zones++; zmd->nr_useable_zones++;
if (dmz_is_rnd(zone)) { if (dmz_is_rnd(zone)) {
zmd->nr_rnd_zones++; zmd->nr_rnd_zones++;
...@@ -1138,12 +1142,6 @@ static void dmz_drop_zones(struct dmz_metadata *zmd) ...@@ -1138,12 +1142,6 @@ static void dmz_drop_zones(struct dmz_metadata *zmd)
zmd->zones = NULL; zmd->zones = NULL;
} }
/*
* The size of a zone report in number of zones.
* This results in 4096*64B=256KB report zones commands.
*/
#define DMZ_REPORT_NR_ZONES 4096
/* /*
* Allocate and initialize zone descriptors using the zone * Allocate and initialize zone descriptors using the zone
* information from disk. * information from disk.
...@@ -1151,11 +1149,7 @@ static void dmz_drop_zones(struct dmz_metadata *zmd) ...@@ -1151,11 +1149,7 @@ static void dmz_drop_zones(struct dmz_metadata *zmd)
static int dmz_init_zones(struct dmz_metadata *zmd) static int dmz_init_zones(struct dmz_metadata *zmd)
{ {
struct dmz_dev *dev = zmd->dev; struct dmz_dev *dev = zmd->dev;
struct dm_zone *zone; int ret;
struct blk_zone *blkz;
unsigned int nr_blkz;
sector_t sector = 0;
int i, ret = 0;
/* Init */ /* Init */
zmd->zone_bitmap_size = dev->zone_nr_blocks >> 3; zmd->zone_bitmap_size = dev->zone_nr_blocks >> 3;
...@@ -1169,54 +1163,38 @@ static int dmz_init_zones(struct dmz_metadata *zmd) ...@@ -1169,54 +1163,38 @@ static int dmz_init_zones(struct dmz_metadata *zmd)
dmz_dev_info(dev, "Using %zu B for zone information", dmz_dev_info(dev, "Using %zu B for zone information",
sizeof(struct dm_zone) * dev->nr_zones); sizeof(struct dm_zone) * dev->nr_zones);
/* Get zone information */
nr_blkz = DMZ_REPORT_NR_ZONES;
blkz = kcalloc(nr_blkz, sizeof(struct blk_zone), GFP_KERNEL);
if (!blkz) {
ret = -ENOMEM;
goto out;
}
/* /*
* Get zone information and initialize zone descriptors. * Get zone information and initialize zone descriptors. At the same
* At the same time, determine where the super block * time, determine where the super block should be: first block of the
* should be: first block of the first randomly writable * first randomly writable zone.
* zone. */
*/ ret = blkdev_report_zones(dev->bdev, 0, BLK_ALL_ZONES, dmz_init_zone,
zone = zmd->zones; zmd);
while (sector < dev->capacity) { if (ret < 0) {
/* Get zone information */ dmz_drop_zones(zmd);
nr_blkz = DMZ_REPORT_NR_ZONES; return ret;
ret = blkdev_report_zones(dev->bdev, sector, blkz, &nr_blkz);
if (ret) {
dmz_dev_err(dev, "Report zones failed %d", ret);
goto out;
} }
if (!nr_blkz) return 0;
break; }
/* Process report */ static int dmz_update_zone_cb(struct blk_zone *blkz, unsigned int idx,
for (i = 0; i < nr_blkz; i++) { void *data)
ret = dmz_init_zone(zmd, zone, &blkz[i]); {
if (ret) struct dm_zone *zone = data;
goto out;
sector += dev->zone_nr_sectors;
zone++;
}
}
/* The entire zone configuration of the disk should now be known */ clear_bit(DMZ_OFFLINE, &zone->flags);
if (sector < dev->capacity) { clear_bit(DMZ_READ_ONLY, &zone->flags);
dmz_dev_err(dev, "Failed to get correct zone information"); if (blkz->cond == BLK_ZONE_COND_OFFLINE)
ret = -ENXIO; set_bit(DMZ_OFFLINE, &zone->flags);
} else if (blkz->cond == BLK_ZONE_COND_READONLY)
out: set_bit(DMZ_READ_ONLY, &zone->flags);
kfree(blkz);
if (ret)
dmz_drop_zones(zmd);
return ret; if (dmz_is_seq(zone))
zone->wp_block = dmz_sect2blk(blkz->wp - blkz->start);
else
zone->wp_block = 0;
return 0;
} }
/* /*
...@@ -1224,9 +1202,7 @@ static int dmz_init_zones(struct dmz_metadata *zmd) ...@@ -1224,9 +1202,7 @@ static int dmz_init_zones(struct dmz_metadata *zmd)
*/ */
static int dmz_update_zone(struct dmz_metadata *zmd, struct dm_zone *zone) static int dmz_update_zone(struct dmz_metadata *zmd, struct dm_zone *zone)
{ {
unsigned int nr_blkz = 1;
unsigned int noio_flag; unsigned int noio_flag;
struct blk_zone blkz;
int ret; int ret;
/* /*
...@@ -1236,29 +1212,18 @@ static int dmz_update_zone(struct dmz_metadata *zmd, struct dm_zone *zone) ...@@ -1236,29 +1212,18 @@ static int dmz_update_zone(struct dmz_metadata *zmd, struct dm_zone *zone)
* GFP_NOIO was specified. * GFP_NOIO was specified.
*/ */
noio_flag = memalloc_noio_save(); noio_flag = memalloc_noio_save();
ret = blkdev_report_zones(zmd->dev->bdev, dmz_start_sect(zmd, zone), ret = blkdev_report_zones(zmd->dev->bdev, dmz_start_sect(zmd, zone), 1,
&blkz, &nr_blkz); dmz_update_zone_cb, zone);
memalloc_noio_restore(noio_flag); memalloc_noio_restore(noio_flag);
if (!nr_blkz)
if (ret == 0)
ret = -EIO; ret = -EIO;
if (ret) { if (ret < 0) {
dmz_dev_err(zmd->dev, "Get zone %u report failed", dmz_dev_err(zmd->dev, "Get zone %u report failed",
dmz_id(zmd, zone)); dmz_id(zmd, zone));
return ret; return ret;
} }
clear_bit(DMZ_OFFLINE, &zone->flags);
clear_bit(DMZ_READ_ONLY, &zone->flags);
if (blkz.cond == BLK_ZONE_COND_OFFLINE)
set_bit(DMZ_OFFLINE, &zone->flags);
else if (blkz.cond == BLK_ZONE_COND_READONLY)
set_bit(DMZ_READ_ONLY, &zone->flags);
if (dmz_is_seq(zone))
zone->wp_block = dmz_sect2blk(blkz.wp - blkz.start);
else
zone->wp_block = 0;
return 0; return 0;
} }
......
...@@ -440,14 +440,48 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) ...@@ -440,14 +440,48 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return dm_get_geometry(md, 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, static int dm_blk_report_zones(struct gendisk *disk, sector_t sector,
struct blk_zone *zones, unsigned int *nr_zones) unsigned int nr_zones, report_zones_cb cb, void *data)
{ {
#ifdef CONFIG_BLK_DEV_ZONED
struct mapped_device *md = disk->private_data; struct mapped_device *md = disk->private_data;
struct dm_target *tgt;
struct dm_table *map; struct dm_table *map;
int srcu_idx, ret; int srcu_idx, ret;
struct dm_report_zones_args args = {
.next_sector = sector,
.orig_data = data,
.orig_cb = cb,
};
if (dm_suspended_md(md)) if (dm_suspended_md(md))
return -EAGAIN; return -EAGAIN;
...@@ -456,38 +490,30 @@ static int dm_blk_report_zones(struct gendisk *disk, sector_t sector, ...@@ -456,38 +490,30 @@ static int dm_blk_report_zones(struct gendisk *disk, sector_t sector,
if (!map) if (!map)
return -EIO; return -EIO;
tgt = dm_table_find_target(map, sector); do {
if (!tgt) { struct dm_target *tgt;
ret = -EIO;
goto out;
}
/* tgt = dm_table_find_target(map, args.next_sector);
* If we are executing this, we already know that the block device if (WARN_ON_ONCE(!tgt->type->report_zones)) {
* is a zoned device and so each target should have support for that
* type of drive. A missing report_zones method means that the target
* driver has a problem.
*/
if (WARN_ON(!tgt->type->report_zones)) {
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
/* args.tgt = tgt;
* blkdev_report_zones() will loop and call this again to cover all the ret = tgt->type->report_zones(tgt, &args, nr_zones);
* zones of the target, eventually moving on to the next target. if (ret < 0)
* So there is no need to loop here trying to fill the entire array goto out;
* of zones. } while (args.zone_idx < nr_zones &&
*/ args.next_sector < get_capacity(disk));
ret = tgt->type->report_zones(tgt, sector, zones, nr_zones);
ret = args.zone_idx;
out: out:
dm_put_live_table(md, srcu_idx); dm_put_live_table(md, srcu_idx);
return ret; return ret;
#else
return -ENOTSUPP;
#endif
} }
#else
#define dm_blk_report_zones NULL
#endif /* CONFIG_BLK_DEV_ZONED */
static int dm_prepare_ioctl(struct mapped_device *md, int *srcu_idx, static int dm_prepare_ioctl(struct mapped_device *md, int *srcu_idx,
struct block_device **bdev) struct block_device **bdev)
...@@ -1213,54 +1239,6 @@ void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors) ...@@ -1213,54 +1239,6 @@ void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors)
} }
EXPORT_SYMBOL_GPL(dm_accept_partial_bio); EXPORT_SYMBOL_GPL(dm_accept_partial_bio);
/*
* The zone descriptors obtained with a zone report indicate
* zone positions within the underlying device of the target. The zone
* descriptors must be remapped to match their position within the dm device.
* The caller target should obtain the zones information using
* blkdev_report_zones() to ensure that remapping for partition offset is
* already handled.
*/
void dm_remap_zone_report(struct dm_target *ti, sector_t start,
struct blk_zone *zones, unsigned int *nr_zones)
{
#ifdef CONFIG_BLK_DEV_ZONED
struct blk_zone *zone;
unsigned int nrz = *nr_zones;
int i;
/*
* Remap the start sector and write pointer position of the zones in
* the array. Since we may have obtained from the target underlying
* device more zones that the target size, also adjust the number
* of zones.
*/
for (i = 0; i < nrz; i++) {
zone = zones + i;
if (zone->start >= start + ti->len) {
memset(zone, 0, sizeof(struct blk_zone) * (nrz - i));
break;
}
zone->start = zone->start + ti->begin - start;
if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
continue;
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 = zone->wp + ti->begin - start;
}
*nr_zones = i;
#else /* !CONFIG_BLK_DEV_ZONED */
*nr_zones = 0;
#endif
}
EXPORT_SYMBOL_GPL(dm_remap_zone_report);
static blk_qc_t __map_bio(struct dm_target_io *tio) static blk_qc_t __map_bio(struct dm_target_io *tio)
{ {
int r; int r;
......
...@@ -213,8 +213,8 @@ blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd, ...@@ -213,8 +213,8 @@ blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd,
unsigned char op, bool all); unsigned char op, bool all);
extern void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes, extern void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes,
struct scsi_sense_hdr *sshdr); struct scsi_sense_hdr *sshdr);
extern int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
struct blk_zone *zones, unsigned int *nr_zones); unsigned int nr_zones, report_zones_cb cb, void *data);
#else /* CONFIG_BLK_DEV_ZONED */ #else /* CONFIG_BLK_DEV_ZONED */
......
...@@ -19,34 +19,27 @@ ...@@ -19,34 +19,27 @@
#include "sd.h" #include "sd.h"
/** static int sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf,
* sd_zbc_parse_report - Convert a zone descriptor to a struct blk_zone, unsigned int idx, report_zones_cb cb, void *data)
* @sdkp: The disk the report originated from
* @buf: Address of the report zone descriptor
* @zone: the destination zone structure
*
* All LBA sized values are converted to 512B sectors unit.
*/
static void sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf,
struct blk_zone *zone)
{ {
struct scsi_device *sdp = sdkp->device; struct scsi_device *sdp = sdkp->device;
struct blk_zone zone = { 0 };
memset(zone, 0, sizeof(struct blk_zone)); zone.type = buf[0] & 0x0f;
zone.cond = (buf[1] >> 4) & 0xf;
zone->type = buf[0] & 0x0f;
zone->cond = (buf[1] >> 4) & 0xf;
if (buf[1] & 0x01) if (buf[1] & 0x01)
zone->reset = 1; zone.reset = 1;
if (buf[1] & 0x02) if (buf[1] & 0x02)
zone->non_seq = 1; zone.non_seq = 1;
zone->len = logical_to_sectors(sdp, get_unaligned_be64(&buf[8])); zone.len = logical_to_sectors(sdp, get_unaligned_be64(&buf[8]));
zone->start = logical_to_sectors(sdp, get_unaligned_be64(&buf[16])); zone.start = logical_to_sectors(sdp, get_unaligned_be64(&buf[16]));
zone->wp = logical_to_sectors(sdp, get_unaligned_be64(&buf[24])); zone.wp = logical_to_sectors(sdp, get_unaligned_be64(&buf[24]));
if (zone->type != ZBC_ZONE_TYPE_CONV && if (zone.type != ZBC_ZONE_TYPE_CONV &&
zone->cond == ZBC_ZONE_COND_FULL) zone.cond == ZBC_ZONE_COND_FULL)
zone->wp = zone->start + zone->len; zone.wp = zone.start + zone.len;
return cb(&zone, idx, data);
} }
/** /**
...@@ -104,11 +97,6 @@ static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf, ...@@ -104,11 +97,6 @@ static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
return 0; return 0;
} }
/*
* Maximum number of zones to get with one report zones command.
*/
#define SD_ZBC_REPORT_MAX_ZONES 8192U
/** /**
* Allocate a buffer for report zones reply. * Allocate a buffer for report zones reply.
* @sdkp: The target disk * @sdkp: The target disk
...@@ -138,74 +126,82 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp, ...@@ -138,74 +126,82 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp,
* sure that the allocated buffer can always be mapped by limiting the * sure that the allocated buffer can always be mapped by limiting the
* number of pages allocated to the HBA max segments limit. * number of pages allocated to the HBA max segments limit.
*/ */
nr_zones = min(nr_zones, SD_ZBC_REPORT_MAX_ZONES); nr_zones = min(nr_zones, sdkp->nr_zones);
bufsize = roundup((nr_zones + 1) * 64, 512); bufsize = roundup((nr_zones + 1) * 64, SECTOR_SIZE);
bufsize = min_t(size_t, bufsize, bufsize = min_t(size_t, bufsize,
queue_max_hw_sectors(q) << SECTOR_SHIFT); queue_max_hw_sectors(q) << SECTOR_SHIFT);
bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT); bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT);
buf = vzalloc(bufsize); while (bufsize >= SECTOR_SIZE) {
if (buf) buf = __vmalloc(bufsize,
GFP_KERNEL | __GFP_ZERO | __GFP_NORETRY,
PAGE_KERNEL);
if (buf) {
*buflen = bufsize; *buflen = bufsize;
return buf; return buf;
}
bufsize >>= 1;
}
return NULL;
} }
/** /**
* sd_zbc_report_zones - Disk report zones operation. * sd_zbc_zone_sectors - Get the device zone size in number of 512B sectors.
* @disk: The target disk * @sdkp: The target disk
* @sector: Start 512B sector of the report
* @zones: Array of zone descriptors
* @nr_zones: Number of descriptors in the array
*
* Execute a report zones command on the target disk.
*/ */
static inline sector_t sd_zbc_zone_sectors(struct scsi_disk *sdkp)
{
return logical_to_sectors(sdkp->device, sdkp->zone_blocks);
}
int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
struct blk_zone *zones, unsigned int *nr_zones) unsigned int nr_zones, report_zones_cb cb, void *data)
{ {
struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_disk *sdkp = scsi_disk(disk);
unsigned int i, nrz = *nr_zones; unsigned int nr, i;
unsigned char *buf; unsigned char *buf;
size_t buflen = 0, offset = 0; size_t offset, buflen = 0;
int ret = 0; int zone_idx = 0;
int ret;
if (!sd_is_zoned(sdkp)) if (!sd_is_zoned(sdkp))
/* Not a zoned device */ /* Not a zoned device */
return -EOPNOTSUPP; return -EOPNOTSUPP;
buf = sd_zbc_alloc_report_buffer(sdkp, nrz, &buflen); buf = sd_zbc_alloc_report_buffer(sdkp, nr_zones, &buflen);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
while (zone_idx < nr_zones && sector < get_capacity(disk)) {
ret = sd_zbc_do_report_zones(sdkp, buf, buflen, ret = sd_zbc_do_report_zones(sdkp, buf, buflen,
sectors_to_logical(sdkp->device, sector), true); sectors_to_logical(sdkp->device, sector), true);
if (ret) if (ret)
goto out; goto out;
nrz = min(nrz, get_unaligned_be32(&buf[0]) / 64); offset = 0;
for (i = 0; i < nrz; i++) { nr = min(nr_zones, get_unaligned_be32(&buf[0]) / 64);
if (!nr)
break;
for (i = 0; i < nr && zone_idx < nr_zones; i++) {
offset += 64; offset += 64;
sd_zbc_parse_report(sdkp, buf + offset, zones); ret = sd_zbc_parse_report(sdkp, buf + offset, zone_idx,
zones++; cb, data);
if (ret)
goto out;
zone_idx++;
} }
*nr_zones = nrz; sector += sd_zbc_zone_sectors(sdkp) * i;
}
ret = zone_idx;
out: out:
kvfree(buf); kvfree(buf);
return ret; return ret;
} }
/**
* sd_zbc_zone_sectors - Get the device zone size in number of 512B sectors.
* @sdkp: The target disk
*/
static inline sector_t sd_zbc_zone_sectors(struct scsi_disk *sdkp)
{
return logical_to_sectors(sdkp->device, sdkp->zone_blocks);
}
/** /**
* sd_zbc_setup_zone_mgmt_cmnd - Prepare a zone ZBC_OUT command. The operations * sd_zbc_setup_zone_mgmt_cmnd - Prepare a zone ZBC_OUT command. The operations
* can be RESET WRITE POINTER, OPEN, CLOSE or FINISH. * can be RESET WRITE POINTER, OPEN, CLOSE or FINISH.
...@@ -339,32 +335,18 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp, ...@@ -339,32 +335,18 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp,
* Returns the zone size in number of blocks upon success or an error code * Returns the zone size in number of blocks upon success or an error code
* upon failure. * upon failure.
*/ */
static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks) static int sd_zbc_check_zones(struct scsi_disk *sdkp, unsigned char *buf,
u32 *zblocks)
{ {
size_t bufsize, buflen;
unsigned int noio_flag;
u64 zone_blocks = 0; u64 zone_blocks = 0;
sector_t max_lba, block = 0; sector_t max_lba;
unsigned char *buf;
unsigned char *rec; unsigned char *rec;
int ret; int ret;
u8 same;
/* Do all memory allocations as if GFP_NOIO was specified */
noio_flag = memalloc_noio_save();
/* Get a buffer */ /* Do a report zone to get max_lba and the size of the first zone */
buf = sd_zbc_alloc_report_buffer(sdkp, SD_ZBC_REPORT_MAX_ZONES, ret = sd_zbc_do_report_zones(sdkp, buf, SD_BUF_SIZE, 0, false);
&bufsize);
if (!buf) {
ret = -ENOMEM;
goto out;
}
/* Do a report zone to get max_lba and the same field */
ret = sd_zbc_do_report_zones(sdkp, buf, bufsize, 0, false);
if (ret) if (ret)
goto out_free; return ret;
if (sdkp->rc_basis == 0) { if (sdkp->rc_basis == 0) {
/* The max_lba field is the capacity of this device */ /* The max_lba field is the capacity of this device */
...@@ -379,82 +361,27 @@ static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks) ...@@ -379,82 +361,27 @@ static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks)
} }
} }
/*
* Check same field: for any value other than 0, we know that all zones
* have the same size.
*/
same = buf[4] & 0x0f;
if (same > 0) {
rec = &buf[64];
zone_blocks = get_unaligned_be64(&rec[8]);
goto out;
}
/*
* Check the size of all zones: all zones must be of
* equal size, except the last zone which can be smaller
* than other zones.
*/
do {
/* Parse REPORT ZONES header */ /* Parse REPORT ZONES header */
buflen = min_t(size_t, get_unaligned_be32(&buf[0]) + 64,
bufsize);
rec = buf + 64; rec = buf + 64;
zone_blocks = get_unaligned_be64(&rec[8]);
/* Parse zone descriptors */ if (!zone_blocks || !is_power_of_2(zone_blocks)) {
while (rec < buf + buflen) {
u64 this_zone_blocks = get_unaligned_be64(&rec[8]);
if (zone_blocks == 0) {
zone_blocks = this_zone_blocks;
} else if (this_zone_blocks != zone_blocks &&
(block + this_zone_blocks < sdkp->capacity
|| this_zone_blocks > zone_blocks)) {
zone_blocks = 0;
goto out;
}
block += this_zone_blocks;
rec += 64;
}
if (block < sdkp->capacity) {
ret = sd_zbc_do_report_zones(sdkp, buf, bufsize, block,
true);
if (ret)
goto out_free;
}
} while (block < sdkp->capacity);
out:
if (!zone_blocks) {
if (sdkp->first_scan)
sd_printk(KERN_NOTICE, sdkp,
"Devices with non constant zone "
"size are not supported\n");
ret = -ENODEV;
} else if (!is_power_of_2(zone_blocks)) {
if (sdkp->first_scan) if (sdkp->first_scan)
sd_printk(KERN_NOTICE, sdkp, sd_printk(KERN_NOTICE, sdkp,
"Devices with non power of 2 zone " "Devices with non power of 2 zone "
"size are not supported\n"); "size are not supported\n");
ret = -ENODEV; return -ENODEV;
} else if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) { }
if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) {
if (sdkp->first_scan) if (sdkp->first_scan)
sd_printk(KERN_NOTICE, sdkp, sd_printk(KERN_NOTICE, sdkp,
"Zone size too large\n"); "Zone size too large\n");
ret = -EFBIG; return -EFBIG;
} else {
*zblocks = zone_blocks;
ret = 0;
} }
out_free: *zblocks = zone_blocks;
memalloc_noio_restore(noio_flag);
kvfree(buf);
return ret; return 0;
} }
int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf) int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
...@@ -480,7 +407,7 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf) ...@@ -480,7 +407,7 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
* Check zone size: only devices with a constant zone size (except * Check zone size: only devices with a constant zone size (except
* an eventual last runt zone) that is a power of 2 are supported. * an eventual last runt zone) that is a power of 2 are supported.
*/ */
ret = sd_zbc_check_zones(sdkp, &zone_blocks); ret = sd_zbc_check_zones(sdkp, buf, &zone_blocks);
if (ret != 0) if (ret != 0)
goto err; goto err;
......
...@@ -2857,15 +2857,21 @@ static int init_percpu_info(struct f2fs_sb_info *sbi) ...@@ -2857,15 +2857,21 @@ static int init_percpu_info(struct f2fs_sb_info *sbi)
} }
#ifdef CONFIG_BLK_DEV_ZONED #ifdef CONFIG_BLK_DEV_ZONED
static int f2fs_report_zone_cb(struct blk_zone *zone, unsigned int idx,
void *data)
{
struct f2fs_dev_info *dev = data;
if (zone->type != BLK_ZONE_TYPE_CONVENTIONAL)
set_bit(idx, dev->blkz_seq);
return 0;
}
static int init_blkz_info(struct f2fs_sb_info *sbi, int devi) static int init_blkz_info(struct f2fs_sb_info *sbi, int devi)
{ {
struct block_device *bdev = FDEV(devi).bdev; struct block_device *bdev = FDEV(devi).bdev;
sector_t nr_sectors = bdev->bd_part->nr_sects; sector_t nr_sectors = bdev->bd_part->nr_sects;
sector_t sector = 0; int ret;
struct blk_zone *zones;
unsigned int i, nr_zones;
unsigned int n = 0;
int err = -EIO;
if (!f2fs_sb_has_blkzoned(sbi)) if (!f2fs_sb_has_blkzoned(sbi))
return 0; return 0;
...@@ -2890,38 +2896,13 @@ static int init_blkz_info(struct f2fs_sb_info *sbi, int devi) ...@@ -2890,38 +2896,13 @@ static int init_blkz_info(struct f2fs_sb_info *sbi, int devi)
if (!FDEV(devi).blkz_seq) if (!FDEV(devi).blkz_seq)
return -ENOMEM; return -ENOMEM;
#define F2FS_REPORT_NR_ZONES 4096
zones = f2fs_kzalloc(sbi,
array_size(F2FS_REPORT_NR_ZONES,
sizeof(struct blk_zone)),
GFP_KERNEL);
if (!zones)
return -ENOMEM;
/* Get block zones type */ /* Get block zones type */
while (zones && sector < nr_sectors) { ret = blkdev_report_zones(bdev, 0, BLK_ALL_ZONES, f2fs_report_zone_cb,
&FDEV(devi));
nr_zones = F2FS_REPORT_NR_ZONES; if (ret < 0)
err = blkdev_report_zones(bdev, sector, zones, &nr_zones); return ret;
if (err)
break;
if (!nr_zones) {
err = -EIO;
break;
}
for (i = 0; i < nr_zones; i++) {
if (zones[i].type != BLK_ZONE_TYPE_CONVENTIONAL)
set_bit(n, FDEV(devi).blkz_seq);
sector += zones[i].len;
n++;
}
}
kvfree(zones);
return err; return 0;
} }
#endif #endif
......
...@@ -349,17 +349,16 @@ struct queue_limits { ...@@ -349,17 +349,16 @@ struct queue_limits {
enum blk_zoned_model zoned; enum blk_zoned_model zoned;
}; };
typedef int (*report_zones_cb)(struct blk_zone *zone, unsigned int idx,
void *data);
#ifdef CONFIG_BLK_DEV_ZONED #ifdef CONFIG_BLK_DEV_ZONED
/* #define BLK_ALL_ZONES ((unsigned int)-1)
* Maximum number of zones to report with a single report zones command. int blkdev_report_zones(struct block_device *bdev, sector_t sector,
*/ unsigned int nr_zones, report_zones_cb cb, void *data);
#define BLK_ZONED_REPORT_MAX_ZONES 8192U
extern unsigned int blkdev_nr_zones(struct block_device *bdev); extern unsigned int blkdev_nr_zones(struct block_device *bdev);
extern int blkdev_report_zones(struct block_device *bdev,
sector_t sector, struct blk_zone *zones,
unsigned int *nr_zones);
extern int blkdev_zone_mgmt(struct block_device *bdev, enum req_opf op, extern int blkdev_zone_mgmt(struct block_device *bdev, enum req_opf op,
sector_t sectors, sector_t nr_sectors, sector_t sectors, sector_t nr_sectors,
gfp_t gfp_mask); gfp_t gfp_mask);
...@@ -1709,7 +1708,7 @@ struct block_device_operations { ...@@ -1709,7 +1708,7 @@ struct block_device_operations {
/* this callback is with swap_lock and sometimes page table lock held */ /* this callback is with swap_lock and sometimes page table lock held */
void (*swap_slot_free_notify) (struct block_device *, unsigned long); void (*swap_slot_free_notify) (struct block_device *, unsigned long);
int (*report_zones)(struct gendisk *, sector_t sector, int (*report_zones)(struct gendisk *, sector_t sector,
struct blk_zone *zones, unsigned int *nr_zones); unsigned int nr_zones, report_zones_cb cb, void *data);
struct module *owner; struct module *owner;
const struct pr_ops *pr_ops; const struct pr_ops *pr_ops;
}; };
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
struct dm_dev; struct dm_dev;
struct dm_target; struct dm_target;
struct dm_table; struct dm_table;
struct dm_report_zones_args;
struct mapped_device; struct mapped_device;
struct bio_vec; struct bio_vec;
...@@ -93,9 +94,9 @@ typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv, ...@@ -93,9 +94,9 @@ typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv,
typedef int (*dm_prepare_ioctl_fn) (struct dm_target *ti, struct block_device **bdev); typedef int (*dm_prepare_ioctl_fn) (struct dm_target *ti, struct block_device **bdev);
typedef int (*dm_report_zones_fn) (struct dm_target *ti, sector_t sector, typedef int (*dm_report_zones_fn) (struct dm_target *ti,
struct blk_zone *zones, struct dm_report_zones_args *args,
unsigned int *nr_zones); unsigned int nr_zones);
/* /*
* These iteration functions are typically used to check (and combine) * These iteration functions are typically used to check (and combine)
...@@ -422,10 +423,23 @@ struct gendisk *dm_disk(struct mapped_device *md); ...@@ -422,10 +423,23 @@ struct gendisk *dm_disk(struct mapped_device *md);
int dm_suspended(struct dm_target *ti); int dm_suspended(struct dm_target *ti);
int dm_noflush_suspending(struct dm_target *ti); int dm_noflush_suspending(struct dm_target *ti);
void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors); void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors);
void dm_remap_zone_report(struct dm_target *ti, sector_t start,
struct blk_zone *zones, unsigned int *nr_zones);
union map_info *dm_get_rq_mapinfo(struct request *rq); union map_info *dm_get_rq_mapinfo(struct request *rq);
#ifdef CONFIG_BLK_DEV_ZONED
struct dm_report_zones_args {
struct dm_target *tgt;
sector_t next_sector;
void *orig_data;
report_zones_cb orig_cb;
unsigned int zone_idx;
/* must be filled by ->report_zones before calling dm_report_zones_cb */
sector_t start;
};
int dm_report_zones_cb(struct blk_zone *zone, unsigned int idx, void *data);
#endif /* CONFIG_BLK_DEV_ZONED */
/* /*
* Device mapper functions to parse and create devices specified by the * Device mapper functions to parse and create devices specified by the
* parameter "dm-mod.create=" * parameter "dm-mod.create="
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment