X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;f=zbd.c;h=9327816aaf8f8eb68f7f971eb8958b9fbcf0e616;hb=dee9b29bef5bc344815d7a53dda6bb21426f2bfa;hp=3eac5df3bef7313261cc864f04fd8db408514fa7;hpb=f0ed01ed095cf1ca7c1945a5a0267e8f73b7b4a9;p=fio.git diff --git a/zbd.c b/zbd.c index 3eac5df3..9327816a 100644 --- a/zbd.c +++ b/zbd.c @@ -319,6 +319,7 @@ static bool zbd_verify_sizes(void) f->min_zone = zbd_zone_idx(f, f->file_offset); f->max_zone = zbd_zone_idx(f, f->file_offset + f->io_size); + assert(f->min_zone < f->max_zone); } } @@ -627,6 +628,11 @@ static int zbd_init_zone_info(struct thread_data *td, struct fio_file *file) return ret; } +static bool zbd_open_zone(struct thread_data *td, const struct fio_file *f, + uint32_t zone_idx); +static int zbd_reset_zone(struct thread_data *td, struct fio_file *f, + struct fio_zone_info *z); + int zbd_setup_files(struct thread_data *td) { struct fio_file *f; @@ -650,6 +656,8 @@ int zbd_setup_files(struct thread_data *td) for_each_file(td, f, i) { struct zoned_block_device_info *zbd = f->zbd_info; + struct fio_zone_info *z; + int zi; if (!zbd) continue; @@ -665,29 +673,58 @@ int zbd_setup_files(struct thread_data *td) log_err("'max_open_zones' value is limited by %u\n", ZBD_MAX_OPEN_ZONES); return 1; } + + for (zi = f->min_zone; zi < f->max_zone; zi++) { + z = &zbd->zone_info[zi]; + if (z->cond != ZBD_ZONE_COND_IMP_OPEN && + z->cond != ZBD_ZONE_COND_EXP_OPEN) + continue; + if (zbd_open_zone(td, f, zi)) + continue; + /* + * If the number of open zones exceeds specified limits, + * reset all extra open zones. + */ + if (zbd_reset_zone(td, f, z) < 0) { + log_err("Failed to reest zone %d\n", zi); + return 1; + } + } } return 0; } +static unsigned int zbd_zone_nr(struct zoned_block_device_info *zbd_info, + struct fio_zone_info *zone) +{ + return zone - zbd_info->zone_info; +} + /** - * zbd_reset_range - reset zones for a range of sectors + * zbd_reset_zone - reset the write pointer of a single zone * @td: FIO thread data. - * @f: Fio file for which to reset zones - * @sector: Starting sector in units of 512 bytes - * @nr_sectors: Number of sectors in units of 512 bytes + * @f: FIO file associated with the disk for which to reset a write pointer. + * @z: Zone to reset. * * Returns 0 upon success and a negative error code upon failure. + * + * The caller must hold z->mutex. */ -static int zbd_reset_range(struct thread_data *td, struct fio_file *f, - uint64_t offset, uint64_t length) +static int zbd_reset_zone(struct thread_data *td, struct fio_file *f, + struct fio_zone_info *z) { - uint32_t zone_idx_b, zone_idx_e; - struct fio_zone_info *zb, *ze, *z; + uint64_t offset = z->start; + uint64_t length = (z+1)->start - offset; int ret = 0; + if (z->wp == z->start) + return 0; + assert(is_valid_offset(f, offset + length - 1)); + dprint(FD_ZBD, "%s: resetting wp of zone %u.\n", f->file_name, + zbd_zone_nr(f->zbd_info, z)); switch (f->zbd_info->model) { case ZBD_HOST_AWARE: case ZBD_HOST_MANAGED: @@ -699,56 +736,34 @@ static int zbd_reset_range(struct thread_data *td, struct fio_file *f, break; } - zone_idx_b = zbd_zone_idx(f, offset); - zb = &f->zbd_info->zone_info[zone_idx_b]; - zone_idx_e = zbd_zone_idx(f, offset + length); - ze = &f->zbd_info->zone_info[zone_idx_e]; - for (z = zb; z < ze; z++) { - pthread_mutex_lock(&z->mutex); - pthread_mutex_lock(&f->zbd_info->mutex); - f->zbd_info->sectors_with_data -= z->wp - z->start; - pthread_mutex_unlock(&f->zbd_info->mutex); - z->wp = z->start; - z->verify_block = 0; - pthread_mutex_unlock(&z->mutex); - } + pthread_mutex_lock(&f->zbd_info->mutex); + f->zbd_info->sectors_with_data -= z->wp - z->start; + pthread_mutex_unlock(&f->zbd_info->mutex); + z->wp = z->start; + z->verify_block = 0; - td->ts.nr_zone_resets += ze - zb; + td->ts.nr_zone_resets++; return ret; } -static unsigned int zbd_zone_nr(struct zoned_block_device_info *zbd_info, - struct fio_zone_info *zone) -{ - return zone - zbd_info->zone_info; -} - -/** - * zbd_reset_zone - reset the write pointer of a single zone - * @td: FIO thread data. - * @f: FIO file associated with the disk for which to reset a write pointer. - * @z: Zone to reset. - * - * Returns 0 upon success and a negative error code upon failure. - */ -static int zbd_reset_zone(struct thread_data *td, struct fio_file *f, - struct fio_zone_info *z) -{ - dprint(FD_ZBD, "%s: resetting wp of zone %u.\n", f->file_name, - zbd_zone_nr(f->zbd_info, z)); - - return zbd_reset_range(td, f, z->start, zbd_zone_end(z) - z->start); -} - /* The caller must hold f->zbd_info->mutex */ static void zbd_close_zone(struct thread_data *td, const struct fio_file *f, - unsigned int open_zone_idx) + unsigned int zone_idx) { - uint32_t zone_idx; + uint32_t open_zone_idx = 0; + + for (; open_zone_idx < f->zbd_info->num_open_zones; open_zone_idx++) { + if (f->zbd_info->open_zones[open_zone_idx] == zone_idx) + break; + } + if (open_zone_idx == f->zbd_info->num_open_zones) { + dprint(FD_ZBD, "%s: zone %d is not open\n", + f->file_name, zone_idx); + return; + } - assert(open_zone_idx < f->zbd_info->num_open_zones); - zone_idx = f->zbd_info->open_zones[open_zone_idx]; + dprint(FD_ZBD, "%s: closing zone %d\n", f->file_name, zone_idx); memmove(f->zbd_info->open_zones + open_zone_idx, f->zbd_info->open_zones + open_zone_idx + 1, (ZBD_MAX_OPEN_ZONES - (open_zone_idx + 1)) * @@ -787,13 +802,8 @@ static int zbd_reset_zones(struct thread_data *td, struct fio_file *f, continue; zone_lock(td, f, z); if (all_zones) { - unsigned int i; - pthread_mutex_lock(&f->zbd_info->mutex); - for (i = 0; i < f->zbd_info->num_open_zones; i++) { - if (f->zbd_info->open_zones[i] == nz) - zbd_close_zone(td, f, i); - } + zbd_close_zone(td, f, nz); pthread_mutex_unlock(&f->zbd_info->mutex); reset_wp = z->wp != z->start; @@ -861,9 +871,8 @@ static uint64_t zbd_process_swd(const struct fio_file *f, enum swd_action a) struct fio_zone_info *zb, *ze, *z; uint64_t swd = 0; - zb = &f->zbd_info->zone_info[zbd_zone_idx(f, f->file_offset)]; - ze = &f->zbd_info->zone_info[zbd_zone_idx(f, f->file_offset + - f->io_size)]; + zb = &f->zbd_info->zone_info[f->min_zone]; + ze = &f->zbd_info->zone_info[f->max_zone]; for (z = zb; z < ze; z++) { pthread_mutex_lock(&z->mutex); swd += z->wp - z->start; @@ -955,11 +964,10 @@ static bool is_zone_open(const struct thread_data *td, const struct fio_file *f, * was not yet open and opening a new zone would cause the zone limit to be * exceeded. */ -static bool zbd_open_zone(struct thread_data *td, const struct io_u *io_u, +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]; - const struct fio_file *f = io_u->file; struct fio_zone_info *z = &f->zbd_info->zone_info[zone_idx]; bool res = true; @@ -974,8 +982,15 @@ static bool zbd_open_zone(struct thread_data *td, const struct io_u *io_u, return false; pthread_mutex_lock(&f->zbd_info->mutex); - if (is_zone_open(td, f, zone_idx)) + if (is_zone_open(td, f, zone_idx)) { + /* + * If the zone is already open and going to be full by writes + * in-flight, handle it as a full zone instead of an open zone. + */ + if (z->wp >= zbd_zone_capacity_end(z)) + res = false; goto out; + } res = false; /* Zero means no limit */ if (td->o.job_max_open_zones > 0 && @@ -1017,6 +1032,7 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td, unsigned int open_zone_idx = -1; uint32_t zone_idx, new_zone_idx; int i; + bool wait_zone_close; assert(is_valid_offset(f, io_u->offset)); @@ -1052,11 +1068,9 @@ static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td, if (td->o.max_open_zones == 0 && td->o.job_max_open_zones == 0) goto examine_zone; if (f->zbd_info->num_open_zones == 0) { - pthread_mutex_unlock(&f->zbd_info->mutex); - pthread_mutex_unlock(&z->mutex); dprint(FD_ZBD, "%s(%s): no zones are open\n", __func__, f->file_name); - return NULL; + goto open_other_zone; } /* @@ -1103,14 +1117,30 @@ examine_zone: pthread_mutex_unlock(&f->zbd_info->mutex); goto out; } - dprint(FD_ZBD, "%s(%s): closing zone %d\n", __func__, f->file_name, - zone_idx); - if (td->o.max_open_zones || td->o.job_max_open_zones) - zbd_close_zone(td, f, open_zone_idx); + +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 || + (td->o.max_open_zones && + f->zbd_info->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); /* Only z->mutex is held. */ + /* + * When number of open zones reaches to one of limits, wait for + * zone close before opening a new zone. + */ + if (wait_zone_close) { + dprint(FD_ZBD, "%s(%s): quiesce to allow open zones to close\n", + __func__, f->file_name); + io_u_quiesce(td); + } + /* Zone 'z' is full, so try to open a new zone. */ for (i = f->io_size / f->zbd_info->zone_size; i > 0; i--) { zone_idx++; @@ -1125,7 +1155,7 @@ examine_zone: zone_lock(td, f, z); if (z->open) continue; - if (zbd_open_zone(td, io_u, zone_idx)) + if (zbd_open_zone(td, f, zone_idx)) goto out; } @@ -1168,7 +1198,7 @@ static struct fio_zone_info *zbd_replay_write_order(struct thread_data *td, const struct fio_file *f = io_u->file; const uint32_t min_bs = td->o.min_bs[DDIR_WRITE]; - if (!zbd_open_zone(td, io_u, z - f->zbd_info->zone_info)) { + if (!zbd_open_zone(td, f, z - f->zbd_info->zone_info)) { pthread_mutex_unlock(&z->mutex); z = zbd_convert_to_open_zone(td, io_u); assert(z); @@ -1197,7 +1227,7 @@ zbd_find_zone(struct thread_data *td, struct io_u *io_u, struct fio_file *f = io_u->file; struct fio_zone_info *z1, *z2; const struct fio_zone_info *const zf = - &f->zbd_info->zone_info[zbd_zone_idx(f, f->file_offset)]; + &f->zbd_info->zone_info[f->min_zone]; /* * Skip to the next non-empty zone in case of sequential I/O and to @@ -1225,6 +1255,28 @@ zbd_find_zone(struct thread_data *td, struct io_u *io_u, return NULL; } +/** + * zbd_end_zone_io - update zone status at command completion + * @io_u: I/O unit + * @z: zone info pointer + * + * If the write command made the zone full, close it. + * + * The caller must hold z->mutex. + */ +static void zbd_end_zone_io(struct thread_data *td, const struct io_u *io_u, + struct fio_zone_info *z) +{ + const struct fio_file *f = io_u->file; + + if (io_u->ddir == DDIR_WRITE && + io_u->offset + io_u->buflen >= zbd_zone_capacity_end(z)) { + pthread_mutex_lock(&f->zbd_info->mutex); + zbd_close_zone(td, f, z - f->zbd_info->zone_info); + pthread_mutex_unlock(&f->zbd_info->mutex); + } +} + /** * zbd_queue_io - update the write pointer of a sequential zone * @io_u: I/O unit @@ -1234,7 +1286,8 @@ zbd_find_zone(struct thread_data *td, struct io_u *io_u, * For write and trim operations, update the write pointer of the I/O unit * target zone. */ -static void zbd_queue_io(struct io_u *io_u, int q, bool success) +static void zbd_queue_io(struct thread_data *td, struct io_u *io_u, int q, + bool success) { const struct fio_file *f = io_u->file; struct zoned_block_device_info *zbd_info = f->zbd_info; @@ -1280,6 +1333,9 @@ static void zbd_queue_io(struct io_u *io_u, int q, bool success) break; } + if (q == FIO_Q_COMPLETED && !io_u->error) + zbd_end_zone_io(td, io_u, z); + unlock: if (!success || q != FIO_Q_QUEUED) { /* BUSY or COMPLETED: unlock the zone */ @@ -1292,7 +1348,7 @@ unlock: * zbd_put_io - Unlock an I/O unit target zone lock * @io_u: I/O unit */ -static void zbd_put_io(const struct io_u *io_u) +static void zbd_put_io(struct thread_data *td, const struct io_u *io_u) { const struct fio_file *f = io_u->file; struct zoned_block_device_info *zbd_info = f->zbd_info; @@ -1314,6 +1370,8 @@ static void zbd_put_io(const struct io_u *io_u) "%s: terminate I/O (%lld, %llu) for zone %u\n", f->file_name, io_u->offset, io_u->buflen, zone_idx); + zbd_end_zone_io(td, io_u, z); + ret = pthread_mutex_unlock(&z->mutex); assert(ret == 0); zbd_check_swd(f); @@ -1489,9 +1547,9 @@ enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u) switch (io_u->ddir) { case DDIR_READ: - if (td->runstate == TD_VERIFYING) { - if (td_write(td)) - zb = zbd_replay_write_order(td, io_u, zb); + if (td->runstate == TD_VERIFYING && td_write(td)) { + zb = zbd_replay_write_order(td, io_u, zb); + pthread_mutex_unlock(&zb->mutex); goto accept; } /* @@ -1504,8 +1562,7 @@ enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u) if (range < min_bs || ((!td_random(td)) && (io_u->offset + min_bs > zb->wp))) { pthread_mutex_unlock(&zb->mutex); - zl = &f->zbd_info->zone_info[zbd_zone_idx(f, - f->file_offset + f->io_size)]; + zl = &f->zbd_info->zone_info[f->max_zone]; zb = zbd_find_zone(td, io_u, zb, zl); if (!zb) { dprint(FD_ZBD, @@ -1551,7 +1608,7 @@ enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u) case DDIR_WRITE: if (io_u->buflen > f->zbd_info->zone_size) goto eof; - if (!zbd_open_zone(td, io_u, zone_idx_b)) { + if (!zbd_open_zone(td, f, zone_idx_b)) { pthread_mutex_unlock(&zb->mutex); zb = zbd_convert_to_open_zone(td, io_u); if (!zb)