/** * blk_revalidate_disk_zones - (re)allocate and initialize zone bitmaps * @disk: Target disk * * Helper function for low-level device drivers to (re) allocate and initialize * a disk request queue zone bitmaps. This functions should normally be called * within the disk ->revalidate method. For BIO based queues, no zone bitmap * is allocated. */ int blk_revalidate_disk_zones(struct gendisk *disk) { struct request_queue *q = disk->queue; unsigned int nr_zones = __blkdev_nr_zones(q, get_capacity(disk)); unsigned long *seq_zones_wlock = NULL, *seq_zones_bitmap = NULL; unsigned int i, rep_nr_zones = 0, z = 0, nrz; struct blk_zone *zones = NULL; sector_t sector = 0; int ret = 0; /* * BIO based queues do not use a scheduler so only q->nr_zones * needs to be updated so that the sysfs exposed value is correct. */ if (!queue_is_rq_based(q)) { q->nr_zones = nr_zones; return 0; } if (!blk_queue_is_zoned(q) || !nr_zones) { nr_zones = 0; goto update; } /* Allocate bitmaps */ ret = -ENOMEM; seq_zones_wlock = blk_alloc_zone_bitmap(q->node, nr_zones); if (!seq_zones_wlock) goto out; seq_zones_bitmap = blk_alloc_zone_bitmap(q->node, nr_zones); if (!seq_zones_bitmap) goto out; /* Get zone information and initialize seq_zones_bitmap */ rep_nr_zones = nr_zones; zones = blk_alloc_zones(q->node, &rep_nr_zones); if (!zones) goto out; while (z < nr_zones) { nrz = min(nr_zones - z, rep_nr_zones); ret = blk_report_zones(disk, sector, zones, &nrz, GFP_NOIO); if (ret) goto out; if (!nrz) break; for (i = 0; i < nrz; i++) { if (zones[i].type != BLK_ZONE_TYPE_CONVENTIONAL) set_bit(z, seq_zones_bitmap); z++; } sector += nrz * blk_queue_zone_sectors(q); } if (WARN_ON(z != nr_zones)) { ret = -EIO; goto out; } update: /* * Install the new bitmaps, making sure the queue is stopped and * all I/Os are completed (i.e. a scheduler is not referencing the * bitmaps). */ blk_mq_freeze_queue(q); q->nr_zones = nr_zones; swap(q->seq_zones_wlock, seq_zones_wlock); swap(q->seq_zones_bitmap, seq_zones_bitmap); blk_mq_unfreeze_queue(q); out: free_pages((unsigned long)zones, get_order(rep_nr_zones * sizeof(struct blk_zone))); kfree(seq_zones_wlock); kfree(seq_zones_bitmap); if (ret) { pr_warn("%s: failed to revalidate zones\n", disk->disk_name); blk_mq_freeze_queue(q); blk_queue_free_zone_bitmaps(q); blk_mq_unfreeze_queue(q); } return ret; }
int dm_request_based(struct mapped_device *md) { return queue_is_rq_based(md->queue); }