Enforce VOL framework version compatibility when registering connectors. Also add a version for the connector itself, some refactoring on the register calls, and move the logic for matching / rejecting a VOL connector class from the plugin module to the VOL module. (#151)
This commit is contained in:
@@ -354,30 +354,19 @@ H5PL__open(const char *path, H5PL_type_t type, const H5PL_key_t *key, hbool_t *s
|
||||
}
|
||||
|
||||
case H5PL_TYPE_VOL: {
|
||||
const H5VL_class_t *cls;
|
||||
const void *cls;
|
||||
|
||||
/* Get the plugin info */
|
||||
if (NULL == (cls = (const H5VL_class_t *)(*get_plugin_info)()))
|
||||
if (NULL == (cls = (const void *)(*get_plugin_info)()))
|
||||
HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "can't get VOL connector info from plugin")
|
||||
|
||||
/* Which kind of key are we looking for? */
|
||||
if (key->vol.kind == H5VL_GET_CONNECTOR_BY_NAME) {
|
||||
/* If the plugin names match, we're done. Set the output parameters. */
|
||||
if (cls->name && !HDstrcmp(cls->name, key->vol.u.name)) {
|
||||
*plugin_info = (const void *)cls;
|
||||
*success = TRUE;
|
||||
} /* end if */
|
||||
} /* end if */
|
||||
else {
|
||||
/* Sanity check */
|
||||
HDassert(key->vol.kind == H5VL_GET_CONNECTOR_BY_VALUE);
|
||||
/* Ask VOL interface if this class is the one we are looking for and is compatible, etc */
|
||||
if (H5VL_check_plugin_load(cls, key, success) < 0)
|
||||
HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, FAIL, "VOL connector compatibility check failed")
|
||||
|
||||
/* If the plugin values match, we're done. Set the output parameters. */
|
||||
if (cls->value == key->vol.u.value) {
|
||||
*plugin_info = (const void *)cls;
|
||||
*success = TRUE;
|
||||
} /* end if */
|
||||
} /* end else */
|
||||
/* Check for finding the correct plugin */
|
||||
if (*success)
|
||||
*plugin_info = cls;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -91,6 +91,9 @@ H5VLregister_connector(const H5VL_class_t *cls, hid_t vipl_id)
|
||||
if (!cls)
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_UNINITIALIZED, H5I_INVALID_HID,
|
||||
"VOL connector class pointer cannot be NULL")
|
||||
if (H5VL_VERSION != cls->version)
|
||||
HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID,
|
||||
"VOL connector has incompatible version")
|
||||
if (!cls->name)
|
||||
HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID,
|
||||
"VOL connector class name cannot be the NULL pointer")
|
||||
@@ -113,7 +116,7 @@ H5VLregister_connector(const H5VL_class_t *cls, hid_t vipl_id)
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a VOL initialize property list")
|
||||
|
||||
/* Register connector */
|
||||
if ((ret_value = H5VL__register_connector(cls, TRUE, vipl_id)) < 0)
|
||||
if ((ret_value = H5VL__register_connector_by_class(cls, TRUE, vipl_id)) < 0)
|
||||
HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector")
|
||||
|
||||
done:
|
||||
|
||||
@@ -445,9 +445,10 @@ typedef struct H5VL_token_class_t {
|
||||
//! [H5VL_class_t_snip]
|
||||
typedef struct H5VL_class_t {
|
||||
/* Overall connector fields & callbacks */
|
||||
unsigned int version; /**< VOL connector class struct version # */
|
||||
unsigned version; /**< VOL connector class struct version # */
|
||||
H5VL_class_value_t value; /**< Value to identify connector */
|
||||
const char * name; /**< Connector name (MUST be unique!) */
|
||||
unsigned conn_version; /**< Version # of connector */
|
||||
unsigned cap_flags; /**< Capability flags for connector */
|
||||
herr_t (*initialize)(hid_t vipl_id); /**< Connector initialization callback */
|
||||
herr_t (*terminate)(void); /**< Connector termination callback */
|
||||
|
||||
@@ -1075,7 +1075,7 @@ done:
|
||||
} /* end H5VL_file_is_same() */
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Function: H5VL_register_connector
|
||||
* Function: H5VL__register_connector
|
||||
*
|
||||
* Purpose: Registers a new VOL connector as a member of the virtual object
|
||||
* layer class.
|
||||
@@ -1091,13 +1091,13 @@ done:
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
hid_t
|
||||
H5VL_register_connector(const void *_cls, hbool_t app_ref, hid_t vipl_id)
|
||||
H5VL__register_connector(const void *_cls, hbool_t app_ref, hid_t vipl_id)
|
||||
{
|
||||
const H5VL_class_t *cls = (const H5VL_class_t *)_cls;
|
||||
H5VL_class_t * saved = NULL;
|
||||
hid_t ret_value = H5I_INVALID_HID;
|
||||
|
||||
FUNC_ENTER_NOAPI(H5I_INVALID_HID)
|
||||
FUNC_ENTER_PACKAGE
|
||||
|
||||
/* Check arguments */
|
||||
HDassert(cls);
|
||||
@@ -1128,10 +1128,10 @@ done:
|
||||
} /* end if */
|
||||
|
||||
FUNC_LEAVE_NOAPI(ret_value)
|
||||
} /* end H5VL_register_connector() */
|
||||
} /* end H5VL__register_connector() */
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Function: H5VL__register_connector
|
||||
* Function: H5VL__register_connector_by_class
|
||||
*
|
||||
* Purpose: Registers a new VOL connector as a member of the virtual object
|
||||
* layer class.
|
||||
@@ -1148,7 +1148,7 @@ done:
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
hid_t
|
||||
H5VL__register_connector(const H5VL_class_t *cls, hbool_t app_ref, hid_t vipl_id)
|
||||
H5VL__register_connector_by_class(const H5VL_class_t *cls, hbool_t app_ref, hid_t vipl_id)
|
||||
{
|
||||
H5VL_get_connector_ud_t op_data; /* Callback info for connector search */
|
||||
hid_t ret_value = H5I_INVALID_HID; /* Return value */
|
||||
@@ -1173,13 +1173,13 @@ H5VL__register_connector(const H5VL_class_t *cls, hbool_t app_ref, hid_t vipl_id
|
||||
} /* end if */
|
||||
else {
|
||||
/* Create a new class ID */
|
||||
if ((ret_value = H5VL_register_connector(cls, app_ref, vipl_id)) < 0)
|
||||
if ((ret_value = H5VL__register_connector(cls, app_ref, vipl_id)) < 0)
|
||||
HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector")
|
||||
} /* end else */
|
||||
|
||||
done:
|
||||
FUNC_LEAVE_NOAPI(ret_value)
|
||||
} /* end H5VL__register_connector() */
|
||||
} /* end H5VL__register_connector_by_class() */
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Function: H5VL__register_connector_by_name
|
||||
@@ -1233,7 +1233,7 @@ H5VL__register_connector_by_name(const char *name, hbool_t app_ref, hid_t vipl_i
|
||||
HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, H5I_INVALID_HID, "unable to load VOL connector")
|
||||
|
||||
/* Register the connector we loaded */
|
||||
if ((ret_value = H5VL_register_connector(cls, app_ref, vipl_id)) < 0)
|
||||
if ((ret_value = H5VL__register_connector(cls, app_ref, vipl_id)) < 0)
|
||||
HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector ID")
|
||||
} /* end else */
|
||||
|
||||
@@ -1293,7 +1293,7 @@ H5VL__register_connector_by_value(H5VL_class_value_t value, hbool_t app_ref, hid
|
||||
HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, H5I_INVALID_HID, "unable to load VOL connector")
|
||||
|
||||
/* Register the connector we loaded */
|
||||
if ((ret_value = H5VL_register_connector(cls, app_ref, vipl_id)) < 0)
|
||||
if ((ret_value = H5VL__register_connector(cls, app_ref, vipl_id)) < 0)
|
||||
HGOTO_ERROR(H5E_VOL, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register VOL connector ID")
|
||||
} /* end else */
|
||||
|
||||
@@ -2341,3 +2341,55 @@ H5VL_wrap_register(H5I_type_t type, void *obj, hbool_t app_ref)
|
||||
done:
|
||||
FUNC_LEAVE_NOAPI(ret_value)
|
||||
} /* end H5VL_wrap_register() */
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Function: H5VL_check_plugin_load
|
||||
*
|
||||
* Purpose: Check if a VOL connector matches the search criteria, and
|
||||
* can be loaded.
|
||||
*
|
||||
* Note: Matching the connector's name / value, but the connector
|
||||
* having an incompatible version is not an error, but means
|
||||
* that the connector isn't a "match". Setting the SUCCEED
|
||||
* value to FALSE and not failing for that case allows the
|
||||
* plugin framework to keep looking for other DLLs that match
|
||||
* and have a compatible version.
|
||||
*
|
||||
* Return: SUCCEED / FAIL
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
herr_t
|
||||
H5VL_check_plugin_load(const H5VL_class_t *cls, const H5PL_key_t *key, hbool_t *success)
|
||||
{
|
||||
herr_t ret_value = SUCCEED; /* Return value */
|
||||
|
||||
FUNC_ENTER_NOAPI(FAIL)
|
||||
|
||||
/* Sanity checks */
|
||||
HDassert(cls);
|
||||
HDassert(key);
|
||||
HDassert(success);
|
||||
|
||||
/* Which kind of key are we looking for? */
|
||||
if (key->vol.kind == H5VL_GET_CONNECTOR_BY_NAME) {
|
||||
/* Check if plugin name matches VOL connector class name */
|
||||
if (cls->name && !HDstrcmp(cls->name, key->vol.u.name))
|
||||
*success = TRUE;
|
||||
} /* end if */
|
||||
else {
|
||||
/* Sanity check */
|
||||
HDassert(key->vol.kind == H5VL_GET_CONNECTOR_BY_VALUE);
|
||||
|
||||
/* Check if plugin value matches VOL connector class value */
|
||||
if (cls->value == key->vol.u.value)
|
||||
*success = TRUE;
|
||||
} /* end else */
|
||||
|
||||
/* Connector is a match, but might not be a compatible version */
|
||||
if (*success && cls->version != H5VL_VERSION)
|
||||
*success = FALSE;
|
||||
|
||||
done:
|
||||
FUNC_LEAVE_NOAPI(ret_value)
|
||||
} /* end H5VL_check_plugin_load() */
|
||||
|
||||
@@ -15,6 +15,16 @@
|
||||
* using HDF5 VFDs.
|
||||
*/
|
||||
|
||||
/****************/
|
||||
/* Module Setup */
|
||||
/****************/
|
||||
|
||||
#define H5VL_FRIEND /* Suppress error about including H5VLpkg */
|
||||
|
||||
/***********/
|
||||
/* Headers */
|
||||
/***********/
|
||||
|
||||
#include "H5private.h" /* Generic Functions */
|
||||
#include "H5Aprivate.h" /* Attributes */
|
||||
#include "H5Dprivate.h" /* Datasets */
|
||||
@@ -25,7 +35,7 @@
|
||||
#include "H5Oprivate.h" /* Object headers */
|
||||
#include "H5Pprivate.h" /* Property lists */
|
||||
#include "H5Tprivate.h" /* Datatypes */
|
||||
#include "H5VLprivate.h" /* Virtual Object Layer */
|
||||
#include "H5VLpkg.h" /* Virtual Object Layer */
|
||||
|
||||
#include "H5VLnative_private.h" /* Native VOL connector */
|
||||
|
||||
@@ -37,9 +47,10 @@ static herr_t H5VL__native_term(void);
|
||||
|
||||
/* Native VOL connector class struct */
|
||||
static const H5VL_class_t H5VL_native_cls_g = {
|
||||
H5VL_NATIVE_VERSION, /* version */
|
||||
H5VL_VERSION, /* VOL class struct version */
|
||||
H5VL_NATIVE_VALUE, /* value */
|
||||
H5VL_NATIVE_NAME, /* name */
|
||||
H5VL_NATIVE_VERSION, /* connector version */
|
||||
0, /* capability flags */
|
||||
NULL, /* initialize */
|
||||
H5VL__native_term, /* terminate */
|
||||
@@ -176,7 +187,7 @@ H5VL_native_register(void)
|
||||
/* Register the native VOL connector, if it isn't already */
|
||||
if (H5I_INVALID_HID == H5VL_NATIVE_ID_g)
|
||||
if ((H5VL_NATIVE_ID_g =
|
||||
H5VL_register_connector(&H5VL_native_cls_g, TRUE, H5P_VOL_INITIALIZE_DEFAULT)) < 0)
|
||||
H5VL__register_connector(&H5VL_native_cls_g, TRUE, H5P_VOL_INITIALIZE_DEFAULT)) < 0)
|
||||
HGOTO_ERROR(H5E_VOL, H5E_CANTINSERT, H5I_INVALID_HID, "can't create ID for native VOL connector")
|
||||
|
||||
/* Set return value */
|
||||
|
||||
@@ -263,9 +263,10 @@ static herr_t H5VL_pass_through_optional(void *obj, int op_type, hid_t dxpl_id,
|
||||
|
||||
/* Pass through VOL connector class struct */
|
||||
static const H5VL_class_t H5VL_pass_through_g = {
|
||||
H5VL_PASSTHRU_VERSION, /* version */
|
||||
H5VL_VERSION, /* VOL class struct version */
|
||||
(H5VL_class_value_t)H5VL_PASSTHRU_VALUE, /* value */
|
||||
H5VL_PASSTHRU_NAME, /* name */
|
||||
H5VL_PASSTHRU_VERSION, /* connector version */
|
||||
0, /* capability flags */
|
||||
H5VL_pass_through_init, /* initialize */
|
||||
H5VL_pass_through_term, /* terminate */
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
/******************************/
|
||||
/* Package Private Prototypes */
|
||||
/******************************/
|
||||
H5_DLL hid_t H5VL__register_connector(const H5VL_class_t *cls, hbool_t app_ref, hid_t vipl_id);
|
||||
H5_DLL hid_t H5VL__register_connector(const void *cls, hbool_t app_ref, hid_t vipl_id);
|
||||
H5_DLL hid_t H5VL__register_connector_by_class(const H5VL_class_t *cls, hbool_t app_ref, hid_t vipl_id);
|
||||
H5_DLL hid_t H5VL__register_connector_by_name(const char *name, hbool_t app_ref, hid_t vipl_id);
|
||||
H5_DLL hid_t H5VL__register_connector_by_value(H5VL_class_value_t value, hbool_t app_ref, hid_t vipl_id);
|
||||
H5_DLL htri_t H5VL__is_connector_registered_by_name(const char *name);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#define _H5VLprivate_H
|
||||
|
||||
/* Include package's public header */
|
||||
#include "H5VLpublic.h" /* Generic Functions */
|
||||
#include "H5VLpublic.h" /* Generic Functions */
|
||||
|
||||
/* Private headers needed by this file */
|
||||
|
||||
@@ -67,7 +67,8 @@ H5_DLL herr_t H5VL_conn_copy(H5VL_connector_prop_t *value);
|
||||
H5_DLL herr_t H5VL_conn_free(const H5VL_connector_prop_t *info);
|
||||
|
||||
/* Functions that deal with VOL connectors */
|
||||
H5_DLL hid_t H5VL_register_connector(const void *cls, hbool_t app_ref, hid_t vipl_id);
|
||||
union H5PL_key_t;
|
||||
H5_DLL herr_t H5VL_check_plugin_load(const H5VL_class_t *cls, const union H5PL_key_t *key, hbool_t *success);
|
||||
|
||||
/* NOTE: The object and ID functions below deal in VOL objects (i.e.;
|
||||
* H5VL_object_t). Similar non-VOL calls exist in H5Iprivate.h. Use
|
||||
|
||||
@@ -25,6 +25,17 @@
|
||||
/* Public Macros */
|
||||
/*****************/
|
||||
|
||||
/**
|
||||
* \ingroup H5VLDEF
|
||||
* \brief Version # of VOL class struct & callbacks
|
||||
*
|
||||
* \details Each VOL connector must set the 'version' field in the H5VL_class_t
|
||||
* struct to the version of the H5VL_class_t struct that the connector
|
||||
* implements. The HDF5 library will reject connectors with
|
||||
* incompatible structs.
|
||||
*/
|
||||
#define H5VL_VERSION 1
|
||||
|
||||
/* VOL connector identifier values
|
||||
* These are H5VL_class_value_t values, NOT hid_t values!
|
||||
*/
|
||||
|
||||
@@ -2040,6 +2040,7 @@ h5_get_dummy_vol_class(void)
|
||||
/* Fill in the minimum parameters to make a VOL connector class that
|
||||
* can be registered.
|
||||
*/
|
||||
vol_class->version = H5VL_VERSION;
|
||||
vol_class->name = "dummy";
|
||||
|
||||
return vol_class;
|
||||
|
||||
@@ -26,9 +26,10 @@
|
||||
|
||||
/* The VOL class struct */
|
||||
static const H5VL_class_t null_vol_g = {
|
||||
0, /* version */
|
||||
H5VL_VERSION, /* VOL class struct version */
|
||||
NULL_VOL_CONNECTOR_VALUE, /* value */
|
||||
NULL_VOL_CONNECTOR_NAME, /* name */
|
||||
0, /* connector version */
|
||||
0, /* capability flags */
|
||||
NULL, /* initialize */
|
||||
NULL, /* terminate */
|
||||
|
||||
22
test/vol.c
22
test/vol.c
@@ -42,9 +42,10 @@ const char *FILENAME[] = {"native_vol_test", NULL};
|
||||
* functionality.
|
||||
*/
|
||||
static const H5VL_class_t fake_vol_g = {
|
||||
0, /* version */
|
||||
H5VL_VERSION, /* VOL class struct version */
|
||||
FAKE_VOL_VALUE, /* value */
|
||||
FAKE_VOL_NAME, /* name */
|
||||
0, /* connector version */
|
||||
0, /* capability flags */
|
||||
NULL, /* initialize */
|
||||
NULL, /* terminate */
|
||||
@@ -181,6 +182,7 @@ test_vol_registration(void)
|
||||
htri_t is_registered = FAIL;
|
||||
hid_t vol_id = H5I_INVALID_HID;
|
||||
hid_t vol_id2 = H5I_INVALID_HID;
|
||||
H5VL_class_t *bad_fake_vol_class = NULL;
|
||||
|
||||
TESTING("VOL registration");
|
||||
|
||||
@@ -204,6 +206,19 @@ test_vol_registration(void)
|
||||
if (H5Pclose(lapl_id) < 0)
|
||||
TEST_ERROR;
|
||||
|
||||
/* Test registering a VOL connector with an incompatible version # */
|
||||
if (NULL == (bad_fake_vol_class = HDmalloc(sizeof(H5VL_class_t))))
|
||||
TEST_ERROR;
|
||||
HDmemcpy(bad_fake_vol_class, &fake_vol_g, sizeof(H5VL_class_t));
|
||||
bad_fake_vol_class->version = H5VL_VERSION + 1;
|
||||
H5E_BEGIN_TRY {
|
||||
vol_id = H5VLregister_connector(bad_fake_vol_class, H5P_DEFAULT);
|
||||
} H5E_END_TRY;
|
||||
if (H5I_INVALID_HID != vol_id)
|
||||
FAIL_PUTS_ERROR("should not be able to register a connector with an incompatible version #");
|
||||
HDfree(bad_fake_vol_class);
|
||||
bad_fake_vol_class = NULL;
|
||||
|
||||
/* Load a VOL interface
|
||||
* The vipl_id does nothing without a VOL that needs it, but we do need to
|
||||
* test creating a property list of that class and passing it along as a
|
||||
@@ -277,8 +292,11 @@ error:
|
||||
H5Pclose(vipl_id);
|
||||
}
|
||||
H5E_END_TRY;
|
||||
return FAIL;
|
||||
|
||||
if (bad_fake_vol_class)
|
||||
HDfree(bad_fake_vol_class);
|
||||
|
||||
return FAIL;
|
||||
} /* end test_vol_registration() */
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user