]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blobdiff - block/blk-zoned.c
Merge tag 'rcu_urgent_for_5.8_rc3' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-hirsute-kernel.git] / block / blk-zoned.c
index 05741c6f618be9162cf642faf83cbbc420023fe8..23831fa8701d85e8d29f30c3be5896e31e965a1d 100644 (file)
 
 #include "blk.h"
 
+#define ZONE_COND_NAME(name) [BLK_ZONE_COND_##name] = #name
+static const char *const zone_cond_name[] = {
+       ZONE_COND_NAME(NOT_WP),
+       ZONE_COND_NAME(EMPTY),
+       ZONE_COND_NAME(IMP_OPEN),
+       ZONE_COND_NAME(EXP_OPEN),
+       ZONE_COND_NAME(CLOSED),
+       ZONE_COND_NAME(READONLY),
+       ZONE_COND_NAME(FULL),
+       ZONE_COND_NAME(OFFLINE),
+};
+#undef ZONE_COND_NAME
+
+/**
+ * blk_zone_cond_str - Return string XXX in BLK_ZONE_COND_XXX.
+ * @zone_cond: BLK_ZONE_COND_XXX.
+ *
+ * Description: Centralize block layer function to convert BLK_ZONE_COND_XXX
+ * into string format. Useful in the debugging and tracing zone conditions. For
+ * invalid BLK_ZONE_COND_XXX it returns string "UNKNOWN".
+ */
+const char *blk_zone_cond_str(enum blk_zone_cond zone_cond)
+{
+       static const char *zone_cond_str = "UNKNOWN";
+
+       if (zone_cond < ARRAY_SIZE(zone_cond_name) && zone_cond_name[zone_cond])
+               zone_cond_str = zone_cond_name[zone_cond];
+
+       return zone_cond_str;
+}
+EXPORT_SYMBOL_GPL(blk_zone_cond_str);
+
 static inline sector_t blk_zone_start(struct request_queue *q,
                                      sector_t sector)
 {
@@ -50,6 +82,20 @@ bool blk_req_needs_zone_write_lock(struct request *rq)
 }
 EXPORT_SYMBOL_GPL(blk_req_needs_zone_write_lock);
 
+bool blk_req_zone_write_trylock(struct request *rq)
+{
+       unsigned int zno = blk_rq_zone_no(rq);
+
+       if (test_and_set_bit(zno, rq->q->seq_zones_wlock))
+               return false;
+
+       WARN_ON_ONCE(rq->rq_flags & RQF_ZONE_WRITE_LOCKED);
+       rq->rq_flags |= RQF_ZONE_WRITE_LOCKED;
+
+       return true;
+}
+EXPORT_SYMBOL_GPL(blk_req_zone_write_trylock);
+
 void __blk_req_zone_write_lock(struct request *rq)
 {
        if (WARN_ON_ONCE(test_and_set_bit(blk_rq_zone_no(rq),
@@ -173,7 +219,7 @@ int blkdev_zone_mgmt(struct block_device *bdev, enum req_opf op,
        if (!op_is_zone_mgmt(op))
                return -EOPNOTSUPP;
 
-       if (!nr_sectors || end_sector > capacity)
+       if (end_sector <= sector || end_sector > capacity)
                /* Out of range */
                return -EINVAL;
 
@@ -425,14 +471,19 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx,
 /**
  * blk_revalidate_disk_zones - (re)allocate and initialize zone bitmaps
  * @disk:      Target disk
+ * @update_driver_data:        Callback to update driver data on the frozen 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 blk-mq based drivers.  For BIO based
  * drivers only q->nr_zones needs to be updated so that the sysfs exposed value
  * is correct.
+ * If the @update_driver_data callback function is not NULL, the callback is
+ * executed with the device request queue frozen after all zones have been
+ * checked.
  */
-int blk_revalidate_disk_zones(struct gendisk *disk)
+int blk_revalidate_disk_zones(struct gendisk *disk,
+                             void (*update_driver_data)(struct gendisk *disk))
 {
        struct request_queue *q = disk->queue;
        struct blk_revalidate_zone_args args = {
@@ -466,6 +517,8 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
                q->nr_zones = args.nr_zones;
                swap(q->seq_zones_wlock, args.seq_zones_wlock);
                swap(q->conv_zones_bitmap, args.conv_zones_bitmap);
+               if (update_driver_data)
+                       update_driver_data(disk);
                ret = 0;
        } else {
                pr_warn("%s: failed to revalidate zones\n", disk->disk_name);