2 * FIO engine for DAOS File System (dfs).
4 * (C) Copyright 2020-2021 Intel Corporation.
13 static bool daos_initialized;
14 static int num_threads;
15 static pthread_mutex_t daos_mutex = PTHREAD_MUTEX_INITIALIZER;
16 daos_handle_t poh; /* pool handle */
17 daos_handle_t coh; /* container handle */
18 daos_oclass_id_t cid = OC_UNKNOWN; /* object class */
19 dfs_t *dfs; /* dfs mount reference */
38 struct daos_fio_options {
40 char *pool; /* Pool UUID */
41 char *cont; /* Container UUID */
42 daos_size_t chsz; /* Chunk size */
43 char *oclass; /* object class */
44 #if !defined(DAOS_API_VERSION_MAJOR) || DAOS_API_VERSION_MAJOR < 1
45 char *svcl; /* service replica list, deprecated */
49 static struct fio_option options[] = {
53 .type = FIO_OPT_STR_STORE,
54 .off1 = offsetof(struct daos_fio_options, pool),
55 .help = "DAOS pool uuid",
56 .category = FIO_OPT_C_ENGINE,
57 .group = FIO_OPT_G_DFS,
61 .lname = "container uuid",
62 .type = FIO_OPT_STR_STORE,
63 .off1 = offsetof(struct daos_fio_options, cont),
64 .help = "DAOS container uuid",
65 .category = FIO_OPT_C_ENGINE,
66 .group = FIO_OPT_G_DFS,
70 .lname = "DFS chunk size",
72 .off1 = offsetof(struct daos_fio_options, chsz),
73 .help = "DFS chunk size in bytes",
74 .def = "0", /* use container default */
75 .category = FIO_OPT_C_ENGINE,
76 .group = FIO_OPT_G_DFS,
79 .name = "object_class",
80 .lname = "object class",
81 .type = FIO_OPT_STR_STORE,
82 .off1 = offsetof(struct daos_fio_options, oclass),
83 .help = "DAOS object class",
84 .category = FIO_OPT_C_ENGINE,
85 .group = FIO_OPT_G_DFS,
87 #if !defined(DAOS_API_VERSION_MAJOR) || DAOS_API_VERSION_MAJOR < 1
90 .lname = "List of service ranks",
91 .type = FIO_OPT_STR_STORE,
92 .off1 = offsetof(struct daos_fio_options, svcl),
93 .help = "List of pool replicated service ranks",
94 .category = FIO_OPT_C_ENGINE,
95 .group = FIO_OPT_G_DFS,
103 static int daos_fio_global_init(struct thread_data *td)
105 struct daos_fio_options *eo = td->eo;
106 uuid_t pool_uuid, co_uuid;
107 daos_pool_info_t pool_info;
108 daos_cont_info_t co_info;
111 #if !defined(DAOS_API_VERSION_MAJOR) || DAOS_API_VERSION_MAJOR < 1
112 if (!eo->pool || !eo->cont || !eo->svcl) {
114 if (!eo->pool || !eo->cont) {
116 log_err("Missing required DAOS options\n");
121 if (rc != -DER_ALREADY && rc) {
122 log_err("Failed to initialize daos %d\n", rc);
123 td_verror(td, rc, "daos_init");
127 rc = uuid_parse(eo->pool, pool_uuid);
129 log_err("Failed to parse 'Pool uuid': %s\n", eo->pool);
130 td_verror(td, EINVAL, "uuid_parse(eo->pool)");
134 rc = uuid_parse(eo->cont, co_uuid);
136 log_err("Failed to parse 'Cont uuid': %s\n", eo->cont);
137 td_verror(td, EINVAL, "uuid_parse(eo->cont)");
141 /* Connect to the DAOS pool */
142 #if !defined(DAOS_API_VERSION_MAJOR) || DAOS_API_VERSION_MAJOR < 1
143 d_rank_list_t *svcl = NULL;
145 svcl = daos_rank_list_parse(eo->svcl, ":");
147 log_err("Failed to parse svcl\n");
148 td_verror(td, EINVAL, "daos_rank_list_parse");
152 rc = daos_pool_connect(pool_uuid, NULL, svcl, DAOS_PC_RW,
153 &poh, &pool_info, NULL);
154 d_rank_list_free(svcl);
156 rc = daos_pool_connect(pool_uuid, NULL, DAOS_PC_RW, &poh, &pool_info,
160 log_err("Failed to connect to pool %d\n", rc);
161 td_verror(td, rc, "daos_pool_connect");
165 /* Open the DAOS container */
166 rc = daos_cont_open(poh, co_uuid, DAOS_COO_RW, &coh, &co_info, NULL);
168 log_err("Failed to open container: %d\n", rc);
169 td_verror(td, rc, "daos_cont_open");
170 (void)daos_pool_disconnect(poh, NULL);
174 /* Mount encapsulated filesystem */
175 rc = dfs_mount(poh, coh, O_RDWR, &dfs);
177 log_err("Failed to mount DFS namespace: %d\n", rc);
178 td_verror(td, rc, "dfs_mount");
179 (void)daos_pool_disconnect(poh, NULL);
180 (void)daos_cont_close(coh, NULL);
184 /* Retrieve object class to use, if specified */
186 cid = daos_oclass_name2id(eo->oclass);
191 static int daos_fio_global_cleanup()
196 rc = dfs_umount(dfs);
198 log_err("failed to umount dfs: %d\n", rc);
201 rc = daos_cont_close(coh, NULL);
203 log_err("failed to close container: %d\n", rc);
207 rc = daos_pool_disconnect(poh, NULL);
209 log_err("failed to disconnect pool: %d\n", rc);
215 log_err("failed to finalize daos: %d\n", rc);
223 static int daos_fio_setup(struct thread_data *td)
228 static int daos_fio_init(struct thread_data *td)
230 struct daos_data *dd;
233 pthread_mutex_lock(&daos_mutex);
235 dd = malloc(sizeof(*dd));
237 log_err("Failed to allocate DAOS-private data\n");
243 dd->num_ios = td->o.iodepth;
244 dd->io_us = calloc(dd->num_ios, sizeof(struct io_u *));
245 if (dd->io_us == NULL) {
246 log_err("Failed to allocate IO queue\n");
251 /* initialize DAOS stack if not already up */
252 if (!daos_initialized) {
253 rc = daos_fio_global_init(td);
256 daos_initialized = true;
259 rc = daos_eq_create(&dd->eqh);
261 log_err("Failed to create event queue: %d\n", rc);
262 td_verror(td, rc, "daos_eq_create");
266 td->io_ops_data = dd;
274 if (num_threads == 0 && daos_initialized) {
275 /* don't clobber error return value */
276 (void)daos_fio_global_cleanup();
277 daos_initialized = false;
280 pthread_mutex_unlock(&daos_mutex);
284 static void daos_fio_cleanup(struct thread_data *td)
286 struct daos_data *dd = td->io_ops_data;
292 rc = daos_eq_destroy(dd->eqh, DAOS_EQ_DESTROY_FORCE);
294 log_err("failed to destroy event queue: %d\n", rc);
295 td_verror(td, rc, "daos_eq_destroy");
301 pthread_mutex_lock(&daos_mutex);
303 if (daos_initialized && num_threads == 0) {
306 ret = daos_fio_global_cleanup();
307 if (ret < 0 && rc == 0) {
308 log_err("failed to clean up: %d\n", ret);
309 td_verror(td, ret, "daos_fio_global_cleanup");
311 daos_initialized = false;
313 pthread_mutex_unlock(&daos_mutex);
316 static int daos_fio_get_file_size(struct thread_data *td, struct fio_file *f)
318 char *file_name = f->file_name;
319 struct stat stbuf = {0};
322 dprint(FD_FILE, "dfs stat %s\n", f->file_name);
324 if (!daos_initialized)
327 rc = dfs_stat(dfs, NULL, file_name, &stbuf);
329 log_err("Failed to stat %s: %d\n", f->file_name, rc);
330 td_verror(td, rc, "dfs_stat");
334 f->real_file_size = stbuf.st_size;
338 static int daos_fio_close(struct thread_data *td, struct fio_file *f)
340 struct daos_data *dd = td->io_ops_data;
343 dprint(FD_FILE, "dfs release %s\n", f->file_name);
345 rc = dfs_release(dd->obj);
347 log_err("Failed to release %s: %d\n", f->file_name, rc);
348 td_verror(td, rc, "dfs_release");
355 static int daos_fio_open(struct thread_data *td, struct fio_file *f)
357 struct daos_data *dd = td->io_ops_data;
358 struct daos_fio_options *eo = td->eo;
362 dprint(FD_FILE, "dfs open %s (%s/%d/%d)\n",
363 f->file_name, td_write(td) & !read_only ? "rw" : "r",
364 td->o.create_on_open, td->o.allow_create);
366 if (td->o.create_on_open && td->o.allow_create)
372 if (td->o.allow_create)
374 } else if (td_read(td)) {
378 rc = dfs_open(dfs, NULL, f->file_name,
379 S_IFREG | S_IRUSR | S_IWUSR,
380 flags, cid, eo->chsz, NULL, &dd->obj);
382 log_err("Failed to open %s: %d\n", f->file_name, rc);
383 td_verror(td, rc, "dfs_open");
390 static int daos_fio_unlink(struct thread_data *td, struct fio_file *f)
394 dprint(FD_FILE, "dfs remove %s\n", f->file_name);
396 rc = dfs_remove(dfs, NULL, f->file_name, false, NULL);
398 log_err("Failed to remove %s: %d\n", f->file_name, rc);
399 td_verror(td, rc, "dfs_remove");
406 static int daos_fio_invalidate(struct thread_data *td, struct fio_file *f)
408 dprint(FD_FILE, "dfs invalidate %s\n", f->file_name);
412 static void daos_fio_io_u_free(struct thread_data *td, struct io_u *io_u)
414 struct daos_iou *io = io_u->engine_data;
417 io_u->engine_data = NULL;
422 static int daos_fio_io_u_init(struct thread_data *td, struct io_u *io_u)
426 io = malloc(sizeof(struct daos_iou));
428 td_verror(td, ENOMEM, "malloc");
432 io_u->engine_data = io;
436 static struct io_u * daos_fio_event(struct thread_data *td, int event)
438 struct daos_data *dd = td->io_ops_data;
440 return dd->io_us[event];
443 static int daos_fio_getevents(struct thread_data *td, unsigned int min,
444 unsigned int max, const struct timespec *t)
446 struct daos_data *dd = td->io_ops_data;
447 daos_event_t *evp[max];
448 unsigned int events = 0;
452 while (events < min) {
453 rc = daos_eq_poll(dd->eqh, 0, DAOS_EQ_NOWAIT, max, evp);
455 log_err("Event poll failed: %d\n", rc);
456 td_verror(td, rc, "daos_eq_poll");
460 for (i = 0; i < rc; i++) {
464 io = container_of(evp[i], struct daos_iou, ev);
466 log_err("Completion on already completed I/O\n");
470 io_u->error = io->ev.ev_error;
474 dd->io_us[events] = io_u;
476 daos_event_fini(&io->ev);
482 dprint(FD_IO, "dfs eq_pool returning %d (%u/%u)\n", events, min, max);
487 static enum fio_q_status daos_fio_queue(struct thread_data *td,
490 struct daos_data *dd = td->io_ops_data;
491 struct daos_iou *io = io_u->engine_data;
492 daos_off_t offset = io_u->offset;
495 if (dd->queued == td->o.iodepth)
499 io->sgl.sg_nr_out = 0;
500 d_iov_set(&io->iov, io_u->xfer_buf, io_u->xfer_buflen);
501 io->sgl.sg_iovs = &io->iov;
502 io->size = io_u->xfer_buflen;
504 io->complete = false;
505 rc = daos_event_init(&io->ev, dd->eqh, NULL);
507 log_err("Event init failed: %d\n", rc);
509 return FIO_Q_COMPLETED;
512 switch (io_u->ddir) {
514 rc = dfs_write(dfs, dd->obj, &io->sgl, offset, &io->ev);
516 log_err("dfs_write failed: %d\n", rc);
518 return FIO_Q_COMPLETED;
522 rc = dfs_read(dfs, dd->obj, &io->sgl, offset, &io->size,
525 log_err("dfs_read failed: %d\n", rc);
527 return FIO_Q_COMPLETED;
532 return FIO_Q_COMPLETED;
534 dprint(FD_IO, "Invalid IO type: %d\n", io_u->ddir);
535 io_u->error = -DER_INVAL;
536 return FIO_Q_COMPLETED;
543 static int daos_fio_prep(struct thread_data fio_unused *td, struct io_u *io_u)
548 /* ioengine_ops for get_ioengine() */
549 FIO_STATIC struct ioengine_ops ioengine = {
551 .version = FIO_IOOPS_VERSION,
552 .flags = FIO_DISKLESSIO | FIO_NODISKUTIL,
554 .setup = daos_fio_setup,
555 .init = daos_fio_init,
556 .prep = daos_fio_prep,
557 .cleanup = daos_fio_cleanup,
559 .open_file = daos_fio_open,
560 .invalidate = daos_fio_invalidate,
561 .get_file_size = daos_fio_get_file_size,
562 .close_file = daos_fio_close,
563 .unlink_file = daos_fio_unlink,
565 .queue = daos_fio_queue,
566 .getevents = daos_fio_getevents,
567 .event = daos_fio_event,
568 .io_u_init = daos_fio_io_u_init,
569 .io_u_free = daos_fio_io_u_free,
571 .option_struct_size = sizeof(struct daos_fio_options),
575 static void fio_init fio_dfs_register(void)
577 register_ioengine(&ioengine);
580 static void fio_exit fio_dfs_unregister(void)
582 unregister_ioengine(&ioengine);