diff --git a/go.mod b/go.mod index 824a30efc..3455636ec 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/aws/aws-sdk-go v1.55.6 github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 github.com/ceph/ceph-csi/api v0.0.0-00010101000000-000000000000 - github.com/ceph/go-ceph v0.32.1-0.20250307053135-38b9676b1d4e + github.com/ceph/go-ceph v0.33.0 github.com/container-storage-interface/spec v1.11.0 github.com/csi-addons/kubernetes-csi-addons v0.12.0 github.com/csi-addons/spec v0.2.1-0.20241104111131-27825f744db5 diff --git a/go.sum b/go.sum index c52328f6d..8bfadf86c 100644 --- a/go.sum +++ b/go.sum @@ -134,8 +134,8 @@ github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4r github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/ceph/go-ceph v0.32.1-0.20250307053135-38b9676b1d4e h1:Ykum5wAFYzyUi+yW0qQFDsbP9pAuRKTOf+ttMoo1jZ4= -github.com/ceph/go-ceph v0.32.1-0.20250307053135-38b9676b1d4e/go.mod h1:bIS41nqhGmD7gQVoSBu3IYCwCiVEMeIxFU5qaqmC4a8= +github.com/ceph/go-ceph v0.33.0 h1:xT9v/MAa+DIBmflyITyFkGRgWngATghGegKJguEOInQ= +github.com/ceph/go-ceph v0.33.0/go.mod h1:6ef0lIyDHnwArykqfWZDWCfbbJAVTXL1tOYrM1M4bAE= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -264,8 +264,8 @@ github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncV github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= -github.com/gofrs/uuid/v5 v5.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk= -github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +github.com/gofrs/uuid/v5 v5.3.2 h1:2jfO8j3XgSwlz/wHqemAEugfnTlikAYHhnqQ8Xh4fE0= +github.com/gofrs/uuid/v5 v5.3.2/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= diff --git a/vendor/github.com/ceph/go-ceph/cephfs/directory.go b/vendor/github.com/ceph/go-ceph/cephfs/directory.go index 5a4e2c40a..6a80ac1ea 100644 --- a/vendor/github.com/ceph/go-ceph/cephfs/directory.go +++ b/vendor/github.com/ceph/go-ceph/cephfs/directory.go @@ -47,7 +47,14 @@ func (mount *MountInfo) OpenDir(path string) (*Directory, error) { // // int ceph_closedir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp); func (dir *Directory) Close() error { - return getError(C.ceph_closedir(dir.mount.mount, dir.dir)) + if dir.dir == nil { + return nil + } + if err := getError(C.ceph_closedir(dir.mount.mount, dir.dir)); err != nil { + return err + } + dir.dir = nil + return nil } // Inode represents an inode number in the file system. @@ -141,6 +148,9 @@ func toDirEntryPlus(de *C.struct_dirent, s C.struct_ceph_statx) *DirEntryPlus { // // int ceph_readdir_r(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, struct dirent *de); func (dir *Directory) ReadDir() (*DirEntry, error) { + if dir.dir == nil { + return nil, errBadFile + } var de C.struct_dirent ret := C.ceph_readdir_r(dir.mount.mount, dir.dir, &de) if ret < 0 { @@ -165,6 +175,9 @@ func (dir *Directory) ReadDir() (*DirEntry, error) { func (dir *Directory) ReadDirPlus( want StatxMask, flags AtFlags) (*DirEntryPlus, error) { + if dir.dir == nil { + return nil, errBadFile + } var ( de C.struct_dirent s C.struct_ceph_statx @@ -193,6 +206,9 @@ func (dir *Directory) ReadDirPlus( // // void ceph_rewinddir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp); func (dir *Directory) RewindDir() { + if dir.dir == nil { + return + } C.ceph_rewinddir(dir.mount.mount, dir.dir) } diff --git a/vendor/github.com/ceph/go-ceph/cephfs/errors.go b/vendor/github.com/ceph/go-ceph/cephfs/errors.go index 5643499ab..7385ae618 100644 --- a/vendor/github.com/ceph/go-ceph/cephfs/errors.go +++ b/vendor/github.com/ceph/go-ceph/cephfs/errors.go @@ -46,4 +46,6 @@ var ( errInvalid = getError(-C.EINVAL) errNameTooLong = getError(-C.ENAMETOOLONG) errRange = getError(-C.ERANGE) + errBadFile = getError(-C.EBADF) + errNotDir = getError(-C.ENOTDIR) ) diff --git a/vendor/github.com/ceph/go-ceph/cephfs/file.go b/vendor/github.com/ceph/go-ceph/cephfs/file.go index 115f63778..f7a8b3264 100644 --- a/vendor/github.com/ceph/go-ceph/cephfs/file.go +++ b/vendor/github.com/ceph/go-ceph/cephfs/file.go @@ -101,6 +101,9 @@ func (f *File) read(buf []byte, offset int64) (int, error) { if err := f.validate(); err != nil { return 0, err } + if len(buf) == 0 { + return 0, nil + } bufptr := (*C.char)(unsafe.Pointer(&buf[0])) ret := C.ceph_read( f.mount.mount, f.fd, bufptr, C.int64_t(len(buf)), C.int64_t(offset)) @@ -178,6 +181,9 @@ func (f *File) write(buf []byte, offset int64) (int, error) { if err := f.validate(); err != nil { return 0, err } + if len(buf) == 0 { + return 0, nil + } bufptr := (*C.char)(unsafe.Pointer(&buf[0])) ret := C.ceph_write( f.mount.mount, f.fd, bufptr, C.int64_t(len(buf)), C.int64_t(offset)) diff --git a/vendor/github.com/ceph/go-ceph/cephfs/fscompat.go b/vendor/github.com/ceph/go-ceph/cephfs/fscompat.go new file mode 100644 index 000000000..84b33906a --- /dev/null +++ b/vendor/github.com/ceph/go-ceph/cephfs/fscompat.go @@ -0,0 +1,408 @@ +//go:build ceph_preview + +package cephfs + +import ( + "errors" + "fmt" + "io" + "io/fs" + "os" + "path" + "strings" + "time" + + "github.com/ceph/go-ceph/internal/log" +) + +var ( + errIsDir = errors.New("is a directory") +) + +// MountWrapper provides a wrapper type that adapts a CephFS Mount into a +// io.FS compatible type. +type MountWrapper struct { + mount *MountInfo + enableTrace bool +} + +type fileWrapper struct { + parent *MountWrapper + file *File + name string +} + +type dirWrapper struct { + parent *MountWrapper + directory *Directory + name string +} + +type dentryWrapper struct { + parent *MountWrapper + de *DirEntryPlus +} + +type infoWrapper struct { + parent *MountWrapper + sx *CephStatx + name string +} + +// Wrap a CephFS Mount object into a new type that is compatible with Go's io.FS +// interface. CephFS Mounts are not compatible with io.FS directly because the +// go-ceph library predates the addition of io.FS to Go as well as the fact that +// go-ceph attempts to provide APIs that match the cephfs libraries first and +// foremost. +func Wrap(mount *MountInfo) *MountWrapper { + wm := &MountWrapper{mount: mount} + debugf(wm, "Wrap", "created") + return wm +} + +/* MountWrapper: +** Implements https://pkg.go.dev/io/fs#FS +** Wraps cephfs.MountInfo + */ + +// SetTracing configures the MountWrapper and objects connected to it for debug +// tracing. True enables tracing and false disables it. A debug logging +// function must also be set using go-ceph's common.log.SetDebugf function. +func (mw *MountWrapper) SetTracing(enable bool) { + mw.enableTrace = enable +} + +// identify the MountWrapper object for logging purposes. +func (mw *MountWrapper) identify() string { + return fmt.Sprintf("MountWrapper<%p>", mw) +} + +// trace returns true if debug tracing is enabled. +func (mw *MountWrapper) trace() bool { + return mw.enableTrace +} + +// Open opens the named file. This may be either a regular file or a directory. +// Directories opened with this function will return object compatible with the +// io.ReadDirFile interface. +func (mw *MountWrapper) Open(name string) (fs.File, error) { + debugf(mw, "Open", "(%v)", name) + // there are a bunch of patterns that fsTetster/testfs looks for that seems + // under-documented. They mainly seem to try and enforce "clean" paths. + // look for them and reject them here because ceph libs won't reject on + // its own + if strings.HasPrefix(name, "/") || + strings.HasSuffix(name, "/.") || + strings.Contains(name, "//") || + strings.Contains(name, "/./") || + strings.Contains(name, "/../") { + return nil, &fs.PathError{Op: "open", Path: name, Err: errInvalid} + } + + d, err := mw.mount.OpenDir(name) + if err == nil { + debugf(mw, "Open", "(%v): dir ok", name) + dw := &dirWrapper{parent: mw, directory: d, name: name} + return dw, nil + } + if !errors.Is(err, errNotDir) { + debugf(mw, "Open", "(%v): dir error: %v", name, err) + return nil, &fs.PathError{Op: "open", Path: name, Err: err} + } + + f, err := mw.mount.Open(name, os.O_RDONLY, 0) + if err == nil { + debugf(mw, "Open", "(%v): file ok", name) + fw := &fileWrapper{parent: mw, file: f, name: name} + return fw, nil + } + debugf(mw, "Open", "(%v): file error: %v", name, err) + return nil, &fs.PathError{Op: "open", Path: name, Err: err} +} + +/* fileWrapper: +** Implements https://pkg.go.dev/io/fs#FS +** Wraps cephfs.File + */ + +func (fw *fileWrapper) Stat() (fs.FileInfo, error) { + debugf(fw, "Stat", "()") + sx, err := fw.file.Fstatx(StatxBasicStats, AtSymlinkNofollow) + if err != nil { + debugf(fw, "Stat", "() -> err:%v", err) + return nil, &fs.PathError{Op: "stat", Path: fw.name, Err: err} + } + debugf(fw, "Stat", "() ok") + return &infoWrapper{fw.parent, sx, path.Base(fw.name)}, nil +} + +func (fw *fileWrapper) Read(b []byte) (int, error) { + debugf(fw, "Read", "(...)") + return fw.file.Read(b) +} + +func (fw *fileWrapper) Close() error { + debugf(fw, "Close", "()") + return fw.file.Close() +} + +func (fw *fileWrapper) identify() string { + return fmt.Sprintf("fileWrapper<%p>[%v]", fw, fw.name) +} + +func (fw *fileWrapper) trace() bool { + return fw.parent.trace() +} + +/* dirWrapper: +** Implements https://pkg.go.dev/io/fs#ReadDirFile +** Wraps cephfs.Directory + */ + +func (dw *dirWrapper) Stat() (fs.FileInfo, error) { + debugf(dw, "Stat", "()") + sx, err := dw.parent.mount.Statx(dw.name, StatxBasicStats, AtSymlinkNofollow) + if err != nil { + debugf(dw, "Stat", "() -> err:%v", err) + return nil, &fs.PathError{Op: "stat", Path: dw.name, Err: err} + } + debugf(dw, "Stat", "() ok") + return &infoWrapper{dw.parent, sx, path.Base(dw.name)}, nil +} + +func (dw *dirWrapper) Read(_ []byte) (int, error) { + debugf(dw, "Read", "(...)") + return 0, &fs.PathError{Op: "read", Path: dw.name, Err: errIsDir} +} + +func (dw *dirWrapper) ReadDir(n int) ([]fs.DirEntry, error) { + debugf(dw, "ReadDir", "(%v)", n) + if n > 0 { + return dw.readDirSome(n) + } + return dw.readDirAll() +} + +const defaultDirReadCount = 256 // how many entries to read per loop + +func (dw *dirWrapper) readDirAll() ([]fs.DirEntry, error) { + debugf(dw, "readDirAll", "()") + var ( + err error + egroup []fs.DirEntry + entries = make([]fs.DirEntry, 0) + size = defaultDirReadCount + ) + for { + egroup, err = dw.readDirSome(size) + entries = append(entries, egroup...) + if err == io.EOF { + err = nil + break + } + if err != nil { + break + } + } + debugf(dw, "readDirAll", "() -> len:%v, err:%v", len(entries), err) + return entries, err +} + +func (dw *dirWrapper) readDirSome(n int) ([]fs.DirEntry, error) { + debugf(dw, "readDirSome", "(%v)", n) + var ( + idx int + err error + entry *DirEntryPlus + entries = make([]fs.DirEntry, n) + ) + for { + entry, err = dw.directory.ReadDirPlus(StatxBasicStats, AtSymlinkNofollow) + debugf(dw, "readDirSome", "(%v): got entry:%v, err:%v", n, entry, err) + if err != nil || entry == nil { + break + } + switch entry.Name() { + case ".", "..": + continue + } + entries[idx] = &dentryWrapper{dw.parent, entry} + idx++ + if idx >= n { + break + } + } + if idx == 0 { + debugf(dw, "readDirSome", "(%v): EOF", n) + return nil, io.EOF + } + debugf(dw, "readDirSome", "(%v): got entry:%v, err:%v", n, entries[:idx], err) + return entries[:idx], err +} + +func (dw *dirWrapper) Close() error { + debugf(dw, "Close", "()") + return dw.directory.Close() +} + +func (dw *dirWrapper) identify() string { + return fmt.Sprintf("dirWrapper<%p>[%v]", dw, dw.name) +} + +func (dw *dirWrapper) trace() bool { + return dw.parent.trace() +} + +/* dentryWrapper: +** Implements https://pkg.go.dev/io/fs#DirEntry +** Wraps cephfs.DirEntryPlus + */ + +func (dew *dentryWrapper) Name() string { + debugf(dew, "Name", "()") + return dew.de.Name() +} + +func (dew *dentryWrapper) IsDir() bool { + v := dew.de.DType() == DTypeDir + debugf(dew, "IsDir", "() -> %v", v) + return v +} + +func (dew *dentryWrapper) Type() fs.FileMode { + m := dew.de.Statx().Mode + v := cephModeToFileMode(m).Type() + debugf(dew, "Type", "() -> %v", v) + return v +} + +func (dew *dentryWrapper) Info() (fs.FileInfo, error) { + debugf(dew, "Info", "()") + sx := dew.de.Statx() + name := dew.de.Name() + return &infoWrapper{dew.parent, sx, name}, nil +} + +func (dew *dentryWrapper) identify() string { + return fmt.Sprintf("dentryWrapper<%p>[%v]", dew, dew.de.Name()) +} + +func (dew *dentryWrapper) trace() bool { + return dew.parent.trace() +} + +/* infoWrapper: +** Implements https://pkg.go.dev/io/fs#FileInfo +** Wraps cephfs.CephStatx + */ + +func (iw *infoWrapper) Name() string { + debugf(iw, "Name", "()") + return iw.name +} + +func (iw *infoWrapper) Size() int64 { + debugf(iw, "Size", "() -> %v", iw.sx.Size) + return int64(iw.sx.Size) +} + +func (iw *infoWrapper) Sys() any { + debugf(iw, "Sys", "()") + return iw.sx +} + +func (iw *infoWrapper) Mode() fs.FileMode { + v := cephModeToFileMode(iw.sx.Mode) + debugf(iw, "Mode", "() -> %#o -> %#o/%v", iw.sx.Mode, uint32(v), v.Type()) + return v +} + +func (iw *infoWrapper) IsDir() bool { + v := iw.sx.Mode&modeIFMT == modeIFDIR + debugf(iw, "IsDir", "() -> %v", v) + return v +} + +func (iw *infoWrapper) ModTime() time.Time { + v := time.Unix(iw.sx.Mtime.Sec, iw.sx.Mtime.Nsec) + debugf(iw, "ModTime", "() -> %v", v) + return v +} + +func (iw *infoWrapper) identify() string { + return fmt.Sprintf("infoWrapper<%p>[%v]", iw, iw.name) +} + +func (iw *infoWrapper) trace() bool { + return iw.parent.trace() +} + +/* copy and paste values from the linux headers. We always need to use +** the linux header values, regardless of the platform go-ceph is built +** for. Rather than jumping through header hoops, copy and paste is +** more consistent and reliable. + */ +const ( + /* file type mask */ + modeIFMT = uint16(0170000) + /* file types */ + modeIFDIR = uint16(0040000) + modeIFCHR = uint16(0020000) + modeIFBLK = uint16(0060000) + modeIFREG = uint16(0100000) + modeIFIFO = uint16(0010000) + modeIFLNK = uint16(0120000) + modeIFSOCK = uint16(0140000) + /* protection bits */ + modeISUID = uint16(0004000) + modeISGID = uint16(0002000) + modeISVTX = uint16(0001000) +) + +// cephModeToFileMode takes a linux compatible cephfs mode value +// and returns a Go-compatiable os-agnostic FileMode value. +func cephModeToFileMode(m uint16) fs.FileMode { + // start with permission bits + mode := fs.FileMode(m & 0777) + // file type - inspired by go's src/os/stat_linux.go + switch m & modeIFMT { + case modeIFBLK: + mode |= fs.ModeDevice + case modeIFCHR: + mode |= fs.ModeDevice | fs.ModeCharDevice + case modeIFDIR: + mode |= fs.ModeDir + case modeIFIFO: + mode |= fs.ModeNamedPipe + case modeIFLNK: + mode |= fs.ModeSymlink + case modeIFREG: + // nothing to do + case modeIFSOCK: + mode |= fs.ModeSocket + } + // protection bits + if m&modeISUID != 0 { + mode |= fs.ModeSetuid + } + if m&modeISGID != 0 { + mode |= fs.ModeSetgid + } + if m&modeISVTX != 0 { + mode |= fs.ModeSticky + } + return mode +} + +// wrapperObject helps identify an object to be logged. +type wrapperObject interface { + identify() string + trace() bool +} + +// debugf formats info about a function and logs it. +func debugf(o wrapperObject, fname, format string, args ...any) { + if o.trace() { + log.Debugf(fmt.Sprintf("%v.%v: %s", o.identify(), fname, format), args...) + } +} diff --git a/vendor/github.com/ceph/go-ceph/rados/rados_getaddrs.go b/vendor/github.com/ceph/go-ceph/rados/rados_getaddrs.go index 093e373d4..8d8599995 100644 --- a/vendor/github.com/ceph/go-ceph/rados/rados_getaddrs.go +++ b/vendor/github.com/ceph/go-ceph/rados/rados_getaddrs.go @@ -1,5 +1,3 @@ -//go:build ceph_preview - package rados // #cgo LDFLAGS: -lrados diff --git a/vendor/github.com/ceph/go-ceph/rbd/diff_iterate_by_id.go b/vendor/github.com/ceph/go-ceph/rbd/diff_iterate_by_id.go new file mode 100644 index 000000000..5edb562e8 --- /dev/null +++ b/vendor/github.com/ceph/go-ceph/rbd/diff_iterate_by_id.go @@ -0,0 +1,127 @@ +//go:build ceph_preview + +package rbd + +/* +#cgo LDFLAGS: -lrbd +#undef _GNU_SOURCE +#include +#include +#include + +#ifndef LIBRBD_SUPPORTS_DIFF_ITERATE3 +#define RBD_DIFF_ITERATE_FLAG_INCLUDE_PARENT (1U<<0) // SHOULD MATCH THE VALUE IN librbd.h +#define RBD_DIFF_ITERATE_FLAG_WHOLE_OBJECT (1U<<1) // SHOULD MATCH THE VALUE IN librbd.h +#endif + +extern int diffIterateByIDCallback(uint64_t, size_t, int, uintptr_t); + +// rbd_diff_iterate3_fn matches the rbd_diff_iterate3 function signature. +typedef int(*rbd_diff_iterate3_fn)(rbd_image_t image, uint64_t from_snap_id, + uint64_t ofs, uint64_t len, uint32_t flags, + int (*cb)(uint64_t, size_t, int, void *), void *arg); + +// rbd_diff_iterate3_dlsym take *fn as rbd_diff_iterate3_fn and calls the dynamically loaded +// rbd_diff_iterate3 function passed as 1st argument. +static inline int rbd_diff_iterate3_dlsym(void *fn, rbd_image_t image, + uint64_t from_snap_id, uint64_t ofs, uint64_t len, uint32_t flags, uintptr_t arg) { + // cast function pointer fn to rbd_diff_iterate3 and call the function + return ((rbd_diff_iterate3_fn) fn)(image, from_snap_id, ofs, len, flags, (void*)diffIterateByIDCallback, (void*)arg); +} +*/ +import "C" + +import ( + "fmt" + "sync" + "unsafe" + + "github.com/ceph/go-ceph/internal/callbacks" + "github.com/ceph/go-ceph/internal/dlsym" +) + +var ( + diffIterateByIDCallbacks = callbacks.New() + diffIterateByIDOnce sync.Once + diffIterateById unsafe.Pointer + diffIterateByIdErr error +) + +// DiffIterateByIDConfig is used to define the parameters of a DiffIterateByID call. +// Callback, Offset, and Length should always be specified when passed to +// DiffIterateByID. The other values are optional. +type DiffIterateByIDConfig struct { + FromSnapID uint64 + Offset uint64 + Length uint64 + IncludeParent DiffIncludeParent + WholeObject DiffWholeObject + Callback DiffIterateCallback + Data interface{} +} + +// DiffIterateByID calls a callback on changed extents of an image. +// +// Calling DiffIterateByID will cause the callback specified in the +// DiffIterateByIDConfig to be called as many times as there are changed +// regions in the image (controlled by the parameters as passed to librbd). +// +// See the documentation of DiffIterateCallback for a description of the +// arguments to the callback and the return behavior. +// +// Implements: +// +// int rbd_diff_iterate3(rbd_image_t image, +// uint64_t from_snap_id, +// uint64_t ofs, uint64_t len, +// uint32_t flags, +// int (*cb)(uint64_t, size_t, int, void *), +// void *arg); +func (image *Image) DiffIterateByID(config DiffIterateByIDConfig) error { + if err := image.validate(imageIsOpen); err != nil { + return err + } + if config.Callback == nil { + return getError(-C.EINVAL) + } + + diffIterateByIDOnce.Do(func() { + diffIterateById, diffIterateByIdErr = dlsym.LookupSymbol("rbd_diff_iterate3") + }) + + if diffIterateByIdErr != nil { + return fmt.Errorf("%w: %w", ErrNotImplemented, diffIterateByIdErr) + } + + cbIndex := diffIterateByIDCallbacks.Add(config) + defer diffIterateByIDCallbacks.Remove(cbIndex) + + flags := C.uint32_t(0) + if config.IncludeParent == IncludeParent { + flags |= C.RBD_DIFF_ITERATE_FLAG_INCLUDE_PARENT + } + if config.WholeObject == EnableWholeObject { + flags |= C.RBD_DIFF_ITERATE_FLAG_WHOLE_OBJECT + } + + ret := C.rbd_diff_iterate3_dlsym( + diffIterateById, + image.image, + C.uint64_t(config.FromSnapID), + C.uint64_t(config.Offset), + C.uint64_t(config.Length), + flags, + C.uintptr_t(cbIndex)) + + return getError(ret) +} + +//export diffIterateByIDCallback +func diffIterateByIDCallback( + offset C.uint64_t, length C.size_t, exists C.int, index uintptr) C.int { + + v := diffIterateByIDCallbacks.Lookup(index) + config := v.(DiffIterateByIDConfig) + return C.int(config.Callback( + uint64(offset), uint64(length), int(exists), config.Data)) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index afd7f52b7..9b919c382 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -196,8 +196,8 @@ github.com/ceph/ceph-csi/api/deploy/kubernetes/cephfs github.com/ceph/ceph-csi/api/deploy/kubernetes/nfs github.com/ceph/ceph-csi/api/deploy/kubernetes/rbd github.com/ceph/ceph-csi/api/deploy/ocp -# github.com/ceph/go-ceph v0.32.1-0.20250307053135-38b9676b1d4e -## explicit; go 1.22 +# github.com/ceph/go-ceph v0.33.0 +## explicit; go 1.23.0 github.com/ceph/go-ceph/cephfs github.com/ceph/go-ceph/cephfs/admin github.com/ceph/go-ceph/common/admin/manager