diff mbox series

null_blk: use zone status for max active/open

Message ID 20201015015349.1400374-1-kbusch@kernel.org (mailing list archive)
State New, archived
Headers show
Series null_blk: use zone status for max active/open | expand

Commit Message

Keith Busch Oct. 15, 2020, 1:53 a.m. UTC
The block layer provides special status codes when requests go beyond
the zone resource limits. Use these codes instead of the generic IOERR
for requests that exceed the max active or open limits the null_blk
device was configured with so that applications know how these special
conditions should be handled.

Cc: Damien Le Moal <damien.lemoal@wdc.com>
Cc: Niklas Cassel <niklas.cassel@wdc.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
---
 drivers/block/null_blk_zoned.c | 71 ++++++++++++++++++++++------------
 1 file changed, 46 insertions(+), 25 deletions(-)

Comments

Niklas Cassel Oct. 15, 2020, 8:47 a.m. UTC | #1
On Wed, Oct 14, 2020 at 06:53:49PM -0700, Keith Busch wrote:
> The block layer provides special status codes when requests go beyond
> the zone resource limits. Use these codes instead of the generic IOERR
> for requests that exceed the max active or open limits the null_blk
> device was configured with so that applications know how these special
> conditions should be handled.
> 
> Cc: Damien Le Moal <damien.lemoal@wdc.com>
> Cc: Niklas Cassel <niklas.cassel@wdc.com>
> Signed-off-by: Keith Busch <kbusch@kernel.org>
> ---
>  drivers/block/null_blk_zoned.c | 71 ++++++++++++++++++++++------------
>  1 file changed, 46 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/block/null_blk_zoned.c b/drivers/block/null_blk_zoned.c
> index fa0cc70f05e6..446ab90153a7 100644
> --- a/drivers/block/null_blk_zoned.c
> +++ b/drivers/block/null_blk_zoned.c
> @@ -220,29 +220,38 @@ static void null_close_first_imp_zone(struct nullb_device *dev)
>  	}
>  }
>  
> -static bool null_can_set_active(struct nullb_device *dev)
> +static blk_status_t null_check_active(struct nullb_device *dev)
>  {
>  	if (!dev->zone_max_active)
> -		return true;
> +		return BLK_STS_OK;
> +
> +	if (dev->nr_zones_exp_open + dev->nr_zones_imp_open +
> +			dev->nr_zones_closed < dev->zone_max_active)
> +		return BLK_STS_OK;
>  
> -	return dev->nr_zones_exp_open + dev->nr_zones_imp_open +
> -	       dev->nr_zones_closed < dev->zone_max_active;
> +	return BLK_STS_ZONE_ACTIVE_RESOURCE;
>  }
>  
> -static bool null_can_open(struct nullb_device *dev)
> +static blk_status_t null_check_open(struct nullb_device *dev)
>  {
> +	blk_status_t ret = BLK_STS_OK;
> +
>  	if (!dev->zone_max_open)
> -		return true;
> +		return ret;
>  
>  	if (dev->nr_zones_exp_open + dev->nr_zones_imp_open < dev->zone_max_open)
> -		return true;
> +		return ret;
> +
> +	if (dev->nr_zones_imp_open) {
> +		ret = null_check_active(dev);
> +		if (ret != BLK_STS_OK)
> +			return ret;

I've been thinking.. I'm not sure that if we want to return ret here.

check_open() checks if we can open a zone without exceeding the
open limit (implicit+explict). ZBC states that if there are implicit
zones open, we should close one implict zone in order to satisfy the
current open request (which can be implicit or explicit).
However, ZBC does not have an active limit, so it is not obvious what
we should return in the case where we do have implicit zones open,
but no room in active limit, so we cannot close an implicit zone in
order to make room for the current open request.

I think the most logical thing is to treat this case the same as
when all "spots" in the open limit are occupied by explict zones.
i.e. I think it makes more sense that null_check_open() only returns
BLK_STS_ZONE_OPEN_RESOURCE.

For a zone that is currently in BLK_ZONE_COND_CLOSED:
calling check_zone_resources() will only check null_can_open(),
since it is already inside/accounted for in the active limit.
So it doesn't make sense to return "Too many active" here.

For a zone that is currently in BLK_ZONE_COND_EMPTY:
calling check_zone_resources() will first check null_check_active(),
if there is not room in active limit, we will return a "Too many active".
Then we will proceed to check null_check_open(), but here we already
concluded that there was room in active, so here it also doesn't make
sense that null_check_open() can return "Too many active".


How about something like:

static blk_status_t null_check_open(struct nullb_device *dev)
{
	if (!dev->zone_max_open)
		return BLK_STS_OK;

	if (dev->nr_zones_exp_open + dev->nr_zones_imp_open < dev->zone_max_open)
		return BLK_STS_OK;

	if (dev->nr_zones_imp_open) {
		blk_status_t ret = null_check_active(dev);
		if (ret == BLK_STS_OK) {
			null_close_first_imp_zone(dev);
			return ret;
		}
	}

	return BLK_STS_ZONE_OPEN_RESOURCE;
}


>  
> -	if (dev->nr_zones_imp_open && null_can_set_active(dev)) {
>  		null_close_first_imp_zone(dev);
> -		return true;
> +		return ret;
>  	}
>  
> -	return false;
> +	return BLK_STS_ZONE_OPEN_RESOURCE;
>  }
>  
>  /*
> @@ -258,19 +267,22 @@ static bool null_can_open(struct nullb_device *dev)
>   * it is not certain that closing an implicit open zone will allow a new zone
>   * to be opened, since we might already be at the active limit capacity.
>   */
> -static bool null_has_zone_resources(struct nullb_device *dev, struct blk_zone *zone)
> +static blk_status_t null_check_zone_resources(struct nullb_device *dev, struct blk_zone *zone)
>  {
> +	blk_status_t ret;
> +
>  	switch (zone->cond) {
>  	case BLK_ZONE_COND_EMPTY:
> -		if (!null_can_set_active(dev))
> -			return false;
> +		ret = null_check_active(dev);
> +		if (ret != BLK_STS_OK)
> +			return ret;
>  		fallthrough;
>  	case BLK_ZONE_COND_CLOSED:
> -		return null_can_open(dev);
> +		return null_check_open(dev);
>  	default:
>  		/* Should never be called for other states */
>  		WARN_ON(1);
> -		return false;
> +		return BLK_STS_IOERR;
>  	}
>  }
>  
> @@ -293,8 +305,9 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
>  		return BLK_STS_IOERR;
>  	case BLK_ZONE_COND_EMPTY:
>  	case BLK_ZONE_COND_CLOSED:
> -		if (!null_has_zone_resources(dev, zone))
> -			return BLK_STS_IOERR;
> +		ret = null_check_zone_resources(dev, zone);
> +		if (ret != BLK_STS_OK)
> +			return ret;
>  		break;
>  	case BLK_ZONE_COND_IMP_OPEN:
>  	case BLK_ZONE_COND_EXP_OPEN:
> @@ -349,6 +362,8 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
>  
>  static blk_status_t null_open_zone(struct nullb_device *dev, struct blk_zone *zone)
>  {
> +	blk_status_t ret;
> +
>  	if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
>  		return BLK_STS_IOERR;
>  
> @@ -357,15 +372,17 @@ static blk_status_t null_open_zone(struct nullb_device *dev, struct blk_zone *zo
>  		/* open operation on exp open is not an error */
>  		return BLK_STS_OK;
>  	case BLK_ZONE_COND_EMPTY:
> -		if (!null_has_zone_resources(dev, zone))
> -			return BLK_STS_IOERR;
> +		ret = null_check_zone_resources(dev, zone);
> +		if (ret != BLK_STS_OK)
> +			return ret;
>  		break;
>  	case BLK_ZONE_COND_IMP_OPEN:
>  		dev->nr_zones_imp_open--;
>  		break;
>  	case BLK_ZONE_COND_CLOSED:
> -		if (!null_has_zone_resources(dev, zone))
> -			return BLK_STS_IOERR;
> +		ret = null_check_zone_resources(dev, zone);
> +		if (ret != BLK_STS_OK)
> +			return ret;
>  		dev->nr_zones_closed--;
>  		break;
>  	case BLK_ZONE_COND_FULL:
> @@ -381,6 +398,8 @@ static blk_status_t null_open_zone(struct nullb_device *dev, struct blk_zone *zo
>  
>  static blk_status_t null_finish_zone(struct nullb_device *dev, struct blk_zone *zone)
>  {
> +	blk_status_t ret;
> +
>  	if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
>  		return BLK_STS_IOERR;
>  
> @@ -389,8 +408,9 @@ static blk_status_t null_finish_zone(struct nullb_device *dev, struct blk_zone *
>  		/* finish operation on full is not an error */
>  		return BLK_STS_OK;
>  	case BLK_ZONE_COND_EMPTY:
> -		if (!null_has_zone_resources(dev, zone))
> -			return BLK_STS_IOERR;
> +		ret = null_check_zone_resources(dev, zone);
> +		if (ret != BLK_STS_OK)
> +			return ret;
>  		break;
>  	case BLK_ZONE_COND_IMP_OPEN:
>  		dev->nr_zones_imp_open--;
> @@ -399,8 +419,9 @@ static blk_status_t null_finish_zone(struct nullb_device *dev, struct blk_zone *
>  		dev->nr_zones_exp_open--;
>  		break;
>  	case BLK_ZONE_COND_CLOSED:
> -		if (!null_has_zone_resources(dev, zone))
> -			return BLK_STS_IOERR;
> +		ret = null_check_zone_resources(dev, zone);
> +		if (ret != BLK_STS_OK)
> +			return ret;
>  		dev->nr_zones_closed--;
>  		break;
>  	default:
> -- 
> 2.24.1
>
diff mbox series

Patch

diff --git a/drivers/block/null_blk_zoned.c b/drivers/block/null_blk_zoned.c
index fa0cc70f05e6..446ab90153a7 100644
--- a/drivers/block/null_blk_zoned.c
+++ b/drivers/block/null_blk_zoned.c
@@ -220,29 +220,38 @@  static void null_close_first_imp_zone(struct nullb_device *dev)
 	}
 }
 
-static bool null_can_set_active(struct nullb_device *dev)
+static blk_status_t null_check_active(struct nullb_device *dev)
 {
 	if (!dev->zone_max_active)
-		return true;
+		return BLK_STS_OK;
+
+	if (dev->nr_zones_exp_open + dev->nr_zones_imp_open +
+			dev->nr_zones_closed < dev->zone_max_active)
+		return BLK_STS_OK;
 
-	return dev->nr_zones_exp_open + dev->nr_zones_imp_open +
-	       dev->nr_zones_closed < dev->zone_max_active;
+	return BLK_STS_ZONE_ACTIVE_RESOURCE;
 }
 
-static bool null_can_open(struct nullb_device *dev)
+static blk_status_t null_check_open(struct nullb_device *dev)
 {
+	blk_status_t ret = BLK_STS_OK;
+
 	if (!dev->zone_max_open)
-		return true;
+		return ret;
 
 	if (dev->nr_zones_exp_open + dev->nr_zones_imp_open < dev->zone_max_open)
-		return true;
+		return ret;
+
+	if (dev->nr_zones_imp_open) {
+		ret = null_check_active(dev);
+		if (ret != BLK_STS_OK)
+			return ret;
 
-	if (dev->nr_zones_imp_open && null_can_set_active(dev)) {
 		null_close_first_imp_zone(dev);
-		return true;
+		return ret;
 	}
 
-	return false;
+	return BLK_STS_ZONE_OPEN_RESOURCE;
 }
 
 /*
@@ -258,19 +267,22 @@  static bool null_can_open(struct nullb_device *dev)
  * it is not certain that closing an implicit open zone will allow a new zone
  * to be opened, since we might already be at the active limit capacity.
  */
-static bool null_has_zone_resources(struct nullb_device *dev, struct blk_zone *zone)
+static blk_status_t null_check_zone_resources(struct nullb_device *dev, struct blk_zone *zone)
 {
+	blk_status_t ret;
+
 	switch (zone->cond) {
 	case BLK_ZONE_COND_EMPTY:
-		if (!null_can_set_active(dev))
-			return false;
+		ret = null_check_active(dev);
+		if (ret != BLK_STS_OK)
+			return ret;
 		fallthrough;
 	case BLK_ZONE_COND_CLOSED:
-		return null_can_open(dev);
+		return null_check_open(dev);
 	default:
 		/* Should never be called for other states */
 		WARN_ON(1);
-		return false;
+		return BLK_STS_IOERR;
 	}
 }
 
@@ -293,8 +305,9 @@  static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
 		return BLK_STS_IOERR;
 	case BLK_ZONE_COND_EMPTY:
 	case BLK_ZONE_COND_CLOSED:
-		if (!null_has_zone_resources(dev, zone))
-			return BLK_STS_IOERR;
+		ret = null_check_zone_resources(dev, zone);
+		if (ret != BLK_STS_OK)
+			return ret;
 		break;
 	case BLK_ZONE_COND_IMP_OPEN:
 	case BLK_ZONE_COND_EXP_OPEN:
@@ -349,6 +362,8 @@  static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
 
 static blk_status_t null_open_zone(struct nullb_device *dev, struct blk_zone *zone)
 {
+	blk_status_t ret;
+
 	if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
 		return BLK_STS_IOERR;
 
@@ -357,15 +372,17 @@  static blk_status_t null_open_zone(struct nullb_device *dev, struct blk_zone *zo
 		/* open operation on exp open is not an error */
 		return BLK_STS_OK;
 	case BLK_ZONE_COND_EMPTY:
-		if (!null_has_zone_resources(dev, zone))
-			return BLK_STS_IOERR;
+		ret = null_check_zone_resources(dev, zone);
+		if (ret != BLK_STS_OK)
+			return ret;
 		break;
 	case BLK_ZONE_COND_IMP_OPEN:
 		dev->nr_zones_imp_open--;
 		break;
 	case BLK_ZONE_COND_CLOSED:
-		if (!null_has_zone_resources(dev, zone))
-			return BLK_STS_IOERR;
+		ret = null_check_zone_resources(dev, zone);
+		if (ret != BLK_STS_OK)
+			return ret;
 		dev->nr_zones_closed--;
 		break;
 	case BLK_ZONE_COND_FULL:
@@ -381,6 +398,8 @@  static blk_status_t null_open_zone(struct nullb_device *dev, struct blk_zone *zo
 
 static blk_status_t null_finish_zone(struct nullb_device *dev, struct blk_zone *zone)
 {
+	blk_status_t ret;
+
 	if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
 		return BLK_STS_IOERR;
 
@@ -389,8 +408,9 @@  static blk_status_t null_finish_zone(struct nullb_device *dev, struct blk_zone *
 		/* finish operation on full is not an error */
 		return BLK_STS_OK;
 	case BLK_ZONE_COND_EMPTY:
-		if (!null_has_zone_resources(dev, zone))
-			return BLK_STS_IOERR;
+		ret = null_check_zone_resources(dev, zone);
+		if (ret != BLK_STS_OK)
+			return ret;
 		break;
 	case BLK_ZONE_COND_IMP_OPEN:
 		dev->nr_zones_imp_open--;
@@ -399,8 +419,9 @@  static blk_status_t null_finish_zone(struct nullb_device *dev, struct blk_zone *
 		dev->nr_zones_exp_open--;
 		break;
 	case BLK_ZONE_COND_CLOSED:
-		if (!null_has_zone_resources(dev, zone))
-			return BLK_STS_IOERR;
+		ret = null_check_zone_resources(dev, zone);
+		if (ret != BLK_STS_OK)
+			return ret;
 		dev->nr_zones_closed--;
 		break;
 	default: