return zbd_get_zone(f, zbd_offset_to_zone_idx(f, offset));
}
+static bool accounting_vdb(struct thread_data *td, const struct fio_file *f)
+{
+ return td->o.zrt.u.f && td_write(td);
+}
+
/**
* zbd_get_zoned_model - Get a device zoned model
* @td: FIO thread data
ret = blkzoned_report_zones(td, f, offset, zones, nr_zones);
if (ret < 0) {
td_verror(td, errno, "report zones failed");
- log_err("%s: report zones from sector %"PRIu64" failed (%d).\n",
- f->file_name, offset >> 9, errno);
+ log_err("%s: report zones from sector %"PRIu64" failed (nr_zones=%d; errno=%d).\n",
+ f->file_name, offset >> 9, nr_zones, errno);
} else if (ret == 0) {
td_verror(td, errno, "Empty zone report");
log_err("%s: report zones from sector %"PRIu64" is empty.\n",
break;
}
- pthread_mutex_lock(&f->zbd_info->mutex);
- f->zbd_info->wp_sectors_with_data -= data_in_zone;
- pthread_mutex_unlock(&f->zbd_info->mutex);
+ if (accounting_vdb(td, f)) {
+ pthread_mutex_lock(&f->zbd_info->mutex);
+ f->zbd_info->wp_valid_data_bytes -= data_in_zone;
+ pthread_mutex_unlock(&f->zbd_info->mutex);
+ }
z->wp = z->start;
/* Verify whether direct I/O is used for all host-managed zoned block drives. */
static bool zbd_using_direct_io(void)
{
- struct thread_data *td;
struct fio_file *f;
- int i, j;
+ int j;
- for_each_td(td, i) {
+ for_each_td(td) {
if (td->o.odirect || !(td->o.td_ddir & TD_DDIR_WRITE))
continue;
for_each_file(td, f, j) {
f->zbd_info->model == ZBD_HOST_MANAGED)
return false;
}
- }
+ } end_for_each();
return true;
}
/* Whether or not the I/O range for f includes one or more sequential zones */
-static bool zbd_is_seq_job(struct fio_file *f)
+static bool zbd_is_seq_job(const struct fio_file *f)
{
uint32_t zone_idx, zone_idx_b, zone_idx_e;
*/
static bool zbd_verify_sizes(void)
{
- struct thread_data *td;
struct fio_file *f;
- int i, j;
+ int j;
- for_each_td(td, i) {
+ for_each_td(td) {
for_each_file(td, f, j) {
if (!zbd_zone_align_file_sizes(td, f))
return false;
}
- }
+ } end_for_each();
return true;
}
static bool zbd_verify_bs(void)
{
- struct thread_data *td;
struct fio_file *f;
- int i, j;
+ int j;
- for_each_td(td, i) {
+ for_each_td(td) {
if (td_trim(td) &&
(td->o.min_bs[DDIR_TRIM] != td->o.max_bs[DDIR_TRIM] ||
td->o.bssplit_nr[DDIR_TRIM])) {
return false;
}
}
- }
+ } end_for_each();
return true;
}
int nr_zones, nrz;
struct zbd_zone *zones, *z;
struct fio_zone_info *p;
- uint64_t zone_size, offset;
+ uint64_t zone_size, offset, capacity;
+ bool same_zone_cap = true;
struct zoned_block_device_info *zbd_info = NULL;
int i, j, ret = -ENOMEM;
}
zone_size = zones[0].len;
+ capacity = zones[0].capacity;
nr_zones = (f->real_file_size + zone_size - 1) / zone_size;
if (td->o.zone_size == 0) {
PTHREAD_MUTEX_RECURSIVE);
p->start = z->start;
p->capacity = z->capacity;
+ if (capacity != z->capacity)
+ same_zone_cap = false;
switch (z->cond) {
case ZBD_ZONE_COND_NOT_WP:
p->cond = z->cond;
if (j > 0 && p->start != p[-1].start + zone_size) {
- log_info("%s: invalid zone data\n",
- f->file_name);
+ log_info("%s: invalid zone data [%d:%d]: %"PRIu64" + %"PRIu64" != %"PRIu64"\n",
+ f->file_name, j, i,
+ p[-1].start, zone_size, p->start);
ret = -EINVAL;
goto out;
}
f->zbd_info->zone_size_log2 = is_power_of_2(zone_size) ?
ilog2(zone_size) : 0;
f->zbd_info->nr_zones = nr_zones;
+
+ if (same_zone_cap)
+ dprint(FD_ZBD, "Zone capacity = %"PRIu64" KB\n",
+ capacity / 1024);
+
zbd_info = NULL;
ret = 0;
*/
static int zbd_init_zone_info(struct thread_data *td, struct fio_file *file)
{
- struct thread_data *td2;
struct fio_file *f2;
- int i, j, ret;
+ int j, ret;
- for_each_td(td2, i) {
+ for_each_td(td2) {
for_each_file(td2, f2, j) {
if (td2 == td && f2 == file)
continue;
file->zbd_info->refcount++;
return 0;
}
- }
+ } end_for_each();
ret = zbd_create_zone_info(td, file);
if (ret < 0)
}
}
+static uint64_t zbd_verify_and_set_vdb(struct thread_data *td,
+ const struct fio_file *f)
+{
+ struct fio_zone_info *zb, *ze, *z;
+ uint64_t wp_vdb = 0;
+ struct zoned_block_device_info *zbdi = f->zbd_info;
+
+ assert(td->runstate < TD_RUNNING);
+ assert(zbdi);
+
+ if (!accounting_vdb(td, f))
+ return 0;
+
+ /*
+ * Ensure that the I/O range includes one or more sequential zones so
+ * that f->min_zone and f->max_zone have different values.
+ */
+ if (!zbd_is_seq_job(f))
+ return 0;
+
+ if (zbdi->write_min_zone != zbdi->write_max_zone) {
+ if (zbdi->write_min_zone != f->min_zone ||
+ zbdi->write_max_zone != f->max_zone) {
+ td_verror(td, EINVAL,
+ "multi-jobs with different write ranges are "
+ "not supported with zone_reset_threshold");
+ log_err("multi-jobs with different write ranges are "
+ "not supported with zone_reset_threshold\n");
+ }
+ return 0;
+ }
+
+ zbdi->write_min_zone = f->min_zone;
+ zbdi->write_max_zone = f->max_zone;
+
+ zb = zbd_get_zone(f, f->min_zone);
+ ze = zbd_get_zone(f, f->max_zone);
+ for (z = zb; z < ze; z++)
+ if (z->has_wp)
+ wp_vdb += z->wp - z->start;
+
+ zbdi->wp_valid_data_bytes = wp_vdb;
+
+ return wp_vdb;
+}
+
int zbd_setup_files(struct thread_data *td)
{
struct fio_file *f;
struct zoned_block_device_info *zbd = f->zbd_info;
struct fio_zone_info *z;
int zi;
+ uint64_t vdb;
assert(zbd);
f->max_zone =
zbd_offset_to_zone_idx(f, f->file_offset + f->io_size);
+ vdb = zbd_verify_and_set_vdb(td, f);
+
+ dprint(FD_ZBD, "%s(%s): valid data bytes = %" PRIu64 "\n",
+ __func__, f->file_name, vdb);
+
/*
* When all zones in the I/O range are conventional, io_size
* can be smaller than zone size, making min_zone the same
return write_cnt == 0;
}
-enum swd_action {
- CHECK_SWD,
- SET_SWD,
-};
-
-/* Calculate the number of sectors with data (swd) and perform action 'a' */
-static uint64_t zbd_process_swd(struct thread_data *td,
- const struct fio_file *f, enum swd_action a)
-{
- struct fio_zone_info *zb, *ze, *z;
- uint64_t wp_swd = 0;
-
- zb = zbd_get_zone(f, f->min_zone);
- ze = zbd_get_zone(f, f->max_zone);
- for (z = zb; z < ze; z++) {
- if (z->has_wp) {
- zone_lock(td, f, z);
- wp_swd += z->wp - z->start;
- }
- }
-
- pthread_mutex_lock(&f->zbd_info->mutex);
- switch (a) {
- case CHECK_SWD:
- assert(f->zbd_info->wp_sectors_with_data == wp_swd);
- break;
- case SET_SWD:
- f->zbd_info->wp_sectors_with_data = wp_swd;
- break;
- }
- pthread_mutex_unlock(&f->zbd_info->mutex);
-
- for (z = zb; z < ze; z++)
- if (z->has_wp)
- zone_unlock(z);
-
- return wp_swd;
-}
-
-/*
- * The swd check is useful for debugging but takes too much time to leave
- * it enabled all the time. Hence it is disabled by default.
- */
-static const bool enable_check_swd = false;
-
-/* Check whether the values of zbd_info.*sectors_with_data are correct. */
-static void zbd_check_swd(struct thread_data *td, const struct fio_file *f)
-{
- if (!enable_check_swd)
- return;
-
- zbd_process_swd(td, f, CHECK_SWD);
-}
-
void zbd_file_reset(struct thread_data *td, struct fio_file *f)
{
struct fio_zone_info *zb, *ze;
- uint64_t swd;
bool verify_data_left = false;
if (!f->zbd_info || !td_write(td))
zb = zbd_get_zone(f, f->min_zone);
ze = zbd_get_zone(f, f->max_zone);
- swd = zbd_process_swd(td, f, SET_SWD);
-
- dprint(FD_ZBD, "%s(%s): swd = %" PRIu64 "\n",
- __func__, f->file_name, swd);
/*
* If data verification is enabled reset the affected zones before
static bool any_io_in_flight(void)
{
- struct thread_data *td;
- int i;
-
- for_each_td(td, i) {
+ for_each_td(td) {
if (td->io_u_in_flight)
return true;
- }
+ } end_for_each();
return false;
}
* z->wp > zone_end means that one or more I/O errors
* have occurred.
*/
- pthread_mutex_lock(&zbd_info->mutex);
- if (z->wp <= zone_end)
- zbd_info->wp_sectors_with_data += zone_end - z->wp;
- pthread_mutex_unlock(&zbd_info->mutex);
+ if (accounting_vdb(td, f) && z->wp <= zone_end) {
+ pthread_mutex_lock(&zbd_info->mutex);
+ zbd_info->wp_valid_data_bytes += zone_end - z->wp;
+ pthread_mutex_unlock(&zbd_info->mutex);
+ }
z->wp = zone_end;
break;
default:
zbd_end_zone_io(td, io_u, z);
zone_unlock(z);
- zbd_check_swd(td, f);
}
/*
io_u->ddir == DDIR_READ && td->o.read_beyond_wp)
return io_u_accept;
- zbd_check_swd(td, f);
-
zone_lock(td, f, zb);
switch (io_u->ddir) {
/* Check whether the zone reset threshold has been exceeded */
if (td->o.zrf.u.f) {
- if (zbdi->wp_sectors_with_data >= f->io_size * td->o.zrt.u.f &&
+ if (zbdi->wp_valid_data_bytes >=
+ f->io_size * td->o.zrt.u.f &&
zbd_dec_and_reset_write_cnt(td, f))
zb->reset_zone = 1;
}