glusterfs: update for new API
[fio.git] / zbd.c
diff --git a/zbd.c b/zbd.c
index 9b603b97b18344b5e17baf31f199371a8c5f11ff..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;
@@ -1111,37 +1117,44 @@ zbd_find_zone(struct thread_data *td, struct io_u *io_u,
        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
@@ -1158,10 +1171,42 @@ static void zbd_post_submit(const struct io_u *io_u, bool success)
        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_check_swd(io_u->file);
+/**
+ * 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;
+
+       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)
@@ -1216,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) {
@@ -1354,8 +1413,10 @@ enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u)
 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: