diff --git a/internal/cutil/cutil.go b/internal/cutil/cutil.go new file mode 100644 index 0000000..ae55f86 --- /dev/null +++ b/internal/cutil/cutil.go @@ -0,0 +1,14 @@ +package cutil + +import "unsafe" + +// VoidPtr casts a uintptr value to an unsafe.Pointer value in order to use it +// directly as a void* argument in a C function call. +// CAUTION: NEVER store the result in a variable, or the Go GC could panic. +func VoidPtr(i uintptr) unsafe.Pointer { + var nullPtr unsafe.Pointer + // It's not possible to cast uintptr directly to unsafe.Pointer. Therefore we + // cast a null pointer to uintptr and apply pointer arithmetic on it, which + // allows us to cast it back to unsafe.Pointer. + return unsafe.Pointer(uintptr(nullPtr) + i) +} diff --git a/internal/cutil/cutil_test.go b/internal/cutil/cutil_test.go new file mode 100644 index 0000000..f996c63 --- /dev/null +++ b/internal/cutil/cutil_test.go @@ -0,0 +1,13 @@ +package cutil + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestVoidPtr(t *testing.T) { + i := uintptr(42) + j := uintptr(VoidPtr(i)) + assert.Equal(t, i, j) +} diff --git a/rbd/diff_iterate.go b/rbd/diff_iterate.go index 3a46179..41ab9ef 100644 --- a/rbd/diff_iterate.go +++ b/rbd/diff_iterate.go @@ -7,18 +7,8 @@ package rbd #include #include +typedef int (*diff_iterate_callback_t)(uint64_t, size_t, int, void *); extern int diffIterateCallback(uint64_t, size_t, int, void *); - -// cgo is having trouble converting the callback from the librbd header -// to a unsafe.Pointer. This shim exists solely to help it along. -static inline int wrap_rbd_diff_iterate2( - rbd_image_t image, - const char *fromsnapname, - uint64_t ofs, uint64_t len, - uint8_t include_parent, uint8_t whole_object, - uintptr_t index) { - return rbd_diff_iterate2(image, fromsnapname, ofs, len, include_parent, whole_object, diffIterateCallback, (void*)index); -} */ import "C" @@ -26,6 +16,7 @@ import ( "unsafe" "github.com/ceph/go-ceph/internal/callbacks" + "github.com/ceph/go-ceph/internal/cutil" ) var diffIterateCallbacks = callbacks.New() @@ -110,14 +101,15 @@ func (image *Image) DiffIterate(config DiffIterateConfig) error { cbIndex := diffIterateCallbacks.Add(config) defer diffIterateCallbacks.Remove(cbIndex) - ret := C.wrap_rbd_diff_iterate2( + ret := C.rbd_diff_iterate2( image.image, cSnapName, C.uint64_t(config.Offset), C.uint64_t(config.Length), C.uint8_t(config.IncludeParent), C.uint8_t(config.WholeObject), - C.uintptr_t(cbIndex)) + C.diff_iterate_callback_t(C.diffIterateCallback), + cutil.VoidPtr(cbIndex)) return getError(ret) } diff --git a/rbd/watchers_mimic.go b/rbd/watchers_mimic.go index 7c9a222..96c31af 100644 --- a/rbd/watchers_mimic.go +++ b/rbd/watchers_mimic.go @@ -9,18 +9,6 @@ package rbd #include extern void imageWatchCallback(void *); - -// cgo has trouble converting the types of the callback and data arg defined in -// librbd header. It wants the callback function to be a byte pointer and -// the arg to be a pointer, which is pretty much the opposite of what we -// actually want. This shim exists to help coerce the auto-type-conversion -// to do the right thing for us. -static inline int wrap_rbd_update_watch( - rbd_image_t image, - uint64_t *handle, - uintptr_t index) { - return rbd_update_watch(image, handle, imageWatchCallback, (void*)index); -} */ import "C" @@ -28,6 +16,7 @@ import ( "unsafe" "github.com/ceph/go-ceph/internal/callbacks" + "github.com/ceph/go-ceph/internal/cutil" "github.com/ceph/go-ceph/internal/retry" ) @@ -118,10 +107,11 @@ func (image *Image) UpdateWatch(cb WatchCallback, data interface{}) (*Watch, err cbIndex: watchCallbacks.Add(wcc), } - ret := C.wrap_rbd_update_watch( + ret := C.rbd_update_watch( image.image, &w.handle, - C.uintptr_t(w.cbIndex)) + C.rbd_update_callback_t(C.imageWatchCallback), + cutil.VoidPtr(w.cbIndex)) if ret != 0 { return nil, getError(ret) }