diff --git a/rbd/group_snap_info.go b/rbd/group_snap_info.go index cb546de..de9c58e 100644 --- a/rbd/group_snap_info.go +++ b/rbd/group_snap_info.go @@ -1,4 +1,4 @@ -//go:build ceph_preview && !(nautilus || octopus || pacific || quincy || reef || squid) +//go:build ceph_preview package rbd @@ -8,17 +8,83 @@ package rbd #include #include +// Types and constants are copied from librbd.h with added "_" as prefix. This +// prevents redefinition of the types on librbd versions that have them +// already. + +typedef enum { + _RBD_GROUP_SNAP_NAMESPACE_TYPE_USER = 0 +} _rbd_group_snap_namespace_type_t; + +typedef struct { + char *image_name; + int64_t pool_id; + uint64_t snap_id; +} _rbd_group_image_snap_info_t; + +typedef struct { + char *id; + char *name; + char *image_snap_name; + rbd_group_snap_state_t state; + _rbd_group_snap_namespace_type_t namespace_type; + size_t image_snaps_count; + _rbd_group_image_snap_info_t *image_snaps; +} _rbd_group_snap_info2_t; + +// rbd_group_snap_get_info_fn matches the rbd_group_snap_get_info function signature. +typedef int(*rbd_group_snap_get_info_fn)(rados_ioctx_t group_p, + const char *group_name, + const char *snap_name, + _rbd_group_snap_info2_t *snaps); + +// rbd_group_snap_get_info_dlsym take *fn as rbd_group_snap_get_info_fn and +// calls the dynamically loaded rbd_group_snap_get_info function passed as 1st +// argument. +static inline int rbd_group_snap_get_info_dlsym(void *fn, + rados_ioctx_t group_p, + const char *group_name, + const char *snap_name, + _rbd_group_snap_info2_t *snaps) { + // cast function pointer fn to rbd_group_snap_get_info and call the function + return ((rbd_group_snap_get_info_fn) fn)(group_p, group_name, snap_name, snaps); +} + +// rbd_group_snap_get_info_cleanup_fn matches the rbd_group_snap_get_info_cleanup function signature. +typedef int(*rbd_group_snap_get_info_cleanup_fn)(_rbd_group_snap_info2_t *snaps); + +// rbd_group_snap_get_info_cleanup_dlsym take *fn as rbd_group_snap_get_info_cleanup_fn and +// calls the dynamically loaded rbd_group_snap_get_info_cleanup function passed as 1st +// argument. +static inline int rbd_group_snap_get_info_cleanup_dlsym(void *fn, + _rbd_group_snap_info2_t *snaps) { + // cast function pointer fn to rbd_group_snap_get_info_cleanup and call the function + return ((rbd_group_snap_get_info_cleanup_fn) fn)(snaps); +} */ import "C" import ( + "fmt" + "sync" "unsafe" "github.com/ceph/go-ceph/internal/cutil" + "github.com/ceph/go-ceph/internal/dlsym" "github.com/ceph/go-ceph/rados" ) -type imgSnapInfoArray [cutil.MaxIdx]C.rbd_group_image_snap_info_t +type imgSnapInfoArray [cutil.MaxIdx]C._rbd_group_image_snap_info_t + +var ( + rbdGroupGetSnapInfoOnce sync.Once + rbdGroupGetSnapInfo unsafe.Pointer + rbdGroupGetSnapInfoErr error + + rbdGroupSnapGetInfoCleanupOnce sync.Once + rbdGroupSnapGetInfoCleanup unsafe.Pointer + rbdGroupSnapGetInfoCleanupErr error +) // GroupSnapGetInfo returns a slice of RBD image snapshots that are part of a // group snapshot. @@ -30,14 +96,31 @@ type imgSnapInfoArray [cutil.MaxIdx]C.rbd_group_image_snap_info_t // const char *snap_name, // rbd_group_snap_info2_t *snaps); func GroupSnapGetInfo(ioctx *rados.IOContext, group, snap string) (GroupSnapInfo, error) { + rbdGroupGetSnapInfoOnce.Do(func() { + rbdGroupGetSnapInfo, rbdGroupGetSnapInfoErr = dlsym.LookupSymbol("rbd_group_snap_get_info") + }) + + if rbdGroupGetSnapInfoErr != nil { + return GroupSnapInfo{}, fmt.Errorf("%w: %w", ErrNotImplemented, rbdGroupGetSnapInfoErr) + } + + rbdGroupSnapGetInfoCleanupOnce.Do(func() { + rbdGroupSnapGetInfoCleanup, rbdGroupSnapGetInfoCleanupErr = dlsym.LookupSymbol("rbd_group_snap_get_info_cleanup") + }) + + if rbdGroupSnapGetInfoCleanupErr != nil { + return GroupSnapInfo{}, fmt.Errorf("%w: %w", ErrNotImplemented, rbdGroupSnapGetInfoCleanupErr) + } + cGroupName := C.CString(group) defer C.free(unsafe.Pointer(cGroupName)) cSnapName := C.CString(snap) defer C.free(unsafe.Pointer(cSnapName)) - cSnapInfo := C.rbd_group_snap_info2_t{} + cSnapInfo := C._rbd_group_snap_info2_t{} - ret := C.rbd_group_snap_get_info( + ret := C.rbd_group_snap_get_info_dlsym( + rbdGroupGetSnapInfo, cephIoctx(ioctx), cGroupName, cSnapName, @@ -66,6 +149,6 @@ func GroupSnapGetInfo(ioctx *rados.IOContext, group, snap string) (GroupSnapInfo } // free C memory allocated by C.rbd_group_snap_get_info call - C.rbd_group_snap_get_info_cleanup(&cSnapInfo) + C.rbd_group_snap_get_info_cleanup_dlsym(rbdGroupSnapGetInfoCleanup, &cSnapInfo) return snapInfo, nil } diff --git a/rbd/group_snap_test.go b/rbd/group_snap_test.go index e64e7a7..1187f18 100644 --- a/rbd/group_snap_test.go +++ b/rbd/group_snap_test.go @@ -1,6 +1,7 @@ package rbd import ( + "errors" "testing" "github.com/stretchr/testify/assert" @@ -113,6 +114,9 @@ func TestGroupSnapshots(t *testing.T) { }() info, err := GroupSnapGetInfo(ioctx, gname, "snapDetails") + if errors.Is(err, ErrNotImplemented) { + t.Skipf("GroupSnapGetInfo is not supported: %v", err) + } assert.NoError(t, err) assert.Equal(t, GroupSnapStateComplete, info.State)