null_blk: introduce zone capacity for zoned device
authorAravind Ramesh <aravind.ramesh@wdc.com>
Mon, 29 Jun 2020 19:06:38 +0000 (12:06 -0700)
committerChristoph Hellwig <hch@lst.de>
Wed, 8 Jul 2020 14:16:19 +0000 (16:16 +0200)
Allow emulation of a zoned device with a per zone capacity smaller than
the zone size as as defined in the Zoned Namespace (ZNS) Command Set
specification. The zone capacity defaults to the zone size if not
specified and must be smaller than the zone size otherwise.

Reviewed-by: Matias Bjørling <matias.bjorling@wdc.com>
Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Daniel Wagner <dwagner@suse.de>
Signed-off-by: Aravind Ramesh <aravind.ramesh@wdc.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/block/null_blk.h
drivers/block/null_blk_main.c
drivers/block/null_blk_zoned.c

index 81b311c9d781ef5d61108093db0d8a79518e4245..daed4a9c34367762d5b66d1415fd12c7eee6df7a 100644 (file)
@@ -49,6 +49,7 @@ struct nullb_device {
        unsigned long completion_nsec; /* time in ns to complete a request */
        unsigned long cache_size; /* disk cache size in MB */
        unsigned long zone_size; /* zone size in MB if device is zoned */
+       unsigned long zone_capacity; /* zone capacity in MB if device is zoned */
        unsigned int zone_nr_conv; /* number of conventional zones */
        unsigned int submit_queues; /* number of submission queues */
        unsigned int home_node; /* home node for the device */
index 907c6858aec0c3b2c042a2f1b4a71b46b2e92f15..47a9dad880af2aac70567889f13dc42680be9a0c 100644 (file)
@@ -200,6 +200,10 @@ static unsigned long g_zone_size = 256;
 module_param_named(zone_size, g_zone_size, ulong, S_IRUGO);
 MODULE_PARM_DESC(zone_size, "Zone size in MB when block device is zoned. Must be power-of-two: Default: 256");
 
+static unsigned long g_zone_capacity;
+module_param_named(zone_capacity, g_zone_capacity, ulong, 0444);
+MODULE_PARM_DESC(zone_capacity, "Zone capacity in MB when block device is zoned. Can be less than or equal to zone size. Default: Zone size");
+
 static unsigned int g_zone_nr_conv;
 module_param_named(zone_nr_conv, g_zone_nr_conv, uint, 0444);
 MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones when block device is zoned. Default: 0");
@@ -341,6 +345,7 @@ NULLB_DEVICE_ATTR(mbps, uint, NULL);
 NULLB_DEVICE_ATTR(cache_size, ulong, NULL);
 NULLB_DEVICE_ATTR(zoned, bool, NULL);
 NULLB_DEVICE_ATTR(zone_size, ulong, NULL);
+NULLB_DEVICE_ATTR(zone_capacity, ulong, NULL);
 NULLB_DEVICE_ATTR(zone_nr_conv, uint, NULL);
 
 static ssize_t nullb_device_power_show(struct config_item *item, char *page)
@@ -457,6 +462,7 @@ static struct configfs_attribute *nullb_device_attrs[] = {
        &nullb_device_attr_badblocks,
        &nullb_device_attr_zoned,
        &nullb_device_attr_zone_size,
+       &nullb_device_attr_zone_capacity,
        &nullb_device_attr_zone_nr_conv,
        NULL,
 };
@@ -510,7 +516,8 @@ 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)
 {
-       return snprintf(page, PAGE_SIZE, "memory_backed,discard,bandwidth,cache,badblocks,zoned,zone_size,zone_nr_conv\n");
+       return snprintf(page, PAGE_SIZE,
+                       "memory_backed,discard,bandwidth,cache,badblocks,zoned,zone_size,zone_capacity,zone_nr_conv\n");
 }
 
 CONFIGFS_ATTR_RO(memb_group_, features);
@@ -571,6 +578,7 @@ static struct nullb_device *null_alloc_dev(void)
        dev->use_per_node_hctx = g_use_per_node_hctx;
        dev->zoned = g_zoned;
        dev->zone_size = g_zone_size;
+       dev->zone_capacity = g_zone_capacity;
        dev->zone_nr_conv = g_zone_nr_conv;
        return dev;
 }
index 624aac09b0054ba940ca8859f1e999089b198b49..3d25c9ad23831bc126f13d9263586fa833c0d1fd 100644 (file)
@@ -28,6 +28,15 @@ int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q)
                return -EINVAL;
        }
 
+       if (!dev->zone_capacity)
+               dev->zone_capacity = dev->zone_size;
+
+       if (dev->zone_capacity > dev->zone_size) {
+               pr_err("null_blk: zone capacity (%lu MB) larger than zone size (%lu MB)\n",
+                                       dev->zone_capacity, dev->zone_size);
+               return -EINVAL;
+       }
+
        dev->zone_size_sects = dev->zone_size << ZONE_SIZE_SHIFT;
        dev->nr_zones = dev_size >>
                                (SECTOR_SHIFT + ilog2(dev->zone_size_sects));
@@ -60,7 +69,7 @@ int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q)
 
                zone->start = zone->wp = sector;
                zone->len = dev->zone_size_sects;
-               zone->capacity = zone->len;
+               zone->capacity = dev->zone_capacity << ZONE_SIZE_SHIFT;
                zone->type = BLK_ZONE_TYPE_SEQWRITE_REQ;
                zone->cond = BLK_ZONE_COND_EMPTY;
 
@@ -187,6 +196,9 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
                        return BLK_STS_IOERR;
                }
 
+               if (zone->wp + nr_sectors > zone->start + zone->capacity)
+                       return BLK_STS_IOERR;
+
                if (zone->cond != BLK_ZONE_COND_EXP_OPEN)
                        zone->cond = BLK_ZONE_COND_IMP_OPEN;
 
@@ -195,7 +207,7 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
                        return ret;
 
                zone->wp += nr_sectors;
-               if (zone->wp == zone->start + zone->len)
+               if (zone->wp == zone->start + zone->capacity)
                        zone->cond = BLK_ZONE_COND_FULL;
                return BLK_STS_OK;
        default: