libzbc: cleanup init code
[fio.git] / zbd.c
1 /*
2  * Copyright (C) 2018 Western Digital Corporation or its affiliates.
3  *
4  * This file is released under the GPL.
5  */
6
7 #include <errno.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <fcntl.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13
14 #include "os/os.h"
15 #include "file.h"
16 #include "fio.h"
17 #include "lib/pow2.h"
18 #include "log.h"
19 #include "oslib/asprintf.h"
20 #include "smalloc.h"
21 #include "verify.h"
22 #include "zbd.h"
23
24 /**
25  * zbd_get_zoned_model - Get a device zoned model
26  * @td: FIO thread data
27  * @f: FIO file for which to get model information
28  */
29 int zbd_get_zoned_model(struct thread_data *td, struct fio_file *f,
30                         enum zbd_zoned_model *model)
31 {
32         int ret;
33
34         if (td->io_ops && td->io_ops->get_zoned_model)
35                 ret = td->io_ops->get_zoned_model(td, f, model);
36         else
37                 ret = blkzoned_get_zoned_model(td, f, model);
38         if (ret < 0) {
39                 td_verror(td, errno, "get zoned model failed");
40                 log_err("%s: get zoned model failed (%d).\n",
41                         f->file_name, errno);
42         }
43
44         return ret;
45 }
46
47 /**
48  * zbd_report_zones - Get zone information
49  * @td: FIO thread data.
50  * @f: FIO file for which to get zone information
51  * @offset: offset from which to report zones
52  * @zones: Array of struct zbd_zone
53  * @nr_zones: Size of @zones array
54  *
55  * Get zone information into @zones starting from the zone at offset @offset
56  * for the device specified by @f.
57  *
58  * Returns the number of zones reported upon success and a negative error code
59  * upon failure. If the zone report is empty, always assume an error (device
60  * problem) and return -EIO.
61  */
62 int zbd_report_zones(struct thread_data *td, struct fio_file *f,
63                      uint64_t offset, struct zbd_zone *zones,
64                      unsigned int nr_zones)
65 {
66         int ret;
67
68         if (td->io_ops && td->io_ops->report_zones)
69                 ret = td->io_ops->report_zones(td, f, offset, zones, nr_zones);
70         else
71                 ret = blkzoned_report_zones(td, f, offset, zones, nr_zones);
72         if (ret < 0) {
73                 td_verror(td, errno, "report zones failed");
74                 log_err("%s: report zones from sector %llu failed (%d).\n",
75                         f->file_name, (unsigned long long)offset >> 9, errno);
76         } else if (ret == 0) {
77                 td_verror(td, errno, "Empty zone report");
78                 log_err("%s: report zones from sector %llu is empty.\n",
79                         f->file_name, (unsigned long long)offset >> 9);
80                 ret = -EIO;
81         }
82
83         return ret;
84 }
85
86 /**
87  * zbd_reset_wp - reset the write pointer of a range of zones
88  * @td: FIO thread data.
89  * @f: FIO file for which to reset zones
90  * @offset: Starting offset of the first zone to reset
91  * @length: Length of the range of zones to reset
92  *
93  * Reset the write pointer of all zones in the range @offset...@offset+@length.
94  * Returns 0 upon success and a negative error code upon failure.
95  */
96 int zbd_reset_wp(struct thread_data *td, struct fio_file *f,
97                  uint64_t offset, uint64_t length)
98 {
99         int ret;
100
101         if (td->io_ops && td->io_ops->reset_wp)
102                 ret = td->io_ops->reset_wp(td, f, offset, length);
103         else
104                 ret = blkzoned_reset_wp(td, f, offset, length);
105         if (ret < 0) {
106                 td_verror(td, errno, "resetting wp failed");
107                 log_err("%s: resetting wp for %llu sectors at sector %llu failed (%d).\n",
108                         f->file_name, (unsigned long long)length >> 9,
109                         (unsigned long long)offset >> 9, errno);
110         }
111
112         return ret;
113 }
114
115 /**
116  * zbd_zone_idx - convert an offset into a zone number
117  * @f: file pointer.
118  * @offset: offset in bytes. If this offset is in the first zone_size bytes
119  *          past the disk size then the index of the sentinel is returned.
120  */
121 static uint32_t zbd_zone_idx(const struct fio_file *f, uint64_t offset)
122 {
123         uint32_t zone_idx;
124
125         if (f->zbd_info->zone_size_log2 > 0)
126                 zone_idx = offset >> f->zbd_info->zone_size_log2;
127         else
128                 zone_idx = offset / f->zbd_info->zone_size;
129
130         return min(zone_idx, f->zbd_info->nr_zones);
131 }
132
133 /**
134  * zbd_zone_swr - Test whether a zone requires sequential writes
135  * @z: zone info pointer.
136  */
137 static inline bool zbd_zone_swr(struct fio_zone_info *z)
138 {
139         return z->type == ZBD_ZONE_TYPE_SWR;
140 }
141
142 /**
143  * zbd_zone_full - verify whether a minimum number of bytes remain in a zone
144  * @f: file pointer.
145  * @z: zone info pointer.
146  * @required: minimum number of bytes that must remain in a zone.
147  *
148  * The caller must hold z->mutex.
149  */
150 static bool zbd_zone_full(const struct fio_file *f, struct fio_zone_info *z,
151                           uint64_t required)
152 {
153         assert((required & 511) == 0);
154
155         return zbd_zone_swr(z) &&
156                 z->wp + required > z->start + f->zbd_info->zone_size;
157 }
158
159 static void zone_lock(struct thread_data *td, struct fio_file *f, struct fio_zone_info *z)
160 {
161         struct zoned_block_device_info *zbd = f->zbd_info;
162         uint32_t nz = z - zbd->zone_info;
163
164         /* A thread should never lock zones outside its working area. */
165         assert(f->min_zone <= nz && nz < f->max_zone);
166
167         /*
168          * Lock the io_u target zone. The zone will be unlocked if io_u offset
169          * is changed or when io_u completes and zbd_put_io() executed.
170          * To avoid multiple jobs doing asynchronous I/Os from deadlocking each
171          * other waiting for zone locks when building an io_u batch, first
172          * only trylock the zone. If the zone is already locked by another job,
173          * process the currently queued I/Os so that I/O progress is made and
174          * zones unlocked.
175          */
176         if (pthread_mutex_trylock(&z->mutex) != 0) {
177                 if (!td_ioengine_flagged(td, FIO_SYNCIO))
178                         io_u_quiesce(td);
179                 pthread_mutex_lock(&z->mutex);
180         }
181 }
182
183 static bool is_valid_offset(const struct fio_file *f, uint64_t offset)
184 {
185         return (uint64_t)(offset - f->file_offset) < f->io_size;
186 }
187
188 /* Verify whether direct I/O is used for all host-managed zoned drives. */
189 static bool zbd_using_direct_io(void)
190 {
191         struct thread_data *td;
192         struct fio_file *f;
193         int i, j;
194
195         for_each_td(td, i) {
196                 if (td->o.odirect || !(td->o.td_ddir & TD_DDIR_WRITE))
197                         continue;
198                 for_each_file(td, f, j) {
199                         if (f->zbd_info &&
200                             f->zbd_info->model == ZBD_HOST_MANAGED)
201                                 return false;
202                 }
203         }
204
205         return true;
206 }
207
208 /* Whether or not the I/O range for f includes one or more sequential zones */
209 static bool zbd_is_seq_job(struct fio_file *f)
210 {
211         uint32_t zone_idx, zone_idx_b, zone_idx_e;
212
213         assert(f->zbd_info);
214         if (f->io_size == 0)
215                 return false;
216         zone_idx_b = zbd_zone_idx(f, f->file_offset);
217         zone_idx_e = zbd_zone_idx(f, f->file_offset + f->io_size - 1);
218         for (zone_idx = zone_idx_b; zone_idx <= zone_idx_e; zone_idx++)
219                 if (zbd_zone_swr(&f->zbd_info->zone_info[zone_idx]))
220                         return true;
221
222         return false;
223 }
224
225 /*
226  * Verify whether offset and size parameters are aligned with zone boundaries.
227  */
228 static bool zbd_verify_sizes(void)
229 {
230         const struct fio_zone_info *z;
231         struct thread_data *td;
232         struct fio_file *f;
233         uint64_t new_offset, new_end;
234         uint32_t zone_idx;
235         int i, j;
236
237         for_each_td(td, i) {
238                 for_each_file(td, f, j) {
239                         if (!f->zbd_info)
240                                 continue;
241                         if (f->file_offset >= f->real_file_size)
242                                 continue;
243                         if (!zbd_is_seq_job(f))
244                                 continue;
245
246                         if (!td->o.zone_size) {
247                                 td->o.zone_size = f->zbd_info->zone_size;
248                                 if (!td->o.zone_size) {
249                                         log_err("%s: invalid 0 zone size\n",
250                                                 f->file_name);
251                                         return false;
252                                 }
253                         } else if (td->o.zone_size != f->zbd_info->zone_size) {
254                                 log_err("%s: job parameter zonesize %llu does not match disk zone size %llu.\n",
255                                         f->file_name, (unsigned long long) td->o.zone_size,
256                                         (unsigned long long) f->zbd_info->zone_size);
257                                 return false;
258                         }
259
260                         if (td->o.zone_skip &&
261                             (td->o.zone_skip < td->o.zone_size ||
262                              td->o.zone_skip % td->o.zone_size)) {
263                                 log_err("%s: zoneskip %llu is not a multiple of the device zone size %llu.\n",
264                                         f->file_name, (unsigned long long) td->o.zone_skip,
265                                         (unsigned long long) td->o.zone_size);
266                                 return false;
267                         }
268
269                         zone_idx = zbd_zone_idx(f, f->file_offset);
270                         z = &f->zbd_info->zone_info[zone_idx];
271                         if ((f->file_offset != z->start) &&
272                             (td->o.td_ddir != TD_DDIR_READ)) {
273                                 new_offset = (z+1)->start;
274                                 if (new_offset >= f->file_offset + f->io_size) {
275                                         log_info("%s: io_size must be at least one zone\n",
276                                                  f->file_name);
277                                         return false;
278                                 }
279                                 log_info("%s: rounded up offset from %llu to %llu\n",
280                                          f->file_name, (unsigned long long) f->file_offset,
281                                          (unsigned long long) new_offset);
282                                 f->io_size -= (new_offset - f->file_offset);
283                                 f->file_offset = new_offset;
284                         }
285                         zone_idx = zbd_zone_idx(f, f->file_offset + f->io_size);
286                         z = &f->zbd_info->zone_info[zone_idx];
287                         new_end = z->start;
288                         if ((td->o.td_ddir != TD_DDIR_READ) &&
289                             (f->file_offset + f->io_size != new_end)) {
290                                 if (new_end <= f->file_offset) {
291                                         log_info("%s: io_size must be at least one zone\n",
292                                                  f->file_name);
293                                         return false;
294                                 }
295                                 log_info("%s: rounded down io_size from %llu to %llu\n",
296                                          f->file_name, (unsigned long long) f->io_size,
297                                          (unsigned long long) new_end - f->file_offset);
298                                 f->io_size = new_end - f->file_offset;
299                         }
300
301                         f->min_zone = zbd_zone_idx(f, f->file_offset);
302                         f->max_zone = zbd_zone_idx(f, f->file_offset + f->io_size);
303                 }
304         }
305
306         return true;
307 }
308
309 static bool zbd_verify_bs(void)
310 {
311         struct thread_data *td;
312         struct fio_file *f;
313         uint32_t zone_size;
314         int i, j, k;
315
316         for_each_td(td, i) {
317                 for_each_file(td, f, j) {
318                         if (!f->zbd_info)
319                                 continue;
320                         zone_size = f->zbd_info->zone_size;
321                         for (k = 0; k < ARRAY_SIZE(td->o.bs); k++) {
322                                 if (td->o.verify != VERIFY_NONE &&
323                                     zone_size % td->o.bs[k] != 0) {
324                                         log_info("%s: block size %llu is not a divisor of the zone size %d\n",
325                                                  f->file_name, td->o.bs[k],
326                                                  zone_size);
327                                         return false;
328                                 }
329                         }
330                 }
331         }
332         return true;
333 }
334
335 static int ilog2(uint64_t i)
336 {
337         int log = -1;
338
339         while (i) {
340                 i >>= 1;
341                 log++;
342         }
343         return log;
344 }
345
346 /*
347  * Initialize f->zbd_info for devices that are not zoned block devices. This
348  * allows to execute a ZBD workload against a non-ZBD device.
349  */
350 static int init_zone_info(struct thread_data *td, struct fio_file *f)
351 {
352         uint32_t nr_zones;
353         struct fio_zone_info *p;
354         uint64_t zone_size = td->o.zone_size;
355         struct zoned_block_device_info *zbd_info = NULL;
356         pthread_mutexattr_t attr;
357         int i;
358
359         if (zone_size == 0) {
360                 log_err("%s: Specifying the zone size is mandatory for regular block devices with --zonemode=zbd\n\n",
361                         f->file_name);
362                 return 1;
363         }
364
365         if (zone_size < 512) {
366                 log_err("%s: zone size must be at least 512 bytes for --zonemode=zbd\n\n",
367                         f->file_name);
368                 return 1;
369         }
370
371         nr_zones = (f->real_file_size + zone_size - 1) / zone_size;
372         zbd_info = scalloc(1, sizeof(*zbd_info) +
373                            (nr_zones + 1) * sizeof(zbd_info->zone_info[0]));
374         if (!zbd_info)
375                 return -ENOMEM;
376
377         pthread_mutexattr_init(&attr);
378         pthread_mutexattr_setpshared(&attr, true);
379         pthread_mutex_init(&zbd_info->mutex, &attr);
380         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
381         zbd_info->refcount = 1;
382         p = &zbd_info->zone_info[0];
383         for (i = 0; i < nr_zones; i++, p++) {
384                 pthread_mutex_init(&p->mutex, &attr);
385                 p->start = i * zone_size;
386                 p->wp = p->start + zone_size;
387                 p->type = ZBD_ZONE_TYPE_SWR;
388                 p->cond = ZBD_ZONE_COND_EMPTY;
389         }
390         /* a sentinel */
391         p->start = nr_zones * zone_size;
392
393         f->zbd_info = zbd_info;
394         f->zbd_info->zone_size = zone_size;
395         f->zbd_info->zone_size_log2 = is_power_of_2(zone_size) ?
396                 ilog2(zone_size) : 0;
397         f->zbd_info->nr_zones = nr_zones;
398         pthread_mutexattr_destroy(&attr);
399         return 0;
400 }
401
402 /*
403  * Maximum number of zones to report in one operation.
404  */
405 #define ZBD_REPORT_MAX_ZONES    8192U
406
407 /*
408  * Parse the device zone report and store it in f->zbd_info. Must be called
409  * only for devices that are zoned, namely those with a model != ZBD_NONE.
410  */
411 static int parse_zone_info(struct thread_data *td, struct fio_file *f)
412 {
413         int nr_zones, nrz;
414         struct zbd_zone *zones, *z;
415         struct fio_zone_info *p;
416         uint64_t zone_size, offset;
417         struct zoned_block_device_info *zbd_info = NULL;
418         pthread_mutexattr_t attr;
419         int i, j, ret = 0;
420
421         pthread_mutexattr_init(&attr);
422         pthread_mutexattr_setpshared(&attr, true);
423
424         zones = calloc(ZBD_REPORT_MAX_ZONES, sizeof(struct zbd_zone));
425         if (!zones)
426                 goto out;
427
428         nrz = zbd_report_zones(td, f, 0, zones, ZBD_REPORT_MAX_ZONES);
429         if (nrz < 0) {
430                 ret = nrz;
431                 log_info("fio: report zones (offset 0) failed for %s (%d).\n",
432                          f->file_name, -ret);
433                 goto out;
434         }
435
436         zone_size = zones[0].len;
437         nr_zones = (f->real_file_size + zone_size - 1) / zone_size;
438
439         if (td->o.zone_size == 0) {
440                 td->o.zone_size = zone_size;
441         } else if (td->o.zone_size != zone_size) {
442                 log_err("fio: %s job parameter zonesize %llu does not match disk zone size %llu.\n",
443                         f->file_name, (unsigned long long) td->o.zone_size,
444                         (unsigned long long) zone_size);
445                 ret = -EINVAL;
446                 goto out;
447         }
448
449         dprint(FD_ZBD, "Device %s has %d zones of size %llu KB\n", f->file_name,
450                nr_zones, (unsigned long long) zone_size / 1024);
451
452         zbd_info = scalloc(1, sizeof(*zbd_info) +
453                            (nr_zones + 1) * sizeof(zbd_info->zone_info[0]));
454         ret = -ENOMEM;
455         if (!zbd_info)
456                 goto out;
457         pthread_mutex_init(&zbd_info->mutex, &attr);
458         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
459         zbd_info->refcount = 1;
460         p = &zbd_info->zone_info[0];
461         for (offset = 0, j = 0; j < nr_zones;) {
462                 z = &zones[0];
463                 for (i = 0; i < nrz; i++, j++, z++, p++) {
464                         pthread_mutex_init(&p->mutex, &attr);
465                         p->start = z->start;
466                         switch (z->cond) {
467                         case ZBD_ZONE_COND_NOT_WP:
468                         case ZBD_ZONE_COND_FULL:
469                                 p->wp = p->start + zone_size;
470                                 break;
471                         default:
472                                 assert(z->start <= z->wp);
473                                 assert(z->wp <= z->start + zone_size);
474                                 p->wp = z->wp;
475                                 break;
476                         }
477                         p->type = z->type;
478                         p->cond = z->cond;
479                         if (j > 0 && p->start != p[-1].start + zone_size) {
480                                 log_info("%s: invalid zone data\n",
481                                          f->file_name);
482                                 ret = -EINVAL;
483                                 goto out;
484                         }
485                 }
486                 z--;
487                 offset = z->start + z->len;
488                 if (j >= nr_zones)
489                         break;
490                 nrz = zbd_report_zones(td, f, offset,
491                                             zones, ZBD_REPORT_MAX_ZONES);
492                 if (nrz < 0) {
493                         ret = nrz;
494                         log_info("fio: report zones (offset %llu) failed for %s (%d).\n",
495                                  (unsigned long long)offset,
496                                  f->file_name, -ret);
497                         goto out;
498                 }
499         }
500
501         /* a sentinel */
502         zbd_info->zone_info[nr_zones].start = offset;
503
504         f->zbd_info = zbd_info;
505         f->zbd_info->zone_size = zone_size;
506         f->zbd_info->zone_size_log2 = is_power_of_2(zone_size) ?
507                 ilog2(zone_size) : 0;
508         f->zbd_info->nr_zones = nr_zones;
509         zbd_info = NULL;
510         ret = 0;
511
512 out:
513         sfree(zbd_info);
514         free(zones);
515         pthread_mutexattr_destroy(&attr);
516         return ret;
517 }
518
519 /*
520  * Allocate zone information and store it into f->zbd_info if zonemode=zbd.
521  *
522  * Returns 0 upon success and a negative error code upon failure.
523  */
524 static int zbd_create_zone_info(struct thread_data *td, struct fio_file *f)
525 {
526         enum zbd_zoned_model zbd_model;
527         int ret;
528
529         assert(td->o.zone_mode == ZONE_MODE_ZBD);
530
531         ret = zbd_get_zoned_model(td, f, &zbd_model);
532         if (ret)
533                 return ret;
534
535         switch (zbd_model) {
536         case ZBD_IGNORE:
537                 return 0;
538         case ZBD_HOST_AWARE:
539         case ZBD_HOST_MANAGED:
540                 ret = parse_zone_info(td, f);
541                 break;
542         case ZBD_NONE:
543                 ret = init_zone_info(td, f);
544                 break;
545         default:
546                 td_verror(td, EINVAL, "Unsupported zoned model");
547                 log_err("Unsupported zoned model\n");
548                 return -EINVAL;
549         }
550
551         if (ret == 0) {
552                 f->zbd_info->model = zbd_model;
553                 f->zbd_info->max_open_zones = td->o.max_open_zones;
554         }
555         return ret;
556 }
557
558 void zbd_free_zone_info(struct fio_file *f)
559 {
560         uint32_t refcount;
561
562         assert(f->zbd_info);
563
564         pthread_mutex_lock(&f->zbd_info->mutex);
565         refcount = --f->zbd_info->refcount;
566         pthread_mutex_unlock(&f->zbd_info->mutex);
567
568         assert((int32_t)refcount >= 0);
569         if (refcount == 0)
570                 sfree(f->zbd_info);
571         f->zbd_info = NULL;
572 }
573
574 /*
575  * Initialize f->zbd_info.
576  *
577  * Returns 0 upon success and a negative error code upon failure.
578  *
579  * Note: this function can only work correctly if it is called before the first
580  * fio fork() call.
581  */
582 static int zbd_init_zone_info(struct thread_data *td, struct fio_file *file)
583 {
584         struct thread_data *td2;
585         struct fio_file *f2;
586         int i, j, ret;
587
588         for_each_td(td2, i) {
589                 for_each_file(td2, f2, j) {
590                         if (td2 == td && f2 == file)
591                                 continue;
592                         if (!f2->zbd_info ||
593                             strcmp(f2->file_name, file->file_name) != 0)
594                                 continue;
595                         file->zbd_info = f2->zbd_info;
596                         file->zbd_info->refcount++;
597                         return 0;
598                 }
599         }
600
601         ret = zbd_create_zone_info(td, file);
602         if (ret < 0)
603                 td_verror(td, -ret, "zbd_create_zone_info() failed");
604         return ret;
605 }
606
607 int zbd_setup_files(struct thread_data *td)
608 {
609         struct fio_file *f;
610         int i;
611
612         for_each_file(td, f, i) {
613                 if (zbd_init_zone_info(td, f))
614                         return 1;
615         }
616
617         if (!zbd_using_direct_io()) {
618                 log_err("Using direct I/O is mandatory for writing to ZBD drives\n\n");
619                 return 1;
620         }
621
622         if (!zbd_verify_sizes())
623                 return 1;
624
625         if (!zbd_verify_bs())
626                 return 1;
627
628         for_each_file(td, f, i) {
629                 struct zoned_block_device_info *zbd = f->zbd_info;
630
631                 if (!zbd)
632                         continue;
633
634                 zbd->max_open_zones = zbd->max_open_zones ?: ZBD_MAX_OPEN_ZONES;
635
636                 if (td->o.max_open_zones > 0 &&
637                     zbd->max_open_zones != td->o.max_open_zones) {
638                         log_err("Different 'max_open_zones' values\n");
639                         return 1;
640                 }
641                 if (zbd->max_open_zones > ZBD_MAX_OPEN_ZONES) {
642                         log_err("'max_open_zones' value is limited by %u\n", ZBD_MAX_OPEN_ZONES);
643                         return 1;
644                 }
645         }
646
647         return 0;
648 }
649
650 /**
651  * zbd_reset_range - reset zones for a range of sectors
652  * @td: FIO thread data.
653  * @f: Fio file for which to reset zones
654  * @sector: Starting sector in units of 512 bytes
655  * @nr_sectors: Number of sectors in units of 512 bytes
656  *
657  * Returns 0 upon success and a negative error code upon failure.
658  */
659 static int zbd_reset_range(struct thread_data *td, struct fio_file *f,
660                            uint64_t offset, uint64_t length)
661 {
662         uint32_t zone_idx_b, zone_idx_e;
663         struct fio_zone_info *zb, *ze, *z;
664         int ret = 0;
665
666         assert(is_valid_offset(f, offset + length - 1));
667
668         switch (f->zbd_info->model) {
669         case ZBD_HOST_AWARE:
670         case ZBD_HOST_MANAGED:
671                 ret = zbd_reset_wp(td, f, offset, length);
672                 if (ret < 0)
673                         return ret;
674                 break;
675         default:
676                 break;
677         }
678
679         zone_idx_b = zbd_zone_idx(f, offset);
680         zb = &f->zbd_info->zone_info[zone_idx_b];
681         zone_idx_e = zbd_zone_idx(f, offset + length);
682         ze = &f->zbd_info->zone_info[zone_idx_e];
683         for (z = zb; z < ze; z++) {
684                 pthread_mutex_lock(&z->mutex);
685                 pthread_mutex_lock(&f->zbd_info->mutex);
686                 f->zbd_info->sectors_with_data -= z->wp - z->start;
687                 pthread_mutex_unlock(&f->zbd_info->mutex);
688                 z->wp = z->start;
689                 z->verify_block = 0;
690                 pthread_mutex_unlock(&z->mutex);
691         }
692
693         td->ts.nr_zone_resets += ze - zb;
694
695         return ret;
696 }
697
698 static unsigned int zbd_zone_nr(struct zoned_block_device_info *zbd_info,
699                                 struct fio_zone_info *zone)
700 {
701         return zone - zbd_info->zone_info;
702 }
703
704 /**
705  * zbd_reset_zone - reset the write pointer of a single zone
706  * @td: FIO thread data.
707  * @f: FIO file associated with the disk for which to reset a write pointer.
708  * @z: Zone to reset.
709  *
710  * Returns 0 upon success and a negative error code upon failure.
711  */
712 static int zbd_reset_zone(struct thread_data *td, struct fio_file *f,
713                           struct fio_zone_info *z)
714 {
715         dprint(FD_ZBD, "%s: resetting wp of zone %u.\n", f->file_name,
716                 zbd_zone_nr(f->zbd_info, z));
717
718         return zbd_reset_range(td, f, z->start, (z+1)->start - z->start);
719 }
720
721 /* The caller must hold f->zbd_info->mutex */
722 static void zbd_close_zone(struct thread_data *td, const struct fio_file *f,
723                            unsigned int open_zone_idx)
724 {
725         uint32_t zone_idx;
726
727         assert(open_zone_idx < f->zbd_info->num_open_zones);
728         zone_idx = f->zbd_info->open_zones[open_zone_idx];
729         memmove(f->zbd_info->open_zones + open_zone_idx,
730                 f->zbd_info->open_zones + open_zone_idx + 1,
731                 (ZBD_MAX_OPEN_ZONES - (open_zone_idx + 1)) *
732                 sizeof(f->zbd_info->open_zones[0]));
733         f->zbd_info->num_open_zones--;
734         td->num_open_zones--;
735         f->zbd_info->zone_info[zone_idx].open = 0;
736 }
737
738 /*
739  * Reset a range of zones. Returns 0 upon success and 1 upon failure.
740  * @td: fio thread data.
741  * @f: fio file for which to reset zones
742  * @zb: first zone to reset.
743  * @ze: first zone not to reset.
744  * @all_zones: whether to reset all zones or only those zones for which the
745  *      write pointer is not a multiple of td->o.min_bs[DDIR_WRITE].
746  */
747 static int zbd_reset_zones(struct thread_data *td, struct fio_file *f,
748                            struct fio_zone_info *const zb,
749                            struct fio_zone_info *const ze, bool all_zones)
750 {
751         struct fio_zone_info *z;
752         const uint32_t min_bs = td->o.min_bs[DDIR_WRITE];
753         bool reset_wp;
754         int res = 0;
755
756         assert(min_bs);
757
758         dprint(FD_ZBD, "%s: examining zones %u .. %u\n", f->file_name,
759                 zbd_zone_nr(f->zbd_info, zb), zbd_zone_nr(f->zbd_info, ze));
760         for (z = zb; z < ze; z++) {
761                 uint32_t nz = z - f->zbd_info->zone_info;
762
763                 if (!zbd_zone_swr(z))
764                         continue;
765                 zone_lock(td, f, z);
766                 if (all_zones) {
767                         unsigned int i;
768
769                         pthread_mutex_lock(&f->zbd_info->mutex);
770                         for (i = 0; i < f->zbd_info->num_open_zones; i++) {
771                                 if (f->zbd_info->open_zones[i] == nz)
772                                         zbd_close_zone(td, f, i);
773                         }
774                         pthread_mutex_unlock(&f->zbd_info->mutex);
775
776                         reset_wp = z->wp != z->start;
777                 } else {
778                         reset_wp = z->wp % min_bs != 0;
779                 }
780                 if (reset_wp) {
781                         dprint(FD_ZBD, "%s: resetting zone %u\n",
782                                f->file_name,
783                                zbd_zone_nr(f->zbd_info, z));
784                         if (zbd_reset_zone(td, f, z) < 0)
785                                 res = 1;
786                 }
787                 pthread_mutex_unlock(&z->mutex);
788         }
789
790         return res;
791 }
792
793 /*
794  * Reset zbd_info.write_cnt, the counter that counts down towards the next
795  * zone reset.
796  */
797 static void _zbd_reset_write_cnt(const struct thread_data *td,
798                                  const struct fio_file *f)
799 {
800         assert(0 <= td->o.zrf.u.f && td->o.zrf.u.f <= 1);
801
802         f->zbd_info->write_cnt = td->o.zrf.u.f ?
803                 min(1.0 / td->o.zrf.u.f, 0.0 + UINT_MAX) : UINT_MAX;
804 }
805
806 static void zbd_reset_write_cnt(const struct thread_data *td,
807                                 const struct fio_file *f)
808 {
809         pthread_mutex_lock(&f->zbd_info->mutex);
810         _zbd_reset_write_cnt(td, f);
811         pthread_mutex_unlock(&f->zbd_info->mutex);
812 }
813
814 static bool zbd_dec_and_reset_write_cnt(const struct thread_data *td,
815                                         const struct fio_file *f)
816 {
817         uint32_t write_cnt = 0;
818
819         pthread_mutex_lock(&f->zbd_info->mutex);
820         assert(f->zbd_info->write_cnt);
821         if (f->zbd_info->write_cnt)
822                 write_cnt = --f->zbd_info->write_cnt;
823         if (write_cnt == 0)
824                 _zbd_reset_write_cnt(td, f);
825         pthread_mutex_unlock(&f->zbd_info->mutex);
826
827         return write_cnt == 0;
828 }
829
830 enum swd_action {
831         CHECK_SWD,
832         SET_SWD,
833 };
834
835 /* Calculate the number of sectors with data (swd) and perform action 'a' */
836 static uint64_t zbd_process_swd(const struct fio_file *f, enum swd_action a)
837 {
838         struct fio_zone_info *zb, *ze, *z;
839         uint64_t swd = 0;
840
841         zb = &f->zbd_info->zone_info[zbd_zone_idx(f, f->file_offset)];
842         ze = &f->zbd_info->zone_info[zbd_zone_idx(f, f->file_offset +
843                                                   f->io_size)];
844         for (z = zb; z < ze; z++) {
845                 pthread_mutex_lock(&z->mutex);
846                 swd += z->wp - z->start;
847         }
848         pthread_mutex_lock(&f->zbd_info->mutex);
849         switch (a) {
850         case CHECK_SWD:
851                 assert(f->zbd_info->sectors_with_data == swd);
852                 break;
853         case SET_SWD:
854                 f->zbd_info->sectors_with_data = swd;
855                 break;
856         }
857         pthread_mutex_unlock(&f->zbd_info->mutex);
858         for (z = zb; z < ze; z++)
859                 pthread_mutex_unlock(&z->mutex);
860
861         return swd;
862 }
863
864 /*
865  * The swd check is useful for debugging but takes too much time to leave
866  * it enabled all the time. Hence it is disabled by default.
867  */
868 static const bool enable_check_swd = false;
869
870 /* Check whether the value of zbd_info.sectors_with_data is correct. */
871 static void zbd_check_swd(const struct fio_file *f)
872 {
873         if (!enable_check_swd)
874                 return;
875
876         zbd_process_swd(f, CHECK_SWD);
877 }
878
879 static void zbd_init_swd(struct fio_file *f)
880 {
881         uint64_t swd;
882
883         if (!enable_check_swd)
884                 return;
885
886         swd = zbd_process_swd(f, SET_SWD);
887         dprint(FD_ZBD, "%s(%s): swd = %" PRIu64 "\n", __func__, f->file_name,
888                swd);
889 }
890
891 void zbd_file_reset(struct thread_data *td, struct fio_file *f)
892 {
893         struct fio_zone_info *zb, *ze;
894
895         if (!f->zbd_info || !td_write(td))
896                 return;
897
898         zb = &f->zbd_info->zone_info[f->min_zone];
899         ze = &f->zbd_info->zone_info[f->max_zone];
900         zbd_init_swd(f);
901         /*
902          * If data verification is enabled reset the affected zones before
903          * writing any data to avoid that a zone reset has to be issued while
904          * writing data, which causes data loss.
905          */
906         zbd_reset_zones(td, f, zb, ze, td->o.verify != VERIFY_NONE &&
907                         td->runstate != TD_VERIFYING);
908         zbd_reset_write_cnt(td, f);
909 }
910
911 /* The caller must hold f->zbd_info->mutex. */
912 static bool is_zone_open(const struct thread_data *td, const struct fio_file *f,
913                          unsigned int zone_idx)
914 {
915         struct zoned_block_device_info *zbdi = f->zbd_info;
916         int i;
917
918         assert(td->o.job_max_open_zones == 0 || td->num_open_zones <= td->o.job_max_open_zones);
919         assert(td->o.job_max_open_zones <= zbdi->max_open_zones);
920         assert(zbdi->num_open_zones <= zbdi->max_open_zones);
921
922         for (i = 0; i < zbdi->num_open_zones; i++)
923                 if (zbdi->open_zones[i] == zone_idx)
924                         return true;
925
926         return false;
927 }
928
929 /*
930  * Open a ZBD zone if it was not yet open. Returns true if either the zone was
931  * already open or if opening a new zone is allowed. Returns false if the zone
932  * was not yet open and opening a new zone would cause the zone limit to be
933  * exceeded.
934  */
935 static bool zbd_open_zone(struct thread_data *td, const struct io_u *io_u,
936                           uint32_t zone_idx)
937 {
938         const uint32_t min_bs = td->o.min_bs[DDIR_WRITE];
939         const struct fio_file *f = io_u->file;
940         struct fio_zone_info *z = &f->zbd_info->zone_info[zone_idx];
941         bool res = true;
942
943         if (z->cond == ZBD_ZONE_COND_OFFLINE)
944                 return false;
945
946         /*
947          * Skip full zones with data verification enabled because resetting a
948          * zone causes data loss and hence causes verification to fail.
949          */
950         if (td->o.verify != VERIFY_NONE && zbd_zone_full(f, z, min_bs))
951                 return false;
952
953         pthread_mutex_lock(&f->zbd_info->mutex);
954         if (is_zone_open(td, f, zone_idx))
955                 goto out;
956         res = false;
957         /* Zero means no limit */
958         if (td->o.job_max_open_zones > 0 &&
959             td->num_open_zones >= td->o.job_max_open_zones)
960                 goto out;
961         if (f->zbd_info->num_open_zones >= f->zbd_info->max_open_zones)
962                 goto out;
963         dprint(FD_ZBD, "%s: opening zone %d\n", f->file_name, zone_idx);
964         f->zbd_info->open_zones[f->zbd_info->num_open_zones++] = zone_idx;
965         td->num_open_zones++;
966         z->open = 1;
967         res = true;
968
969 out:
970         pthread_mutex_unlock(&f->zbd_info->mutex);
971         return res;
972 }
973
974 /* Anything goes as long as it is not a constant. */
975 static uint32_t pick_random_zone_idx(const struct fio_file *f,
976                                      const struct io_u *io_u)
977 {
978         return io_u->offset * f->zbd_info->num_open_zones / f->real_file_size;
979 }
980
981 /*
982  * Modify the offset of an I/O unit that does not refer to an open zone such
983  * that it refers to an open zone. Close an open zone and open a new zone if
984  * necessary. This algorithm can only work correctly if all write pointers are
985  * a multiple of the fio block size. The caller must neither hold z->mutex
986  * nor f->zbd_info->mutex. Returns with z->mutex held upon success.
987  */
988 static struct fio_zone_info *zbd_convert_to_open_zone(struct thread_data *td,
989                                                       struct io_u *io_u)
990 {
991         const uint32_t min_bs = td->o.min_bs[io_u->ddir];
992         struct fio_file *f = io_u->file;
993         struct fio_zone_info *z;
994         unsigned int open_zone_idx = -1;
995         uint32_t zone_idx, new_zone_idx;
996         int i;
997
998         assert(is_valid_offset(f, io_u->offset));
999
1000         if (td->o.job_max_open_zones) {
1001                 /*
1002                  * This statement accesses f->zbd_info->open_zones[] on purpose
1003                  * without locking.
1004                  */
1005                 zone_idx = f->zbd_info->open_zones[pick_random_zone_idx(f, io_u)];
1006         } else {
1007                 zone_idx = zbd_zone_idx(f, io_u->offset);
1008         }
1009         if (zone_idx < f->min_zone)
1010                 zone_idx = f->min_zone;
1011         else if (zone_idx >= f->max_zone)
1012                 zone_idx = f->max_zone - 1;
1013         dprint(FD_ZBD, "%s(%s): starting from zone %d (offset %lld, buflen %lld)\n",
1014                __func__, f->file_name, zone_idx, io_u->offset, io_u->buflen);
1015
1016         /*
1017          * Since z->mutex is the outer lock and f->zbd_info->mutex the inner
1018          * lock it can happen that the state of the zone with index zone_idx
1019          * has changed after 'z' has been assigned and before f->zbd_info->mutex
1020          * has been obtained. Hence the loop.
1021          */
1022         for (;;) {
1023                 uint32_t tmp_idx;
1024
1025                 z = &f->zbd_info->zone_info[zone_idx];
1026
1027                 zone_lock(td, f, z);
1028                 pthread_mutex_lock(&f->zbd_info->mutex);
1029                 if (td->o.job_max_open_zones == 0)
1030                         goto examine_zone;
1031                 if (f->zbd_info->num_open_zones == 0) {
1032                         pthread_mutex_unlock(&f->zbd_info->mutex);
1033                         pthread_mutex_unlock(&z->mutex);
1034                         dprint(FD_ZBD, "%s(%s): no zones are open\n",
1035                                __func__, f->file_name);
1036                         return NULL;
1037                 }
1038
1039                 /*
1040                  * List of opened zones is per-device, shared across all threads.
1041                  * Start with quasi-random candidate zone.
1042                  * Ignore zones which don't belong to thread's offset/size area.
1043                  */
1044                 open_zone_idx = pick_random_zone_idx(f, io_u);
1045                 assert(open_zone_idx < f->zbd_info->num_open_zones);
1046                 tmp_idx = open_zone_idx;
1047                 for (i = 0; i < f->zbd_info->num_open_zones; i++) {
1048                         uint32_t tmpz;
1049
1050                         if (tmp_idx >= f->zbd_info->num_open_zones)
1051                                 tmp_idx = 0;
1052                         tmpz = f->zbd_info->open_zones[tmp_idx];
1053                         if (f->min_zone <= tmpz && tmpz < f->max_zone) {
1054                                 open_zone_idx = tmp_idx;
1055                                 goto found_candidate_zone;
1056                         }
1057
1058                         tmp_idx++;
1059                 }
1060
1061                 dprint(FD_ZBD, "%s(%s): no candidate zone\n",
1062                         __func__, f->file_name);
1063                 pthread_mutex_unlock(&f->zbd_info->mutex);
1064                 pthread_mutex_unlock(&z->mutex);
1065                 return NULL;
1066
1067 found_candidate_zone:
1068                 new_zone_idx = f->zbd_info->open_zones[open_zone_idx];
1069                 if (new_zone_idx == zone_idx)
1070                         break;
1071                 zone_idx = new_zone_idx;
1072                 pthread_mutex_unlock(&f->zbd_info->mutex);
1073                 pthread_mutex_unlock(&z->mutex);
1074         }
1075
1076         /* Both z->mutex and f->zbd_info->mutex are held. */
1077
1078 examine_zone:
1079         if (z->wp + min_bs <= (z+1)->start) {
1080                 pthread_mutex_unlock(&f->zbd_info->mutex);
1081                 goto out;
1082         }
1083         dprint(FD_ZBD, "%s(%s): closing zone %d\n", __func__, f->file_name,
1084                zone_idx);
1085         if (td->o.job_max_open_zones)
1086                 zbd_close_zone(td, f, open_zone_idx);
1087         pthread_mutex_unlock(&f->zbd_info->mutex);
1088
1089         /* Only z->mutex is held. */
1090
1091         /* Zone 'z' is full, so try to open a new zone. */
1092         for (i = f->io_size / f->zbd_info->zone_size; i > 0; i--) {
1093                 zone_idx++;
1094                 pthread_mutex_unlock(&z->mutex);
1095                 z++;
1096                 if (!is_valid_offset(f, z->start)) {
1097                         /* Wrap-around. */
1098                         zone_idx = f->min_zone;
1099                         z = &f->zbd_info->zone_info[zone_idx];
1100                 }
1101                 assert(is_valid_offset(f, z->start));
1102                 zone_lock(td, f, z);
1103                 if (z->open)
1104                         continue;
1105                 if (zbd_open_zone(td, io_u, zone_idx))
1106                         goto out;
1107         }
1108
1109         /* Only z->mutex is held. */
1110
1111         /* Check whether the write fits in any of the already opened zones. */
1112         pthread_mutex_lock(&f->zbd_info->mutex);
1113         for (i = 0; i < f->zbd_info->num_open_zones; i++) {
1114                 zone_idx = f->zbd_info->open_zones[i];
1115                 if (zone_idx < f->min_zone || zone_idx >= f->max_zone)
1116                         continue;
1117                 pthread_mutex_unlock(&f->zbd_info->mutex);
1118                 pthread_mutex_unlock(&z->mutex);
1119
1120                 z = &f->zbd_info->zone_info[zone_idx];
1121
1122                 zone_lock(td, f, z);
1123                 if (z->wp + min_bs <= (z+1)->start)
1124                         goto out;
1125                 pthread_mutex_lock(&f->zbd_info->mutex);
1126         }
1127         pthread_mutex_unlock(&f->zbd_info->mutex);
1128         pthread_mutex_unlock(&z->mutex);
1129         dprint(FD_ZBD, "%s(%s): did not open another zone\n", __func__,
1130                f->file_name);
1131         return NULL;
1132
1133 out:
1134         dprint(FD_ZBD, "%s(%s): returning zone %d\n", __func__, f->file_name,
1135                zone_idx);
1136         io_u->offset = z->start;
1137         return z;
1138 }
1139
1140 /* The caller must hold z->mutex. */
1141 static struct fio_zone_info *zbd_replay_write_order(struct thread_data *td,
1142                                                     struct io_u *io_u,
1143                                                     struct fio_zone_info *z)
1144 {
1145         const struct fio_file *f = io_u->file;
1146         const uint32_t min_bs = td->o.min_bs[DDIR_WRITE];
1147
1148         if (!zbd_open_zone(td, io_u, z - f->zbd_info->zone_info)) {
1149                 pthread_mutex_unlock(&z->mutex);
1150                 z = zbd_convert_to_open_zone(td, io_u);
1151                 assert(z);
1152         }
1153
1154         if (z->verify_block * min_bs >= f->zbd_info->zone_size)
1155                 log_err("%s: %d * %d >= %llu\n", f->file_name, z->verify_block,
1156                         min_bs, (unsigned long long) f->zbd_info->zone_size);
1157         io_u->offset = z->start + z->verify_block++ * min_bs;
1158         return z;
1159 }
1160
1161 /*
1162  * Find another zone for which @io_u fits below the write pointer. Start
1163  * searching in zones @zb + 1 .. @zl and continue searching in zones
1164  * @zf .. @zb - 1.
1165  *
1166  * Either returns NULL or returns a zone pointer and holds the mutex for that
1167  * zone.
1168  */
1169 static struct fio_zone_info *
1170 zbd_find_zone(struct thread_data *td, struct io_u *io_u,
1171               struct fio_zone_info *zb, struct fio_zone_info *zl)
1172 {
1173         const uint32_t min_bs = td->o.min_bs[io_u->ddir];
1174         struct fio_file *f = io_u->file;
1175         struct fio_zone_info *z1, *z2;
1176         const struct fio_zone_info *const zf =
1177                 &f->zbd_info->zone_info[zbd_zone_idx(f, f->file_offset)];
1178
1179         /*
1180          * Skip to the next non-empty zone in case of sequential I/O and to
1181          * the nearest non-empty zone in case of random I/O.
1182          */
1183         for (z1 = zb + 1, z2 = zb - 1; z1 < zl || z2 >= zf; z1++, z2--) {
1184                 if (z1 < zl && z1->cond != ZBD_ZONE_COND_OFFLINE) {
1185                         zone_lock(td, f, z1);
1186                         if (z1->start + min_bs <= z1->wp)
1187                                 return z1;
1188                         pthread_mutex_unlock(&z1->mutex);
1189                 } else if (!td_random(td)) {
1190                         break;
1191                 }
1192                 if (td_random(td) && z2 >= zf &&
1193                     z2->cond != ZBD_ZONE_COND_OFFLINE) {
1194                         zone_lock(td, f, z2);
1195                         if (z2->start + min_bs <= z2->wp)
1196                                 return z2;
1197                         pthread_mutex_unlock(&z2->mutex);
1198                 }
1199         }
1200         dprint(FD_ZBD, "%s: adjusting random read offset failed\n",
1201                f->file_name);
1202         return NULL;
1203 }
1204
1205 /**
1206  * zbd_queue_io - update the write pointer of a sequential zone
1207  * @io_u: I/O unit
1208  * @success: Whether or not the I/O unit has been queued successfully
1209  * @q: queueing status (busy, completed or queued).
1210  *
1211  * For write and trim operations, update the write pointer of the I/O unit
1212  * target zone.
1213  */
1214 static void zbd_queue_io(struct io_u *io_u, int q, bool success)
1215 {
1216         const struct fio_file *f = io_u->file;
1217         struct zoned_block_device_info *zbd_info = f->zbd_info;
1218         struct fio_zone_info *z;
1219         uint32_t zone_idx;
1220         uint64_t zone_end;
1221
1222         if (!zbd_info)
1223                 return;
1224
1225         zone_idx = zbd_zone_idx(f, io_u->offset);
1226         assert(zone_idx < zbd_info->nr_zones);
1227         z = &zbd_info->zone_info[zone_idx];
1228
1229         if (!zbd_zone_swr(z))
1230                 return;
1231
1232         if (!success)
1233                 goto unlock;
1234
1235         dprint(FD_ZBD,
1236                "%s: queued I/O (%lld, %llu) for zone %u\n",
1237                f->file_name, io_u->offset, io_u->buflen, zone_idx);
1238
1239         switch (io_u->ddir) {
1240         case DDIR_WRITE:
1241                 zone_end = min((uint64_t)(io_u->offset + io_u->buflen),
1242                                (z + 1)->start);
1243                 pthread_mutex_lock(&zbd_info->mutex);
1244                 /*
1245                  * z->wp > zone_end means that one or more I/O errors
1246                  * have occurred.
1247                  */
1248                 if (z->wp <= zone_end)
1249                         zbd_info->sectors_with_data += zone_end - z->wp;
1250                 pthread_mutex_unlock(&zbd_info->mutex);
1251                 z->wp = zone_end;
1252                 break;
1253         case DDIR_TRIM:
1254                 assert(z->wp == z->start);
1255                 break;
1256         default:
1257                 break;
1258         }
1259
1260 unlock:
1261         if (!success || q != FIO_Q_QUEUED) {
1262                 /* BUSY or COMPLETED: unlock the zone */
1263                 pthread_mutex_unlock(&z->mutex);
1264                 io_u->zbd_put_io = NULL;
1265         }
1266 }
1267
1268 /**
1269  * zbd_put_io - Unlock an I/O unit target zone lock
1270  * @io_u: I/O unit
1271  */
1272 static void zbd_put_io(const struct io_u *io_u)
1273 {
1274         const struct fio_file *f = io_u->file;
1275         struct zoned_block_device_info *zbd_info = f->zbd_info;
1276         struct fio_zone_info *z;
1277         uint32_t zone_idx;
1278         int ret;
1279
1280         if (!zbd_info)
1281                 return;
1282
1283         zone_idx = zbd_zone_idx(f, io_u->offset);
1284         assert(zone_idx < zbd_info->nr_zones);
1285         z = &zbd_info->zone_info[zone_idx];
1286
1287         if (!zbd_zone_swr(z))
1288                 return;
1289
1290         dprint(FD_ZBD,
1291                "%s: terminate I/O (%lld, %llu) for zone %u\n",
1292                f->file_name, io_u->offset, io_u->buflen, zone_idx);
1293
1294         ret = pthread_mutex_unlock(&z->mutex);
1295         assert(ret == 0);
1296         zbd_check_swd(f);
1297 }
1298
1299 /*
1300  * Windows and MacOS do not define this.
1301  */
1302 #ifndef EREMOTEIO
1303 #define EREMOTEIO       121     /* POSIX value */
1304 #endif
1305
1306 bool zbd_unaligned_write(int error_code)
1307 {
1308         switch (error_code) {
1309         case EIO:
1310         case EREMOTEIO:
1311                 return true;
1312         }
1313         return false;
1314 }
1315
1316 /**
1317  * setup_zbd_zone_mode - handle zoneskip as necessary for ZBD drives
1318  * @td: FIO thread data.
1319  * @io_u: FIO I/O unit.
1320  *
1321  * For sequential workloads, change the file offset to skip zoneskip bytes when
1322  * no more IO can be performed in the current zone.
1323  * - For read workloads, zoneskip is applied when the io has reached the end of
1324  *   the zone or the zone write position (when td->o.read_beyond_wp is false).
1325  * - For write workloads, zoneskip is applied when the zone is full.
1326  * This applies only to read and write operations.
1327  */
1328 void setup_zbd_zone_mode(struct thread_data *td, struct io_u *io_u)
1329 {
1330         struct fio_file *f = io_u->file;
1331         enum fio_ddir ddir = io_u->ddir;
1332         struct fio_zone_info *z;
1333         uint32_t zone_idx;
1334
1335         assert(td->o.zone_mode == ZONE_MODE_ZBD);
1336         assert(td->o.zone_size);
1337
1338         /*
1339          * zone_skip is valid only for sequential workloads.
1340          */
1341         if (td_random(td) || !td->o.zone_skip)
1342                 return;
1343
1344         /*
1345          * It is time to switch to a new zone if:
1346          * - zone_bytes == zone_size bytes have already been accessed
1347          * - The last position reached the end of the current zone.
1348          * - For reads with td->o.read_beyond_wp == false, the last position
1349          *   reached the zone write pointer.
1350          */
1351         zone_idx = zbd_zone_idx(f, f->last_pos[ddir]);
1352         z = &f->zbd_info->zone_info[zone_idx];
1353
1354         if (td->zone_bytes >= td->o.zone_size ||
1355             f->last_pos[ddir] >= (z+1)->start ||
1356             (ddir == DDIR_READ &&
1357              (!td->o.read_beyond_wp) && f->last_pos[ddir] >= z->wp)) {
1358                 /*
1359                  * Skip zones.
1360                  */
1361                 td->zone_bytes = 0;
1362                 f->file_offset += td->o.zone_size + td->o.zone_skip;
1363
1364                 /*
1365                  * Wrap from the beginning, if we exceed the file size
1366                  */
1367                 if (f->file_offset >= f->real_file_size)
1368                         f->file_offset = get_start_offset(td, f);
1369
1370                 f->last_pos[ddir] = f->file_offset;
1371                 td->io_skip_bytes += td->o.zone_skip;
1372         }
1373 }
1374
1375 /**
1376  * zbd_adjust_ddir - Adjust an I/O direction for zonedmode=zbd.
1377  *
1378  * @td: FIO thread data.
1379  * @io_u: FIO I/O unit.
1380  * @ddir: I/O direction before adjustment.
1381  *
1382  * Return adjusted I/O direction.
1383  */
1384 enum fio_ddir zbd_adjust_ddir(struct thread_data *td, struct io_u *io_u,
1385                               enum fio_ddir ddir)
1386 {
1387         /*
1388          * In case read direction is chosen for the first random I/O, fio with
1389          * zonemode=zbd stops because no data can be read from zoned block
1390          * devices with all empty zones. Overwrite the first I/O direction as
1391          * write to make sure data to read exists.
1392          */
1393         if (ddir != DDIR_READ || !td_rw(td))
1394                 return ddir;
1395
1396         if (io_u->file->zbd_info->sectors_with_data ||
1397             td->o.read_beyond_wp)
1398                 return DDIR_READ;
1399
1400         return DDIR_WRITE;
1401 }
1402
1403 /**
1404  * zbd_adjust_block - adjust the offset and length as necessary for ZBD drives
1405  * @td: FIO thread data.
1406  * @io_u: FIO I/O unit.
1407  *
1408  * Locking strategy: returns with z->mutex locked if and only if z refers
1409  * to a sequential zone and if io_u_accept is returned. z is the zone that
1410  * corresponds to io_u->offset at the end of this function.
1411  */
1412 enum io_u_action zbd_adjust_block(struct thread_data *td, struct io_u *io_u)
1413 {
1414         struct fio_file *f = io_u->file;
1415         uint32_t zone_idx_b;
1416         struct fio_zone_info *zb, *zl, *orig_zb;
1417         uint32_t orig_len = io_u->buflen;
1418         uint32_t min_bs = td->o.min_bs[io_u->ddir];
1419         uint64_t new_len;
1420         int64_t range;
1421
1422         if (!f->zbd_info)
1423                 return io_u_accept;
1424
1425         assert(min_bs);
1426         assert(is_valid_offset(f, io_u->offset));
1427         assert(io_u->buflen);
1428         zone_idx_b = zbd_zone_idx(f, io_u->offset);
1429         zb = &f->zbd_info->zone_info[zone_idx_b];
1430         orig_zb = zb;
1431
1432         /* Accept the I/O offset for conventional zones. */
1433         if (!zbd_zone_swr(zb))
1434                 return io_u_accept;
1435
1436         /*
1437          * Accept the I/O offset for reads if reading beyond the write pointer
1438          * is enabled.
1439          */
1440         if (zb->cond != ZBD_ZONE_COND_OFFLINE &&
1441             io_u->ddir == DDIR_READ && td->o.read_beyond_wp)
1442                 return io_u_accept;
1443
1444         zbd_check_swd(f);
1445
1446         zone_lock(td, f, zb);
1447
1448         switch (io_u->ddir) {
1449         case DDIR_READ:
1450                 if (td->runstate == TD_VERIFYING) {
1451                         if (td_write(td))
1452                                 zb = zbd_replay_write_order(td, io_u, zb);
1453                         goto accept;
1454                 }
1455                 /*
1456                  * Check that there is enough written data in the zone to do an
1457                  * I/O of at least min_bs B. If there isn't, find a new zone for
1458                  * the I/O.
1459                  */
1460                 range = zb->cond != ZBD_ZONE_COND_OFFLINE ?
1461                         zb->wp - zb->start : 0;
1462                 if (range < min_bs ||
1463                     ((!td_random(td)) && (io_u->offset + min_bs > zb->wp))) {
1464                         pthread_mutex_unlock(&zb->mutex);
1465                         zl = &f->zbd_info->zone_info[zbd_zone_idx(f,
1466                                                 f->file_offset + f->io_size)];
1467                         zb = zbd_find_zone(td, io_u, zb, zl);
1468                         if (!zb) {
1469                                 dprint(FD_ZBD,
1470                                        "%s: zbd_find_zone(%lld, %llu) failed\n",
1471                                        f->file_name, io_u->offset,
1472                                        io_u->buflen);
1473                                 goto eof;
1474                         }
1475                         /*
1476                          * zbd_find_zone() returned a zone with a range of at
1477                          * least min_bs.
1478                          */
1479                         range = zb->wp - zb->start;
1480                         assert(range >= min_bs);
1481
1482                         if (!td_random(td))
1483                                 io_u->offset = zb->start;
1484                 }
1485                 /*
1486                  * Make sure the I/O is within the zone valid data range while
1487                  * maximizing the I/O size and preserving randomness.
1488                  */
1489                 if (range <= io_u->buflen)
1490                         io_u->offset = zb->start;
1491                 else if (td_random(td))
1492                         io_u->offset = zb->start +
1493                                 ((io_u->offset - orig_zb->start) %
1494                                  (range - io_u->buflen)) / min_bs * min_bs;
1495                 /*
1496                  * Make sure the I/O does not cross over the zone wp position.
1497                  */
1498                 new_len = min((unsigned long long)io_u->buflen,
1499                               (unsigned long long)(zb->wp - io_u->offset));
1500                 new_len = new_len / min_bs * min_bs;
1501                 if (new_len < io_u->buflen) {
1502                         io_u->buflen = new_len;
1503                         dprint(FD_IO, "Changed length from %u into %llu\n",
1504                                orig_len, io_u->buflen);
1505                 }
1506                 assert(zb->start <= io_u->offset);
1507                 assert(io_u->offset + io_u->buflen <= zb->wp);
1508                 goto accept;
1509         case DDIR_WRITE:
1510                 if (io_u->buflen > f->zbd_info->zone_size)
1511                         goto eof;
1512                 if (!zbd_open_zone(td, io_u, zone_idx_b)) {
1513                         pthread_mutex_unlock(&zb->mutex);
1514                         zb = zbd_convert_to_open_zone(td, io_u);
1515                         if (!zb)
1516                                 goto eof;
1517                         zone_idx_b = zb - f->zbd_info->zone_info;
1518                 }
1519                 /* Check whether the zone reset threshold has been exceeded */
1520                 if (td->o.zrf.u.f) {
1521                         if (f->zbd_info->sectors_with_data >=
1522                             f->io_size * td->o.zrt.u.f &&
1523                             zbd_dec_and_reset_write_cnt(td, f)) {
1524                                 zb->reset_zone = 1;
1525                         }
1526                 }
1527                 /* Reset the zone pointer if necessary */
1528                 if (zb->reset_zone || zbd_zone_full(f, zb, min_bs)) {
1529                         assert(td->o.verify == VERIFY_NONE);
1530                         /*
1531                          * Since previous write requests may have been submitted
1532                          * asynchronously and since we will submit the zone
1533                          * reset synchronously, wait until previously submitted
1534                          * write requests have completed before issuing a
1535                          * zone reset.
1536                          */
1537                         io_u_quiesce(td);
1538                         zb->reset_zone = 0;
1539                         if (zbd_reset_zone(td, f, zb) < 0)
1540                                 goto eof;
1541                 }
1542                 /* Make writes occur at the write pointer */
1543                 assert(!zbd_zone_full(f, zb, min_bs));
1544                 io_u->offset = zb->wp;
1545                 if (!is_valid_offset(f, io_u->offset)) {
1546                         dprint(FD_ZBD, "Dropped request with offset %llu\n",
1547                                io_u->offset);
1548                         goto eof;
1549                 }
1550                 /*
1551                  * Make sure that the buflen is a multiple of the minimal
1552                  * block size. Give up if shrinking would make the request too
1553                  * small.
1554                  */
1555                 new_len = min((unsigned long long)io_u->buflen,
1556                               (zb + 1)->start - io_u->offset);
1557                 new_len = new_len / min_bs * min_bs;
1558                 if (new_len == io_u->buflen)
1559                         goto accept;
1560                 if (new_len >= min_bs) {
1561                         io_u->buflen = new_len;
1562                         dprint(FD_IO, "Changed length from %u into %llu\n",
1563                                orig_len, io_u->buflen);
1564                         goto accept;
1565                 }
1566                 log_err("Zone remainder %lld smaller than minimum block size %d\n",
1567                         ((zb + 1)->start - io_u->offset),
1568                         min_bs);
1569                 goto eof;
1570         case DDIR_TRIM:
1571                 /* fall-through */
1572         case DDIR_SYNC:
1573         case DDIR_DATASYNC:
1574         case DDIR_SYNC_FILE_RANGE:
1575         case DDIR_WAIT:
1576         case DDIR_LAST:
1577         case DDIR_INVAL:
1578                 goto accept;
1579         }
1580
1581         assert(false);
1582
1583 accept:
1584         assert(zb);
1585         assert(zb->cond != ZBD_ZONE_COND_OFFLINE);
1586         assert(!io_u->zbd_queue_io);
1587         assert(!io_u->zbd_put_io);
1588         io_u->zbd_queue_io = zbd_queue_io;
1589         io_u->zbd_put_io = zbd_put_io;
1590         return io_u_accept;
1591
1592 eof:
1593         if (zb)
1594                 pthread_mutex_unlock(&zb->mutex);
1595         return io_u_eof;
1596 }
1597
1598 /* Return a string with ZBD statistics */
1599 char *zbd_write_status(const struct thread_stat *ts)
1600 {
1601         char *res;
1602
1603         if (asprintf(&res, "; %llu zone resets", (unsigned long long) ts->nr_zone_resets) < 0)
1604                 return NULL;
1605         return res;
1606 }