diff options
-rw-r--r-- | release_docs/RELEASE.txt | 25 | ||||
-rw-r--r-- | src/H5FD.c | 105 | ||||
-rw-r--r-- | src/H5FDcore.c | 1 | ||||
-rw-r--r-- | src/H5FDdevelop.h | 2 | ||||
-rw-r--r-- | src/H5FDdirect.c | 1 | ||||
-rw-r--r-- | src/H5FDfamily.c | 1 | ||||
-rw-r--r-- | src/H5FDhdfs.c | 1 | ||||
-rw-r--r-- | src/H5FDlog.c | 1 | ||||
-rw-r--r-- | src/H5FDmirror.c | 1 | ||||
-rw-r--r-- | src/H5FDmpi.c | 90 | ||||
-rw-r--r-- | src/H5FDmpio.c | 223 | ||||
-rw-r--r-- | src/H5FDmulti.c | 51 | ||||
-rw-r--r-- | src/H5FDprivate.h | 14 | ||||
-rw-r--r-- | src/H5FDpublic.h | 71 | ||||
-rw-r--r-- | src/H5FDros3.c | 1 | ||||
-rw-r--r-- | src/H5FDsec2.c | 48 | ||||
-rw-r--r-- | src/H5FDsplitter.c | 60 | ||||
-rw-r--r-- | src/H5FDstdio.c | 1 | ||||
-rw-r--r-- | test/h5test.c | 1 | ||||
-rw-r--r-- | test/vfd.c | 544 |
20 files changed, 1082 insertions, 160 deletions
diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index ed12c5e..6043145 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -471,6 +471,31 @@ New Features Library: -------- + - Adds new "ctl" callback to VFD H5FD_class_t structure + with the following prototype: + + herr_t (*ctl)(H5FD_t *file, uint64_t op_code, + uint64_t flags, const void *input, + void **output); + + This newly-added "ctl" callback allows Virtual File + Drivers to intercept and handle arbitary operations + identified by an operation code. Its parameters are + as follows: + + `file` [in] - A pointer to the file to be operated on + `op_code` [in] - The operation code identifying the + operation to be performed + `flags` [in] - Flags governing the behavior of the + operation performed (see H5FDpublic.h + for a list of valid flags) + `input` [in] - A pointer to arguments passed to the + VFD performing the operation + `output` [out] - A pointer for the receiving VFD to + use for output from the operation + + (JRM - 2021/08/16) + - Change how the release part of version, in major.minor.release is checked for compatibility @@ -1688,6 +1688,111 @@ done: } /* end H5FD_unlock() */ /*------------------------------------------------------------------------- + * Function: H5FDctl + * + * Purpose: Perform a CTL operation. + * + * The desired operation is specified by the op_code + * parameter. + * + * The flags parameter controls management of op_codes that + * are unknown to the callback + * + * The input and output parameters allow op_code specific + * input and output + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: JRM -- 8/3/21 + * + *------------------------------------------------------------------------- + */ +herr_t +H5FDctl(H5FD_t *file, uint64_t op_code, uint64_t flags, const void *input, void **output) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE5("e", "*#ULUL*x**x", file, op_code, flags, input, output); + + /* Check arguments */ + if (!file) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file pointer cannot be NULL") + + if (!file->cls) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file class pointer cannot be NULL") + + /* Don't attempt to validate the op code. If appropriate, that will + * be done by the underlying VFD callback, along with the input and + * output parameters. + */ + + /* Call private function */ + if (H5FD_ctl(file, op_code, flags, input, output) < 0) + HGOTO_ERROR(H5E_VFL, H5E_FCNTL, FAIL, "VFD ctl request failed") + +done: + + FUNC_LEAVE_API(ret_value) + +} /* end H5FDctl() */ + +/*------------------------------------------------------------------------- + * Function: H5FD_ctl + * + * Purpose: Private version of H5FDctl() + * + * The desired operation is specified by the op_code + * parameter. + * + * The flags parameter controls management of op_codes that + * are unknown to the callback + * + * The input and output parameters allow op_code specific + * input and output + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: JRM -- 8/3/21 + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_ctl(H5FD_t *file, uint64_t op_code, uint64_t flags, const void *input, void **output) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity checks */ + HDassert(file); + HDassert(file->cls); + + /* Dispatch to driver if the ctl function exists. + * + * If it doesn't, fail if the H5FD_CTL__FAIL_IF_UNKNOWN_FLAG is set. + * + * Otherwise, report success. + */ + if (file->cls->ctl) { + + if ((file->cls->ctl)(file, op_code, flags, input, output) < 0) + + HGOTO_ERROR(H5E_VFL, H5E_FCNTL, FAIL, "VFD ctl request failed") + } + else if (flags & H5FD_CTL__FAIL_IF_UNKNOWN_FLAG) { + + HGOTO_ERROR(H5E_VFL, H5E_FCNTL, FAIL, + "VFD ctl request failed (no ctl callback and fail if unknown flag is set)") + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) + +} /* end H5FD_ctl() */ + +/*------------------------------------------------------------------------- * Function: H5FD_get_fileno * * Purpose: Quick and dirty routine to retrieve the file's 'fileno' value diff --git a/src/H5FDcore.c b/src/H5FDcore.c index 50288c4..820c74f 100644 --- a/src/H5FDcore.c +++ b/src/H5FDcore.c @@ -183,6 +183,7 @@ static const H5FD_class_t H5FD_core_g = { H5FD__core_lock, /* lock */ H5FD__core_unlock, /* unlock */ H5FD__core_delete, /* del */ + NULL, /* ctl */ H5FD_FLMAP_DICHOTOMY /* fl_map */ }; diff --git a/src/H5FDdevelop.h b/src/H5FDdevelop.h index 57f0a42..4895658 100644 --- a/src/H5FDdevelop.h +++ b/src/H5FDdevelop.h @@ -192,6 +192,7 @@ typedef struct H5FD_class_t { herr_t (*lock)(H5FD_t *file, hbool_t rw); herr_t (*unlock)(H5FD_t *file); herr_t (*del)(const char *name, hid_t fapl); + herr_t (*ctl)(H5FD_t *file, uint64_t op_code, uint64_t flags, const void *input, void **output); H5FD_mem_t fl_map[H5FD_MEM_NTYPES]; } H5FD_class_t; @@ -254,6 +255,7 @@ H5_DLL herr_t H5FDtruncate(H5FD_t *file, hid_t dxpl_id, hbool_t closing); H5_DLL herr_t H5FDlock(H5FD_t *file, hbool_t rw); H5_DLL herr_t H5FDunlock(H5FD_t *file); H5_DLL herr_t H5FDdelete(const char *name, hid_t fapl_id); +H5_DLL herr_t H5FDctl(H5FD_t *file, uint64_t op_code, uint64_t flags, const void *input, void **output); #ifdef __cplusplus } diff --git a/src/H5FDdirect.c b/src/H5FDdirect.c index a1b7b7e..7cca09f 100644 --- a/src/H5FDdirect.c +++ b/src/H5FDdirect.c @@ -172,6 +172,7 @@ static const H5FD_class_t H5FD_direct_g = { H5FD__direct_lock, /* lock */ H5FD__direct_unlock, /* unlock */ H5FD__direct_delete, /* del */ + NULL, /* ctl */ H5FD_FLMAP_DICHOTOMY /* fl_map */ }; diff --git a/src/H5FDfamily.c b/src/H5FDfamily.c index 8cf9f9e..af67c78 100644 --- a/src/H5FDfamily.c +++ b/src/H5FDfamily.c @@ -137,6 +137,7 @@ static const H5FD_class_t H5FD_family_g = { H5FD__family_lock, /* lock */ H5FD__family_unlock, /* unlock */ H5FD__family_delete, /* del */ + NULL, /* ctl */ H5FD_FLMAP_DICHOTOMY /* fl_map */ }; diff --git a/src/H5FDhdfs.c b/src/H5FDhdfs.c index 2c4bff6..ac48b42 100644 --- a/src/H5FDhdfs.c +++ b/src/H5FDhdfs.c @@ -310,6 +310,7 @@ static const H5FD_class_t H5FD_hdfs_g = { NULL, /* lock */ NULL, /* unlock */ NULL, /* del */ + NULL, /* ctl */ H5FD_FLMAP_DICHOTOMY /* fl_map */ }; diff --git a/src/H5FDlog.c b/src/H5FDlog.c index f996b9e..87871ab 100644 --- a/src/H5FDlog.c +++ b/src/H5FDlog.c @@ -212,6 +212,7 @@ static const H5FD_class_t H5FD_log_g = { H5FD__log_lock, /* lock */ H5FD__log_unlock, /* unlock */ H5FD__log_delete, /* del */ + NULL, /* ctl */ H5FD_FLMAP_DICHOTOMY /* fl_map */ }; diff --git a/src/H5FDmirror.c b/src/H5FDmirror.c index 8cbeff6..d539f4d 100644 --- a/src/H5FDmirror.c +++ b/src/H5FDmirror.c @@ -192,6 +192,7 @@ static const H5FD_class_t H5FD_mirror_g = { H5FD__mirror_lock, /* lock */ H5FD__mirror_unlock, /* unlock */ NULL, /* del */ + NULL, /* ctl */ H5FD_FLMAP_DICHOTOMY /* fl_map */ }; diff --git a/src/H5FDmpi.c b/src/H5FDmpi.c index 048b8f3..7eb1463 100644 --- a/src/H5FDmpi.c +++ b/src/H5FDmpi.c @@ -41,26 +41,42 @@ * Programmer: Quincey Koziol * Friday, January 30, 2004 * + * Changes: Reworked function to use the ctl callback so we can get + * rid of H5FD_class_mpi_t. Since there are no real limits + * on what the ctl callback can do, its file parameter can't + * be constant. Thus, I had to remove the const qualifier + * on this functions file parameter as well. Note also the + * circumlocution required to use the ctl callbacks output + * parameter to pass back the rank without introducing + * compiler warnings. + * JRM -- 8/13/21 + * *------------------------------------------------------------------------- */ int -H5FD_mpi_get_rank(const H5FD_t *file) +H5FD_mpi_get_rank(H5FD_t *file) { - const H5FD_class_mpi_t *cls; - - int ret_value; + const H5FD_class_t *cls; + uint64_t flags = H5FD_CTL__FAIL_IF_UNKNOWN_FLAG | H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG; + int rank = -1; + void * rank_ptr = (void *)(&rank); + int ret_value; FUNC_ENTER_NOAPI(FAIL) HDassert(file); - cls = (const H5FD_class_mpi_t *)(file->cls); + cls = (const H5FD_class_t *)(file->cls); HDassert(cls); - HDassert(cls->get_rank); /* All MPI drivers must implement this */ + HDassert(cls->ctl); /* All MPI drivers must implement this */ /* Dispatch to driver */ - if ((ret_value = (cls->get_rank)(file)) < 0) + if ((cls->ctl)(file, H5FD_CTL__GET_MPI_RANK_OPCODE, flags, NULL, &rank_ptr) < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "driver get_rank request failed") + HDassert(rank >= 0); + + ret_value = rank; + done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD_mpi_get_rank() */ @@ -77,25 +93,43 @@ done: * Programmer: Quincey Koziol * Friday, January 30, 2004 * + * Changes: Reworked function to use the ctl callback so we can get + * rid of H5FD_class_mpi_t. Since there are no real limits + * on what the ctl callback can do, its file parameter can't + * be constant. Thus, I had to remove the const qualifier + * on this functions file parameter as well. Note also the + * circumlocution required to use the ctl callbacks output + * parameter to pass back the rank without introducing + * compiler warnings. + * JRM -- 8/13/21 + * *------------------------------------------------------------------------- */ int -H5FD_mpi_get_size(const H5FD_t *file) +H5FD_mpi_get_size(H5FD_t *file) { - const H5FD_class_mpi_t *cls; - int ret_value; + const H5FD_class_t *cls; + uint64_t flags = H5FD_CTL__FAIL_IF_UNKNOWN_FLAG | H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG; + int size = 0; + void * size_ptr = (void *)(&size); + int ret_value; FUNC_ENTER_NOAPI(FAIL) HDassert(file); - cls = (const H5FD_class_mpi_t *)(file->cls); + cls = (const H5FD_class_t *)(file->cls); HDassert(cls); - HDassert(cls->get_size); /* All MPI drivers must implement this */ + HDassert(cls->ctl); /* All MPI drivers must implement this */ /* Dispatch to driver */ - if ((ret_value = (cls->get_size)(file)) < 0) + if ((cls->ctl)(file, H5FD_CTL__GET_MPI_SIZE_OPCODE, flags, NULL, &size_ptr) < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "driver get_size request failed") + if (0 >= size) + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "driver get_size request returned bad value") + + ret_value = size; + done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD_mpi_get_size() */ @@ -112,25 +146,43 @@ done: * Programmer: Quincey Koziol * Friday, January 30, 2004 * + * Changes: Reworked function to use the ctl callback so we can get + * rid of H5FD_class_mpi_t. Since there are no real limits + * on what the ctl callback can do, its file parameter can't + * be constant. Thus, I had to remove the const qualifier + * on this functions file parameter as well. Note also the + * circumlocution required to use the ctl callbacks output + * parameter to pass back the rank without introducing + * compiler warnings. + * JRM -- 8/13/21 + * *------------------------------------------------------------------------- */ MPI_Comm -H5FD_mpi_get_comm(const H5FD_t *file) +H5FD_mpi_get_comm(H5FD_t *file) { - const H5FD_class_mpi_t *cls; - MPI_Comm ret_value; + const H5FD_class_t *cls; + uint64_t flags = H5FD_CTL__FAIL_IF_UNKNOWN_FLAG | H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG; + MPI_Comm comm = MPI_COMM_NULL; + void * comm_ptr = (void *)(&comm); + MPI_Comm ret_value; FUNC_ENTER_NOAPI(MPI_COMM_NULL) HDassert(file); - cls = (const H5FD_class_mpi_t *)(file->cls); + cls = (const H5FD_class_t *)(file->cls); HDassert(cls); - HDassert(cls->get_comm); /* All MPI drivers must implement this */ + HDassert(cls->ctl); /* All MPI drivers must implement this */ /* Dispatch to driver */ - if ((ret_value = (cls->get_comm)(file)) == MPI_COMM_NULL) + if ((cls->ctl)(file, H5FD_CTL__GET_MPI_COMMUNICATOR_OPCODE, flags, NULL, &comm_ptr) < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTGET, MPI_COMM_NULL, "driver get_comm request failed") + if (comm == MPI_COMM_NULL) + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, MPI_COMM_NULL, "driver get_comm request failed -- bad comm") + + ret_value = comm; + done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD_mpi_get_comm() */ diff --git a/src/H5FDmpio.c b/src/H5FDmpio.c index dd40399..7c85897 100644 --- a/src/H5FDmpio.c +++ b/src/H5FDmpio.c @@ -72,66 +72,60 @@ typedef struct H5FD_mpio_t { /* Private Prototypes */ /* Callbacks */ -static herr_t H5FD__mpio_term(void); -static H5FD_t * H5FD__mpio_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr); -static herr_t H5FD__mpio_close(H5FD_t *_file); -static herr_t H5FD__mpio_query(const H5FD_t *_f1, unsigned long *flags); -static haddr_t H5FD__mpio_get_eoa(const H5FD_t *_file, H5FD_mem_t type); -static herr_t H5FD__mpio_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr); -static haddr_t H5FD__mpio_get_eof(const H5FD_t *_file, H5FD_mem_t type); -static herr_t H5FD__mpio_get_handle(H5FD_t *_file, hid_t fapl, void **file_handle); -static herr_t H5FD__mpio_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size, - void *buf); -static herr_t H5FD__mpio_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size, - const void *buf); -static herr_t H5FD__mpio_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closing); -static herr_t H5FD__mpio_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing); -static herr_t H5FD__mpio_delete(const char *filename, hid_t fapl_id); -static int H5FD__mpio_mpi_rank(const H5FD_t *_file); -static int H5FD__mpio_mpi_size(const H5FD_t *_file); -static MPI_Comm H5FD__mpio_communicator(const H5FD_t *_file); +static herr_t H5FD__mpio_term(void); +static H5FD_t *H5FD__mpio_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr); +static herr_t H5FD__mpio_close(H5FD_t *_file); +static herr_t H5FD__mpio_query(const H5FD_t *_f1, unsigned long *flags); +static haddr_t H5FD__mpio_get_eoa(const H5FD_t *_file, H5FD_mem_t type); +static herr_t H5FD__mpio_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr); +static haddr_t H5FD__mpio_get_eof(const H5FD_t *_file, H5FD_mem_t type); +static herr_t H5FD__mpio_get_handle(H5FD_t *_file, hid_t fapl, void **file_handle); +static herr_t H5FD__mpio_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size, + void *buf); +static herr_t H5FD__mpio_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size, + const void *buf); +static herr_t H5FD__mpio_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closing); +static herr_t H5FD__mpio_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing); +static herr_t H5FD__mpio_delete(const char *filename, hid_t fapl_id); +static herr_t H5FD__mpio_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, const void *input, + void **output); /* The MPIO file driver information */ -static const H5FD_class_mpi_t H5FD_mpio_g = { - { - /* Start of superclass information */ - "mpio", /* name */ - HADDR_MAX, /* maxaddr */ - H5F_CLOSE_SEMI, /* fc_degree */ - H5FD__mpio_term, /* terminate */ - NULL, /* sb_size */ - NULL, /* sb_encode */ - NULL, /* sb_decode */ - 0, /* fapl_size */ - NULL, /* fapl_get */ - NULL, /* fapl_copy */ - NULL, /* fapl_free */ - 0, /* dxpl_size */ - NULL, /* dxpl_copy */ - NULL, /* dxpl_free */ - H5FD__mpio_open, /* open */ - H5FD__mpio_close, /* close */ - NULL, /* cmp */ - H5FD__mpio_query, /* query */ - NULL, /* get_type_map */ - NULL, /* alloc */ - NULL, /* free */ - H5FD__mpio_get_eoa, /* get_eoa */ - H5FD__mpio_set_eoa, /* set_eoa */ - H5FD__mpio_get_eof, /* get_eof */ - H5FD__mpio_get_handle, /* get_handle */ - H5FD__mpio_read, /* read */ - H5FD__mpio_write, /* write */ - H5FD__mpio_flush, /* flush */ - H5FD__mpio_truncate, /* truncate */ - NULL, /* lock */ - NULL, /* unlock */ - H5FD__mpio_delete, /* del */ - H5FD_FLMAP_DICHOTOMY /* fl_map */ - }, /* End of superclass information */ - H5FD__mpio_mpi_rank, /* get_rank */ - H5FD__mpio_mpi_size, /* get_size */ - H5FD__mpio_communicator /* get_comm */ +static const H5FD_class_t H5FD_mpio_g = { + "mpio", /* name */ + HADDR_MAX, /* maxaddr */ + H5F_CLOSE_SEMI, /* fc_degree */ + H5FD__mpio_term, /* terminate */ + NULL, /* sb_size */ + NULL, /* sb_encode */ + NULL, /* sb_decode */ + 0, /* fapl_size */ + NULL, /* fapl_get */ + NULL, /* fapl_copy */ + NULL, /* fapl_free */ + 0, /* dxpl_size */ + NULL, /* dxpl_copy */ + NULL, /* dxpl_free */ + H5FD__mpio_open, /* open */ + H5FD__mpio_close, /* close */ + NULL, /* cmp */ + H5FD__mpio_query, /* query */ + NULL, /* get_type_map */ + NULL, /* alloc */ + NULL, /* free */ + H5FD__mpio_get_eoa, /* get_eoa */ + H5FD__mpio_set_eoa, /* set_eoa */ + H5FD__mpio_get_eof, /* get_eof */ + H5FD__mpio_get_handle, /* get_handle */ + H5FD__mpio_read, /* read */ + H5FD__mpio_write, /* write */ + H5FD__mpio_flush, /* flush */ + H5FD__mpio_truncate, /* truncate */ + NULL, /* lock */ + NULL, /* unlock */ + H5FD__mpio_delete, /* del */ + H5FD__mpio_ctl, /* ctl */ + H5FD_FLMAP_DICHOTOMY /* fl_map */ }; #ifdef H5FDmpio_DEBUG @@ -245,7 +239,7 @@ H5FD_mpio_init(void) /* Register the MPI-IO VFD, if it isn't already */ if (H5I_VFL != H5I_get_type(H5FD_MPIO_g)) - H5FD_MPIO_g = H5FD_register((const H5FD_class_t *)&H5FD_mpio_g, sizeof(H5FD_class_mpi_t), FALSE); + H5FD_MPIO_g = H5FD_register((const H5FD_class_t *)&H5FD_mpio_g, sizeof(H5FD_class_t), FALSE); if (!H5FD_mpio_Debug_inited) { const char *s; /* String for environment variables */ @@ -1802,83 +1796,78 @@ done: } /* end H5FD__mpio_delete() */ /*------------------------------------------------------------------------- - * Function: H5FD__mpio_mpi_rank + * Function: H5FD__mpio_ctl * - * Purpose: Returns the MPI rank for a process + * Purpose: MPIO version of the ctl callback. * - * Return: Success: non-negative - * Failure: negative + * The desired operation is specified by the op_code + * parameter. * - * Programmer: Quincey Koziol - * Thursday, May 16, 2002 + * The flags parameter controls management of op_codes that + * are unknown to the callback * - *------------------------------------------------------------------------- - */ -static int -H5FD__mpio_mpi_rank(const H5FD_t *_file) -{ - const H5FD_mpio_t *file = (const H5FD_mpio_t *)_file; - - FUNC_ENTER_STATIC_NOERR - - /* Sanity checks */ - HDassert(file); - HDassert(H5FD_MPIO == file->pub.driver_id); - - FUNC_LEAVE_NOAPI(file->mpi_rank) -} /* end H5FD__mpio_mpi_rank() */ - -/*------------------------------------------------------------------------- - * Function: H5FD__mpio_mpi_size + * The input and output parameters allow op_code specific + * input and output * - * Purpose: Returns the number of MPI processes + * At present, the supported op codes are: * - * Return: Success: non-negative - * Failure: negative + * H5FD_CTL__GET_MPI_COMMUNICATOR_OPCODE + * H5FD_CTL__GET_MPI_RANK_OPCODE + * H5FD_CTL__GET_MPI_SIZE_OPCODE * - * Programmer: Quincey Koziol - * Thursday, May 16, 2002 + * Note that these opcodes must be supported by all VFDs that + * support MPI. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: JRM -- 8/3/21 * *------------------------------------------------------------------------- */ -static int -H5FD__mpio_mpi_size(const H5FD_t *_file) +static herr_t +H5FD__mpio_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, const void H5_ATTR_UNUSED *input, + void **output) { - const H5FD_mpio_t *file = (const H5FD_mpio_t *)_file; + H5FD_mpio_t *file = (H5FD_mpio_t *)_file; + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_STATIC_NOERR + FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ HDassert(file); HDassert(H5FD_MPIO == file->pub.driver_id); - FUNC_LEAVE_NOAPI(file->mpi_size) -} /* end H5FD__mpio_mpi_size() */ + switch (op_code) { -/*------------------------------------------------------------------------- - * Function: H5FD__mpio_communicator - * - * Purpose: Returns the MPI communicator for the file. - * - * Return: Success: The communicator - * Failure: Can't fail - * - * Programmer: Robb Matzke - * Monday, August 9, 1999 - * - *------------------------------------------------------------------------- - */ -static MPI_Comm -H5FD__mpio_communicator(const H5FD_t *_file) -{ - const H5FD_mpio_t *file = (const H5FD_mpio_t *)_file; + case H5FD_CTL__GET_MPI_COMMUNICATOR_OPCODE: + HDassert(output); + HDassert(*output); + **((MPI_Comm **)output) = file->comm; + break; - FUNC_ENTER_STATIC_NOERR + case H5FD_CTL__GET_MPI_RANK_OPCODE: + HDassert(output); + HDassert(*output); + **((int **)output) = file->mpi_rank; + break; - /* Sanity checks */ - HDassert(file); - HDassert(H5FD_MPIO == file->pub.driver_id); + case H5FD_CTL__GET_MPI_SIZE_OPCODE: + HDassert(output); + HDassert(*output); + **((int **)output) = file->mpi_size; + break; + + default: /* unknown op code */ + if (flags & H5FD_CTL__FAIL_IF_UNKNOWN_FLAG) { + + HGOTO_ERROR(H5E_VFL, H5E_FCNTL, FAIL, "unknown op_code and fail if unknown") + } + break; + } + +done: + + FUNC_LEAVE_NOAPI(ret_value) - FUNC_LEAVE_NOAPI(file->comm) -} /* end H5FD__mpio_communicator() */ +} /* end H5FD__mpio_ctl() */ #endif /* H5_HAVE_PARALLEL */ diff --git a/src/H5FDmulti.c b/src/H5FDmulti.c index cae4174..0d1967d 100644 --- a/src/H5FDmulti.c +++ b/src/H5FDmulti.c @@ -166,6 +166,8 @@ static herr_t H5FD_multi_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing static herr_t H5FD_multi_lock(H5FD_t *_file, hbool_t rw); static herr_t H5FD_multi_unlock(H5FD_t *_file); static herr_t H5FD_multi_delete(const char *filename, hid_t fapl_id); +static herr_t H5FD_multi_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, const void *input, + void **output); /* The class struct */ static const H5FD_class_t H5FD_multi_g = { @@ -201,6 +203,7 @@ static const H5FD_class_t H5FD_multi_g = { H5FD_multi_lock, /* lock */ H5FD_multi_unlock, /* unlock */ H5FD_multi_delete, /* del */ + H5FD_multi_ctl, /* ctl */ H5FD_FLMAP_DEFAULT /* fl_map */ }; @@ -2070,6 +2073,54 @@ H5FD_multi_delete(const char *filename, hid_t fapl_id) } /* end H5FD_multi_delete() */ H5_MULTI_GCC_DIAG_ON("format-nonliteral") +/*------------------------------------------------------------------------- + * Function: H5FD_multi_ctl + * + * Purpose: Multi VFD version of the ctl callback. + * + * The desired operation is specified by the op_code + * parameter. + * + * The flags parameter controls management of op_codes that + * are unknown to the callback + * + * The input and output parameters allow op_code specific + * input and output + * + * At present, this VFD supports no op codes of its own. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_multi_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, const void *input, void **output) +{ + H5FD_multi_t * file = (H5FD_multi_t *)_file; + static const char *func = "H5FD_multi_ctl"; /* Function Name for error reporting */ + herr_t ret_value = 0; + + /* Silence compiler */ + (void)file; + (void)input; + (void)output; + + /* Clear the error stack */ + H5Eclear2(H5E_DEFAULT); + + switch (op_code) { + /* Unknown op code */ + default: + if (flags & H5FD_CTL__FAIL_IF_UNKNOWN_FLAG) + H5Epush_ret(func, H5E_ERR_CLS, H5E_VFL, H5E_FCNTL, + "VFD ctl request failed (unknown op code and fail if unknown flag is set)", -1); + + break; + } + + return ret_value; +} /* end H5FD_multi_ctl() */ + #ifdef H5private_H /* * This is not related to the functionality of the driver code. diff --git a/src/H5FDprivate.h b/src/H5FDprivate.h index c00c123..6dbd483 100644 --- a/src/H5FDprivate.h +++ b/src/H5FDprivate.h @@ -45,13 +45,6 @@ /* Definitions for file MPI type property */ #define H5FD_MPI_XFER_FILE_MPI_TYPE_NAME "H5FD_mpi_file_mpi_type" -/* Sub-class the H5FD_class_t to add more specific functions for MPI-based VFDs */ -typedef struct H5FD_class_mpi_t { - H5FD_class_t super; /* Superclass information & methods */ - int (*get_rank)(const H5FD_t *file); /* Get the MPI rank of a process */ - int (*get_size)(const H5FD_t *file); /* Get the MPI size of a communicator */ - MPI_Comm (*get_comm)(const H5FD_t *file); /* Get the communicator for a file */ -} H5FD_class_mpi_t; #endif /****************************/ @@ -137,6 +130,7 @@ H5_DLL herr_t H5FD_truncate(H5FD_t *file, hbool_t closing); H5_DLL herr_t H5FD_lock(H5FD_t *file, hbool_t rw); H5_DLL herr_t H5FD_unlock(H5FD_t *file); H5_DLL herr_t H5FD_delete(const char *name, hid_t fapl_id); +H5_DLL herr_t H5FD_ctl(H5FD_t *file, uint64_t op_code, uint64_t flags, const void *input, void **output); H5_DLL herr_t H5FD_get_fileno(const H5FD_t *file, unsigned long *filenum); H5_DLL herr_t H5FD_get_vfd_handle(H5FD_t *file, hid_t fapl, void **file_handle); H5_DLL herr_t H5FD_set_base_addr(H5FD_t *file, haddr_t base_addr); @@ -156,9 +150,9 @@ H5_DLL herr_t H5FD_set_mpio_atomicity(H5FD_t *file, hbool_t flag); H5_DLL herr_t H5FD_get_mpio_atomicity(H5FD_t *file, hbool_t *flag); /* Driver specific methods */ -H5_DLL int H5FD_mpi_get_rank(const H5FD_t *file); -H5_DLL int H5FD_mpi_get_size(const H5FD_t *file); -H5_DLL MPI_Comm H5FD_mpi_get_comm(const H5FD_t *_file); +H5_DLL int H5FD_mpi_get_rank(H5FD_t *file); +H5_DLL int H5FD_mpi_get_size(H5FD_t *file); +H5_DLL MPI_Comm H5FD_mpi_get_comm(H5FD_t *file); #endif /* H5_HAVE_PARALLEL */ #endif /* H5FDprivate_H */ diff --git a/src/H5FDpublic.h b/src/H5FDpublic.h index 0cfb072..b8f4f12 100644 --- a/src/H5FDpublic.h +++ b/src/H5FDpublic.h @@ -138,6 +138,77 @@ */ #define H5FD_FEAT_DEFAULT_VFD_COMPATIBLE 0x00008000 +/* ctl function definitions: */ +#define H5FD_CTL_OPC_RESERVED 512 /* Opcodes below this value are reserved for library use */ +#define H5FD_CTL_OPC_EXPER_MIN \ + H5FD_CTL_OPC_RESERVED /* Minimum opcode value available for experimental use \ + */ +#define H5FD_CTL_OPC_EXPER_MAX \ + (H5FD_CTL_OPC_RESERVED + 511) /* Maximum opcode value available for experimental use */ + +/* ctl function op codes: */ +#define H5FD_CTL__INVALID_OPCODE 0 +#define H5FD_CTL__TEST_OPCODE 1 +#define H5FD_CTL__GET_MPI_COMMUNICATOR_OPCODE 2 +#define H5FD_CTL__GET_MPI_RANK_OPCODE 3 +#define H5FD_CTL__GET_MPI_SIZE_OPCODE 4 + +/* ctl function flags: */ + +/* Definitions: + * + * WARNING: While the following definitions of Terminal + * and Passthrough VFDs should be workable for now, they + * have to be adjusted as our use cases for VFDs expand. + * + * JRM -- 8/4/21 + * + * + * Terminal VFD: Lowest VFD in the VFD stack through + * which all VFD calls pass. Note that this definition + * is situational. For example, the sec2 VFD is typically + * terminal. However, in the context of the family file + * driver, it is not -- the family file driver is the + * bottom VFD through which all VFD calls pass, and thus + * it is terminal. + * + * Similarly, on the splitter VFD, a sec2 VFD on the + * R/W channel is terminal, but a sec2 VFD on the W/O + * channel is not. + * + * + * Pass through VFD: Any VFD that relays all VFD calls + * (with the possible exception of some non-I/O related + * calls) to underlying VFD(s). + */ + +/* Unknown op codes should be ignored silently unless the + * H5FD_CTL__FAIL_IF_UNKNOWN_FLAG is set. + * + * On terminal VFDs, unknown op codes should generate an + * error unconditionally if this flag is set. + * + * On pass through VFDs, unknown op codes should be routed + * to the underlying VFD(s) as indicated by any routing + * flags. In the absence of such flags, the VFD should + * generate an error. + */ +#define H5FD_CTL__FAIL_IF_UNKNOWN_FLAG 0x0001 + +/* The H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG is used only + * by non-ternminal VFDs, and only applies to unknown + * opcodes. (known op codes should be handled as + * appropriate.) + * + * If this flag is set for an uknown op code, that + * op code should be passed to the next VFD down + * the VFD stack en-route to the terminal VFD. + * If that VFD does not support the ctl call, the + * pass through VFD should fail or succeed as directed + * by the H5FD_CTL__FAIL_IF_UNKNOWN_FLAG. + */ +#define H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG 0x0002 + /*******************/ /* Public Typedefs */ /*******************/ diff --git a/src/H5FDros3.c b/src/H5FDros3.c index c0361f9..a32d65e 100644 --- a/src/H5FDros3.c +++ b/src/H5FDros3.c @@ -269,6 +269,7 @@ static const H5FD_class_t H5FD_ros3_g = { NULL, /* lock */ NULL, /* unlock */ NULL, /* del */ + NULL, /* ctl */ H5FD_FLMAP_DICHOTOMY /* fl_map */ }; diff --git a/src/H5FDsec2.c b/src/H5FDsec2.c index d823e3c..15103da 100644 --- a/src/H5FDsec2.c +++ b/src/H5FDsec2.c @@ -139,6 +139,8 @@ static herr_t H5FD__sec2_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing static herr_t H5FD__sec2_lock(H5FD_t *_file, hbool_t rw); static herr_t H5FD__sec2_unlock(H5FD_t *_file); static herr_t H5FD__sec2_delete(const char *filename, hid_t fapl_id); +static herr_t H5FD__sec2_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, const void *input, + void **output); static const H5FD_class_t H5FD_sec2_g = { "sec2", /* name */ @@ -173,6 +175,7 @@ static const H5FD_class_t H5FD_sec2_g = { H5FD__sec2_lock, /* lock */ H5FD__sec2_unlock, /* unlock */ H5FD__sec2_delete, /* del */ + H5FD__sec2_ctl, /* ctl */ H5FD_FLMAP_DICHOTOMY /* fl_map */ }; @@ -1068,3 +1071,48 @@ H5FD__sec2_delete(const char *filename, hid_t H5_ATTR_UNUSED fapl_id) done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__sec2_delete() */ + +/*------------------------------------------------------------------------- + * Function: H5FD__sec2_ctl + * + * Purpose: Sec2 VFD version of the ctl callback. + * + * The desired operation is specified by the op_code + * parameter. + * + * The flags parameter controls management of op_codes that + * are unknown to the callback + * + * The input and output parameters allow op_code specific + * input and output + * + * At present, no op codes are supported by this VFD. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD__sec2_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, const void H5_ATTR_UNUSED *input, + void H5_ATTR_UNUSED **output) +{ + H5FD_sec2_t *file = (H5FD_sec2_t *)_file; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(file); + HDassert(H5FD_SEC2 == file->pub.driver_id); + + switch (op_code) { + /* Unknown op code */ + default: + if (flags & H5FD_CTL__FAIL_IF_UNKNOWN_FLAG) + HGOTO_ERROR(H5E_VFL, H5E_FCNTL, FAIL, "unknown op_code and fail if unknown flag is set") + break; + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD__sec2_ctl() */ diff --git a/src/H5FDsplitter.c b/src/H5FDsplitter.c index 73c898a..3113e8b 100644 --- a/src/H5FDsplitter.c +++ b/src/H5FDsplitter.c @@ -129,6 +129,8 @@ static herr_t H5FD__splitter_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closin static herr_t H5FD__splitter_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing); static herr_t H5FD__splitter_lock(H5FD_t *_file, hbool_t rw); static herr_t H5FD__splitter_unlock(H5FD_t *_file); +static herr_t H5FD__splitter_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, const void *input, + void **output); static const H5FD_class_t H5FD_splitter_g = { "splitter", /* name */ @@ -163,6 +165,7 @@ static const H5FD_class_t H5FD_splitter_g = { H5FD__splitter_lock, /* lock */ H5FD__splitter_unlock, /* unlock */ NULL, /* del */ + H5FD__splitter_ctl, /* ctl */ H5FD_FLMAP_DICHOTOMY /* fl_map */ }; @@ -1145,6 +1148,63 @@ done: } /* end H5FD__splitter_unlock */ /*------------------------------------------------------------------------- + * Function: H5FD__splitter_ctl + * + * Purpose: Splitter VFD version of the ctl callback. + * + * The desired operation is specified by the op_code + * parameter. + * + * The flags parameter controls management of op_codes that + * are unknown to the callback + * + * The input and output parameters allow op_code specific + * input and output + * + * At present, this VFD supports no op codes of its own and + * simply passes ctl calls on to the R/W channel VFD. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD__splitter_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, const void *input, void **output) +{ + H5FD_splitter_t *file = (H5FD_splitter_t *)_file; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(file); + HDassert(H5FD_SPLITTER == file->pub.driver_id); + + switch (op_code) { + /* Unknown op code */ + default: + if (flags & H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG) { + /* Pass ctl call down to R/W channel VFD */ + if (H5FDctl(file->rw_file, op_code, flags, input, output) < 0) + HGOTO_ERROR(H5E_VFL, H5E_FCNTL, FAIL, "VFD ctl request failed") + } + else { + /* If no valid VFD routing flag is specified, fail for unknown op code + * if H5FD_CTL__FAIL_IF_UNKNOWN_FLAG flag is set. + */ + if (flags & H5FD_CTL__FAIL_IF_UNKNOWN_FLAG) + HGOTO_ERROR(H5E_VFL, H5E_FCNTL, FAIL, + "VFD ctl request failed (unknown op code and fail if unknown flag is set)") + } + + break; + } + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FD__splitter_ctl() */ + +/*------------------------------------------------------------------------- * Function: H5FD__splitter_query * * Purpose: Set the flags that this VFL driver is capable of supporting. diff --git a/src/H5FDstdio.c b/src/H5FDstdio.c index 6631325..312263c 100644 --- a/src/H5FDstdio.c +++ b/src/H5FDstdio.c @@ -215,6 +215,7 @@ static const H5FD_class_t H5FD_stdio_g = { H5FD_stdio_lock, /* lock */ H5FD_stdio_unlock, /* unlock */ H5FD_stdio_delete, /* del */ + NULL, /* ctl */ H5FD_FLMAP_DICHOTOMY /* fl_map */ }; diff --git a/test/h5test.c b/test/h5test.c index 09fb5b5..ba0662a 100644 --- a/test/h5test.c +++ b/test/h5test.c @@ -1925,6 +1925,7 @@ static const H5FD_class_t H5FD_dummy_g = { NULL, /* lock */ NULL, /* unlock */ NULL, /* del */ + NULL, /* ctl */ H5FD_FLMAP_DICHOTOMY /* fl_map */ }; @@ -48,20 +48,22 @@ #define DSET2_DIM 4 #endif /* H5_HAVE_DIRECT */ -const char *FILENAME[] = {"sec2_file", /*0*/ - "core_file", /*1*/ - "family_file", /*2*/ - "new_family_v16_", /*3*/ - "multi_file", /*4*/ - "direct_file", /*5*/ - "log_file", /*6*/ - "stdio_file", /*7*/ - "windows_file", /*8*/ - "new_multi_file_v16", /*9*/ - "ro_s3_file", /*10*/ - "splitter_rw_file", /*11*/ - "splitter_wo_file", /*12*/ - "splitter.log", /*13*/ +const char *FILENAME[] = {"sec2_file", /*0*/ + "core_file", /*1*/ + "family_file", /*2*/ + "new_family_v16_", /*3*/ + "multi_file", /*4*/ + "direct_file", /*5*/ + "log_file", /*6*/ + "stdio_file", /*7*/ + "windows_file", /*8*/ + "new_multi_file_v16", /*9*/ + "ro_s3_file", /*10*/ + "splitter_rw_file", /*11*/ + "splitter_wo_file", /*12*/ + "splitter.log", /*13*/ + "ctl_file", /*14*/ + "ctl_splitter_wo_file", /*15*/ NULL}; #define LOG_FILENAME "log_vfd_out.log" @@ -94,6 +96,13 @@ struct splitter_dataset_def { int n_dims; /* rank */ }; +/* Op code type enum for ctl callback test */ +typedef enum { + CTL_OPC_KNOWN_PASSTHROUGH, /* op code known to passthrough VFD */ + CTL_OPC_KNOWN_TERMINAL, /* op code known to terminal VFD */ + CTL_OPC_UNKNOWN /* unknown op code */ +} ctl_test_opc_type; + static int splitter_prepare_file_paths(H5FD_splitter_vfd_config_t *vfd_config, char *filename_rw_out); static int splitter_create_single_file_at(const char *filename, hid_t fapl_id, const struct splitter_dataset_def *data); @@ -104,6 +113,19 @@ static int splitter_RO_test(const struct splitter_dataset_def *data, hid_t child static int splitter_tentative_open_test(hid_t child_fapl_id); static int file_exists(const char *filename, hid_t fapl_id); +static herr_t run_ctl_test(uint64_t op_code, uint64_t flags, ctl_test_opc_type opc_type, hid_t fapl_id); +static H5FD_t *H5FD__ctl_test_vfd_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr); +static herr_t H5FD__ctl_test_vfd_close(H5FD_t *_file); +static haddr_t H5FD__ctl_test_vfd_get_eoa(const H5FD_t *_file, H5FD_mem_t type); +static herr_t H5FD__ctl_test_vfd_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr); +static haddr_t H5FD__ctl_test_vfd_get_eof(const H5FD_t *_file, H5FD_mem_t type); +static herr_t H5FD__ctl_test_vfd_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, + size_t size, void *buf); +static herr_t H5FD__ctl_test_vfd_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, + size_t size, const void *buf); +static herr_t H5FD__ctl_test_vfd_ctl(H5FD_t *_file, uint64_t op_code, uint64_t flags, const void *input, + void **output); + /*------------------------------------------------------------------------- * Function: test_sec2 * @@ -3398,6 +3420,499 @@ error: #undef SPLITTER_TEST_FAULT +/* + * Callback implementations for ctl feature testing VFD + */ +static H5FD_t * +H5FD__ctl_test_vfd_open(const char H5_ATTR_UNUSED *name, unsigned H5_ATTR_UNUSED flags, + hid_t H5_ATTR_UNUSED fapl_id, haddr_t H5_ATTR_UNUSED maxaddr) +{ + return HDcalloc(1, sizeof(H5FD_t)); +} +static herr_t +H5FD__ctl_test_vfd_close(H5FD_t H5_ATTR_UNUSED *_file) +{ + HDfree(_file); + return SUCCEED; +} +static haddr_t +H5FD__ctl_test_vfd_get_eoa(const H5FD_t H5_ATTR_UNUSED *file, H5FD_mem_t H5_ATTR_UNUSED type) +{ + return HADDR_UNDEF; +} +static herr_t +H5FD__ctl_test_vfd_set_eoa(H5FD_t H5_ATTR_UNUSED *_file, H5FD_mem_t H5_ATTR_UNUSED type, + haddr_t H5_ATTR_UNUSED addr) +{ + return FAIL; +} +static haddr_t +H5FD__ctl_test_vfd_get_eof(const H5FD_t H5_ATTR_UNUSED *file, H5FD_mem_t H5_ATTR_UNUSED type) +{ + return HADDR_UNDEF; +} +static herr_t +H5FD__ctl_test_vfd_read(H5FD_t H5_ATTR_UNUSED *_file, H5FD_mem_t H5_ATTR_UNUSED type, + hid_t H5_ATTR_UNUSED fapl_id, haddr_t H5_ATTR_UNUSED addr, size_t H5_ATTR_UNUSED size, + void H5_ATTR_UNUSED *buf) +{ + return FAIL; +} +static herr_t +H5FD__ctl_test_vfd_write(H5FD_t H5_ATTR_UNUSED *_file, H5FD_mem_t H5_ATTR_UNUSED type, + hid_t H5_ATTR_UNUSED fapl_id, haddr_t H5_ATTR_UNUSED addr, + size_t H5_ATTR_UNUSED size, const void H5_ATTR_UNUSED *buf) +{ + return FAIL; +} +static herr_t +H5FD__ctl_test_vfd_ctl(H5FD_t H5_ATTR_UNUSED *_file, uint64_t op_code, uint64_t flags, + const void H5_ATTR_UNUSED *input, void H5_ATTR_UNUSED **output) +{ + herr_t ret_value = SUCCEED; + + switch (op_code) { + /* Op code for testing purposes */ + case H5FD_CTL__TEST_OPCODE: + break; + + /* Unknown op code */ + default: + if (flags & H5FD_CTL__FAIL_IF_UNKNOWN_FLAG) + ret_value = FAIL; + break; + } + + return ret_value; +} + +/* Minimal VFD for ctl feature tests */ +static const H5FD_class_t H5FD_ctl_test_vfd_g = { + "ctl_test_vfd", /* name */ + HADDR_MAX, /* maxaddr */ + H5F_CLOSE_SEMI, /* fc_degree */ + NULL, /* terminate */ + NULL, /* sb_size */ + NULL, /* sb_encode */ + NULL, /* sb_decode */ + 0, /* fapl_size */ + NULL, /* fapl_get */ + NULL, /* fapl_copy */ + NULL, /* fapl_free */ + 0, /* dxpl_size */ + NULL, /* dxpl_copy */ + NULL, /* dxpl_free */ + H5FD__ctl_test_vfd_open, /* open */ + H5FD__ctl_test_vfd_close, /* close */ + NULL, /* cmp */ + NULL, /* query */ + NULL, /* get_type_map */ + NULL, /* alloc */ + NULL, /* free */ + H5FD__ctl_test_vfd_get_eoa, /* get_eoa */ + H5FD__ctl_test_vfd_set_eoa, /* set_eoa */ + H5FD__ctl_test_vfd_get_eof, /* get_eof */ + NULL, /* get_handle */ + H5FD__ctl_test_vfd_read, /* read */ + H5FD__ctl_test_vfd_write, /* write */ + NULL, /* flush */ + NULL, /* truncate */ + NULL, /* lock */ + NULL, /* unlock */ + NULL, /* del */ + H5FD__ctl_test_vfd_ctl, /* ctl */ + H5FD_FLMAP_DICHOTOMY /* fl_map */ +}; + +/*------------------------------------------------------------------------- + * Function: run_ctl_test + * + * Purpose: Helper method for VFD "ctl" callback test + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +static herr_t +run_ctl_test(uint64_t op_code, uint64_t flags, ctl_test_opc_type opc_type, hid_t fapl_id) +{ + hbool_t fail_if_unknown = FALSE; + hbool_t routing_flag_set = FALSE; + hbool_t is_passthrough_vfd = FALSE; + hbool_t expect_fail = FALSE; + H5FD_t *file_drv_ptr = NULL; + herr_t ctl_result = SUCCEED; + hid_t driver_id = H5I_INVALID_HID; + char filename[1024]; + + /* Check for a few ctl function flags */ + fail_if_unknown = (flags & H5FD_CTL__FAIL_IF_UNKNOWN_FLAG); + routing_flag_set = (flags & H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG); + + /* Determine if the top-level VFD is a passthrough VFD */ + if ((driver_id = H5Pget_driver(fapl_id)) < 0) + PUTS_ERROR("couldn't get VFD ID from FAPL"); + + is_passthrough_vfd = ((driver_id == H5FD_SPLITTER) || (driver_id == H5FD_MULTI)); + + /* + * "Open" testing file. Note that our VFD for testing the ctl + * feature doesn't actually create or open files, so we don't + * need to create the testing file; we just need the VFD to + * give us a pointer to a H5FD_t structure. + */ + h5_fixname(FILENAME[14], fapl_id, filename, sizeof(filename)); + if (NULL == (file_drv_ptr = H5FDopen(filename, H5F_ACC_RDWR, fapl_id, HADDR_UNDEF))) + PUTS_ERROR("couldn't get pointer to H5FD_t structure"); + + /* Determine whether the H5FDctl call is expected to fail */ + expect_fail = fail_if_unknown && (CTL_OPC_UNKNOWN == opc_type); + if (is_passthrough_vfd) { + /* Should fail if op code is unknown to passthrough VFD + * (but known to terminal VFD), no routing flag is specified + * and the "fail if unknown" flag is specified. + */ + expect_fail = + expect_fail || ((CTL_OPC_KNOWN_TERMINAL == opc_type) && !routing_flag_set && fail_if_unknown); + } + + /* Issue opcode to VFD */ + if (expect_fail) { + H5E_BEGIN_TRY + { + ctl_result = H5FDctl(file_drv_ptr, op_code, flags, NULL, NULL); + } + H5E_END_TRY; + } + else + ctl_result = H5FDctl(file_drv_ptr, op_code, flags, NULL, NULL); + + /* Verify result of H5FDctl call */ + if (expect_fail) { + if (ctl_result == SUCCEED) + PUTS_ERROR("H5FDctl call succeeded when it should have failed"); + } + else { + if (ctl_result != SUCCEED) + PUTS_ERROR("H5FDctl call failed when it should have succeeded"); + } + + /* Close H5FD_t structure pointer */ + if (H5FDclose(file_drv_ptr) < 0) + PUTS_ERROR("couldn't close H5FD_t structure pointer"); + file_drv_ptr = NULL; + + return 0; + +error: + H5E_BEGIN_TRY + { + H5FDclose(file_drv_ptr); + } + H5E_END_TRY; + + return -1; +} + +/*------------------------------------------------------------------------- + * Function: test_ctl + * + * Purpose: Tests the VFD "ctl" callback + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +static herr_t +test_ctl(void) +{ + H5FD_splitter_vfd_config_t *splitter_config = NULL; + uint64_t op_code; + uint64_t flags; + hid_t driver_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t sub_fapl_id = H5I_INVALID_HID; + + TESTING("VFD ctl callback"); + HDputs(""); + + /* Register VFD for test */ + if ((driver_id = H5FDregister(&H5FD_ctl_test_vfd_g)) < 0) + PUTS_ERROR("couldn't register VFD for testing"); + + if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) + PUTS_ERROR("couldn't create FAPL"); + if (H5Pset_driver(fapl_id, driver_id, NULL) < 0) + PUTS_ERROR("couldn't set testing VFD on FAPL"); + + TESTING_2("known op code to terminal VFD (without fail on unknown flag)") + + op_code = H5FD_CTL__TEST_OPCODE; + flags = 0; + + /* H5FDctl call should succeed normally */ + if (run_ctl_test(op_code, flags, CTL_OPC_KNOWN_TERMINAL, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2("known op code to terminal VFD (with fail on unknown flag)") + + op_code = H5FD_CTL__TEST_OPCODE; + flags = H5FD_CTL__FAIL_IF_UNKNOWN_FLAG; + + /* H5FDctl call should succeed normally */ + if (run_ctl_test(op_code, flags, CTL_OPC_KNOWN_TERMINAL, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2("known op code to terminal VFD (without fail on unknown flag/route to terminal VFD)") + + op_code = H5FD_CTL__TEST_OPCODE; + flags = H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG; + + /* H5FDctl call should succeed normally */ + if (run_ctl_test(op_code, flags, CTL_OPC_KNOWN_TERMINAL, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2("known op code to terminal VFD (with fail on unknown flag/route to terminal VFD)") + + op_code = H5FD_CTL__TEST_OPCODE; + flags = H5FD_CTL__FAIL_IF_UNKNOWN_FLAG | H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG; + + /* H5FDctl call should succeed normally */ + if (run_ctl_test(op_code, flags, CTL_OPC_KNOWN_TERMINAL, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2("unknown op code to terminal VFD (without fail on unknown flag)") + + op_code = H5FD_CTL_OPC_RESERVED; + flags = 0; + + /* H5FDctl call should silently ignore unknown op code and succeed */ + if (run_ctl_test(op_code, flags, CTL_OPC_UNKNOWN, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2("unknown op code to terminal VFD (with fail on unknown flag)") + + op_code = H5FD_CTL_OPC_RESERVED; + flags = H5FD_CTL__FAIL_IF_UNKNOWN_FLAG; + + /* H5FDctl call should fail due to 'fail if unknown' flag being specified */ + if (run_ctl_test(op_code, flags, CTL_OPC_UNKNOWN, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2("unknown op code to terminal VFD (without fail on unknown flag/route to terminal VFD)") + + op_code = H5FD_CTL_OPC_RESERVED; + flags = H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG; + + /* H5FDctl call should silently ignore unknown op code and succeed */ + if (run_ctl_test(op_code, flags, CTL_OPC_UNKNOWN, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2("unknown op code to terminal VFD (with fail on unknown flag/route to terminal VFD)") + + op_code = H5FD_CTL_OPC_RESERVED; + flags = H5FD_CTL__FAIL_IF_UNKNOWN_FLAG | H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG; + + /* H5FDctl call should fail due to 'fail if unknown' flag being specified */ + if (run_ctl_test(op_code, flags, CTL_OPC_UNKNOWN, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + /* Set up splitter VFD config */ + if (NULL == (splitter_config = HDcalloc(1, sizeof(H5FD_splitter_vfd_config_t)))) + TEST_ERROR; + + splitter_config->magic = H5FD_SPLITTER_MAGIC; + splitter_config->version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION; + splitter_config->ignore_wo_errs = TRUE; + splitter_config->rw_fapl_id = H5P_DEFAULT; + splitter_config->wo_fapl_id = H5P_DEFAULT; + h5_fixname(FILENAME[15], splitter_config->wo_fapl_id, splitter_config->wo_path, H5FD_SPLITTER_PATH_MAX); + + if ((sub_fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) + PUTS_ERROR("couldn't create FAPL"); + if (H5Pset_driver(sub_fapl_id, driver_id, NULL) < 0) + PUTS_ERROR("couldn't set testing VFD on FAPL"); + splitter_config->rw_fapl_id = sub_fapl_id; + + if (H5Pset_fapl_splitter(fapl_id, splitter_config) < 0) + PUTS_ERROR("couldn't set splitter VFD on FAPL"); + + TESTING_2("known op code through passthrough VFD to terminal VFD (without fail on unknown flag/no " + "routing flag)") + + op_code = H5FD_CTL__TEST_OPCODE; + flags = 0; + + /* + * H5FDctl call should silently ignore unknown op code in + * passthrough VFD since no routing flag is specified and + * 'fail if unknown' flag is not specified. + */ + if (run_ctl_test(op_code, flags, CTL_OPC_KNOWN_TERMINAL, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2( + "known op code through passthrough VFD to terminal VFD (with fail on unknown flag/no routing flag)") + + op_code = H5FD_CTL__TEST_OPCODE; + flags = H5FD_CTL__FAIL_IF_UNKNOWN_FLAG; + + /* + * H5FDctl call should fail since op code is unknown to + * passthrough VFD (though known to terminal VFD), no + * routing flag is specified and the 'fail if unknown' + * flag is specified. + */ + if (run_ctl_test(op_code, flags, CTL_OPC_KNOWN_TERMINAL, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2("known op code through passthrough VFD to terminal VFD (without fail on unknown flag/route to " + "terminal VFD)") + + op_code = H5FD_CTL__TEST_OPCODE; + flags = H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG; + + /* + * H5Dctl call should succeed since the passthrough VFD + * doesn't recognize the op code, but has been instructed + * to route it down to the terminal VFD. + */ + if (run_ctl_test(op_code, flags, CTL_OPC_KNOWN_TERMINAL, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2("known op code through passthrough VFD to terminal VFD (with fail on unknown flag/route to " + "terminal VFD)") + + op_code = H5FD_CTL__TEST_OPCODE; + flags = H5FD_CTL__FAIL_IF_UNKNOWN_FLAG | H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG; + + /* + * H5Dctl call should succeed since the passthrough VFD + * doesn't recognize the op code, but has been instructed + * to route it down to the terminal VFD. + */ + if (run_ctl_test(op_code, flags, CTL_OPC_KNOWN_TERMINAL, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2("unknown op code to passthrough VFD (without fail on unknown flag)") + + op_code = H5FD_CTL_OPC_RESERVED; + flags = 0; + + /* + * H5FDctl call should silently ignore unknown op code in + * passthrough VFD since no routing flag is specified and + * 'fail if unknown' flag is not specified. + */ + if (run_ctl_test(op_code, flags, CTL_OPC_UNKNOWN, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2("unknown op code to passthrough VFD (with fail on unknown flag)") + + op_code = H5FD_CTL_OPC_RESERVED; + flags = H5FD_CTL__FAIL_IF_UNKNOWN_FLAG; + + /* + * H5FDctl call should fail since op code is unknown to + * passthrough VFD, no routing flag is specified and the + * 'fail if unknown' flag is specified. + */ + if (run_ctl_test(op_code, flags, CTL_OPC_UNKNOWN, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2("unknown op code to passthrough VFD (without fail on unknown flag/route to terminal VFD)") + + op_code = H5FD_CTL_OPC_RESERVED; + flags = H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG; + + /* + * H5Dctl call should succeed since the passthrough VFD + * doesn't recognize the op code, but has been instructed + * to route it down to the terminal VFD and the 'fail if + * unknown' flag has not been specified. Therefore, the + * terminal VFD should silently ignore the unknown op + * code. + */ + if (run_ctl_test(op_code, flags, CTL_OPC_UNKNOWN, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2("unknown op code to passthrough VFD (with fail on unknown flag/route to terminal VFD)") + + op_code = H5FD_CTL_OPC_RESERVED; + flags = H5FD_CTL__FAIL_IF_UNKNOWN_FLAG | H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG; + + /* + * H5Dctl call should fail since the passthrough VFD + * doesn't recognize the op code, but has been instructed + * to route it down to the terminal VFD and the 'fail if + * unknown' flag has been specified. Therefore, the + * terminal VFD will throw an error for the unknown op + * code. + */ + if (run_ctl_test(op_code, flags, CTL_OPC_UNKNOWN, fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + TESTING_2("test cleanup") + + HDfree(splitter_config); + + if (H5FDunregister(driver_id) < 0) + TEST_ERROR; + if (H5Pclose(sub_fapl_id) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (splitter_config) + HDfree(splitter_config); + H5FDunregister(driver_id); + H5Pclose(sub_fapl_id); + H5Pclose(fapl_id); + } + H5E_END_TRY; + + return -1; +} + /*------------------------------------------------------------------------- * Function: main * @@ -3429,6 +3944,7 @@ main(void) nerrors += test_windows() < 0 ? 1 : 0; nerrors += test_ros3() < 0 ? 1 : 0; nerrors += test_splitter() < 0 ? 1 : 0; + nerrors += test_ctl() < 0 ? 1 : 0; if (nerrors) { HDprintf("***** %d Virtual File Driver TEST%s FAILED! *****\n", nerrors, nerrors > 1 ? "S" : ""); |