#include "fio.h"
#include "err.h"
#include "zbd_types.h"
+#include "zbd.h"
struct libzbc_data {
struct zbc_device *zdev;
enum zbc_dev_model model;
uint64_t nr_sectors;
+ uint32_t max_open_seq_req;
};
static int libzbc_get_dev_info(struct libzbc_data *ld, struct fio_file *f)
zbc_get_device_info(ld->zdev, zinfo);
ld->model = zinfo->zbd_model;
ld->nr_sectors = zinfo->zbd_sectors;
+ ld->max_open_seq_req = zinfo->zbd_max_nr_open_seq_req;
dprint(FD_ZBD, "%s: vendor_id:%s, type: %s, model: %s\n",
f->file_name, zinfo->zbd_vendor_id,
return -EINVAL;
}
- if (td_write(td)) {
+ if (td_write(td) || td_trim(td)) {
if (!read_only)
flags |= O_RDWR;
} else if (td_read(td)) {
- if (f->filetype == FIO_TYPE_CHAR && !read_only)
- flags |= O_RDWR;
- else
flags |= O_RDONLY;
- } else if (td_trim(td)) {
- td_verror(td, EINVAL, "libzbc does not support trim");
- log_err("%s: libzbc does not support trim\n", f->file_name);
- return -EINVAL;
- }
-
- if (td->o.oatomic) {
- td_verror(td, EINVAL, "libzbc does not support O_ATOMIC");
- log_err("%s: libzbc does not support O_ATOMIC\n", f->file_name);
- return -EINVAL;
}
ld = calloc(1, sizeof(*ld));
return -ENOMEM;
ret = zbc_open(f->file_name,
- flags | ZBC_O_DRV_SCSI | ZBC_O_DRV_ATA, &ld->zdev);
+ flags | ZBC_O_DRV_SCSI | ZBC_O_DRV_ATA,
+ &ld->zdev);
if (ret) {
log_err("%s: zbc_open() failed, err=%d\n",
f->file_name, ret);
struct libzbc_data *ld;
int ret;
- if (f->filetype != FIO_TYPE_BLOCK && f->filetype != FIO_TYPE_CHAR) {
- *model = ZBD_IGNORE;
- return 0;
- }
+ if (f->filetype != FIO_TYPE_BLOCK && f->filetype != FIO_TYPE_CHAR)
+ return -EINVAL;
ret = libzbc_open_dev(td, f, &ld);
if (ret)
zbdz->start = zones[i].zbz_start << 9;
zbdz->len = zones[i].zbz_length << 9;
zbdz->wp = zones[i].zbz_write_pointer << 9;
+ /*
+ * ZBC/ZAC do not define zone capacity, so use the zone size as
+ * the zone capacity.
+ */
+ zbdz->capacity = zbdz->len;
switch (zones[i].zbz_type) {
case ZBC_ZT_CONVENTIONAL:
default:
/* Treat all these conditions as offline (don't use!) */
zbdz->cond = ZBD_ZONE_COND_OFFLINE;
- break;
+ zbdz->wp = zbdz->start;
}
}
return -ret;
}
+static int libzbc_finish_zone(struct thread_data *td, struct fio_file *f,
+ uint64_t offset, uint64_t length)
+{
+ struct libzbc_data *ld = td->io_ops_data;
+ uint64_t sector = offset >> 9;
+ unsigned int nr_zones;
+ struct zbc_errno err;
+ int i, ret;
+
+ assert(ld);
+ assert(ld->zdev);
+
+ nr_zones = (length + td->o.zone_size - 1) / td->o.zone_size;
+ assert(nr_zones > 0);
+
+ for (i = 0; i < nr_zones; i++, sector += td->o.zone_size >> 9) {
+ ret = zbc_finish_zone(ld->zdev, sector, 0);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ zbc_errno(ld->zdev, &err);
+ td_verror(td, errno, "zbc_finish_zone failed");
+ if (err.sk)
+ log_err("%s: finish zone failed %s:%s\n",
+ f->file_name,
+ zbc_sk_str(err.sk), zbc_asc_ascq_str(err.asc_ascq));
+ return -ret;
+}
+
+static int libzbc_get_max_open_zones(struct thread_data *td, struct fio_file *f,
+ unsigned int *max_open_zones)
+{
+ struct libzbc_data *ld;
+ int ret;
+
+ ret = libzbc_open_dev(td, f, &ld);
+ if (ret)
+ return ret;
+
+ if (ld->max_open_seq_req == ZBC_NO_LIMIT)
+ *max_open_zones = 0;
+ else
+ *max_open_zones = ld->max_open_seq_req;
+
+ return 0;
+}
+
ssize_t libzbc_rw(struct thread_data *td, struct io_u *io_u)
{
struct libzbc_data *ld = td->io_ops_data;
ret = zbc_flush(ld->zdev);
if (ret)
log_err("zbc_flush error %zd\n", ret);
- } else if (io_u->ddir != DDIR_TRIM) {
+ } else if (io_u->ddir == DDIR_TRIM) {
+ ret = zbd_do_io_u_trim(td, io_u);
+ if (!ret)
+ ret = EINVAL;
+ } else {
log_err("Unsupported operation %u\n", io_u->ddir);
ret = -EINVAL;
}
.get_zoned_model = libzbc_get_zoned_model,
.report_zones = libzbc_report_zones,
.reset_wp = libzbc_reset_wp,
+ .get_max_open_zones = libzbc_get_max_open_zones,
+ .finish_zone = libzbc_finish_zone,
.queue = libzbc_queue,
.flags = FIO_SYNCIO | FIO_NOEXTEND | FIO_RAWIO,
};