summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhendersonHDF <jhenderson@hdfgroup.org>2021-09-30 04:00:24 (GMT)
committerGitHub <noreply@github.com>2021-09-30 04:00:24 (GMT)
commit5b5f0c08c9f15bb1740208de67d9242463fa0cb4 (patch)
treecd5784d67bec559dc5bbe840c1b9fceacc72f867
parent3da0802c40d58759995916bf9d0880e19f0af44d (diff)
downloadhdf5-5b5f0c08c9f15bb1740208de67d9242463fa0cb4.zip
hdf5-5b5f0c08c9f15bb1740208de67d9242463fa0cb4.tar.gz
hdf5-5b5f0c08c9f15bb1740208de67d9242463fa0cb4.tar.bz2
Update compact dataset I/O routines to handle driver-level memory copy (#1054)
* Update compact dataset I/O routines to handle driver-level memory copy * Combine compact I/O read/write struct into single I/O struct Rename CTL memory copy flag and H5Fquery routine to get file driver structure * Add RELEASE.txt entry for new "ctl" memory copy operation
-rw-r--r--release_docs/RELEASE.txt42
-rw-r--r--src/H5Dcompact.c106
-rw-r--r--src/H5FDpublic.h24
-rw-r--r--src/H5Fprivate.h5
-rw-r--r--src/H5Fquery.c23
5 files changed, 187 insertions, 13 deletions
diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt
index 0c3a398..ec558c6 100644
--- a/release_docs/RELEASE.txt
+++ b/release_docs/RELEASE.txt
@@ -469,6 +469,48 @@ New Features
Library:
--------
+ - Adds new file driver-level memory copy operation for
+ "ctl" callback and updates compact dataset I/O routines
+ to utilize it
+
+ When accessing an HDF5 file with a file driver that uses
+ memory allocated in special ways (e.g., without standard
+ library's `malloc`), a crash could be observed when HDF5
+ tries to perform `memcpy` operations on such a memory
+ region.
+
+ These changes add a new H5FD_FEAT_MEMMANAGE VFD feature
+ flag, which, if specified as supported by a VFD, will
+ inform HDF5 that the VFD either uses special memory
+ management routines or wishes to perform memory management
+ in a specific way. Therefore, this flag instructs HDF5 to
+ ask the file driver to perform memory management for
+ certain operations.
+
+ These changes also introduce a new "ctl" callback
+ operation identified by the H5FD_CTL__MEM_COPY op code.
+ This operation simply asks a VFD to perform a memory copy.
+ The arguments to this operation are passed to the "ctl"
+ callback's "input" parameter as a pointer to a struct
+ defined as:
+
+ struct H5FD_ctl_memcpy_args_t {
+ void * dstbuf; /**< Destination buffer */
+ hsize_t dst_off; /**< Offset within destination buffer */
+ const void *srcbuf; /**< Source buffer */
+ hsize_t src_off; /**< Offset within source buffer */
+ size_t len; /**< Length of data to copy from source buffer */
+ } H5FD_ctl_memcpy_args_t;
+
+ Further, HDF5's compact dataset I/O routines were
+ identified as a problematic area that could cause a crash
+ for VFDs that make use of special memory management. Those
+ I/O routines were therefore updated to make use of this new
+ "ctl" callback operation in order to ask the underlying
+ file driver to correctly handle memory copies.
+
+ (JTH - 2021/09/28)
+
- Adds new "ctl" callback to VFD H5FD_class_t structure
with the following prototype:
diff --git a/src/H5Dcompact.c b/src/H5Dcompact.c
index fe41298..88926c2 100644
--- a/src/H5Dcompact.c
+++ b/src/H5Dcompact.c
@@ -47,6 +47,15 @@
/* Local Typedefs */
/******************/
+/* Callback info for I/O operation when file driver
+ * wishes to do its own memory management
+ */
+typedef struct H5D_compact_iovv_memmanage_ud_t {
+ H5F_shared_t *f_sh; /* Shared file for dataset */
+ void * dstbuf; /* Pointer to buffer to be read into/written into */
+ const void * srcbuf; /* Pointer to buffer to be read from/written from */
+} H5D_compact_iovv_memmanage_ud_t;
+
/********************/
/* Local Prototypes */
/********************/
@@ -57,6 +66,7 @@ static hbool_t H5D__compact_is_space_alloc(const H5O_storage_t *storage);
static herr_t H5D__compact_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info,
hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space,
H5D_chunk_map_t *cm);
+static herr_t H5D__compact_iovv_memmanage_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata);
static ssize_t H5D__compact_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *dset_curr_seq,
size_t dset_size_arr[], hsize_t dset_offset_arr[], size_t mem_max_nseq,
size_t *mem_curr_seq, size_t mem_size_arr[], hsize_t mem_offset_arr[]);
@@ -240,6 +250,48 @@ H5D__compact_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t H5_ATTR
} /* end H5D__compact_io_init() */
/*-------------------------------------------------------------------------
+ * Function: H5D__compact_iovv_memmanage_cb
+ *
+ * Purpose: Callback operator for H5D__compact_readvv()/_writevv() to
+ * send a memory copy request to the underlying file driver.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D__compact_iovv_memmanage_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata)
+{
+ H5D_compact_iovv_memmanage_ud_t *udata = (H5D_compact_iovv_memmanage_ud_t *)_udata;
+ H5FD_ctl_memcpy_args_t op_args;
+ uint64_t op_flags;
+ H5FD_t * file_handle = NULL;
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC
+
+ /* Retrieve pointer to file driver structure for ctl call */
+ if (H5F_shared_get_file_driver(udata->f_sh, &file_handle) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL, "can't get file handle")
+
+ /* Setup operation flags and arguments */
+ op_flags = H5FD_CTL__ROUTE_TO_TERMINAL_VFD_FLAG | H5FD_CTL__FAIL_IF_UNKNOWN_FLAG;
+
+ op_args.dstbuf = udata->dstbuf;
+ op_args.dst_off = dst_off;
+ op_args.srcbuf = udata->srcbuf;
+ op_args.src_off = src_off;
+ op_args.len = len;
+
+ /* Make request to file driver */
+ if (H5FD_ctl(file_handle, H5FD_CTL__MEM_COPY, op_flags, &op_args, NULL) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_FCNTL, FAIL, "VFD memcpy request failed")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D__compact_iovv_memmanage_cb() */
+
+/*-------------------------------------------------------------------------
* Function: H5D__compact_readvv
*
* Purpose: Reads some data vectors from a dataset into a buffer.
@@ -268,11 +320,28 @@ H5D__compact_readvv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t *
HDassert(io_info);
- /* Use the vectorized memory copy routine to do actual work */
- if ((ret_value = H5VM_memcpyvv(io_info->u.rbuf, mem_max_nseq, mem_curr_seq, mem_size_arr, mem_offset_arr,
- io_info->store->compact.buf, dset_max_nseq, dset_curr_seq, dset_size_arr,
- dset_offset_arr)) < 0)
- HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vectorized memcpy failed")
+ /* Check if file driver wishes to do its own memory management */
+ if (H5F_SHARED_HAS_FEATURE(io_info->f_sh, H5FD_FEAT_MEMMANAGE)) {
+ H5D_compact_iovv_memmanage_ud_t udata;
+
+ /* Set up udata for memory copy operation */
+ udata.f_sh = io_info->f_sh;
+ udata.dstbuf = io_info->u.rbuf;
+ udata.srcbuf = io_info->store->compact.buf;
+
+ /* Request that file driver does the memory copy */
+ if ((ret_value = H5VM_opvv(mem_max_nseq, mem_curr_seq, mem_size_arr, mem_offset_arr, dset_max_nseq,
+ dset_curr_seq, dset_size_arr, dset_offset_arr,
+ H5D__compact_iovv_memmanage_cb, &udata)) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vectorized memcpy failed")
+ }
+ else {
+ /* Use the vectorized memory copy routine to do actual work */
+ if ((ret_value = H5VM_memcpyvv(io_info->u.rbuf, mem_max_nseq, mem_curr_seq, mem_size_arr,
+ mem_offset_arr, io_info->store->compact.buf, dset_max_nseq,
+ dset_curr_seq, dset_size_arr, dset_offset_arr)) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vectorized memcpy failed")
+ }
done:
FUNC_LEAVE_NOAPI(ret_value)
@@ -310,11 +379,28 @@ H5D__compact_writevv(const H5D_io_info_t *io_info, size_t dset_max_nseq, size_t
HDassert(io_info);
- /* Use the vectorized memory copy routine to do actual work */
- if ((ret_value = H5VM_memcpyvv(io_info->store->compact.buf, dset_max_nseq, dset_curr_seq, dset_size_arr,
- dset_offset_arr, io_info->u.wbuf, mem_max_nseq, mem_curr_seq, mem_size_arr,
- mem_offset_arr)) < 0)
- HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vectorized memcpy failed")
+ /* Check if file driver wishes to do its own memory management */
+ if (H5F_SHARED_HAS_FEATURE(io_info->f_sh, H5FD_FEAT_MEMMANAGE)) {
+ H5D_compact_iovv_memmanage_ud_t udata;
+
+ /* Set up udata for memory copy operation */
+ udata.f_sh = io_info->f_sh;
+ udata.dstbuf = io_info->store->compact.buf;
+ udata.srcbuf = io_info->u.wbuf;
+
+ /* Request that file driver does the memory copy */
+ if ((ret_value = H5VM_opvv(dset_max_nseq, dset_curr_seq, dset_size_arr, dset_offset_arr, mem_max_nseq,
+ mem_curr_seq, mem_size_arr, mem_offset_arr, H5D__compact_iovv_memmanage_cb,
+ &udata)) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vectorized memcpy failed")
+ }
+ else {
+ /* Use the vectorized memory copy routine to do actual work */
+ if ((ret_value = H5VM_memcpyvv(io_info->store->compact.buf, dset_max_nseq, dset_curr_seq,
+ dset_size_arr, dset_offset_arr, io_info->u.wbuf, mem_max_nseq,
+ mem_curr_seq, mem_size_arr, mem_offset_arr)) < 0)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vectorized memcpy failed")
+ }
/* Mark the compact dataset's buffer as dirty */
*io_info->store->compact.dirty = TRUE;
diff --git a/src/H5FDpublic.h b/src/H5FDpublic.h
index a72dc80..d774210 100644
--- a/src/H5FDpublic.h
+++ b/src/H5FDpublic.h
@@ -170,6 +170,14 @@
* enabled may be used as the Write-Only (W/O) channel driver.
*/
#define H5FD_FEAT_DEFAULT_VFD_COMPATIBLE 0x00008000
+/*
+ * Defining H5FD_FEAT_MEMMANAGE for a VFL driver means that
+ * the driver uses special memory management routines or wishes
+ * to do memory management in a specific manner. Therefore, HDF5
+ * should request that the driver handle any memory management
+ * operations when appropriate.
+ */
+#define H5FD_FEAT_MEMMANAGE 0x00010000
/* ctl function definitions: */
#define H5FD_CTL_OPC_RESERVED 512 /* Opcodes below this value are reserved for library use */
@@ -185,6 +193,9 @@
#define H5FD_CTL__GET_MPI_COMMUNICATOR_OPCODE 2
#define H5FD_CTL__GET_MPI_RANK_OPCODE 3
#define H5FD_CTL__GET_MPI_SIZE_OPCODE 4
+#define H5FD_CTL__MEM_ALLOC 5
+#define H5FD_CTL__MEM_FREE 6
+#define H5FD_CTL__MEM_COPY 7
/* ctl function flags: */
@@ -367,6 +378,19 @@ typedef struct {
} H5FD_file_image_callbacks_t;
//! <!-- [H5FD_file_image_callbacks_t_snip] -->
+/**
+ * Define structure to hold "ctl memory copy" parameters
+ */
+//! <!-- [H5FD_ctl_memcpy_args_t_snip] -->
+typedef struct H5FD_ctl_memcpy_args_t {
+ void * dstbuf; /**< Destination buffer */
+ hsize_t dst_off; /**< Offset within destination buffer */
+ const void *srcbuf; /**< Source buffer */
+ hsize_t src_off; /**< Offset within source buffer */
+ size_t len; /**< Length of data to copy from source buffer */
+} H5FD_ctl_memcpy_args_t;
+//! <!-- [H5FD_ctl_memcpy_args_t_snip] -->
+
/********************/
/* Public Variables */
/********************/
diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h
index 051abd9..a5ccbab 100644
--- a/src/H5Fprivate.h
+++ b/src/H5Fprivate.h
@@ -24,11 +24,9 @@ typedef struct H5F_t H5F_t;
/* Include package's public header */
#include "H5Fpublic.h"
-/* Public headers needed by this file */
-#include "H5FDpublic.h" /* File drivers */
-
/* Private headers needed by this file */
#include "H5MMprivate.h" /* Memory management */
+#include "H5FDprivate.h" /* File drivers */
#ifdef H5_HAVE_PARALLEL
#include "H5Pprivate.h" /* Property lists */
#endif /* H5_HAVE_PARALLEL */
@@ -906,6 +904,7 @@ H5_DLL hbool_t H5F_shared_has_feature(const H5F_shared_t *f, unsigned feature);
H5_DLL hbool_t H5F_has_feature(const H5F_t *f, unsigned feature);
H5_DLL haddr_t H5F_shared_get_eoa(const H5F_shared_t *f_sh, H5FD_mem_t type);
H5_DLL haddr_t H5F_get_eoa(const H5F_t *f, H5FD_mem_t type);
+H5_DLL herr_t H5F_shared_get_file_driver(const H5F_shared_t *f_sh, H5FD_t **file_handle);
H5_DLL herr_t H5F_get_vfd_handle(const H5F_t *file, hid_t fapl, void **file_handle);
/* File mounting routines */
diff --git a/src/H5Fquery.c b/src/H5Fquery.c
index 04792b4..a625897 100644
--- a/src/H5Fquery.c
+++ b/src/H5Fquery.c
@@ -950,6 +950,29 @@ done:
} /* end H5F_get_eoa() */
/*-------------------------------------------------------------------------
+ * Function: H5F_shared_get_file_driver
+ *
+ * Purpose: Returns a pointer to the file driver structure of the
+ * file's 'shared' structure.
+ *
+ * Return: file handle on success/abort on failure (shouldn't fail)
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5F_shared_get_file_driver(const H5F_shared_t *f_sh, H5FD_t **file_handle)
+{
+ /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ HDassert(f_sh);
+ HDassert(file_handle);
+
+ *file_handle = f_sh->lf;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5F_shared_get_file_driver() */
+
+/*-------------------------------------------------------------------------
* Function: H5F_get_vfd_handle
*
* Purpose: Returns a pointer to the file handle of the low-level file