fio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] fix max open zones handling when using multiple jobs
@ 2021-06-24 17:23 Niklas Cassel
  2021-06-24 17:23 ` [PATCH 1/3] zbd: create a local zbdi variable for f->zbd_info Niklas Cassel
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Niklas Cassel @ 2021-06-24 17:23 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Shinichiro Kawasaki, adobriyan, Niklas Cassel

From: Niklas Cassel <niklas.cassel@wdc.com>

Currently, the fio handling of max open zones is very fragile.

zbd_open_zone() uses zbd_info->max_open_zones when checking
the max open zones limit, while zbd_convert_to_open_zone()
uses td->o.max_open_zones when performing the same limit check.

It is simply wrong to use td->o.max_open_zones after zbd_setup_files().

Change zbd_convert_to_open_zone() to use zbd_info->max_open_zones.
This way, the global max open zones limit (which is per device) will be
respected for all jobs.

This series also adds a patch that reintroduces the ability to
run write workloads with no limit on the maximum number of open zones.
In this case, tracking of open zones in the zbd_info->open_zones array
is disabled to reduce overhead.


Niklas Cassel (3):
  zbd: create a local zbdi variable for f->zbd_info
  zbd: allow an unlimited global max open zones limit
  zbd: ensure that global max open zones limit is respected

 zbd.c | 111 +++++++++++++++++++++++++++++++++++++---------------------
 zbd.h |   3 +-
 2 files changed, 73 insertions(+), 41 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/3] zbd: create a local zbdi variable for f->zbd_info
  2021-06-24 17:23 [PATCH 0/3] fix max open zones handling when using multiple jobs Niklas Cassel
@ 2021-06-24 17:23 ` Niklas Cassel
  2021-06-24 20:09   ` Alexey Dobriyan
  2021-06-25  7:07   ` Damien Le Moal
  2021-06-24 17:23 ` [PATCH 2/3] zbd: allow an unlimited global max open zones limit Niklas Cassel
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 11+ messages in thread
From: Niklas Cassel @ 2021-06-24 17:23 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Shinichiro Kawasaki, adobriyan, Niklas Cassel

From: Niklas Cassel <niklas.cassel@wdc.com>

Create a local zbdi variable for f->zbd_info for the following functions:
zbd_open_zone(), zbd_convert_to_open_zone(), and zbd_adjust_block().

This avoids unnecessary indirections.

No functional change intended.

Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
---
 zbd.c | 69 +++++++++++++++++++++++++++++++----------------------------
 1 file changed, 36 insertions(+), 33 deletions(-)

diff --git a/zbd.c b/zbd.c
index 8e99eb95..f09b0ee6 100644
--- a/zbd.c
+++ b/zbd.c
@@ -1114,6 +1114,7 @@ static bool zbd_open_zone(struct thread_data *td, const struct fio_file *f,
 			  uint32_t zone_idx)
 {
 	const uint32_t min_bs = td->o.min_bs[DDIR_WRITE];
+	struct zoned_block_device_info *zbdi = f->zbd_info;
 	struct fio_zone_info *z = get_zone(f, zone_idx);
 	bool res = true;
 
@@ -1127,7 +1128,7 @@ static bool zbd_open_zone(struct thread_data *td, const struct fio_file *f,
 	if (td->o.verify != VERIFY_NONE && zbd_zone_full(f, z, min_bs))
 		return false;
 
-	pthread_mutex_lock(&f->zbd_info->mutex);
+	pthread_mutex_lock(&zbdi->mutex);
 	if (is_zone_open(td, f, zone_idx)) {
 		/*
 		 * If the zone is already open and going to be full by writes
@@ -1142,16 +1143,16 @@ static bool zbd_open_zone(struct thread_data *td, const struct fio_file *f,
 	if (td->o.job_max_open_zones > 0 &&
 	    td->num_open_zones >= td->o.job_max_open_zones)
 		goto out;
-	if (f->zbd_info->num_open_zones >= f->zbd_info->max_open_zones)
+	if (zbdi->num_open_zones >= zbdi->max_open_zones)
 		goto out;
 	dprint(FD_ZBD, "%s: opening zone %d\n", f->file_name, zone_idx);
-	f->zbd_info->open_zones[f->zbd_info->num_open_zones++] = zone_idx;
+	zbdi->open_zones[zbdi->num_open_zones++] = zone_idx;
 	td->num_open_zones++;
 	z->open = 1;
 	res = true;
 
 out:
-	pthread_mutex_unlock(&f->zbd_info->mutex);
+	pthread_mutex_unlock(&zbdi->mutex);
 	return res;
 }
 
@@ -1175,6 +1176,7 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
 {
 	const uint32_t min_bs = td->o.min_bs[io_u->ddir];
 	struct fio_file *f = io_u->file;
+	struct zoned_block_device_info *zbdi = f->zbd_info;
 	struct fio_zone_info *z;
 	unsigned int open_zone_idx = -1;
 	uint32_t zone_idx, new_zone_idx;
@@ -1185,10 +1187,10 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
 
 	if (td->o.max_open_zones || td->o.job_max_open_zones) {
 		/*
-		 * This statement accesses f->zbd_info->open_zones[] on purpose
+		 * This statement accesses zbdi->open_zones[] on purpose
 		 * without locking.
 		 */
-		zone_idx = f->zbd_info->open_zones[pick_random_zone_idx(f, io_u)];
+		zone_idx = zbdi->open_zones[pick_random_zone_idx(f, io_u)];
 	} else {
 		zone_idx = zbd_zone_idx(f, io_u->offset);
 	}
@@ -1200,9 +1202,9 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
 	       __func__, f->file_name, zone_idx, io_u->offset, io_u->buflen);
 
 	/*
-	 * Since z->mutex is the outer lock and f->zbd_info->mutex the inner
+	 * Since z->mutex is the outer lock and zbdi->mutex the inner
 	 * lock it can happen that the state of the zone with index zone_idx
-	 * has changed after 'z' has been assigned and before f->zbd_info->mutex
+	 * has changed after 'z' has been assigned and before zbdi->mutex
 	 * has been obtained. Hence the loop.
 	 */
 	for (;;) {
@@ -1211,12 +1213,12 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
 		z = get_zone(f, zone_idx);
 		if (z->has_wp)
 			zone_lock(td, f, z);
-		pthread_mutex_lock(&f->zbd_info->mutex);
+		pthread_mutex_lock(&zbdi->mutex);
 		if (z->has_wp) {
 			if (z->cond != ZBD_ZONE_COND_OFFLINE &&
 			    td->o.max_open_zones == 0 && td->o.job_max_open_zones == 0)
 				goto examine_zone;
-			if (f->zbd_info->num_open_zones == 0) {
+			if (zbdi->num_open_zones == 0) {
 				dprint(FD_ZBD, "%s(%s): no zones are open\n",
 				       __func__, f->file_name);
 				goto open_other_zone;
@@ -1230,14 +1232,14 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
 		 */
 		open_zone_idx = pick_random_zone_idx(f, io_u);
 		assert(!open_zone_idx ||
-		       open_zone_idx < f->zbd_info->num_open_zones);
+		       open_zone_idx < zbdi->num_open_zones);
 		tmp_idx = open_zone_idx;
-		for (i = 0; i < f->zbd_info->num_open_zones; i++) {
+		for (i = 0; i < zbdi->num_open_zones; i++) {
 			uint32_t tmpz;
 
-			if (tmp_idx >= f->zbd_info->num_open_zones)
+			if (tmp_idx >= zbdi->num_open_zones)
 				tmp_idx = 0;
-			tmpz = f->zbd_info->open_zones[tmp_idx];
+			tmpz = zbdi->open_zones[tmp_idx];
 			if (f->min_zone <= tmpz && tmpz < f->max_zone) {
 				open_zone_idx = tmp_idx;
 				goto found_candidate_zone;
@@ -1248,39 +1250,39 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
 
 		dprint(FD_ZBD, "%s(%s): no candidate zone\n",
 			__func__, f->file_name);
-		pthread_mutex_unlock(&f->zbd_info->mutex);
+		pthread_mutex_unlock(&zbdi->mutex);
 		if (z->has_wp)
 			zone_unlock(z);
 		return NULL;
 
 found_candidate_zone:
-		new_zone_idx = f->zbd_info->open_zones[open_zone_idx];
+		new_zone_idx = zbdi->open_zones[open_zone_idx];
 		if (new_zone_idx == zone_idx)
 			break;
 		zone_idx = new_zone_idx;
-		pthread_mutex_unlock(&f->zbd_info->mutex);
+		pthread_mutex_unlock(&zbdi->mutex);
 		if (z->has_wp)
 			zone_unlock(z);
 	}
 
-	/* Both z->mutex and f->zbd_info->mutex are held. */
+	/* Both z->mutex and zbdi->mutex are held. */
 
 examine_zone:
 	if (z->wp + min_bs <= zbd_zone_capacity_end(z)) {
-		pthread_mutex_unlock(&f->zbd_info->mutex);
+		pthread_mutex_unlock(&zbdi->mutex);
 		goto out;
 	}
 
 open_other_zone:
 	/* Check if number of open zones reaches one of limits. */
 	wait_zone_close =
-		f->zbd_info->num_open_zones == f->max_zone - f->min_zone ||
+		zbdi->num_open_zones == f->max_zone - f->min_zone ||
 		(td->o.max_open_zones &&
-		 f->zbd_info->num_open_zones == td->o.max_open_zones) ||
+		 zbdi->num_open_zones == td->o.max_open_zones) ||
 		(td->o.job_max_open_zones &&
 		 td->num_open_zones == td->o.job_max_open_zones);
 
-	pthread_mutex_unlock(&f->zbd_info->mutex);
+	pthread_mutex_unlock(&zbdi->mutex);
 
 	/* Only z->mutex is held. */
 
@@ -1295,7 +1297,7 @@ open_other_zone:
 	}
 
 	/* Zone 'z' is full, so try to open a new zone. */
-	for (i = f->io_size / f->zbd_info->zone_size; i > 0; i--) {
+	for (i = f->io_size / zbdi->zone_size; i > 0; i--) {
 		zone_idx++;
 		if (z->has_wp)
 			zone_unlock(z);
@@ -1318,12 +1320,12 @@ open_other_zone:
 	/* Only z->mutex is held. */
 
 	/* Check whether the write fits in any of the already opened zones. */
-	pthread_mutex_lock(&f->zbd_info->mutex);
-	for (i = 0; i < f->zbd_info->num_open_zones; i++) {
-		zone_idx = f->zbd_info->open_zones[i];
+	pthread_mutex_lock(&zbdi->mutex);
+	for (i = 0; i < zbdi->num_open_zones; i++) {
+		zone_idx = zbdi->open_zones[i];
 		if (zone_idx < f->min_zone || zone_idx >= f->max_zone)
 			continue;
-		pthread_mutex_unlock(&f->zbd_info->mutex);
+		pthread_mutex_unlock(&zbdi->mutex);
 		zone_unlock(z);
 
 		z = get_zone(f, zone_idx);
@@ -1331,9 +1333,9 @@ open_other_zone:
 		zone_lock(td, f, z);
 		if (z->wp + min_bs <= zbd_zone_capacity_end(z))
 			goto out;
-		pthread_mutex_lock(&f->zbd_info->mutex);
+		pthread_mutex_lock(&zbdi->mutex);
 	}
-	pthread_mutex_unlock(&f->zbd_info->mutex);
+	pthread_mutex_unlock(&zbdi->mutex);
 	zone_unlock(z);
 	dprint(FD_ZBD, "%s(%s): did not open another zone\n", __func__,
 	       f->file_name);
@@ -1683,6 +1685,7 @@ enum fio_ddir zbd_adjust_ddir(struct thread_data *td, struct io_u *io_u,
 enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u)
 {
 	struct fio_file *f = io_u->file;
+	struct zoned_block_device_info *zbdi = f->zbd_info;
 	uint32_t zone_idx_b;
 	struct fio_zone_info *zb, *zl, *orig_zb;
 	uint32_t orig_len = io_u->buflen;
@@ -1690,7 +1693,7 @@ enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u)
 	uint64_t new_len;
 	int64_t range;
 
-	assert(f->zbd_info);
+	assert(zbdi);
 	assert(min_bs);
 	assert(is_valid_offset(f, io_u->offset));
 	assert(io_u->buflen);
@@ -1802,12 +1805,12 @@ enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u)
 		assert(io_u->offset + io_u->buflen <= zb->wp);
 		goto accept;
 	case DDIR_WRITE:
-		if (io_u->buflen > f->zbd_info->zone_size) {
+		if (io_u->buflen > zbdi->zone_size) {
 			td_verror(td, EINVAL, "I/O buflen exceeds zone size");
 			dprint(FD_IO,
 			       "%s: I/O buflen %llu exceeds zone size %llu\n",
 			       f->file_name, io_u->buflen,
-			       (unsigned long long) f->zbd_info->zone_size);
+			       (unsigned long long) zbdi->zone_size);
 			goto eof;
 		}
 		if (!zbd_open_zone(td, f, zone_idx_b)) {
@@ -1822,7 +1825,7 @@ enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u)
 		}
 		/* Check whether the zone reset threshold has been exceeded */
 		if (td->o.zrf.u.f) {
-			if (f->zbd_info->wp_sectors_with_data >=
+			if (zbdi->wp_sectors_with_data >=
 			    f->io_size * td->o.zrt.u.f &&
 			    zbd_dec_and_reset_write_cnt(td, f)) {
 				zb->reset_zone = 1;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/3] zbd: allow an unlimited global max open zones limit
  2021-06-24 17:23 [PATCH 0/3] fix max open zones handling when using multiple jobs Niklas Cassel
  2021-06-24 17:23 ` [PATCH 1/3] zbd: create a local zbdi variable for f->zbd_info Niklas Cassel
