int ring_fd;
struct io_u **io_u_index;
+ char *md_buf;
int *fds;
unsigned int uncached;
unsigned int nowait;
unsigned int force_async;
+ unsigned int md_per_io_size;
enum uring_cmd_type cmd_type;
};
.group = FIO_OPT_G_IOURING,
},
CMDPRIO_OPTIONS(struct ioring_options, FIO_OPT_G_IOURING),
+ {
+ .name = "md_per_io_size",
+ .lname = "Separate Metadata Buffer Size per I/O",
+ .type = FIO_OPT_INT,
+ .off1 = offsetof(struct ioring_options, md_per_io_size),
+ .def = "0",
+ .help = "Size of separate metadata buffer per I/O (Default: 0)",
+ .category = FIO_OPT_C_ENGINE,
+ .group = FIO_OPT_G_IOURING,
+ },
{
.name = NULL,
},
fio_cmdprio_cleanup(&ld->cmdprio);
free(ld->io_u_index);
+ free(ld->md_buf);
free(ld->iovecs);
free(ld->fds);
free(ld->dsm);
{
struct ioring_options *o = td->eo;
struct ioring_data *ld;
+ unsigned long long md_size;
int ret;
/* sqthread submission requires registered files */
/* io_u index */
ld->io_u_index = calloc(td->o.iodepth, sizeof(struct io_u *));
+
+ /*
+ * metadata buffer for nvme command.
+ * We are only supporting iomem=malloc / mem=malloc as of now.
+ */
+ if (!strcmp(td->io_ops->name, "io_uring_cmd") &&
+ (o->cmd_type == FIO_URING_CMD_NVME) && o->md_per_io_size) {
+ md_size = (unsigned long long) o->md_per_io_size
+ * (unsigned long long) td->o.iodepth;
+ md_size += page_mask + td->o.mem_align;
+ if (td->o.mem_align && td->o.mem_align > page_size)
+ md_size += td->o.mem_align - page_size;
+ if (td->o.mem_type == MEM_MALLOC) {
+ ld->md_buf = malloc(md_size);
+ if (!ld->md_buf)
+ return 1;
+ } else {
+ log_err("fio: Only iomem=malloc or mem=malloc is supported\n");
+ return 1;
+ }
+ }
+
ld->iovecs = calloc(td->o.iodepth, sizeof(struct iovec));
td->io_ops_data = ld;
static int fio_ioring_io_u_init(struct thread_data *td, struct io_u *io_u)
{
struct ioring_data *ld = td->io_ops_data;
+ struct ioring_options *o = td->eo;
+ char *p;
ld->io_u_index[io_u->index] = io_u;
+
+ if (!strcmp(td->io_ops->name, "io_uring_cmd")) {
+ p = PTR_ALIGN(ld->md_buf, page_mask) + td->o.mem_align;
+ p += o->md_per_io_size * io_u->index;
+ io_u->mmap_data = p;
+ }
+
return 0;
}
td_verror(td, EINVAL, "fio_ioring_cmd_open_file");
return 1;
}
+ if (data->ms && !data->lba_ext && ddir != DDIR_TRIM &&
+ (o->md_per_io_size < ((td->o.max_bs[ddir] / data->lba_size) *
+ data->ms))) {
+ log_err("%s: md_per_io_size should be at least %llu bytes\n",
+ f->file_name,
+ ((td->o.max_bs[ddir] / data->lba_size) * data->ms));
+ td_verror(td, EINVAL, "fio_ioring_cmd_open_file");
+ return 1;
+ }
}
}
if (!ld || !o->registerfiles)
cmd->addr = (__u64)(uintptr_t)io_u->xfer_buf;
cmd->data_len = io_u->xfer_buflen;
}
+ if (data->lba_shift && data->ms) {
+ cmd->metadata = (__u64)(uintptr_t)io_u->mmap_data;
+ cmd->metadata_len = (nlb + 1) * data->ms;
+ }
cmd->nsid = data->nsid;
return 0;
}
format_idx = (ns.flbas & 0xf) + (((ns.flbas >> 5) & 0x3) << 4);
data->lba_size = 1 << ns.lbaf[format_idx].ds;
+ data->ms = le16_to_cpu(ns.lbaf[format_idx].ms);
/*
- * Only extended LBA can be supported.
* Bit 4 for flbas indicates if metadata is transferred at the end of
* logical block creating an extended LBA.
*/
- data->ms = le16_to_cpu(ns.lbaf[format_idx].ms);
- if (data->ms && !((ns.flbas >> 4) & 0x1)) {
- log_err("%s: only extended logical block can be supported\n",
- f->file_name);
- err = -ENOTSUP;
- goto out;
- }
-
- if (data->ms)
+ if (data->ms && ((ns.flbas >> 4) & 0x1))
data->lba_ext = data->lba_size + data->ms;
else
data->lba_shift = ilog2(data->lba_size);