struct workqueue_work work;
};
+#ifdef CONFIG_LINUX_BLKZONED
/*
- * Post-submit callback. Used by the ZBD code. @success == true means
- * that the I/O operation has been queued or completed successfully.
+ * ZBD mode zbd_queue_io callback: called after engine->queue operation
+ * to advance a zone write pointer and eventually unlock the I/O zone.
+ * @q indicates the I/O queue status (busy, queued or completed).
+ * @success == true means that the I/O operation has been queued or
+ * completed successfully.
*/
- void (*post_submit)(const struct io_u *, bool success);
+ void (*zbd_queue_io)(struct io_u *, int q, bool success);
+
+ /*
+ * ZBD mode zbd_put_io callback: called in after completion of an I/O
+ * or commit of an async I/O to unlock the I/O target zone.
+ */
+ void (*zbd_put_io)(const struct io_u *);
+#endif
/*
* Callback for io completion
return NULL;
}
-
/**
- * zbd_post_submit - update the write pointer and unlock the zone lock
+ * zbd_queue_io - update the write pointer of a sequential zone
* @io_u: I/O unit
- * @success: Whether or not the I/O unit has been executed successfully
+ * @success: Whether or not the I/O unit has been queued successfully
+ * @q: queueing status (busy, completed or queued).
*
- * For write and trim operations, update the write pointer of all affected
- * zones.
+ * For write and trim operations, update the write pointer of the I/O unit
+ * target zone.
*/
-static void zbd_post_submit(const struct io_u *io_u, bool success)
+static void zbd_queue_io(struct io_u *io_u, int q, bool success)
{
- struct zoned_block_device_info *zbd_info;
+ const struct fio_file *f = io_u->file;
+ struct zoned_block_device_info *zbd_info = f->zbd_info;
struct fio_zone_info *z;
uint32_t zone_idx;
- uint64_t end, zone_end;
+ uint64_t zone_end;
- zbd_info = io_u->file->zbd_info;
if (!zbd_info)
return;
- zone_idx = zbd_zone_idx(io_u->file, io_u->offset);
- end = io_u->offset + io_u->buflen;
- z = &zbd_info->zone_info[zone_idx];
+ zone_idx = zbd_zone_idx(f, io_u->offset);
assert(zone_idx < zbd_info->nr_zones);
+ z = &zbd_info->zone_info[zone_idx];
+
if (z->type != BLK_ZONE_TYPE_SEQWRITE_REQ)
return;
+
if (!success)
goto unlock;
+
+ dprint(FD_ZBD,
+ "%s: queued I/O (%lld, %llu) for zone %u\n",
+ f->file_name, io_u->offset, io_u->buflen, zone_idx);
+
switch (io_u->ddir) {
case DDIR_WRITE:
- zone_end = min(end, (z + 1)->start);
+ zone_end = min((uint64_t)(io_u->offset + io_u->buflen),
+ (z + 1)->start);
pthread_mutex_lock(&zbd_info->mutex);
/*
* z->wp > zone_end means that one or more I/O errors
default:
break;
}
+
unlock:
- pthread_mutex_unlock(&z->mutex);
+ if (!success || q != FIO_Q_QUEUED) {
+ /* BUSY or COMPLETED: unlock the zone */
+ pthread_mutex_unlock(&z->mutex);
+ io_u->zbd_put_io = NULL;
+ }
+}
+
+/**
+ * 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)
+{
+ const struct fio_file *f = io_u->file;
+ struct zoned_block_device_info *zbd_info = f->zbd_info;
+ struct fio_zone_info *z;
+ uint32_t zone_idx;
+
+ if (!zbd_info)
+ return;
- zbd_check_swd(io_u->file);
+ zone_idx = zbd_zone_idx(f, io_u->offset);
+ assert(zone_idx < zbd_info->nr_zones);
+ z = &zbd_info->zone_info[zone_idx];
+
+ if (z->type != BLK_ZONE_TYPE_SEQWRITE_REQ)
+ return;
+
+ dprint(FD_ZBD,
+ "%s: terminate I/O (%lld, %llu) for zone %u\n",
+ f->file_name, io_u->offset, io_u->buflen, zone_idx);
+
+ assert(pthread_mutex_unlock(&z->mutex) == 0);
+ zbd_check_swd(f);
}
bool zbd_unaligned_write(int error_code)
accept:
assert(zb);
assert(zb->cond != BLK_ZONE_COND_OFFLINE);
- assert(!io_u->post_submit);
- io_u->post_submit = zbd_post_submit;
+ assert(!io_u->zbd_queue_io);
+ assert(!io_u->zbd_put_io);
+ io_u->zbd_queue_io = zbd_queue_io;
+ io_u->zbd_put_io = zbd_put_io;
return io_u_accept;
eof:
bool zbd_unaligned_write(int error_code);
enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u);
char *zbd_write_status(const struct thread_stat *ts);
+
+static inline void zbd_queue_io_u(struct io_u *io_u, enum fio_q_status status)
+{
+ if (io_u->zbd_queue_io) {
+ io_u->zbd_queue_io(io_u, status, io_u->error == 0);
+ io_u->zbd_queue_io = NULL;
+ }
+}
+
+static inline void zbd_put_io_u(struct io_u *io_u)
+{
+ if (io_u->zbd_put_io) {
+ io_u->zbd_put_io(io_u);
+ io_u->zbd_queue_io = NULL;
+ io_u->zbd_put_io = NULL;
+ }
+}
+
#else
static inline void zbd_free_zone_info(struct fio_file *f)
{
{
return NULL;
}
+
+static inline void zbd_queue_io_u(struct io_u *io_u,
+ enum fio_q_status status) {}
+static inline void zbd_put_io_u(struct io_u *io_u) {}
#endif
#endif /* FIO_ZBD_H */