fio: fix aio trim completion latencies
[fio.git] / zbd.c
diff --git a/zbd.c b/zbd.c
index 310b1732749702e551f475d1af4dd0f3b57c60dc..d7e91e37e010c0194da07636b29ce058ebd2db13 100644 (file)
--- a/zbd.c
+++ b/zbd.c
@@ -186,11 +186,14 @@ static bool zbd_verify_bs(void)
  * size of @buf.
  *
  * Returns 0 upon success and a negative error code upon failure.
+ * If the zone report is empty, always assume an error (device problem) and
+ * return -EIO.
  */
 static int read_zone_info(int fd, uint64_t start_sector,
                          void *buf, unsigned int bufsz)
 {
        struct blk_zone_report *hdr = buf;
+       int ret;
 
        if (bufsz < sizeof(*hdr))
                return -EINVAL;
@@ -199,7 +202,12 @@ static int read_zone_info(int fd, uint64_t start_sector,
 
        hdr->nr_zones = (bufsz - sizeof(*hdr)) / sizeof(struct blk_zone);
        hdr->sector = start_sector;
-       return ioctl(fd, BLKREPORTZONE, hdr) >= 0 ? 0 : -errno;
+       ret = ioctl(fd, BLKREPORTZONE, hdr);
+       if (ret)
+               return -errno;
+       if (!hdr->nr_zones)
+               return -EIO;
+       return 0;
 }
 
 /*
@@ -418,8 +426,6 @@ static int parse_zone_info(struct thread_data *td, struct fio_file *f)
                        p->start = z->start << 9;
                        switch (z->cond) {
                        case BLK_ZONE_COND_NOT_WP:
-                               p->wp = p->start;
-                               break;
                        case BLK_ZONE_COND_FULL:
                                p->wp = p->start + zone_size;
                                break;
@@ -1255,7 +1261,21 @@ enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u)
 
        zbd_check_swd(f);
 
-       pthread_mutex_lock(&zb->mutex);
+       /*
+        * Lock the io_u target zone. The zone will be unlocked if io_u offset
+        * is changed or when io_u completes and zbd_put_io() executed.
+        * To avoid multiple jobs doing asynchronous I/Os from deadlocking each
+        * other waiting for zone locks when building an io_u batch, first
+        * only trylock the zone. If the zone is already locked by another job,
+        * process the currently queued I/Os so that I/O progress is made and
+        * zones unlocked.
+        */
+       if (pthread_mutex_trylock(&zb->mutex) != 0) {
+               if (!td_ioengine_flagged(td, FIO_SYNCIO))
+                       io_u_quiesce(td);
+               pthread_mutex_lock(&zb->mutex);
+       }
+
        switch (io_u->ddir) {
        case DDIR_READ:
                if (td->runstate == TD_VERIFYING) {