summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--release_docs/RELEASE.txt25
-rw-r--r--src/H5FD.c105
-rw-r--r--src/H5FDcore.c1
-rw-r--r--src/H5FDdevelop.h2
-rw-r--r--src/H5FDdirect.c1
-rw-r--r--src/H5FDfamily.c1
-rw-r--r--src/H5FDhdfs.c1
-rw-r--r--src/H5FDlog.c1
-rw-r--r--src/H5FDmirror.c1
-rw-r--r--src/H5FDmpi.c90
-rw-r--r--src/H5FDmpio.c223
-rw-r--r--src/H5FDmulti.c51
-rw-r--r--src/H5FDprivate.h14
-rw-r--r--src/H5FDpublic.h71
-rw-r--r--src/H5FDros3.c1
-rw-r--r--src/H5FDsec2.c48
-rw-r--r--src/H5FDsplitter.c60
-rw-r--r--src/H5FDstdio.c1
-rw-r--r--test/h5test.c1
-rw-r--r--test/vfd.c544
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
diff --git a/src/H5FD.c b/src/H5FD.c
index abda921..d3f72e8 100644
--- a/src/H5FD.c
+++ b/src/H5FD.c
@@ -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 */
};
diff --git a/test/vfd.c b/test/vfd.c
index f4cb988..4e9b9ee 100644
--- a/test/vfd.c
+++ b/test/vfd.c
@@ -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" : "");