@ 2021-06-24 17:23 ` Niklas Cassel
  2021-06-25  7:09   ` Damien Le Moal
  2021-06-24 17:23 ` [PATCH 3/3] zbd: ensure that global max open zones limit is respected Niklas Cassel
  2021-06-29 13:44 ` [PATCH 0/3] fix max open zones handling when using multiple jobs Jens Axboe
  3 siblings, 1 reply; 11+ messages in thread
From: Niklas Cassel @ 2021-06-24 17:23 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Shinichiro Kawasaki, adobriyan, Niklas Cassel

From: Niklas Cassel <niklas.cassel@wdc.com>

Commit 219c662d3b12 ("zbd: introduce per job maximum open zones limit")
Introduced a global max open zones limit stored in zbd_info->max_open_zones.

This commit also removed the following check from zbd_open_zone():

if (!td->o.max_open_zones)
        return true;

Before the commit in question, if td->o.max_open_zones == 0, zbd_open_zone()
would not track the zone as open in the zbd_info->open_zones array.

After the commit in question, zbd_open_zone() would always track the zone
as open in the zbd_info->open_zones array, regardless if a --max_open_zones
limit was set or not.

Change the initialization of zbd_info->max_open_zones to yet again allow
unlimited max open zones. If zbd_info->max_open_zones is unlimited,
we do not track the open zones in the zbd_info->open zone array.

