zbd: disable crossing from conventional to sequential zones
authorShin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Wed, 27 Jan 2021 04:19:23 +0000 (13:19 +0900)
committerJens Axboe <axboe@kernel.dk>
Fri, 29 Jan 2021 15:14:00 +0000 (08:14 -0700)
Write I/Os to conventional zones may have the range that spans across
zone boundaries. Such writes may cause I/O errors when its next zone
is a sequential zone.

To avoid such I/O errors, check for the cross over from a conventional
to a sequential zone. When the write crosses the boundary, shrink the
I/O length to fit within the first zone. If the offset is too close to
the end of the zone, wrap it around to the beginning of the same zone.

Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
zbd.c

diff --git a/zbd.c b/zbd.c
index cebde1b696b61793ae7c67e306b8ff1950c73653..2cebc5e6d0126bcbe5755dcc4bbf77352cda5b80 100644 (file)
--- a/zbd.c
+++ b/zbd.c
@@ -1563,9 +1563,31 @@ enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u)
        zb = get_zone(f, zone_idx_b);
        orig_zb = zb;
 
-       /* Accept the I/O offset for conventional zones. */
-       if (!zb->has_wp)
+       if (!zb->has_wp) {
+               /* Accept non-write I/Os for conventional zones. */
+               if (io_u->ddir != DDIR_WRITE)
+                       return io_u_accept;
+               /*
+                * Make sure that writes to conventional zones
+                * don't cross over to any sequential zones.
+                */
+               if (!(zb + 1)->has_wp ||
+                   io_u->offset + io_u->buflen <= (zb + 1)->start)
+                       return io_u_accept;
+
+               if (io_u->offset + min_bs > (zb + 1)->start) {
+                       dprint(FD_IO,
+                              "%s: off=%llu + min_bs=%u > next zone %lu\n",
+                              f->file_name, io_u->offset, min_bs,
+                              (zb + 1)->start);
+                       io_u->offset = zb->start + (zb + 1)->start - io_u->offset;
+                       new_len = min(io_u->buflen, (zb + 1)->start - io_u->offset);
+               } else {
+                       new_len = (zb + 1)->start - io_u->offset;
+               }
+               io_u->buflen = new_len / min_bs * min_bs;
                return io_u_accept;
+       }
 
        /*
         * Accept the I/O offset for reads if reading beyond the write pointer