Commit 3bdde070 authored by Damien Le Moal's avatar Damien Le Moal Committed by Jens Axboe

null_blk: Do zone resource management only if necessary

For zoned null_blk devices setup without any limit on the maximum number
of open and active zones, there is no need to count the number of zones
that are implicitly open, explicitly open and closed. This is indicated
by the boolean field need_zone_res_mgmt of sturct nullb_device.

Modify the zone management functions null_reset_zone(),
null_finish_zone(), null_open_zone() and null_close_zone() to manage
the zone condition counters only if the device need_zone_res_mgmt field
is true. With this change, the function __null_close_zone() is removed
and integrated into the 2 caller sites directly, with the
null_close_imp_open_zone() call site greatly simplified as this function
closes zones that are known to be in the implicit open condition.

null_zone_write() is modified in a similar manner to do zone condition
accouting only when the device need_zone_res_mgmt field is true.

With these changes, the inline helpers null_lock_zone_res() and
null_unlock_zone_res() are removed and replaced with direct calls to
spin_lock()/spin_unlock().
Signed-off-by: default avatarDamien Le Moal <dlemoal@kernel.org>
Link: https://lore.kernel.org/r/20240411085502.728558-3-dlemoal@kernel.orgSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent cb9e5273
...@@ -19,18 +19,6 @@ static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect) ...@@ -19,18 +19,6 @@ static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect)
return sect >> ilog2(dev->zone_size_sects); return sect >> ilog2(dev->zone_size_sects);
} }
static inline void null_lock_zone_res(struct nullb_device *dev)
{
if (dev->need_zone_res_mgmt)
spin_lock_irq(&dev->zone_res_lock);
}
static inline void null_unlock_zone_res(struct nullb_device *dev)
{
if (dev->need_zone_res_mgmt)
spin_unlock_irq(&dev->zone_res_lock);
}
static inline void null_init_zone_lock(struct nullb_device *dev, static inline void null_init_zone_lock(struct nullb_device *dev,
struct nullb_zone *zone) struct nullb_zone *zone)
{ {
...@@ -251,35 +239,6 @@ size_t null_zone_valid_read_len(struct nullb *nullb, ...@@ -251,35 +239,6 @@ size_t null_zone_valid_read_len(struct nullb *nullb,
return (zone->wp - sector) << SECTOR_SHIFT; return (zone->wp - sector) << SECTOR_SHIFT;
} }
static blk_status_t __null_close_zone(struct nullb_device *dev,
struct nullb_zone *zone)
{
switch (zone->cond) {
case BLK_ZONE_COND_CLOSED:
/* close operation on closed is not an error */
return BLK_STS_OK;
case BLK_ZONE_COND_IMP_OPEN:
dev->nr_zones_imp_open--;
break;
case BLK_ZONE_COND_EXP_OPEN:
dev->nr_zones_exp_open--;
break;
case BLK_ZONE_COND_EMPTY:
case BLK_ZONE_COND_FULL:
default:
return BLK_STS_IOERR;
}
if (zone->wp == zone->start) {
zone->cond = BLK_ZONE_COND_EMPTY;
} else {
zone->cond = BLK_ZONE_COND_CLOSED;
dev->nr_zones_closed++;
}
return BLK_STS_OK;
}
static void null_close_imp_open_zone(struct nullb_device *dev) static void null_close_imp_open_zone(struct nullb_device *dev)
{ {
struct nullb_zone *zone; struct nullb_zone *zone;
...@@ -296,7 +255,13 @@ static void null_close_imp_open_zone(struct nullb_device *dev) ...@@ -296,7 +255,13 @@ static void null_close_imp_open_zone(struct nullb_device *dev)
zno = dev->zone_nr_conv; zno = dev->zone_nr_conv;
if (zone->cond == BLK_ZONE_COND_IMP_OPEN) { if (zone->cond == BLK_ZONE_COND_IMP_OPEN) {
__null_close_zone(dev, zone); dev->nr_zones_imp_open--;
if (zone->wp == zone->start) {
zone->cond = BLK_ZONE_COND_EMPTY;
} else {
zone->cond = BLK_ZONE_COND_CLOSED;
dev->nr_zones_closed++;
}
dev->imp_close_zone_no = zno; dev->imp_close_zone_no = zno;
return; return;
} }
...@@ -392,7 +357,7 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector, ...@@ -392,7 +357,7 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
zone->cond == BLK_ZONE_COND_OFFLINE) { zone->cond == BLK_ZONE_COND_OFFLINE) {
/* Cannot write to the zone */ /* Cannot write to the zone */
ret = BLK_STS_IOERR; ret = BLK_STS_IOERR;
goto unlock; goto unlock_zone;
} }
/* /*
...@@ -406,22 +371,23 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector, ...@@ -406,22 +371,23 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
blk_mq_rq_from_pdu(cmd)->__sector = sector; blk_mq_rq_from_pdu(cmd)->__sector = sector;
} else if (sector != zone->wp) { } else if (sector != zone->wp) {
ret = BLK_STS_IOERR; ret = BLK_STS_IOERR;
goto unlock; goto unlock_zone;
} }
if (zone->wp + nr_sectors > zone->start + zone->capacity) { if (zone->wp + nr_sectors > zone->start + zone->capacity) {
ret = BLK_STS_IOERR; ret = BLK_STS_IOERR;
goto unlock; goto unlock_zone;
} }
if (zone->cond == BLK_ZONE_COND_CLOSED || if (zone->cond == BLK_ZONE_COND_CLOSED ||
zone->cond == BLK_ZONE_COND_EMPTY) { zone->cond == BLK_ZONE_COND_EMPTY) {
null_lock_zone_res(dev); if (dev->need_zone_res_mgmt) {
spin_lock(&dev->zone_res_lock);
ret = null_check_zone_resources(dev, zone); ret = null_check_zone_resources(dev, zone);
if (ret != BLK_STS_OK) { if (ret != BLK_STS_OK) {
null_unlock_zone_res(dev); spin_unlock(&dev->zone_res_lock);
goto unlock; goto unlock_zone;
} }
if (zone->cond == BLK_ZONE_COND_CLOSED) { if (zone->cond == BLK_ZONE_COND_CLOSED) {
dev->nr_zones_closed--; dev->nr_zones_closed--;
...@@ -430,30 +396,32 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector, ...@@ -430,30 +396,32 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
dev->nr_zones_imp_open++; dev->nr_zones_imp_open++;
} }
if (zone->cond != BLK_ZONE_COND_EXP_OPEN) spin_unlock(&dev->zone_res_lock);
zone->cond = BLK_ZONE_COND_IMP_OPEN; }
null_unlock_zone_res(dev); zone->cond = BLK_ZONE_COND_IMP_OPEN;
} }
ret = null_process_cmd(cmd, REQ_OP_WRITE, sector, nr_sectors); ret = null_process_cmd(cmd, REQ_OP_WRITE, sector, nr_sectors);
if (ret != BLK_STS_OK) if (ret != BLK_STS_OK)
goto unlock; goto unlock_zone;
zone->wp += nr_sectors; zone->wp += nr_sectors;
if (zone->wp == zone->start + zone->capacity) { if (zone->wp == zone->start + zone->capacity) {
null_lock_zone_res(dev); if (dev->need_zone_res_mgmt) {
spin_lock(&dev->zone_res_lock);
if (zone->cond == BLK_ZONE_COND_EXP_OPEN) if (zone->cond == BLK_ZONE_COND_EXP_OPEN)
dev->nr_zones_exp_open--; dev->nr_zones_exp_open--;
else if (zone->cond == BLK_ZONE_COND_IMP_OPEN) else if (zone->cond == BLK_ZONE_COND_IMP_OPEN)
dev->nr_zones_imp_open--; dev->nr_zones_imp_open--;
spin_unlock(&dev->zone_res_lock);
}
zone->cond = BLK_ZONE_COND_FULL; zone->cond = BLK_ZONE_COND_FULL;
null_unlock_zone_res(dev);
} }
ret = BLK_STS_OK; ret = BLK_STS_OK;
unlock: unlock_zone:
null_unlock_zone(dev, zone); null_unlock_zone(dev, zone);
return ret; return ret;
...@@ -467,54 +435,100 @@ static blk_status_t null_open_zone(struct nullb_device *dev, ...@@ -467,54 +435,100 @@ static blk_status_t null_open_zone(struct nullb_device *dev,
if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL) if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
return BLK_STS_IOERR; return BLK_STS_IOERR;
null_lock_zone_res(dev);
switch (zone->cond) { switch (zone->cond) {
case BLK_ZONE_COND_EXP_OPEN: case BLK_ZONE_COND_EXP_OPEN:
/* open operation on exp open is not an error */ /* Open operation on exp open is not an error */
goto unlock; return BLK_STS_OK;
case BLK_ZONE_COND_EMPTY:
case BLK_ZONE_COND_IMP_OPEN:
case BLK_ZONE_COND_CLOSED:
break;
case BLK_ZONE_COND_FULL:
default:
return BLK_STS_IOERR;
}
if (dev->need_zone_res_mgmt) {
spin_lock(&dev->zone_res_lock);
switch (zone->cond) {
case BLK_ZONE_COND_EMPTY: case BLK_ZONE_COND_EMPTY:
ret = null_check_zone_resources(dev, zone); ret = null_check_zone_resources(dev, zone);
if (ret != BLK_STS_OK) if (ret != BLK_STS_OK) {
goto unlock; spin_unlock(&dev->zone_res_lock);
return ret;
}
break; break;
case BLK_ZONE_COND_IMP_OPEN: case BLK_ZONE_COND_IMP_OPEN:
dev->nr_zones_imp_open--; dev->nr_zones_imp_open--;
break; break;
case BLK_ZONE_COND_CLOSED: case BLK_ZONE_COND_CLOSED:
ret = null_check_zone_resources(dev, zone); ret = null_check_zone_resources(dev, zone);
if (ret != BLK_STS_OK) if (ret != BLK_STS_OK) {
goto unlock; spin_unlock(&dev->zone_res_lock);
return ret;
}
dev->nr_zones_closed--; dev->nr_zones_closed--;
break; break;
case BLK_ZONE_COND_FULL:
default: default:
ret = BLK_STS_IOERR; break;
goto unlock;
} }
zone->cond = BLK_ZONE_COND_EXP_OPEN;
dev->nr_zones_exp_open++; dev->nr_zones_exp_open++;
unlock: spin_unlock(&dev->zone_res_lock);
null_unlock_zone_res(dev); }
return ret; zone->cond = BLK_ZONE_COND_EXP_OPEN;
return BLK_STS_OK;
} }
static blk_status_t null_close_zone(struct nullb_device *dev, static blk_status_t null_close_zone(struct nullb_device *dev,
struct nullb_zone *zone) struct nullb_zone *zone)
{ {
blk_status_t ret;
if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL) if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
return BLK_STS_IOERR; return BLK_STS_IOERR;
null_lock_zone_res(dev); switch (zone->cond) {
ret = __null_close_zone(dev, zone); case BLK_ZONE_COND_CLOSED:
null_unlock_zone_res(dev); /* close operation on closed is not an error */
return BLK_STS_OK;
case BLK_ZONE_COND_IMP_OPEN:
case BLK_ZONE_COND_EXP_OPEN:
break;
case BLK_ZONE_COND_EMPTY:
case BLK_ZONE_COND_FULL:
default:
return BLK_STS_IOERR;
}
return ret; if (dev->need_zone_res_mgmt) {
spin_lock(&dev->zone_res_lock);
switch (zone->cond) {
case BLK_ZONE_COND_IMP_OPEN:
dev->nr_zones_imp_open--;
break;
case BLK_ZONE_COND_EXP_OPEN:
dev->nr_zones_exp_open--;
break;
default:
break;
}
if (zone->wp > zone->start)
dev->nr_zones_closed++;
spin_unlock(&dev->zone_res_lock);
}
if (zone->wp == zone->start)
zone->cond = BLK_ZONE_COND_EMPTY;
else
zone->cond = BLK_ZONE_COND_CLOSED;
return BLK_STS_OK;
} }
static blk_status_t null_finish_zone(struct nullb_device *dev, static blk_status_t null_finish_zone(struct nullb_device *dev,
...@@ -525,16 +539,20 @@ static blk_status_t null_finish_zone(struct nullb_device *dev, ...@@ -525,16 +539,20 @@ static blk_status_t null_finish_zone(struct nullb_device *dev,
if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL) if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
return BLK_STS_IOERR; return BLK_STS_IOERR;
null_lock_zone_res(dev); if (dev->need_zone_res_mgmt) {
spin_lock(&dev->zone_res_lock);
switch (zone->cond) { switch (zone->cond) {
case BLK_ZONE_COND_FULL: case BLK_ZONE_COND_FULL:
/* finish operation on full is not an error */ /* Finish operation on full is not an error */
goto unlock; spin_unlock(&dev->zone_res_lock);
return BLK_STS_OK;
case BLK_ZONE_COND_EMPTY: case BLK_ZONE_COND_EMPTY:
ret = null_check_zone_resources(dev, zone); ret = null_check_zone_resources(dev, zone);
if (ret != BLK_STS_OK) if (ret != BLK_STS_OK) {
goto unlock; spin_unlock(&dev->zone_res_lock);
return ret;
}
break; break;
case BLK_ZONE_COND_IMP_OPEN: case BLK_ZONE_COND_IMP_OPEN:
dev->nr_zones_imp_open--; dev->nr_zones_imp_open--;
...@@ -544,22 +562,24 @@ static blk_status_t null_finish_zone(struct nullb_device *dev, ...@@ -544,22 +562,24 @@ static blk_status_t null_finish_zone(struct nullb_device *dev,
break; break;
case BLK_ZONE_COND_CLOSED: case BLK_ZONE_COND_CLOSED:
ret = null_check_zone_resources(dev, zone); ret = null_check_zone_resources(dev, zone);
if (ret != BLK_STS_OK) if (ret != BLK_STS_OK) {
goto unlock; spin_unlock(&dev->zone_res_lock);
return ret;
}
dev->nr_zones_closed--; dev->nr_zones_closed--;
break; break;
default: default:
ret = BLK_STS_IOERR; spin_unlock(&dev->zone_res_lock);
goto unlock; return BLK_STS_IOERR;
}
spin_unlock(&dev->zone_res_lock);
} }
zone->cond = BLK_ZONE_COND_FULL; zone->cond = BLK_ZONE_COND_FULL;
zone->wp = zone->start + zone->len; zone->wp = zone->start + zone->len;
unlock: return BLK_STS_OK;
null_unlock_zone_res(dev);
return ret;
} }
static blk_status_t null_reset_zone(struct nullb_device *dev, static blk_status_t null_reset_zone(struct nullb_device *dev,
...@@ -568,13 +588,10 @@ static blk_status_t null_reset_zone(struct nullb_device *dev, ...@@ -568,13 +588,10 @@ static blk_status_t null_reset_zone(struct nullb_device *dev,
if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL) if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
return BLK_STS_IOERR; return BLK_STS_IOERR;
null_lock_zone_res(dev); if (dev->need_zone_res_mgmt) {
spin_lock(&dev->zone_res_lock);
switch (zone->cond) { switch (zone->cond) {
case BLK_ZONE_COND_EMPTY:
/* reset operation on empty is not an error */
null_unlock_zone_res(dev);
return BLK_STS_OK;
case BLK_ZONE_COND_IMP_OPEN: case BLK_ZONE_COND_IMP_OPEN:
dev->nr_zones_imp_open--; dev->nr_zones_imp_open--;
break; break;
...@@ -584,18 +601,20 @@ static blk_status_t null_reset_zone(struct nullb_device *dev, ...@@ -584,18 +601,20 @@ static blk_status_t null_reset_zone(struct nullb_device *dev,
case BLK_ZONE_COND_CLOSED: case BLK_ZONE_COND_CLOSED:
dev->nr_zones_closed--; dev->nr_zones_closed--;
break; break;
case BLK_ZONE_COND_EMPTY:
case BLK_ZONE_COND_FULL: case BLK_ZONE_COND_FULL:
break; break;
default: default:
null_unlock_zone_res(dev); spin_unlock(&dev->zone_res_lock);
return BLK_STS_IOERR; return BLK_STS_IOERR;
} }
spin_unlock(&dev->zone_res_lock);
}
zone->cond = BLK_ZONE_COND_EMPTY; zone->cond = BLK_ZONE_COND_EMPTY;
zone->wp = zone->start; zone->wp = zone->start;
null_unlock_zone_res(dev);
if (dev->memory_backed) if (dev->memory_backed)
return null_handle_discard(dev, zone->start, zone->len); return null_handle_discard(dev, zone->start, zone->len);
......
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