Not tracking open zones reduces fio overhead for testing the performance of
zoned block devices that do not have a limit on the maximum number of open
zones.

Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
---
 zbd.c | 28 ++++++++++++++++++++++++----
 zbd.h |  3 ++-
 2 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/zbd.c b/zbd.c
index f09b0ee6..f19e3d47 100644
--- a/zbd.c
+++ b/zbd.c
@@ -636,8 +636,12 @@ static int zbd_set_max_open_zones(struct thread_data *td, struct fio_file *f)
 
 out:
 	/* Ensure that the limit is not larger than FIO's internal limit */
-	zbd->max_open_zones = min_not_zero(zbd->max_open_zones,
-					   (uint32_t) ZBD_MAX_OPEN_ZONES);
+	if (zbd->max_open_zones > ZBD_MAX_OPEN_ZONES) {
+		td_verror(td, EINVAL, "'max_open_zones' value is too large");
+		log_err("'max_open_zones' value is larger than %u\n", ZBD_MAX_OPEN_ZONES);
+		return -EINVAL;
+	}
+
 	dprint(FD_ZBD, "%s: using max open zones limit: %"PRIu32"\n",
 	       f->file_name, zbd->max_open_zones);
 
@@ -827,8 +831,14 @@ int zbd_setup_files(struct thread_data *td)
 			log_err("Different 'max_open_zones' values\n");
 			return 1;
 		}
