IOR
aiori-DFS.c
Go to the documentation of this file.
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  */
4 /*
5  * Copyright (C) 2018-2020 Intel Corporation
6  * See the file COPYRIGHT for a complete copyright notice and license.
7  */
8 
9 /*
10  * This file implements the abstract I/O interface for DAOS FS API.
11  */
12 
13 #define _BSD_SOURCE
14 
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18 
19 #include <string.h>
20 #include <assert.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <dirent.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <libgen.h>
29 
30 #include <mpi.h>
31 #include <gurt/common.h>
32 #include <gurt/hash.h>
33 #include <daos.h>
34 #include <daos_fs.h>
35 
36 #include "aiori.h"
37 #include "utilities.h"
38 #include "iordef.h"
39 
40 #if defined(DAOS_API_VERSION_MAJOR) && defined(DAOS_API_VERSION_MINOR)
41 #define CHECK_DAOS_API_VERSION(major, minor) \
42  ((DAOS_API_VERSION_MAJOR > (major)) \
43  || (DAOS_API_VERSION_MAJOR == (major) && DAOS_API_VERSION_MINOR >= (minor)))
44 #else
45 #define CHECK_DAOS_API_VERSION(major, minor) 0
46 #endif
47 
48 static dfs_t *dfs;
49 static daos_handle_t poh, coh;
50 static daos_oclass_id_t objectClass;
51 static daos_oclass_id_t dir_oclass;
52 static struct d_hash_table *aiori_dfs_hash = NULL;
53 static int dfs_init_count;
54 
55 struct aiori_dir_hdl {
56  d_list_t entry;
57  dfs_obj_t *oh;
58  char name[PATH_MAX];
59 };
60 
61 enum handleType {
65 };
66 
67 /************************** O P T I O N S *****************************/
68 typedef struct {
69  char *pool;
70  char *group;
71  char *cont;
73  char *oclass;
74  char *dir_oclass;
75  char *prefix;
76  int destroy;
78 
79 static option_help * DFS_options(aiori_mod_opt_t ** init_backend_options,
80  aiori_mod_opt_t * init_values){
81  DFS_options_t * o = malloc(sizeof(DFS_options_t));
82 
83  if (init_values != NULL) {
84  memcpy(o, init_values, sizeof(DFS_options_t));
85  } else {
86  memset(o, 0, sizeof(DFS_options_t));
87  }
88 
89  *init_backend_options = (aiori_mod_opt_t *) o;
90 
91  option_help h [] = {
92  {0, "dfs.pool", "Pool label or uuid", OPTION_OPTIONAL_ARGUMENT, 's', &o->pool},
93  {0, "dfs.group", "DAOS system name", OPTION_OPTIONAL_ARGUMENT, 's', &o->group},
94  {0, "dfs.cont", "Container label or uuid", OPTION_OPTIONAL_ARGUMENT, 's', &o->cont},
95  {0, "dfs.chunk_size", "File chunk size in bytes (e.g.: 8, 4k, 2m, 1g)", OPTION_OPTIONAL_ARGUMENT, 'd', &o->chunk_size},
96  {0, "dfs.oclass", "File object class", OPTION_OPTIONAL_ARGUMENT, 's', &o->oclass},
97  {0, "dfs.dir_oclass", "Directory object class", OPTION_OPTIONAL_ARGUMENT, 's',
98  &o->dir_oclass},
99  {0, "dfs.prefix", "Mount prefix", OPTION_OPTIONAL_ARGUMENT, 's', &o->prefix},
100  {0, "dfs.destroy", "Destroy DFS container on finalize", OPTION_FLAG, 'd', &o->destroy},
102  };
103 
104  option_help * help = malloc(sizeof(h));
105  memcpy(help, h, sizeof(h));
106  return help;
107 }
108 
109 /**************************** P R O T O T Y P E S *****************************/
110 static void DFS_Init(aiori_mod_opt_t *);
111 static void DFS_Finalize(aiori_mod_opt_t *);
112 static aiori_fd_t *DFS_Create(char *, int, aiori_mod_opt_t *);
113 static aiori_fd_t *DFS_Open(char *, int, aiori_mod_opt_t *);
116 static void DFS_Close(aiori_fd_t *, aiori_mod_opt_t *);
117 static void DFS_Delete(char *, aiori_mod_opt_t *);
118 static char* DFS_GetVersion();
119 static void DFS_Fsync(aiori_fd_t *, aiori_mod_opt_t *);
120 static void DFS_Sync(aiori_mod_opt_t *);
122 static int DFS_Statfs (const char *, ior_aiori_statfs_t *, aiori_mod_opt_t *);
123 static int DFS_Stat (const char *, struct stat *, aiori_mod_opt_t *);
124 static int DFS_Mkdir (const char *, mode_t, aiori_mod_opt_t *);
125 static int DFS_Rename(const char *, const char *, aiori_mod_opt_t *);
126 static int DFS_Rmdir (const char *, aiori_mod_opt_t *);
127 static int DFS_Access (const char *, int, aiori_mod_opt_t *);
128 static option_help * DFS_options();
130 static int DFS_check_params(aiori_mod_opt_t *);
131 
132 /************************** D E C L A R A T I O N S ***************************/
133 
135  .name = "DFS",
136  .initialize = DFS_Init,
137  .finalize = DFS_Finalize,
138  .create = DFS_Create,
139  .open = DFS_Open,
140  .xfer = DFS_Xfer,
141  .close = DFS_Close,
142  .delete = DFS_Delete,
143  .get_version = DFS_GetVersion,
144  .fsync = DFS_Fsync,
145  .sync = DFS_Sync,
146  .get_file_size = DFS_GetFileSize,
147  .xfer_hints = DFS_init_xfer_options,
148  .statfs = DFS_Statfs,
149  .mkdir = DFS_Mkdir,
150  .rename = DFS_Rename,
151  .rmdir = DFS_Rmdir,
152  .access = DFS_Access,
153  .stat = DFS_Stat,
154  .get_options = DFS_options,
155  .check_params = DFS_check_params,
156  .enable_mdtest = true,
157 };
158 
159 /***************************** F U N C T I O N S ******************************/
160 
161 /* For DAOS methods. */
162 #define DCHECK(rc, format, ...) \
163 do { \
164  int _rc = (rc); \
165  \
166  if (_rc != 0) { \
167  fprintf(stderr, "ERROR (%s:%d): %d: %d: " \
168  format"\n", __FILE__, __LINE__, rank, _rc, \
169  ##__VA_ARGS__); \
170  fflush(stderr); \
171  goto out; \
172  } \
173 } while (0)
174 
175 #define INFO(level, format, ...) \
176 do { \
177  if (verbose >= level) \
178  printf("[%d] "format"\n", rank, ##__VA_ARGS__); \
179 } while (0)
180 
181 #define DERR(format, ...) \
182 do { \
183  fprintf(stderr, format"\n", ##__VA_ARGS__); \
184  fflush(stderr); \
185  rc = -1; \
186  goto out; \
187 } while (0)
188 
190 
192 {
193  hints = params;
194 }
195 
197  DFS_options_t *o = (DFS_options_t *) options;
198 
199  if (o->pool == NULL || o->cont == NULL)
200  ERR("Invalid pool or container options\n");
201 
202  if (testComm == MPI_COMM_NULL)
203  testComm = MPI_COMM_WORLD;
204 
205  return 0;
206 }
207 
208 static inline struct aiori_dir_hdl *
209 hdl_obj(d_list_t *rlink)
210 {
211  return container_of(rlink, struct aiori_dir_hdl, entry);
212 }
213 
214 static bool
215 key_cmp(struct d_hash_table *htable, d_list_t *rlink,
216  const void *key, unsigned int ksize)
217 {
218  struct aiori_dir_hdl *hdl = hdl_obj(rlink);
219 
220  return (strcmp(hdl->name, (const char *)key) == 0);
221 }
222 
223 static void
224 rec_free(struct d_hash_table *htable, d_list_t *rlink)
225 {
226  struct aiori_dir_hdl *hdl = hdl_obj(rlink);
227 
228  dfs_release(hdl->oh);
229  free(hdl);
230 }
231 
232 static bool
233 rec_decref(struct d_hash_table *htable, d_list_t *rlink)
234 {
235  return true;
236 }
237 
238 static uint32_t
239 rec_hash(struct d_hash_table *htable, d_list_t *rlink)
240 {
241  struct aiori_dir_hdl *hdl = hdl_obj(rlink);
242 
243  return d_hash_string_u32(hdl->name, strlen(hdl->name));
244 }
245 
246 static d_hash_table_ops_t hdl_hash_ops = {
247  .hop_key_cmp = key_cmp,
248  .hop_rec_decref = rec_decref,
249  .hop_rec_free = rec_free,
250  .hop_rec_hash = rec_hash
251 };
252 
253 /* Distribute process 0's pool or container handle to others. */
254 static int
256 {
257  d_iov_t global;
258  int rc;
259 
260  global.iov_buf = NULL;
261  global.iov_buf_len = 0;
262  global.iov_len = 0;
263 
264  assert(type == POOL_HANDLE || type == CONT_HANDLE || type == DFS_HANDLE);
265  if (rank == 0) {
266  /* Get the global handle size. */
267  if (type == POOL_HANDLE)
268  rc = daos_pool_local2global(poh, &global);
269  else if (type == CONT_HANDLE)
270  rc = daos_cont_local2global(coh, &global);
271  else
272  rc = dfs_local2global(dfs, &global);
273  DCHECK(rc, "Failed to get global handle size");
274  }
275 
276  MPI_CHECK(MPI_Bcast(&global.iov_buf_len, 1, MPI_UINT64_T, 0, testComm),
277  "Failed to bcast global handle buffer size");
278 
279  global.iov_len = global.iov_buf_len;
280  global.iov_buf = malloc(global.iov_buf_len);
281  if (global.iov_buf == NULL)
282  ERR("Failed to allocate global handle buffer");
283 
284  if (rank == 0) {
285  if (type == POOL_HANDLE)
286  rc = daos_pool_local2global(poh, &global);
287  else if (type == CONT_HANDLE)
288  rc = daos_cont_local2global(coh, &global);
289  else
290  rc = dfs_local2global(dfs, &global);
291  DCHECK(rc, "Failed to create global handle");
292  }
293 
294  MPI_CHECK(MPI_Bcast(global.iov_buf, global.iov_buf_len, MPI_BYTE, 0, testComm),
295  "Failed to bcast global pool handle");
296 
297  if (rank != 0) {
298  if (type == POOL_HANDLE)
299  rc = daos_pool_global2local(global, &poh);
300  else if (type == CONT_HANDLE)
301  rc = daos_cont_global2local(poh, global, &coh);
302  else
303  rc = dfs_global2local(poh, coh, 0, global, &dfs);
304  DCHECK(rc, "Failed to get local handle");
305  }
306 
307 out:
308  if (global.iov_buf)
309  free(global.iov_buf);
310  return rc;
311 }
312 
313 static int
314 parse_filename(const char *path, char **_obj_name, char **_cont_name)
315 {
316  char *f1 = NULL;
317  char *f2 = NULL;
318  char *fname = NULL;
319  char *cont_name = NULL;
320  int rc = 0;
321 
322  if (path == NULL || _obj_name == NULL || _cont_name == NULL)
323  return -EINVAL;
324 
325  f1 = strdup(path);
326  if (f1 == NULL) {
327  rc = -ENOMEM;
328  goto out;
329  }
330 
331  f2 = strdup(path);
332  if (f2 == NULL) {
333  rc = -ENOMEM;
334  goto out;
335  }
336 
337  fname = basename(f1);
338  cont_name = dirname(f2);
339 
340  if (cont_name[0] != '/') {
341  char *ptr;
342  char buf[PATH_MAX];
343 
344  ptr = realpath(cont_name, buf);
345  if (ptr == NULL) {
346  rc = errno;
347  goto out;
348  }
349 
350  cont_name = strdup(ptr);
351  if (cont_name == NULL) {
352  rc = ENOMEM;
353  goto out;
354  }
355  *_cont_name = cont_name;
356  } else {
357  *_cont_name = strdup(cont_name);
358  if (*_cont_name == NULL) {
359  rc = ENOMEM;
360  goto out;
361  }
362  }
363 
364  *_obj_name = strdup(fname);
365  if (*_obj_name == NULL) {
366  rc = ENOMEM;
367  goto out;
368  }
369 
370 out:
371  if (f1)
372  free(f1);
373  if (f2)
374  free(f2);
375  return rc;
376 }
377 
378 static int
379 share_file_handle(dfs_obj_t **file, MPI_Comm comm)
380 {
381  d_iov_t global;
382  int rc;
383 
384  global.iov_buf = NULL;
385  global.iov_buf_len = 0;
386  global.iov_len = 0;
387 
388  if (rank == 0) {
389  rc = dfs_obj_local2global(dfs, *file, &global);
390  DCHECK(rc, "Failed to get global handle size");
391  }
392 
393  MPI_CHECK(MPI_Bcast(&global.iov_buf_len, 1, MPI_UINT64_T, 0, testComm),
394  "Failed to bcast global handle buffer size");
395 
396  global.iov_len = global.iov_buf_len;
397  global.iov_buf = malloc(global.iov_buf_len);
398  if (global.iov_buf == NULL)
399  ERR("Failed to allocate global handle buffer");
400 
401  if (rank == 0) {
402  rc = dfs_obj_local2global(dfs, *file, &global);
403  DCHECK(rc, "Failed to create global handle");
404  }
405 
406  MPI_CHECK(MPI_Bcast(global.iov_buf, global.iov_buf_len, MPI_BYTE, 0, testComm),
407  "Failed to bcast global pool handle");
408 
409  if (rank != 0) {
410  rc = dfs_obj_global2local(dfs, 0, global, file);
411  DCHECK(rc, "Failed to get local handle");
412  }
413 
414 out:
415  if (global.iov_buf)
416  free(global.iov_buf);
417  return rc;
418 }
419 
420 static dfs_obj_t *
421 lookup_insert_dir(const char *name, mode_t *mode)
422 {
423  struct aiori_dir_hdl *hdl;
424  dfs_obj_t *oh;
425  d_list_t *rlink;
426  size_t len = strlen(name);
427  int rc;
428 
429  rlink = d_hash_rec_find(aiori_dfs_hash, name, len);
430  if (rlink != NULL) {
431  hdl = hdl_obj(rlink);
432  return hdl->oh;
433  }
434 
435  rc = dfs_lookup(dfs, name, O_RDWR, &oh, mode, NULL);
436  if (rc)
437  return NULL;
438 
439  if (mode && !S_ISDIR(*mode))
440  return oh;
441 
442  hdl = calloc(1, sizeof(struct aiori_dir_hdl));
443  if (hdl == NULL)
444  return NULL;
445 
446  strncpy(hdl->name, name, len);
447  hdl->oh = oh;
448 
449  rc = d_hash_rec_insert(aiori_dfs_hash, hdl->name, len, &hdl->entry, false);
450  if (rc) {
451  fprintf(stderr, "Failed to insert dir handle in hashtable\n");
452  dfs_release(hdl->oh);
453  free(hdl);
454  return NULL;
455  }
456 
457  return hdl->oh;
458 }
459 
460 static void
462 {
463  DFS_options_t *o = (DFS_options_t *)options;
464  bool pool_connect, cont_create, cont_open, dfs_mounted;
465  uuid_t co_uuid;
466  int rc;
467 
468  dfs_init_count++;
469  if (dfs_init_count > 1) {
470  pool_connect = cont_create = cont_open = dfs_mounted = true;
472  if (o->oclass) {
473  objectClass = daos_oclass_name2id(o->oclass);
474  if (objectClass == OC_UNKNOWN)
475  DERR("Invalid DAOS object class: %s\n", o->oclass);
476  }
477  if (o->dir_oclass) {
478  dir_oclass = daos_oclass_name2id(o->dir_oclass);
479  if (dir_oclass == OC_UNKNOWN)
480  DERR("Invalid DAOS directory object class: %s\n", o->dir_oclass);
481  }
482  return;
483  }
484 
486  if (o->pool == NULL || o->cont == NULL) {
487  dfs_init_count--;
488  return;
489  }
490 
491  pool_connect = cont_create = cont_open = dfs_mounted = false;
492 
493  rc = daos_init();
494  DCHECK(rc, "Failed to initialize daos");
495 
496  if (o->oclass) {
497  objectClass = daos_oclass_name2id(o->oclass);
498  if (objectClass == OC_UNKNOWN)
499  DERR("Invalid DAOS object class: %s\n", o->oclass);
500  }
501 
502  if (o->dir_oclass) {
503  dir_oclass = daos_oclass_name2id(o->dir_oclass);
504  if (dir_oclass == OC_UNKNOWN)
505  DERR("Invalid DAOS directory object class: %s\n", o->dir_oclass);
506  }
507 
508  rc = d_hash_table_create(D_HASH_FT_EPHEMERAL | D_HASH_FT_NOLOCK | D_HASH_FT_LRU,
510  DCHECK(rc, "Failed to initialize dir hashtable");
511 
512  if (rank == 0) {
513  daos_pool_info_t pool_info;
514  daos_cont_info_t co_info;
515 
516  INFO(VERBOSE_1, "DFS Pool = %s", o->pool);
517  INFO(VERBOSE_1, "DFS Container = %s", o->cont);
518 
519 #if CHECK_DAOS_API_VERSION(1, 4)
520  rc = daos_pool_connect(o->pool, o->group, DAOS_PC_RW, &poh, &pool_info, NULL);
521  DCHECK(rc, "Failed to connect to pool %s", o->pool);
522  pool_connect = true;
523 
524  rc = daos_cont_open(poh, o->cont, DAOS_COO_RW, &coh, &co_info, NULL);
525 #else
526  uuid_t pool_uuid;
527 
528  rc = uuid_parse(o->pool, pool_uuid);
529  DCHECK(rc, "Failed to parse 'Pool uuid': %s", o->pool);
530  rc = uuid_parse(o->cont, co_uuid);
531  DCHECK(rc, "Failed to parse 'Cont uuid': %s", o->cont);
532 
533  rc = daos_pool_connect(pool_uuid, o->group, DAOS_PC_RW, &poh, &pool_info, NULL);
534  DCHECK(rc, "Failed to connect to pool %s", o->pool);
535  pool_connect = true;
536 
537  rc = daos_cont_open(poh, co_uuid, DAOS_COO_RW, &coh, &co_info, NULL);
538 #endif
539  /* If NOEXIST we create it */
540  if (rc == -DER_NONEXIST) {
541  INFO(VERBOSE_1, "Creating DFS Container ...\n");
542 #if CHECK_DAOS_API_VERSION(1, 4)
543  if (uuid_parse(o->cont, co_uuid) != 0)
545  rc = dfs_cont_create_with_label(poh, o->cont, NULL, &co_uuid, &coh, NULL);
546  else
548 #endif
549  rc = dfs_cont_create(poh, co_uuid, NULL, &coh, NULL);
550  if (rc)
551  DCHECK(rc, "Failed to create container");
552  cont_create = true;
553  } else if (rc) {
554  DCHECK(rc, "Failed to create container");
555  }
556  cont_open = true;
557 
558  rc = dfs_mount(poh, coh, O_RDWR, &dfs);
559  DCHECK(rc, "Failed to mount DFS namespace");
560  dfs_mounted = true;
561  }
562 
564  pool_connect = true;
566  cont_open = true;
568  dfs_mounted = true;
569 
570  if (o->prefix) {
571  rc = dfs_set_prefix(dfs, o->prefix);
572  DCHECK(rc, "Failed to set DFS Prefix");
573  }
574 
575 out:
576  if (rc) {
577  if (dfs_mounted)
578  dfs_umount(dfs);
579  if (cont_open)
580  daos_cont_close(coh, NULL);
581  if (cont_create && rank == 0) {
582 #if CHECK_DAOS_API_VERSION(1, 4)
583  daos_cont_destroy(poh, o->cont, 1, NULL);
584 #else
585  daos_cont_destroy(poh, co_uuid, 1, NULL);
586 #endif
587  }
588  if (pool_connect)
589  daos_pool_disconnect(poh, NULL);
590  if (aiori_dfs_hash)
591  d_hash_table_destroy(aiori_dfs_hash, false);
592  daos_fini();
593  dfs_init_count--;
594  ERR("Failed to initialize DAOS DFS driver");
595  }
596 }
597 
598 static void
600 {
601  DFS_options_t *o = (DFS_options_t *)options;
602  int rc;
603 
604  objectClass = 0;
605  dir_oclass = 0;
606 
607  dfs_init_count --;
608  if (dfs_init_count != 0)
609  return;
610 
611  MPI_Barrier(testComm);
612 
613  while (1) {
614  d_list_t *rlink = NULL;
615 
616  rlink = d_hash_rec_first(aiori_dfs_hash);
617  if (rlink == NULL)
618  break;
619  d_hash_rec_decref(aiori_dfs_hash, rlink);
620  }
621 
622  rc = d_hash_table_destroy(aiori_dfs_hash, false);
623  DCHECK(rc, "Failed to destroy DFS hash");
624  MPI_Barrier(testComm);
625 
626  rc = dfs_umount(dfs);
627  DCHECK(rc, "Failed to umount DFS namespace");
628  MPI_Barrier(testComm);
629 
630  rc = daos_cont_close(coh, NULL);
631  DCHECK(rc, "Failed to close container %s (%d)", o->cont, rc);
632  MPI_Barrier(testComm);
633 
634  if (o->destroy) {
635  if (rank == 0) {
636  INFO(VERBOSE_1, "Destroying DFS Container: %s", o->cont);
637 #if CHECK_DAOS_API_VERSION(1, 4)
638  daos_cont_destroy(poh, o->cont, 1, NULL);
639 #else
640  uuid_t uuid;
641  uuid_parse(o->cont, uuid);
642  rc = daos_cont_destroy(poh, uuid, 1, NULL);
643 #endif
644  DCHECK(rc, "Failed to destroy container %s", o->cont);
645  }
646 
647  MPI_Bcast(&rc, 1, MPI_INT, 0, testComm);
648  if (rc) {
649  if (rank == 0)
650  DCHECK(rc, "Failed to destroy container %s (%d)", o->cont, rc);
651  }
652  }
653 
654  if (rank == 0)
655  INFO(VERBOSE_1, "Disconnecting from DAOS POOL");
656 
657  rc = daos_pool_disconnect(poh, NULL);
658  DCHECK(rc, "Failed to disconnect from pool");
659 
660  MPI_CHECK(MPI_Barrier(testComm), "barrier error");
661 
662  if (rank == 0)
663  INFO(VERBOSE_1, "Finalizing DAOS..");
664 
665  rc = daos_fini();
666  DCHECK(rc, "Failed to finalize DAOS");
667 
668 out:
670  o->pool = NULL;
671  o->group = NULL;
672  o->cont = NULL;
673  o->chunk_size = 0;
674  o->oclass = NULL;
675  o->dir_oclass = NULL;
676  o->prefix = NULL;
677  o->destroy = 0;
678 }
679 
680 /*
681  * Create and open a file through the DFS interface.
682  */
683 static aiori_fd_t *
684 DFS_Create(char *testFileName, int flags, aiori_mod_opt_t *param)
685 {
686  DFS_options_t *o = (DFS_options_t*) param;
687  char *name = NULL, *dir_name = NULL;
688  dfs_obj_t *obj = NULL, *parent = NULL;
689  mode_t mode = 0664;
690  int fd_oflag = 0;
691  int rc;
692 
693  rc = parse_filename(testFileName, &name, &dir_name);
694  DCHECK(rc, "Failed to parse path %s", testFileName);
695  assert(dir_name);
696  assert(name);
697 
698  mode = S_IFREG | mode;
699  if (hints->filePerProc || rank == 0) {
700  fd_oflag |= O_CREAT | O_RDWR | O_EXCL;
701 
702  parent = lookup_insert_dir(dir_name, NULL);
703  if (parent == NULL)
704  DERR("Failed to lookup parent: %s", dir_name);
705 
706  rc = dfs_open(dfs, parent, name, mode, fd_oflag,
707  objectClass, o->chunk_size, NULL, &obj);
708  DCHECK(rc, "dfs_open() of %s Failed", name);
709  }
710 
711  if (!hints->filePerProc) {
712  rc = share_file_handle(&obj, testComm);
713  DCHECK(rc, "global open of %s Failed", name);
714  }
715 
716 out:
717  if (name)
718  free(name);
719  if (dir_name)
720  free(dir_name);
721  return (aiori_fd_t *)(obj);
722 }
723 
724 /*
725  * Open a file through the DFS interface.
726  */
727 static aiori_fd_t *
728 DFS_Open(char *testFileName, int flags, aiori_mod_opt_t *param)
729 {
730  DFS_options_t *o = (DFS_options_t*) param;
731  char *name = NULL, *dir_name = NULL;
732  dfs_obj_t *obj = NULL, *parent = NULL;
733  mode_t mode = 0664;
734  int fd_oflag = 0;
735  int rc;
736 
737  fd_oflag |= O_RDWR;
738  mode = S_IFREG | flags;
739 
740  rc = parse_filename(testFileName, &name, &dir_name);
741  DCHECK(rc, "Failed to parse path %s", testFileName);
742  assert(dir_name);
743  assert(name);
744 
745  if (hints->filePerProc || rank == 0) {
746  parent = lookup_insert_dir(dir_name, NULL);
747  if (parent == NULL)
748  DERR("Failed to lookup parent: %s", dir_name);
749 
750  rc = dfs_open(dfs, parent, name, mode, fd_oflag, objectClass,
751  o->chunk_size, NULL, &obj);
752  DCHECK(rc, "dfs_open() of %s Failed", name);
753  }
754 
755  if (!hints->filePerProc) {
756  rc = share_file_handle(&obj, testComm);
757  DCHECK(rc, "global open of %s Failed", name);
758  }
759 
760 out:
761  if (name)
762  free(name);
763  if (dir_name)
764  free(dir_name);
765 
766  return (aiori_fd_t *)(obj);
767 }
768 
769 /*
770  * Write or read access to file using the DFS interface.
771  */
772 static IOR_offset_t
773 DFS_Xfer(int access, aiori_fd_t *file, IOR_size_t *buffer, IOR_offset_t length,
774  IOR_offset_t off, aiori_mod_opt_t *param)
775 {
776  int xferRetries = 0;
777  long long remaining = (long long)length;
778  char *ptr = (char *)buffer;
779  daos_size_t ret;
780  int rc;
781  dfs_obj_t *obj;
782 
783  obj = (dfs_obj_t *)file;
784 
785  while (remaining > 0) {
786  d_iov_t iov;
787  d_sg_list_t sgl;
788 
790  sgl.sg_nr = 1;
791  sgl.sg_nr_out = 0;
792  d_iov_set(&iov, (void *)ptr, remaining);
793  sgl.sg_iovs = &iov;
794 
795  /* write/read file */
796  if (access == WRITE) {
797  rc = dfs_write(dfs, obj, &sgl, off, NULL);
798  if (rc)
799  ERRF("dfs_write(%p, %lld) failed (%d): %s\n",
800  (void*)ptr, remaining, rc, strerror(rc));
801  ret = remaining;
802  } else {
803  rc = dfs_read(dfs, obj, &sgl, off, &ret, NULL);
804  if (rc)
805  ERRF("dfs_read(%p, %lld) failed (%d): %s\n",
806  (void*)ptr, remaining, rc, strerror(rc));
807  if (ret == 0)
808  ERRF("dfs_read(%p, %lld) returned EOF prematurely",
809  (void*)ptr, remaining);
810  }
811 
812  if (ret < remaining) {
813  if (hints->singleXferAttempt == TRUE)
814  exit(EXIT_FAILURE);
815  if (xferRetries > MAX_RETRY)
816  ERR("too many retries -- aborting");
817  }
818 
819  assert(ret >= 0);
820  assert(ret <= remaining);
821  remaining -= ret;
822  ptr += ret;
823  xferRetries++;
824  }
825 
826  return (length);
827 }
828 
829 /*
830  * Perform fsync().
831  */
832 static void
834 {
835  /* no cache in DFS, so this is a no-op currently */
836  dfs_sync(dfs);
837  return;
838 }
839 
840 /*
841  * Perform sync() on the dfs mount.
842  */
843 static void
845 {
846  /* no cache in DFS, so this is a no-op currently */
847  dfs_sync(dfs);
848  return;
849 }
850 
851 /*
852  * Close a file through the DFS interface.
853  */
854 static void
856 {
857  dfs_release((dfs_obj_t *)fd);
858 }
859 
860 /*
861  * Delete a file through the DFS interface.
862  */
863 static void
864 DFS_Delete(char *testFileName, aiori_mod_opt_t * param)
865 {
866  char *name = NULL, *dir_name = NULL;
867  dfs_obj_t *parent = NULL;
868  int rc;
869 
870  rc = parse_filename(testFileName, &name, &dir_name);
871  DCHECK(rc, "Failed to parse path %s", testFileName);
872 
873  assert(dir_name);
874  assert(name);
875 
876  parent = lookup_insert_dir(dir_name, NULL);
877  if (parent == NULL)
878  DERR("Failed to lookup parent: %s", dir_name);
879 
880  rc = dfs_remove(dfs, parent, name, false, NULL);
881  DCHECK(rc, "Failed to remove path %s", testFileName);
882 out:
883  if (name)
884  free(name);
885  if (dir_name)
886  free(dir_name);
887 }
888 
889 static char* DFS_GetVersion()
890 {
891  static char ver[1024] = {};
892 
893  sprintf(ver, "%s", "DAOS");
894  return ver;
895 }
896 
897 /*
898  * Use DFS stat() to return aggregate file size.
899  */
900 static IOR_offset_t
901 DFS_GetFileSize(aiori_mod_opt_t * test, char *testFileName)
902 {
903  dfs_obj_t *obj;
904  MPI_Comm comm;
905  daos_size_t fsize;
906  int rc;
907 
908  if (hints->filePerProc == TRUE) {
909  comm = MPI_COMM_SELF;
910  } else {
911  comm = testComm;
912  }
913 
914  if (hints->filePerProc || rank == 0) {
915  rc = dfs_lookup(dfs, testFileName, O_RDONLY, &obj, NULL, NULL);
916  if (rc) {
917  fprintf(stderr, "dfs_lookup() of %s Failed (%d)", testFileName, rc);
918  return -1;
919  }
920 
921  rc = dfs_get_size(dfs, obj, &fsize);
922  dfs_release(obj);
923  if (rc)
924  return -1;
925  }
926 
927  if (!hints->filePerProc) {
928  rc = MPI_Bcast(&fsize, 1, MPI_UINT64_T, 0, comm);
929  if (rc)
930  return rc;
931  }
932 
933  return (fsize);
934 }
935 
936 static int
937 DFS_Statfs(const char *path, ior_aiori_statfs_t *sfs, aiori_mod_opt_t * param)
938 {
939  daos_pool_info_t info = {.pi_bits = DPI_SPACE};
940  int rc;
941 
942  rc = daos_pool_query(poh, NULL, &info, NULL, NULL);
943  DCHECK(rc, "Failed to query pool");
944 
945  sfs->f_blocks = info.pi_space.ps_space.s_total[DAOS_MEDIA_SCM]
946  + info.pi_space.ps_space.s_total[DAOS_MEDIA_NVME];
947  sfs->f_bfree = info.pi_space.ps_space.s_free[DAOS_MEDIA_SCM]
948  + info.pi_space.ps_space.s_free[DAOS_MEDIA_NVME];
949  sfs->f_bsize = 1;
950  sfs->f_files = -1;
951  sfs->f_ffree = -1;
952  sfs->f_bavail = sfs->f_bfree;
953 
954 out:
955  if (rc)
956  rc = -1;
957  return rc;
958 }
959 
960 static int
961 DFS_Mkdir(const char *path, mode_t mode, aiori_mod_opt_t * param)
962 {
963  dfs_obj_t *parent = NULL;
964  char *name = NULL, *dir_name = NULL;
965  int rc;
966 
967  rc = parse_filename(path, &name, &dir_name);
968  DCHECK(rc, "Failed to parse path %s", path);
969 
970  assert(dir_name);
971  if (!name)
972  return 0;
973 
974  parent = lookup_insert_dir(dir_name, NULL);
975  if (parent == NULL)
976  DERR("Failed to lookup parent: %s", dir_name);
977 
978  rc = dfs_mkdir(dfs, parent, name, mode, dir_oclass);
979 
980 out:
981  if (name)
982  free(name);
983  if (dir_name)
984  free(dir_name);
985  if (rc)
986  rc = -1;
987  return rc;
988 }
989 
990 static int
991 DFS_Rename(const char *oldfile, const char *newfile, aiori_mod_opt_t * param)
992 {
993  dfs_obj_t *old_parent = NULL, *new_parent = NULL;
994  char *old_name = NULL, *old_dir_name = NULL;
995  char *new_name = NULL, *new_dir_name = NULL;
996  int rc;
997 
998  rc = parse_filename(oldfile, &old_name, &old_dir_name);
999  DCHECK(rc, "Failed to parse path %s", oldfile);
1000  assert(old_dir_name);
1001  assert(old_name);
1002 
1003  rc = parse_filename(newfile, &new_name, &new_dir_name);
1004  DCHECK(rc, "Failed to parse path %s", newfile);
1005  assert(new_dir_name);
1006  assert(new_name);
1007 
1008  old_parent = lookup_insert_dir(old_dir_name, NULL);
1009  if (old_parent == NULL)
1010  DERR("Failed to lookup parent: %s", old_dir_name);
1011 
1012  new_parent = lookup_insert_dir(new_dir_name, NULL);
1013  if (new_parent == NULL)
1014  DERR("Failed to lookup parent: %s", new_dir_name);
1015 
1016  rc = dfs_move(dfs, old_parent, old_name, new_parent, new_name, NULL);
1017 
1018 out:
1019  if (old_name)
1020  free(old_name);
1021  if (old_dir_name)
1022  free(old_dir_name);
1023  if (new_name)
1024  free(new_name);
1025  if (new_dir_name)
1026  free(new_dir_name);
1027  if (rc)
1028  return -1;
1029  return rc;
1030 }
1031 
1032 static int
1033 DFS_Rmdir(const char *path, aiori_mod_opt_t * param)
1034 {
1035  dfs_obj_t *parent = NULL;
1036  char *name = NULL, *dir_name = NULL;
1037  int rc;
1038 
1039  rc = parse_filename(path, &name, &dir_name);
1040  DCHECK(rc, "Failed to parse path %s", path);
1041 
1042  assert(dir_name);
1043  assert(name);
1044 
1045  parent = lookup_insert_dir(dir_name, NULL);
1046  if (parent == NULL)
1047  DERR("Failed to lookup parent: %s", dir_name);
1048 
1049  rc = dfs_remove(dfs, parent, name, false, NULL);
1050 
1051 out:
1052  if (name)
1053  free(name);
1054  if (dir_name)
1055  free(dir_name);
1056  if (rc)
1057  return -1;
1058  return rc;
1059 }
1060 
1061 static int
1062 DFS_Access(const char *path, int mode, aiori_mod_opt_t * param)
1063 {
1064  dfs_obj_t *parent = NULL;
1065  dfs_obj_t *obj = NULL;
1066  char *name = NULL, *dir_name = NULL;
1067  int rc;
1068 
1069  rc = parse_filename(path, &name, &dir_name);
1070  DCHECK(rc, "Failed to parse path %s", path);
1071 
1072  assert(dir_name);
1073  assert(name);
1074 
1075  parent = lookup_insert_dir(dir_name, NULL);
1076  if (parent == NULL)
1077  DERR("Failed to lookup parent: %s", dir_name);
1078 
1079  if (strcmp(name, "/") == 0) {
1080  free(name);
1081  name = NULL;
1082  }
1083 
1084  rc = dfs_access(dfs, parent, name, mode);
1085 
1086 out:
1087  if (name)
1088  free(name);
1089  if (dir_name)
1090  free(dir_name);
1091  if (rc)
1092  return -1;
1093  return rc;
1094 }
1095 
1096 static int
1097 DFS_Stat(const char *path, struct stat *buf, aiori_mod_opt_t * param)
1098 {
1099  dfs_obj_t *parent = NULL;
1100  char *name = NULL, *dir_name = NULL;
1101  int rc;
1102 
1103  rc = parse_filename(path, &name, &dir_name);
1104  DCHECK(rc, "Failed to parse path %s", path);
1105 
1106  assert(dir_name);
1107  assert(name);
1108 
1109  parent = lookup_insert_dir(dir_name, NULL);
1110  if (parent == NULL)
1111  DERR("Failed to lookup parent: %s", dir_name);
1112 
1113  rc = dfs_stat(dfs, parent, name, buf);
1114 
1115 out:
1116  if (name)
1117  free(name);
1118  if (dir_name)
1119  free(dir_name);
1120  if (rc)
1121  return -1;
1122  return rc;
1123 }
static void rec_free(struct d_hash_table *htable, d_list_t *rlink)
Definition: aiori-DFS.c:224
#define ERRF(FORMAT,...)
Definition: aiori-debug.h:67
uint64_t f_blocks
Definition: aiori.h:53
handleType
Definition: aiori-DFS.c:61
uint64_t f_bfree
Definition: aiori.h:54
static struct aiori_dir_hdl * hdl_obj(d_list_t *rlink)
Definition: aiori-DFS.c:209
#define LAST_OPTION
Definition: option.h:39
CURLcode rc
Definition: aiori-S3-4c.c:111
int errno
#define DCHECK(rc, format,...)
Definition: aiori-DFS.c:162
struct benchmark_options o
Definition: md-workbench.c:133
static daos_handle_t coh
Definition: aiori-DFS.c:49
dfs_obj_t * oh
Definition: aiori-DFS.c:57
static dfs_t * dfs
Definition: aiori-DFS.c:48
#define DERR(format,...)
Definition: aiori-DFS.c:181
static bool rec_decref(struct d_hash_table *htable, d_list_t *rlink)
Definition: aiori-DFS.c:233
static struct d_hash_table * aiori_dfs_hash
Definition: aiori-DFS.c:52
static int parse_filename(const char *path, char **_obj_name, char **_cont_name)
Definition: aiori-DFS.c:314
uint64_t f_ffree
Definition: aiori.h:57
static d_hash_table_ops_t hdl_hash_ops
Definition: aiori-DFS.c:246
static IOR_offset_t DFS_Xfer(int, aiori_fd_t *, IOR_size_t *, IOR_offset_t, IOR_offset_t, aiori_mod_opt_t *)
Definition: aiori-DFS.c:773
static aiori_fd_t * DFS_Create(char *, int, aiori_mod_opt_t *)
Definition: aiori-DFS.c:684
#define MPI_CHECK(MPI_STATUS, MSG)
Definition: aiori-debug.h:97
#define WRITE
Definition: iordef.h:100
static int DFS_Access(const char *, int, aiori_mod_opt_t *)
Definition: aiori-DFS.c:1062
static void DFS_Finalize(aiori_mod_opt_t *)
Definition: aiori-DFS.c:599
char * dir_oclass
Definition: aiori-DFS.c:74
#define INFO(level, format,...)
Definition: aiori-DFS.c:175
static aiori_xfer_hint_t * hints
Definition: aiori-DFS.c:189
uint64_t f_files
Definition: aiori.h:56
MPI_Comm testComm
Definition: utilities.c:73
static option_help options[]
Definition: aiori-CEPHFS.c:59
uint64_t f_bsize
Definition: aiori.h:52
static int DFS_Rename(const char *, const char *, aiori_mod_opt_t *)
Definition: aiori-DFS.c:991
#define PATH_MAX
Definition: iordef.h:117
static void DFS_Sync(aiori_mod_opt_t *)
Definition: aiori-DFS.c:844
static daos_oclass_id_t dir_oclass
Definition: aiori-DFS.c:51
static IOR_offset_t DFS_GetFileSize(aiori_mod_opt_t *, char *)
Definition: aiori-DFS.c:901
int singleXferAttempt
Definition: aiori.h:75
static int DFS_Mkdir(const char *, mode_t, aiori_mod_opt_t *)
Definition: aiori-DFS.c:961
static void DFS_init_xfer_options(aiori_xfer_hint_t *)
Definition: aiori-DFS.c:191
#define MAX_RETRY
Definition: iordef.h:115
static option_help * DFS_options(aiori_mod_opt_t **init_backend_options, aiori_mod_opt_t *init_values)
Definition: aiori-DFS.c:79
static daos_handle_t poh
Definition: aiori-DFS.c:49
char * pool
Definition: aiori-DFS.c:69
static void DFS_Delete(char *, aiori_mod_opt_t *)
Definition: aiori-DFS.c:864
static daos_oclass_id_t objectClass
Definition: aiori-DFS.c:50
static uint32_t rec_hash(struct d_hash_table *htable, d_list_t *rlink)
Definition: aiori-DFS.c:239
char * oclass
Definition: aiori-DFS.c:73
ior_aiori_t dfs_aiori
Definition: aiori-DFS.c:134
long long int IOR_size_t
Definition: iordef.h:124
static char * DFS_GetVersion()
Definition: aiori-DFS.c:889
static void DFS_Close(aiori_fd_t *, aiori_mod_opt_t *)
Definition: aiori-DFS.c:855
uint64_t f_bavail
Definition: aiori.h:55
static int DFS_Statfs(const char *, ior_aiori_statfs_t *, aiori_mod_opt_t *)
Definition: aiori-DFS.c:937
static dfs_obj_t * lookup_insert_dir(const char *name, mode_t *mode)
Definition: aiori-DFS.c:421
static int HandleDistribute(enum handleType type)
Definition: aiori-DFS.c:255
static int DFS_Stat(const char *, struct stat *, aiori_mod_opt_t *)
Definition: aiori-DFS.c:1097
char * prefix
Definition: aiori-DFS.c:75
static void DFS_Fsync(aiori_fd_t *, aiori_mod_opt_t *)
Definition: aiori-DFS.c:833
int chunk_size
Definition: aiori-DFS.c:72
d_list_t entry
Definition: aiori-DFS.c:56
static void DFS_Init(aiori_mod_opt_t *)
Definition: aiori-DFS.c:461
#define ERR(MSG)
Definition: aiori-debug.h:75
char name[PATH_MAX]
Definition: aiori-DFS.c:58
#define VERBOSE_1
Definition: iordef.h:107
static aiori_fd_t * DFS_Open(char *, int, aiori_mod_opt_t *)
Definition: aiori-DFS.c:728
static int share_file_handle(dfs_obj_t **file, MPI_Comm comm)
Definition: aiori-DFS.c:379
char * name
Definition: aiori.h:88
int filePerProc
Definition: aiori.h:65
static int dfs_init_count
Definition: aiori-DFS.c:53
long long int IOR_offset_t
Definition: iordef.h:123
char * group
Definition: aiori-DFS.c:70
static int DFS_Rmdir(const char *, aiori_mod_opt_t *)
Definition: aiori-DFS.c:1033
int rank
Definition: utilities.c:70
#define TRUE
Definition: iordef.h:80
static bool key_cmp(struct d_hash_table *htable, d_list_t *rlink, const void *key, unsigned int ksize)
Definition: aiori-DFS.c:215
static int DFS_check_params(aiori_mod_opt_t *)
Definition: aiori-DFS.c:196
char * cont
Definition: aiori-DFS.c:71
#define NULL
Definition: iordef.h:84