-		if (zbd->max_open_zones > ZBD_MAX_OPEN_ZONES) {
-			log_err("'max_open_zones' value is limited by %u\n", ZBD_MAX_OPEN_ZONES);
+
+		/*
+		 * The per job max open zones limit cannot be used without a
+		 * global max open zones limit. (As the tracking of open zones
+		 * is disabled when there is no global max open zones limit.)
+		 */
+		if (td->o.job_max_open_zones && !zbd->max_open_zones) {
+			log_err("'job_max_open_zones' cannot be used without a global open zones limit\n");
 			return 1;
 		}
 
@@ -1093,6 +1103,8 @@ static bool is_zone_open(const struct thread_data *td, const struct fio_file *f,
 	struct zoned_block_device_info *zbdi = f->zbd_info;
 	int i;
 
+	/* This function should never be called when zbdi->max_open_zones == 0 */
+	assert(zbdi->max_open_zones);
 	assert(td->o.job_max_open_zones == 0 || td->num_open_zones <= td->o.job_max_open_zones);
 	assert(td->o.job_max_open_zones <= zbdi->max_open_zones);
 	assert(zbdi->num_open_zones <= zbdi->max_open_zones);
@@ -1128,6 +1140,14 @@ static bool zbd_open_zone(struct thread_data *td, const struct fio_file *f,
 	if (td->o.verify != VERIFY_NONE && zbd_zone_full(f, z, min_bs))
 		return false;
 
+	/*
+	 * zbdi->max_open_zones == 0 means that there is no limit on the maximum
+	 * number of open zones. In this case, do no track open zones in
+	 * zbdi->open_zones array.
+	 */
+	if (!zbdi->max_open_zones)
+		return true;
+
 	pthread_mutex_lock(&zbdi->mutex);
 	if (is_zone_open(td, f, zone_idx)) {
 		/*
diff --git a/zbd.h b/zbd.h
index 64534393..39dc45e3 100644
--- a/zbd.h
+++ b/zbd.h
@@ -50,7 +50,8 @@ struct fio_zone_info {
  * zoned_block_device_info - zoned block device characteristics
  * @model: Device model.
  * @max_open_zones: global limit on the number of simultaneously opened
- *	sequential write zones.
+ *	sequential write zones. A zero value means unlimited open zones,
+ *	and that open zones will not be tracked in the open_zones array.
  * @mutex: Protects the modifiable members in this structure (refcount and
  *		num_open_zones).
  * @zone_size: size of a single zone in bytes.
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/3] zbd: ensure that global max open zones limit is respected
  2021-06-24 17:23 [PATCH 0/3] fix max open zones handling when using multiple jobs Niklas Cassel
  2021-06-24 17:23 ` [PATCH 1/3] zbd: create a local zbdi variable for f->zbd_info Niklas Cassel
  2021-06-24 17:23 ` [PATCH 2/3] zbd: allow an unlimited global max open zones limit Niklas Cassel
@ 2021-06-24 17:23 ` Niklas Cassel
  2021-06-25  7:11   ` Damien Le Moal
  2021-06-25  7:48   ` Shinichiro Kawasaki
  2021-06-29 13:44 ` [PATCH 0/3] fix max open zones handling when using multiple jobs Jens Axboe
  3 siblings, 2 replies; 11+ messages in thread
From: Niklas Cassel @ 2021-06-24 17:23 UTC (permalink / raw)
  To: axboe; +Cc: fio, Damien Le Moal, Shinichiro Kawasaki, adobriyan, Niklas Cassel

From: Niklas Cassel <niklas.cassel@wdc.com>

Commit 219c662d3b12 ("zbd: introduce per job maximum open zones limit")
Introduced a global max open zones limit stored in zbd_info->max_open_zones.

This commit also changed checks against td->o.max_open_zones in zbd_open_zone()
with checks against zbd_info->max_open_zones.

It is obvious that zbd_info->max_open_zones was intended to replace
td->o.max_open_zones in all code that is executed after zbd_setup_files().

The commit itself was needed since zbd_info is shared over different jobs,
so it is important that the global limit of max open zones is the same,
for different jobs targeting the same device.

The problem with this commit is that in zbd_convert_to_open_zone(),
instead of replacing td->o.max_open_zones with zbd_info->max_open_zones,
it incorrectly just removed the references to td->o.max_open_zones.

This caused commit 00ca8df5468e ("zbd: Fix max_open_zones checks")
(written by another author) to incorrectly re-add the removed
td->o.max_open_zones checks in zbd_convert_to_open_zone().
The proper fix here should have been to add checks against
zbd_info->max_open_zones instead of td->o.max_open_zones,
just like the original author did for zbd_open_zone().

Replace all td->o.max_open_zones uses past zbd_setup_files() with
zbd_info->max_open_zones, and force set td->o.max_open_zones to
zbd_info->max_open_zones in zbd_setup_files(), so that even if checks are
introduced against the wrong limit, fio will still respect the global limit.

Fixes: 00ca8df5468e ("zbd: Fix max_open_zones checks")
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
---
 zbd.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/zbd.c b/zbd.c
index f19e3d47..04c68dea 100644
--- a/zbd.c
+++ b/zbd.c
@@ -842,6 +842,14 @@ int zbd_setup_files(struct thread_data *td)
 			return 1;
 		}
 
+		/*
+		 * zbd->max_open_zones is the global limit shared for all jobs
+		 * that target the same zoned block device. Force sync the per
+		 * thread global limit with the actual global limit. (The real
+		 * per thread/job limit is stored in td->o.job_max_open_zones).
+		 */
+		td->o.max_open_zones = zbd->max_open_zones;
+
 		for (zi = f->min_zone; zi < f->max_zone; zi++) {
 			z = &zbd->zone_info[zi];
 			if (z->cond != ZBD_ZONE_COND_IMP_OPEN &&
@@ -1205,7 +1213,7 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
 
 	assert(is_valid_offset(f, io_u->offset));
 
-	if (td->o.max_open_zones || td->o.job_max_open_zones) {
+	if (zbdi->max_open_zones || td->o.job_max_open_zones) {
 		/*
 		 * This statement accesses zbdi->open_zones[] on purpose
 		 * without locking.
@@ -1236,7 +1244,7 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
 		pthread_mutex_lock(&zbdi->mutex);
 		if (z->has_wp) {
 			if (z->cond != ZBD_ZONE_COND_OFFLINE &&
-			    td->o.max_open_zones == 0 && td->o.job_max_open_zones == 0)
+			    zbdi->max_open_zones == 0 && td->o.job_max_open_zones == 0)
 				goto examine_zone;
 			if (zbdi->num_open_zones == 0) {
 				dprint(FD_ZBD, "%s(%s): no zones are open\n",
@@ -1297,8 +1305,8 @@ open_other_zone:
 	/* Check if number of open zones reaches one of limits. */
 	wait_zone_close =
 		zbdi->num_open_zones == f->max_zone - f->min_zone ||
-		(td->o.max_open_zones &&
-		 zbdi->num_open_zones == td->o.max_open_zones) ||
+		(zbdi->max_open_zones &&
+		 zbdi->num_open_zones == zbdi->max_open_zones) ||
 		(td->o.job_max_open_zones &&
 		 td->num_open_zones == td->o.job_max_open_zones);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/3] zbd: create a local zbdi variable for f->zbd_info
  2021-06-24 17:23 ` [PATCH 1/3] zbd: create a local zbdi variable for f->zbd_info Niklas Cassel
@ 2021-06-24 20:09   ` Alexey Dobriyan
  2021-06-28 10:42     ` Niklas Cassel
  2021-06-25  7:07   ` Damien Le Moal
  1 sibling, 1 reply; 11+ messages in thread
From: Alexey Dobriyan @ 2021-06-24 20:09 UTC (permalink / raw)
  To: Niklas Cassel; +Cc: axboe, fio, Damien Le Moal, Shinichiro Kawasaki

On Thu, Jun 24, 2021 at 05:23:07PM +0000, Niklas Cassel wrote:
> +	struct zoned_block_device_info *zbdi = f->zbd_info;

It is unrelated to the patch. But! It is impossible to type
"zoned_block_device_info" without autocompletion.

Can it be renamed just to 

	struct zbd * const zbd = f->zbd_info;

"info" is kind of information free word, too.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/3] zbd: create a local zbdi variable for f->zbd_info
  2021-06-24 17:23 ` [PATCH 1/3] zbd: create a local zbdi variable for f->zbd_info Niklas Cassel
  2021-06-24 20:09   ` Alexey Dobriyan
@ 2021-06-25  7:07   ` Damien Le Moal
  1 sibling, 0 replies; 11+ messages in thread
From: Damien Le Moal @ 2021-06-25  7:07 UTC (permalink / raw)
  To: Niklas Cassel, axboe; +Cc: fio, Shinichiro Kawasaki, adobriyan

On 2021/06/25 2:23, Niklas Cassel wrote:
> From: Niklas Cassel <niklas.cassel@wdc.com>
> 
> Create a local zbdi variable for f->zbd_info for the following functions:
> zbd_open_zone(), zbd_convert_to_open_zone(), and zbd_adjust_block().
> 
> This avoids unnecessary indirections.
> 
> No functional change intended.
> 
> Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
> ---
>  zbd.c | 69 +++++++++++++++++++++++++++++++----------------------------
>  1 file changed, 36 insertions(+), 33 deletions(-)
> 
> diff --git a/zbd.c b/zbd.c
> index 8e99eb95..f09b0ee6 100644
> --- a/zbd.c
> +++ b/zbd.c
> @@ -1114,6 +1114,7 @@ static bool zbd_open_zone(struct thread_data *td, const struct fio_file *f,
>  			  uint32_t zone_idx)
>  {
>  	const uint32_t min_bs = td->o.min_bs[DDIR_WRITE];
> +	struct zoned_block_device_info *zbdi = f->zbd_info;
>  	struct fio_zone_info *z = get_zone(f, zone_idx);
>  	bool res = true;
>  
> @@ -1127,7 +1128,7 @@ static bool zbd_open_zone(struct thread_data *td, const struct fio_file *f,
>  	if (td->o.verify != VERIFY_NONE && zbd_zone_full(f, z, min_bs))
>  		return false;
>  
> -	pthread_mutex_lock(&f->zbd_info->mutex);
> +	pthread_mutex_lock(&zbdi->mutex);
>  	if (is_zone_open(td, f, zone_idx)) {
>  		/*
>  		 * If the zone is already open and going to be full by writes
> @@ -1142,16 +1143,16 @@ static bool zbd_open_zone(struct thread_data *td, const struct fio_file *f,
>  	if (td->o.job_max_open_zones > 0 &&
>  	    td->num_open_zones >= td->o.job_max_open_zones)
>  		goto out;
> -	if (f->zbd_info->num_open_zones >= f->zbd_info->max_open_zones)
> +	if (zbdi->num_open_zones >= zbdi->max_open_zones)
>  		goto out;
>  	dprint(FD_ZBD, "%s: opening zone %d\n", f->file_name, zone_idx);
> -	f->zbd_info->open_zones[f->zbd_info->num_open_zones++] = zone_idx;
> +	zbdi->open_zones[zbdi->num_open_zones++] = zone_idx;
>  	td->num_open_zones++;
>  	z->open = 1;
>  	res = true;
>  
>  out:
> -	pthread_mutex_unlock(&f->zbd_info->mutex);
> +	pthread_mutex_unlock(&zbdi->mutex);
>  	return res;
>  }
>  
> @@ -1175,6 +1176,7 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
>  {
>  	const uint32_t min_bs = td->o.min_bs[io_u->ddir];
>  	struct fio_file *f = io_u->file;
> +	struct zoned_block_device_info *zbdi = f->zbd_info;
>  	struct fio_zone_info *z;
>  	unsigned int open_zone_idx = -1;
>  	uint32_t zone_idx, new_zone_idx;
> @@ -1185,10 +1187,10 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
>  
>  	if (td->o.max_open_zones || td->o.job_max_open_zones) {
>  		/*
> -		 * This statement accesses f->zbd_info->open_zones[] on purpose
> +		 * This statement accesses zbdi->open_zones[] on purpose
>  		 * without locking.
>  		 */
> -		zone_idx = f->zbd_info->open_zones[pick_random_zone_idx(f, io_u)];
> +		zone_idx = zbdi->open_zones[pick_random_zone_idx(f, io_u)];
>  	} else {
>  		zone_idx = zbd_zone_idx(f, io_u->offset);
>  	}
> @@ -1200,9 +1202,9 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
>  	       __func__, f->file_name, zone_idx, io_u->offset, io_u->buflen);
>  
>  	/*
> -	 * Since z->mutex is the outer lock and f->zbd_info->mutex the inner
> +	 * Since z->mutex is the outer lock and zbdi->mutex the inner
>  	 * lock it can happen that the state of the zone with index zone_idx
> -	 * has changed after 'z' has been assigned and before f->zbd_info->mutex
> +	 * has changed after 'z' has been assigned and before zbdi->mutex
>  	 * has been obtained. Hence the loop.
>  	 */
>  	for (;;) {
> @@ -1211,12 +1213,12 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
>  		z = get_zone(f, zone_idx);
>  		if (z->has_wp)
>  			zone_lock(td, f, z);
> -		pthread_mutex_lock(&f->zbd_info->mutex);
> +		pthread_mutex_lock(&zbdi->mutex);
>  		if (z->has_wp) {
>  			if (z->cond != ZBD_ZONE_COND_OFFLINE &&
>  			    td->o.max_open_zones == 0 && td->o.job_max_open_zones == 0)
>  				goto examine_zone;
> -			if (f->zbd_info->num_open_zones == 0) {
> +			if (zbdi->num_open_zones == 0) {
>  				dprint(FD_ZBD, "%s(%s): no zones are open\n",
>  				       __func__, f->file_name);
>  				goto open_other_zone;
> @@ -1230,14 +1232,14 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
>  		 */
>  		open_zone_idx = pick_random_zone_idx(f, io_u);
>  		assert(!open_zone_idx ||
> -		       open_zone_idx < f->zbd_info->num_open_zones);
> +		       open_zone_idx < zbdi->num_open_zones);
>  		tmp_idx = open_zone_idx;
> -		for (i = 0; i < f->zbd_info->num_open_zones; i++) {
> +		for (i = 0; i < zbdi->num_open_zones; i++) {
>  			uint32_t tmpz;
>  
> -			if (tmp_idx >= f->zbd_info->num_open_zones)
> +			if (tmp_idx >= zbdi->num_open_zones)
>  				tmp_idx = 0;
> -			tmpz = f->zbd_info->open_zones[tmp_idx];
> +			tmpz = zbdi->open_zones[tmp_idx];
>  			if (f->min_zone <= tmpz && tmpz < f->max_zone) {
>  				open_zone_idx = tmp_idx;
>  				goto found_candidate_zone;
> @@ -1248,39 +1250,39 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
>  
>  		dprint(FD_ZBD, "%s(%s): no candidate zone\n",
>  			__func__, f->file_name);
> -		pthread_mutex_unlock(&f->zbd_info->mutex);
> +		pthread_mutex_unlock(&zbdi->mutex);
>  		if (z->has_wp)
>  			zone_unlock(z);
>  		return NULL;
>  
>  found_candidate_zone:
> -		new_zone_idx = f->zbd_info->open_zones[open_zone_idx];
> +		new_zone_idx = zbdi->open_zones[open_zone_idx];
>  		if (new_zone_idx == zone_idx)
>  			break;
>  		zone_idx = new_zone_idx;
> -		pthread_mutex_unlock(&f->zbd_info->mutex);
> +		pthread_mutex_unlock(&zbdi->mutex);
>  		if (z->has_wp)
>  			zone_unlock(z);
>  	}
>  
> -	/* Both z->mutex and f->zbd_info->mutex are held. */
> +	/* Both z->mutex and zbdi->mutex are held. */
>  
>  examine_zone:
>  	if (z->wp + min_bs <= zbd_zone_capacity_end(z)) {
> -		pthread_mutex_unlock(&f->zbd_info->mutex);
> +		pthread_mutex_unlock(&zbdi->mutex);
>  		goto out;
>  	}
>  
>  open_other_zone:
>  	/* Check if number of open zones reaches one of limits. */
>  	wait_zone_close =
> -		f->zbd_info->num_open_zones == f->max_zone - f->min_zone ||
> +		zbdi->num_open_zones == f->max_zone - f->min_zone ||
>  		(td->o.max_open_zones &&
> -		 f->zbd_info->num_open_zones == td->o.max_open_zones) ||
> +		 zbdi->num_open_zones == td->o.max_open_zones) ||
>  		(td->o.job_max_open_zones &&
>  		 td->num_open_zones == td->o.job_max_open_zones);
>  
> -	pthread_mutex_unlock(&f->zbd_info->mutex);
> +	pthread_mutex_unlock(&zbdi->mutex);
>  
>  	/* Only z->mutex is held. */
>  
> @@ -1295,7 +1297,7 @@ open_other_zone:
>  	}
>  
>  	/* Zone 'z' is full, so try to open a new zone. */
> -	for (i = f->io_size / f->zbd_info->zone_size; i > 0; i--) {
> +	for (i = f->io_size / zbdi->zone_size; i > 0; i--) {
>  		zone_idx++;
>  		if (z->has_wp)
>  			zone_unlock(z);
> @@ -1318,12 +1320,12 @@ open_other_zone:
>  	/* Only z->mutex is held. */
>  
>  	/* Check whether the write fits in any of the already opened zones. */
> -	pthread_mutex_lock(&f->zbd_info->mutex);
> -	for (i = 0; i < f->zbd_info->num_open_zones; i++) {
> -		zone_idx = f->zbd_info->open_zones[i];
> +	pthread_mutex_lock(&zbdi->mutex);
> +	for (i = 0; i < zbdi->num_open_zones; i++) {
> +		zone_idx = zbdi->open_zones[i];
>  		if (zone_idx < f->min_zone || zone_idx >= f->max_zone)
>  			continue;
> -		pthread_mutex_unlock(&f->zbd_info->mutex);
> +		pthread_mutex_unlock(&zbdi->mutex);
>  		zone_unlock(z);
>  
>  		z = get_zone(f, zone_idx);
> @@ -1331,9 +1333,9 @@ open_other_zone:
>  		zone_lock(td, f, z);
>  		if (z->wp + min_bs <= zbd_zone_capacity_end(z))
>  			goto out;
> -		pthread_mutex_lock(&f->zbd_info->mutex);
> +		pthread_mutex_lock(&zbdi->mutex);
>  	}
> -	pthread_mutex_unlock(&f->zbd_info->mutex);
> +	pthread_mutex_unlock(&zbdi->mutex);
>  	zone_unlock(z);
>  	dprint(FD_ZBD, "%s(%s): did not open another zone\n", __func__,
>  	       f->file_name);
> @@ -1683,6 +1685,7 @@ enum fio_ddir zbd_adjust_ddir(struct thread_data *td, struct io_u *io_u,
>  enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u)
>  {
>  	struct fio_file *f = io_u->file;
> +	struct zoned_block_device_info *zbdi = f->zbd_info;
>  	uint32_t zone_idx_b;
>  	struct fio_zone_info *zb, *zl, *orig_zb;
>  	uint32_t orig_len = io_u->buflen;
> @@ -1690,7 +1693,7 @@ enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u)
>  	uint64_t new_len;
>  	int64_t range;
>  
> -	assert(f->zbd_info);
> +	assert(zbdi);
>  	assert(min_bs);
>  	assert(is_valid_offset(f, io_u->offset));
>  	assert(io_u->buflen);
> @@ -1802,12 +1805,12 @@ enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u)
>  		assert(io_u->offset + io_u->buflen <= zb->wp);
>  		goto accept;
>  	case DDIR_WRITE:
> -		if (io_u->buflen > f->zbd_info->zone_size) {
> +		if (io_u->buflen > zbdi->zone_size) {
>  			td_verror(td, EINVAL, "I/O buflen exceeds zone size");
>  			dprint(FD_IO,
>  			       "%s: I/O buflen %llu exceeds zone size %llu\n",
>  			       f->file_name, io_u->buflen,
> -			       (unsigned long long) f->zbd_info->zone_size);
> +			       (unsigned long long) zbdi->zone_size);
>  			goto eof;
>  		}
>  		if (!zbd_open_zone(td, f, zone_idx_b)) {
> @@ -1822,7 +1825,7 @@ enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u)
>  		}
>  		/* Check whether the zone reset threshold has been exceeded */
>  		if (td->o.zrf.u.f) {
> -			if (f->zbd_info->wp_sectors_with_data >=
> +			if (zbdi->wp_sectors_with_data >=
>  			    f->io_size * td->o.zrt.u.f &&
>  			    zbd_dec_and_reset_write_cnt(td, f)) {
>  				zb->reset_zone = 1;
> 

Looks good.

Reviewed-by: Damien Le Moal <damien.lemoal@wdc.com>

-- 
Damien Le Moal
Western Digital Research


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/3] zbd: allow an unlimited global max open zones limit
  2021-06-24 17:23 ` [PATCH 2/3] zbd: allow an unlimited global max open zones limit Niklas Cassel
@ 2021-06-25  7:09   ` Damien Le Moal
  0 siblings, 0 replies; 11+ messages in thread
From: Damien Le Moal @ 2021-06-25  7:09 UTC (permalink / raw)
  To: Niklas Cassel, axboe; +Cc: fio, Shinichiro Kawasaki, adobriyan

On 2021/06/25 2:23, Niklas Cassel wrote:
> From: Niklas Cassel <niklas.cassel@wdc.com>
> 
> Commit 219c662d3b12 ("zbd: introduce per job maximum open zones limit")
> Introduced a global max open zones limit stored in zbd_info->max_open_zones.
> 
> This commit also removed the following check from zbd_open_zone():
> 
> if (!td->o.max_open_zones)
>         return true;
> 
> Before the commit in question, if td->o.max_open_zones == 0, zbd_open_zone()
> would not track the zone as open in the zbd_info->open_zones array.
> 
> After the commit in question, zbd_open_zone() would always track the zone
> as open in the zbd_info->open_zones array, regardless if a --max_open_zones
> limit was set or not.
> 
> Change the initialization of zbd_info->max_open_zones to yet again allow
> unlimited max open zones. If zbd_info->max_open_zones is unlimited,
> we do not track the open zones in the zbd_info->open zone array.
> 
> Not tracking open zones reduces fio overhead for testing the performance of
> zoned block devices that do not have a limit on the maximum number of open
> zones.
> 
> Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
> Cc: Alexey Dobriyan <adobriyan@gmail.com>
> ---
>  zbd.c | 28 ++++++++++++++++++++++++----
>  zbd.h |  3 ++-
>  2 files changed, 26 insertions(+), 5 deletions(-)
> 
> diff --git a/zbd.c b/zbd.c
> index f09b0ee6..f19e3d47 100644
> --- a/zbd.c
> +++ b/zbd.c
> @@ -636,8 +636,12 @@ static int zbd_set_max_open_zones(struct thread_data *td, struct fio_file *f)
>  
>  out:
>  	/* Ensure that the limit is not larger than FIO's internal limit */
> -	zbd->max_open_zones = min_not_zero(zbd->max_open_zones,
> -					   (uint32_t) ZBD_MAX_OPEN_ZONES);
> +	if (zbd->max_open_zones > ZBD_MAX_OPEN_ZONES) {
> +		td_verror(td, EINVAL, "'max_open_zones' value is too large");
> +		log_err("'max_open_zones' value is larger than %u\n", ZBD_MAX_OPEN_ZONES);
> +		return -EINVAL;
> +	}
> +
>  	dprint(FD_ZBD, "%s: using max open zones limit: %"PRIu32"\n",
>  	       f->file_name, zbd->max_open_zones);
>  
> @@ -827,8 +831,14 @@ int zbd_setup_files(struct thread_data *td)
>  			log_err("Different 'max_open_zones' values\n");
>  			return 1;
>  		}
> -		if (zbd->max_open_zones > ZBD_MAX_OPEN_ZONES) {
> -			log_err("'max_open_zones' value is limited by %u\n", ZBD_MAX_OPEN_ZONES);
> +
> +		/*
> +		 * The per job max open zones limit cannot be used without a
> +		 * global max open zones limit. (As the tracking of open zones
> +		 * is disabled when there is no global max open zones limit.)
> +		 */
> +		if (td->o.job_max_open_zones && !zbd->max_open_zones) {
> +			log_err("'job_max_open_zones' cannot be used without a global open zones limit\n");
>  			return 1;
>  		}
>  
> @@ -1093,6 +1103,8 @@ static bool is_zone_open(const struct thread_data *td, const struct fio_file *f,
>  	struct zoned_block_device_info *zbdi = f->zbd_info;
>  	int i;
>  
> +	/* This function should never be called when zbdi->max_open_zones == 0 */
> +	assert(zbdi->max_open_zones);
>  	assert(td->o.job_max_open_zones == 0 || td->num_open_zones <= td->o.job_max_open_zones);
>  	assert(td->o.job_max_open_zones <= zbdi->max_open_zones);
>  	assert(zbdi->num_open_zones <= zbdi->max_open_zones);
> @@ -1128,6 +1140,14 @@ static bool zbd_open_zone(struct thread_data *td, const struct fio_file *f,
>  	if (td->o.verify != VERIFY_NONE && zbd_zone_full(f, z, min_bs))
>  		return false;
>  
> +	/*
> +	 * zbdi->max_open_zones == 0 means that there is no limit on the maximum
> +	 * number of open zones. In this case, do no track open zones in
> +	 * zbdi->open_zones array.
> +	 */
> +	if (!zbdi->max_open_zones)
> +		return true;
> +
>  	pthread_mutex_lock(&zbdi->mutex);
>  	if (is_zone_open(td, f, zone_idx)) {
>  		/*
> diff --git a/zbd.h b/zbd.h
> index 64534393..39dc45e3 100644
> --- a/zbd.h
> +++ b/zbd.h
> @@ -50,7 +50,8 @@ struct fio_zone_info {
>   * zoned_block_device_info - zoned block device characteristics
>   * @model: Device model.
>   * @max_open_zones: global limit on the number of simultaneously opened
> - *	sequential write zones.
> + *	sequential write zones. A zero value means unlimited open zones,
> + *	and that open zones will not be tracked in the open_zones array.
>   * @mutex: Protects the modifiable members in this structure (refcount and
>   *		num_open_zones).
>   * @zone_size: size of a single zone in bytes.
> 

Looks good.

Reviewed-by: Damien Le Moal <damien.lemoal@wdc.com>


-- 
Damien Le Moal
Western Digital Research


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/3] zbd: ensure that global max open zones limit is respected
  2021-06-24 17:23 ` [PATCH 3/3] zbd: ensure that global max open zones limit is respected Niklas Cassel
@ 2021-06-25  7:11   ` Damien Le Moal
  2021-06-25  7:48   ` Shinichiro Kawasaki
  1 sibling, 0 replies; 11+ messages in thread
From: Damien Le Moal @ 2021-06-25  7:11 UTC (permalink / raw)
  To: Niklas Cassel, axboe; +Cc: fio, Shinichiro Kawasaki, adobriyan

On 2021/06/25 2:23, Niklas Cassel wrote:
> From: Niklas Cassel <niklas.cassel@wdc.com>
> 
> Commit 219c662d3b12 ("zbd: introduce per job maximum open zones limit")
> Introduced a global max open zones limit stored in zbd_info->max_open_zones.
> 
> This commit also changed checks against td->o.max_open_zones in zbd_open_zone()
> with checks against zbd_info->max_open_zones.
> 
> It is obvious that zbd_info->max_open_zones was intended to replace
> td->o.max_open_zones in all code that is executed after zbd_setup_files().
> 
> The commit itself was needed since zbd_info is shared over different jobs,
> so it is important that the global limit of max open zones is the same,
> for different jobs targeting the same device.
> 
> The problem with this commit is that in zbd_convert_to_open_zone(),
> instead of replacing td->o.max_open_zones with zbd_info->max_open_zones,
> it incorrectly just removed the references to td->o.max_open_zones.
> 
> This caused commit 00ca8df5468e ("zbd: Fix max_open_zones checks")
> (written by another author) to incorrectly re-add the removed
> td->o.max_open_zones checks in zbd_convert_to_open_zone().
> The proper fix here should have been to add checks against
> zbd_info->max_open_zones instead of td->o.max_open_zones,
> just like the original author did for zbd_open_zone().
> 
> Replace all td->o.max_open_zones uses past zbd_setup_files() with
> zbd_info->max_open_zones, and force set td->o.max_open_zones to
> zbd_info->max_open_zones in zbd_setup_files(), so that even if checks are
> introduced against the wrong limit, fio will still respect the global limit.
> 
> Fixes: 00ca8df5468e ("zbd: Fix max_open_zones checks")
> Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
> Cc: Alexey Dobriyan <adobriyan@gmail.com>
> Cc: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
> ---
>  zbd.c | 16 ++++++++++++----
>  1 file changed, 12 insertions(+), 4 deletions(-)
> 
> diff --git a/zbd.c b/zbd.c
> index f19e3d47..04c68dea 100644
> --- a/zbd.c
> +++ b/zbd.c
> @@ -842,6 +842,14 @@ int zbd_setup_files(struct thread_data *td)
>  			return 1;
>  		}
>  
> +		/*
> +		 * zbd->max_open_zones is the global limit shared for all jobs
> +		 * that target the same zoned block device. Force sync the per
> +		 * thread global limit with the actual global limit. (The real
> +		 * per thread/job limit is stored in td->o.job_max_open_zones).
> +		 */
> +		td->o.max_open_zones = zbd->max_open_zones;
> +
>  		for (zi = f->min_zone; zi < f->max_zone; zi++) {
>  			z = &zbd->zone_info[zi];
>  			if (z->cond != ZBD_ZONE_COND_IMP_OPEN &&
> @@ -1205,7 +1213,7 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
>  
>  	assert(is_valid_offset(f, io_u->offset));
>  
> -	if (td->o.max_open_zones || td->o.job_max_open_zones) {
> +	if (zbdi->max_open_zones || td->o.job_max_open_zones) {
>  		/*
>  		 * This statement accesses zbdi->open_zones[] on purpose
>  		 * without locking.
> @@ -1236,7 +1244,7 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
>  		pthread_mutex_lock(&zbdi->mutex);
>  		if (z->has_wp) {
>  			if (z->cond != ZBD_ZONE_COND_OFFLINE &&
> -			    td->o.max_open_zones == 0 && td->o.job_max_open_zones == 0)
> +			    zbdi->max_open_zones == 0 && td->o.job_max_open_zones == 0)
>  				goto examine_zone;
>  			if (zbdi->num_open_zones == 0) {
>  				dprint(FD_ZBD, "%s(%s): no zones are open\n",
> @@ -1297,8 +1305,8 @@ open_other_zone:
>  	/* Check if number of open zones reaches one of limits. */
>  	wait_zone_close =
>  		zbdi->num_open_zones == f->max_zone - f->min_zone ||
> -		(td->o.max_open_zones &&
> -		 zbdi->num_open_zones == td->o.max_open_zones) ||
> +		(zbdi->max_open_zones &&
> +		 zbdi->num_open_zones == zbdi->max_open_zones) ||
>  		(td->o.job_max_open_zones &&
>  		 td->num_open_zones == td->o.job_max_open_zones);
>  
> 

Looks good.

Reviewed-by: Damien Le Moal <damien.lemoal@wdc.com>

-- 
Damien Le Moal
Western Digital Research


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/3] zbd: ensure that global max open zones limit is respected
  2021-06-24 17:23 ` [PATCH 3/3] zbd: ensure that global max open zones limit is respected Niklas Cassel
  2021-06-25  7:11   ` Damien Le Moal
@ 2021-06-25  7:48   ` Shinichiro Kawasaki
  1 sibling, 0 replies; 11+ messages in thread
From: Shinichiro Kawasaki @ 2021-06-25  7:48 UTC (permalink / raw)
  To: Niklas Cassel; +Cc: axboe, fio, Damien Le Moal, adobriyan

On Jun 24, 2021 / 17:23, Niklas Cassel wrote:
> From: Niklas Cassel <niklas.cassel@wdc.com>
> 
> Commit 219c662d3b12 ("zbd: introduce per job maximum open zones limit")
> Introduced a global max open zones limit stored in zbd_info->max_open_zones.
> 
> This commit also changed checks against td->o.max_open_zones in zbd_open_zone()
> with checks against zbd_info->max_open_zones.
> 
> It is obvious that zbd_info->max_open_zones was intended to replace
> td->o.max_open_zones in all code that is executed after zbd_setup_files().
> 
> The commit itself was needed since zbd_info is shared over different jobs,
> so it is important that the global limit of max open zones is the same,
> for different jobs targeting the same device.
> 
> The problem with this commit is that in zbd_convert_to_open_zone(),
> instead of replacing td->o.max_open_zones with zbd_info->max_open_zones,
> it incorrectly just removed the references to td->o.max_open_zones.
> 
> This caused commit 00ca8df5468e ("zbd: Fix max_open_zones checks")
> (written by another author) to incorrectly re-add the removed
> td->o.max_open_zones checks in zbd_convert_to_open_zone().
> The proper fix here should have been to add checks against
> zbd_info->max_open_zones instead of td->o.max_open_zones,
> just like the original author did for zbd_open_zone().
> 
> Replace all td->o.max_open_zones uses past zbd_setup_files() with
> zbd_info->max_open_zones, and force set td->o.max_open_zones to
> zbd_info->max_open_zones in zbd_setup_files(), so that even if checks are
> introduced against the wrong limit, fio will still respect the global limit.
> 
> Fixes: 00ca8df5468e ("zbd: Fix max_open_zones checks")
> Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
> Cc: Alexey Dobriyan <adobriyan@gmail.com>
> Cc: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>

Thank you for the fix. Looks good to me.

Reviewed-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>

-- 
Best Regards,
Shin'ichiro Kawasaki

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/3] zbd: create a local zbdi variable for f->zbd_info
  2021-06-24 20:09   ` Alexey Dobriyan
@ 2021-06-28 10:42     ` Niklas Cassel
  0 siblings, 0 replies; 11+ messages in thread
From: Niklas Cassel @ 2021-06-28 10:42 UTC (permalink / raw)
  To: Alexey Dobriyan; +Cc: axboe, fio, Damien Le Moal, Shinichiro Kawasaki

On Thu, Jun 24, 2021 at 11:09:11PM +0300, Alexey Dobriyan wrote:
> On Thu, Jun 24, 2021 at 05:23:07PM +0000, Niklas Cassel wrote:
> > +	struct zoned_block_device_info *zbdi = f->zbd_info;
> 
> It is unrelated to the patch. But! It is impossible to type
> "zoned_block_device_info" without autocompletion.
> 
> Can it be renamed just to 
> 
> 	struct zbd * const zbd = f->zbd_info;
> 
> "info" is kind of information free word, too.

Hello Alexey!


Like you say, such a change seems unrelated to this patch.

Feel free to send out a patch that renames struct zoned_block_device_info
to something else.
(Although, you might want to wait until this series has been merged.)

If we were to rename the struct, I personally think that "struct zbd_info"
is a better name than just "struct zbd".


Kind regards,
Niklas

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/3] fix max open zones handling when using multiple jobs
  2021-06-24 17:23 [PATCH 0/3] fix max open zones handling when using multiple jobs Niklas Cassel
                   ` (2 preceding siblings ...)
  2021-06-24 17:23 ` [PATCH 3/3] zbd: ensure that global max open zones limit is respected Niklas Cassel
@ 2021-06-29 13:44 ` Jens Axboe
  3 siblings, 0 replies; 11+ messages in thread
From: Jens Axboe @ 2021-06-29 13:44 UTC (permalink / raw)
  To: Niklas Cassel; +Cc: fio, Damien Le Moal, Shinichiro Kawasaki, adobriyan

On 6/24/21 11:23 AM, Niklas Cassel wrote:
> From: Niklas Cassel <niklas.cassel@wdc.com>
> 
> Currently, the fio handling of max open zones is very fragile.
> 
> zbd_open_zone() uses zbd_info->max_open_zones when checking
> the max open zones limit, while zbd_convert_to_open_zone()
> uses td->o.max_open_zones when performing the same limit check.
> 
> It is simply wrong to use td->o.max_open_zones after zbd_setup_files().
> 
> Change zbd_convert_to_open_zone() to use zbd_info->max_open_zones.
> This way, the global max open zones limit (which is per device) will be
> respected for all jobs.
> 
> This series also adds a patch that reintroduces the ability to
> run write workloads with no limit on the maximum number of open zones.
> In this case, tracking of open zones in the zbd_info->open_zones array
> is disabled to reduce overhead.

Applied, thanks.

-- 
Jens Axboe



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2021-06-29 13:44 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-24 17:23 [PATCH 0/3] fix max open zones handling when using multiple jobs Niklas Cassel
2021-06-24 17:23 ` [PATCH 1/3] zbd: create a local zbdi variable for f->zbd_info Niklas Cassel
2021-06-24 20:09   ` Alexey Dobriyan
2021-06-28 10:42     ` Niklas Cassel
2021-06-25  7:07   ` Damien Le Moal
2021-06-24 17:23 ` [PATCH 2/3] zbd: allow an unlimited global max open zones limit Niklas Cassel
2021-06-25  7:09   ` Damien Le Moal
2021-06-24 17:23 ` [PATCH 3/3] zbd: ensure that global max open zones limit is respected Niklas Cassel
2021-06-25  7:11   ` Damien Le Moal
2021-06-25  7:48   ` Shinichiro Kawasaki
2021-06-29 13:44 ` [PATCH 0/3] fix max open zones handling when using multiple jobs Jens Axboe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).