diff --git a/go.mod b/go.mod index 58f4227f8ab..29b0e1bfdd8 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ceph/ceph-csi go 1.13 require ( - github.com/ceph/go-ceph v0.4.0 + github.com/ceph/go-ceph v0.5.0 github.com/container-storage-interface/spec v1.2.0 github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect diff --git a/go.sum b/go.sum index 6849b41b898..a1c0922b85e 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,8 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/ceph/go-ceph v0.4.0 h1:KJsT6j1IbsEtui3ZtDcZO//uZ+IVBNT6KO7u9PuMovE= -github.com/ceph/go-ceph v0.4.0/go.mod h1:wd+keAOqrcsN//20VQnHBGtnBnY0KHl0PA024Ng8HfQ= +github.com/ceph/go-ceph v0.5.0 h1:x5VmFq19Op6DjzWuxAUG3wZZoC3L160Rt6pJOOiRfW0= +github.com/ceph/go-ceph v0.5.0/go.mod h1:wd+keAOqrcsN//20VQnHBGtnBnY0KHl0PA024Ng8HfQ= github.com/cespare/prettybench v0.0.0-20150116022406-03b8cfe5406c/go.mod h1:Xe6ZsFhtM8HrDku0pxJ3/Lr51rwykrzgFwpmTzleatY= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= diff --git a/vendor/github.com/ceph/go-ceph/internal/cutil/splitbuf.go b/vendor/github.com/ceph/go-ceph/internal/cutil/splitbuf.go new file mode 100644 index 00000000000..2f439b09179 --- /dev/null +++ b/vendor/github.com/ceph/go-ceph/internal/cutil/splitbuf.go @@ -0,0 +1,49 @@ +package cutil + +import "C" + +import ( + "bytes" +) + +// SplitBuffer splits a byte-slice buffer, typically returned from C code, +// into a slice of strings. +// The contents of the buffer are assumed to be null-byte separated. +// If the buffer contains a sequence of null-bytes it will assume that the +// "space" between the bytes are meant to be empty strings. +func SplitBuffer(b []byte) []string { + return splitBufStrings(b, true) +} + +// SplitSparseBuffer splits a byte-slice buffer, typically returned from C code, +// into a slice of strings. +// The contents of the buffer are assumed to be null-byte separated. +// This function assumes that buffer to be "sparse" such that only non-null-byte +// strings will be returned, and no "empty" strings exist if null-bytes +// are found adjacent to each other. +func SplitSparseBuffer(b []byte) []string { + return splitBufStrings(b, false) +} + +// If keepEmpty is true, empty substrings will be returned, by default they are +// excluded from the results. +// This is almost certainly a suboptimal implementation, especially for +// keepEmpty=true case. Optimizing the functions is a job for another day. +func splitBufStrings(b []byte, keepEmpty bool) []string { + values := make([]string, 0) + // the final null byte should be the terminating null in C + // we never want to preserve the empty string after it + if len(b) > 0 && b[len(b)-1] == 0 { + b = b[:len(b)-1] + } + if len(b) == 0 { + return values + } + for _, s := range bytes.Split(b, []byte{0}) { + if !keepEmpty && len(s) == 0 { + continue + } + values = append(values, string(s)) + } + return values +} diff --git a/vendor/github.com/ceph/go-ceph/internal/errutil/strerror.go b/vendor/github.com/ceph/go-ceph/internal/errutil/strerror.go index 907c70213e0..2fb24cbc599 100644 --- a/vendor/github.com/ceph/go-ceph/internal/errutil/strerror.go +++ b/vendor/github.com/ceph/go-ceph/internal/errutil/strerror.go @@ -14,6 +14,7 @@ package errutil import "C" import ( + "fmt" "unsafe" ) @@ -37,9 +38,15 @@ func FormatErrno(errno int) (int, string) { return errno, C.GoString((*C.char)(unsafe.Pointer(&buf[0]))) } -// StrError returns a string describing the errno. The string will be empty if -// the errno is not known. -func StrError(errno int) string { - _, s := FormatErrno(errno) - return s +// FormatErrorCode returns a string that describes the supplied error source +// and error code as a string. Suitable to use in Error() methods. If the +// error code maps to an errno the string will contain a description of the +// error. Otherwise the string will only indicate the source and value if the +// value does not map to a known errno. +func FormatErrorCode(source string, errValue int) string { + _, s := FormatErrno(errValue) + if s == "" { + return fmt.Sprintf("%s: ret=%d", source, errValue) + } + return fmt.Sprintf("%s: ret=%d, %s", source, errValue, s) } diff --git a/vendor/github.com/ceph/go-ceph/internal/timespec/timespec.go b/vendor/github.com/ceph/go-ceph/internal/timespec/timespec.go new file mode 100644 index 00000000000..54076e3a3d6 --- /dev/null +++ b/vendor/github.com/ceph/go-ceph/internal/timespec/timespec.go @@ -0,0 +1,30 @@ +package timespec + +/* +#include +*/ +import "C" + +import ( + "unsafe" + + "golang.org/x/sys/unix" +) + +// Timespec behaves similarly to C's struct timespec. +// Timespec is used to retain fidelity to the C based file systems +// apis that could be lossy with the use of Go time types. +type Timespec unix.Timespec + +// CTimespecPtr is an unsafe pointer wrapping C's `struct timespec`. +type CTimespecPtr unsafe.Pointer + +// CStructToTimespec creates a new Timespec for the C 'struct timespec'. +func CStructToTimespec(cts CTimespecPtr) Timespec { + t := (*C.struct_timespec)(cts) + + return Timespec{ + Sec: int64(t.tv_sec), + Nsec: int64(t.tv_nsec), + } +} diff --git a/vendor/github.com/ceph/go-ceph/rados/conn.go b/vendor/github.com/ceph/go-ceph/rados/conn.go index d1040f5792b..a88a81b22d3 100644 --- a/vendor/github.com/ceph/go-ceph/rados/conn.go +++ b/vendor/github.com/ceph/go-ceph/rados/conn.go @@ -6,12 +6,14 @@ package rados import "C" import ( - "bytes" "unsafe" + "github.com/ceph/go-ceph/internal/cutil" "github.com/ceph/go-ceph/internal/retry" ) +var argvPlaceholder = "placeholder" + // ClusterStat represents Ceph cluster statistics. type ClusterStat struct { Kb uint64 @@ -117,14 +119,7 @@ func (c *Conn) ListPools() (names []string, err error) { continue } - tmp := bytes.SplitAfter(buf[:ret-1], []byte{0}) - for _, s := range tmp { - if len(s) > 0 { - name := C.GoString((*C.char)(unsafe.Pointer(&s[0]))) - names = append(names, name) - } - } - + names = cutil.SplitSparseBuffer(buf[:ret]) return names, nil } } @@ -197,28 +192,47 @@ func (c *Conn) GetClusterStats() (stat ClusterStat, err error) { }, nil } -// ParseCmdLineArgs configures the connection from command line arguments. -func (c *Conn) ParseCmdLineArgs(args []string) error { - // add an empty element 0 -- Ceph treats the array as the actual contents - // of argv and skips the first element (the executable name) - argc := C.int(len(args) + 1) - argv := make([]*C.char, argc) - - // make the first element a string just in case it is ever examined - argv[0] = C.CString("placeholder") - defer C.free(unsafe.Pointer(argv[0])) - - for i, arg := range args { - argv[i+1] = C.CString(arg) - defer C.free(unsafe.Pointer(argv[i+1])) +// ParseConfigArgv configures the connection using a unix style command line +// argument vector. +// +// Implements: +// int rados_conf_parse_argv(rados_t cluster, int argc, +// const char **argv); +func (c *Conn) ParseConfigArgv(argv []string) error { + if c.cluster == nil { + return ErrNotConnected + } + if len(argv) == 0 { + return ErrEmptyArgument + } + cargv := make([]*C.char, len(argv)) + for i := range argv { + cargv[i] = C.CString(argv[i]) + defer C.free(unsafe.Pointer(cargv[i])) } - ret := C.rados_conf_parse_argv(c.cluster, argc, &argv[0]) + ret := C.rados_conf_parse_argv(c.cluster, C.int(len(cargv)), &cargv[0]) return getError(ret) } +// ParseCmdLineArgs configures the connection from command line arguments. +// +// This function passes a placeholder value to Ceph as argv[0], see +// ParseConfigArgv for a version of this function that allows the caller to +// specify argv[0]. +func (c *Conn) ParseCmdLineArgs(args []string) error { + argv := make([]string, len(args)+1) + // Ceph expects a proper argv array as the actual contents with the + // first element containing the executable name + argv[0] = argvPlaceholder + for i := range args { + argv[i+1] = args[i] + } + return c.ParseConfigArgv(argv) +} + // ParseDefaultConfigEnv configures the connection from the default Ceph -// environment variable(s). +// environment variable CEPH_ARGS. func (c *Conn) ParseDefaultConfigEnv() error { ret := C.rados_conf_parse_env(c.cluster, nil) return getError(ret) @@ -273,7 +287,7 @@ func (c *Conn) GetPoolByName(name string) (int64, error) { defer C.free(unsafe.Pointer(c_name)) ret := int64(C.rados_pool_lookup(c.cluster, c_name)) if ret < 0 { - return 0, RadosError(ret) + return 0, radosError(ret) } return ret, nil } @@ -287,7 +301,7 @@ func (c *Conn) GetPoolByID(id int64) (string, error) { c_id := C.int64_t(id) ret := int(C.rados_pool_reverse_lookup(c.cluster, c_id, (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)))) if ret < 0 { - return "", RadosError(ret) + return "", radosError(ret) } return C.GoString((*C.char)(unsafe.Pointer(&buf[0]))), nil } diff --git a/vendor/github.com/ceph/go-ceph/rados/errors.go b/vendor/github.com/ceph/go-ceph/rados/errors.go index 3cd5f007d43..6039d120302 100644 --- a/vendor/github.com/ceph/go-ceph/rados/errors.go +++ b/vendor/github.com/ceph/go-ceph/rados/errors.go @@ -7,32 +7,27 @@ import "C" import ( "errors" - "fmt" "github.com/ceph/go-ceph/internal/errutil" ) -// revive:disable:exported Temporarily live with stuttering +// radosError represents an error condition returned from the Ceph RADOS APIs. +type radosError int -// RadosError represents an error condition returned from the Ceph RADOS APIs. -type RadosError int - -// revive:enable:exported +// Error returns the error string for the radosError type. +func (e radosError) Error() string { + return errutil.FormatErrorCode("rados", int(e)) +} -// Error returns the error string for the RadosError type. -func (e RadosError) Error() string { - errno, s := errutil.FormatErrno(int(e)) - if s == "" { - return fmt.Sprintf("rados: ret=%d", errno) - } - return fmt.Sprintf("rados: ret=%d, %s", errno, s) +func (e radosError) ErrorCode() int { + return int(e) } func getError(e C.int) error { if e == 0 { return nil } - return RadosError(e) + return radosError(e) } // getErrorIfNegative converts a ceph return code to error if negative. @@ -48,19 +43,26 @@ func getErrorIfNegative(ret C.int) error { // Public go errors: var ( - // ErrNotConnected is returned when functions are called without a RADOS connection + // ErrNotConnected is returned when functions are called + // without a RADOS connection. ErrNotConnected = errors.New("RADOS not connected") + // ErrEmptyArgument may be returned if a function argument is passed + // a zero-length slice or map. + ErrEmptyArgument = errors.New("Argument must contain at least one item") + // ErrInvalidIOContext may be returned if an api call requires an IOContext + // but IOContext is not ready for use. + ErrInvalidIOContext = errors.New("IOContext is not ready for use") ) -// Public RadosErrors: +// Public radosErrors: const ( // ErrNotFound indicates a missing resource. - ErrNotFound = RadosError(-C.ENOENT) + ErrNotFound = radosError(-C.ENOENT) // ErrPermissionDenied indicates a permissions issue. - ErrPermissionDenied = RadosError(-C.EPERM) + ErrPermissionDenied = radosError(-C.EPERM) // ErrObjectExists indicates that an exclusive object creation failed. - ErrObjectExists = RadosError(-C.EEXIST) + ErrObjectExists = radosError(-C.EEXIST) // RadosErrorNotFound indicates a missing resource. // @@ -75,7 +77,7 @@ const ( // Private errors: const ( - errNameTooLong = RadosError(-C.ENAMETOOLONG) + errNameTooLong = radosError(-C.ENAMETOOLONG) - errRange = RadosError(-C.ERANGE) + errRange = radosError(-C.ERANGE) ) diff --git a/vendor/github.com/ceph/go-ceph/rados/ioctx.go b/vendor/github.com/ceph/go-ceph/rados/ioctx.go index b0663cc586f..26519d61889 100644 --- a/vendor/github.com/ceph/go-ceph/rados/ioctx.go +++ b/vendor/github.com/ceph/go-ceph/rados/ioctx.go @@ -92,6 +92,15 @@ type IOContext struct { ioctx C.rados_ioctx_t } +// validate returns an error if the ioctx is not ready to be used +// with ceph C calls. +func (ioctx *IOContext) validate() error { + if ioctx.ioctx == nil { + return ErrInvalidIOContext + } + return nil +} + // Pointer returns a pointer reference to an internal structure. // This function should NOT be used outside of go-ceph itself. func (ioctx *IOContext) Pointer() unsafe.Pointer { @@ -249,6 +258,15 @@ func (ioctx *IOContext) GetPoolStats() (stat PoolStat, err error) { }, nil } +// GetPoolID returns the pool ID associated with the I/O context. +// +// Implements: +// int64_t rados_ioctx_get_id(rados_ioctx_t io) +func (ioctx *IOContext) GetPoolID() int64 { + ret := C.rados_ioctx_get_id(ioctx.ioctx) + return int64(ret) +} + // GetPoolName returns the name of the pool associated with the I/O context. func (ioctx *IOContext) GetPoolName() (name string, err error) { var ( @@ -589,7 +607,7 @@ func (ioctx *IOContext) ListLockers(oid, name string) (*LockInfo, error) { } if ret < 0 { - return nil, RadosError(ret) + return nil, radosError(ret) } return &LockInfo{int(ret), c_exclusive == 1, C.GoString(c_tag), splitCString(c_clients, c_clients_len), splitCString(c_cookies, c_cookies_len), splitCString(c_addrs, c_addrs_len)}, nil } @@ -628,3 +646,16 @@ func (ioctx *IOContext) BreakLock(oid, name, client, cookie string) (int, error) return int(ret), getError(ret) } } + +// GetLastVersion will return the version number of the last object read or +// written to. +// +// Implements: +// uint64_t rados_get_last_version(rados_ioctx_t io); +func (ioctx *IOContext) GetLastVersion() (uint64, error) { + if err := ioctx.validate(); err != nil { + return 0, err + } + v := C.rados_get_last_version(ioctx.ioctx) + return uint64(v), nil +} diff --git a/vendor/github.com/ceph/go-ceph/rados/snapshot.go b/vendor/github.com/ceph/go-ceph/rados/snapshot.go new file mode 100644 index 00000000000..db4d145ff77 --- /dev/null +++ b/vendor/github.com/ceph/go-ceph/rados/snapshot.go @@ -0,0 +1,189 @@ +package rados + +// #cgo LDFLAGS: -lrados +// #include +// #include +import "C" + +import ( + "time" + "unsafe" + + "github.com/ceph/go-ceph/internal/retry" +) + +// CreateSnap creates a pool-wide snapshot. +// +// Implements: +// int rados_ioctx_snap_create(rados_ioctx_t io, const char *snapname) +func (ioctx *IOContext) CreateSnap(snapName string) error { + if err := ioctx.validate(); err != nil { + return err + } + + cSnapName := C.CString(snapName) + defer C.free(unsafe.Pointer(cSnapName)) + + ret := C.rados_ioctx_snap_create(ioctx.ioctx, cSnapName) + return getError(ret) +} + +// RemoveSnap deletes the pool snapshot. +// +// Implements: +// int rados_ioctx_snap_remove(rados_ioctx_t io, const char *snapname) +func (ioctx *IOContext) RemoveSnap(snapName string) error { + if err := ioctx.validate(); err != nil { + return err + } + + cSnapName := C.CString(snapName) + defer C.free(unsafe.Pointer(cSnapName)) + + ret := C.rados_ioctx_snap_remove(ioctx.ioctx, cSnapName) + return getError(ret) +} + +// SnapID represents the ID of a rados snapshot. +type SnapID C.rados_snap_t + +// LookupSnap returns the ID of a pool snapshot. +// +// Implements: +// int rados_ioctx_snap_lookup(rados_ioctx_t io, const char *name, rados_snap_t *id) +func (ioctx *IOContext) LookupSnap(snapName string) (SnapID, error) { + var snapID SnapID + + if err := ioctx.validate(); err != nil { + return snapID, err + } + + cSnapName := C.CString(snapName) + defer C.free(unsafe.Pointer(cSnapName)) + + ret := C.rados_ioctx_snap_lookup( + ioctx.ioctx, + cSnapName, + (*C.rados_snap_t)(&snapID)) + return snapID, getError(ret) +} + +// GetSnapName returns the name of a pool snapshot with the given snapshot ID. +// +// Implements: +// int rados_ioctx_snap_get_name(rados_ioctx_t io, rados_snap_t id, char *name, int maxlen) +func (ioctx *IOContext) GetSnapName(snapID SnapID) (string, error) { + if err := ioctx.validate(); err != nil { + return "", err + } + + var ( + buf []byte + err error + ) + // range from 1k to 64KiB + retry.WithSizes(1024, 1<<16, func(len int) retry.Hint { + cLen := C.int(len) + buf = make([]byte, cLen) + ret := C.rados_ioctx_snap_get_name( + ioctx.ioctx, + (C.rados_snap_t)(snapID), + (*C.char)(unsafe.Pointer(&buf[0])), + cLen) + err = getError(ret) + return retry.Size(int(cLen)).If(err == errRange) + }) + + if err != nil { + return "", err + } + return C.GoString((*C.char)(unsafe.Pointer(&buf[0]))), nil +} + +// GetSnapStamp returns the time of the pool snapshot creation. +// +// Implements: +// int rados_ioctx_snap_get_stamp(rados_ioctx_t io, rados_snap_t id, time_t *t) +func (ioctx *IOContext) GetSnapStamp(snapID SnapID) (time.Time, error) { + var cTime C.time_t + + if err := ioctx.validate(); err != nil { + return time.Unix(int64(cTime), 0), err + } + + ret := C.rados_ioctx_snap_get_stamp( + ioctx.ioctx, + (C.rados_snap_t)(snapID), + &cTime) + return time.Unix(int64(cTime), 0), getError(ret) +} + +// ListSnaps returns a slice containing the SnapIDs of existing pool snapshots. +// +// Implements: +// int rados_ioctx_snap_list(rados_ioctx_t io, rados_snap_t *snaps, int maxlen) +func (ioctx *IOContext) ListSnaps() ([]SnapID, error) { + if err := ioctx.validate(); err != nil { + return nil, err + } + + var ( + snapList []SnapID + cLen C.int + err error + ret C.int + ) + retry.WithSizes(100, 1000, func(maxlen int) retry.Hint { + cLen = C.int(maxlen) + snapList = make([]SnapID, cLen) + ret = C.rados_ioctx_snap_list( + ioctx.ioctx, + (*C.rados_snap_t)(unsafe.Pointer(&snapList[0])), + cLen) + err = getErrorIfNegative(ret) + return retry.Size(int(cLen)).If(err == errRange) + }) + + if err != nil { + return nil, err + } + return snapList[:ret], nil +} + +// RollbackSnap rollbacks the object with key oID to the pool snapshot. +// The contents of the object will be the same as when the snapshot was taken. +// +// Implements: +// int rados_ioctx_snap_rollback(rados_ioctx_t io, const char *oid, const char *snapname); +func (ioctx *IOContext) RollbackSnap(oid, snapName string) error { + if err := ioctx.validate(); err != nil { + return err + } + + coid := C.CString(oid) + defer C.free(unsafe.Pointer(coid)) + cSnapName := C.CString(snapName) + defer C.free(unsafe.Pointer(cSnapName)) + + ret := C.rados_ioctx_snap_rollback(ioctx.ioctx, coid, cSnapName) + return getError(ret) +} + +// SnapHead is the representation of LIBRADOS_SNAP_HEAD from librados. +// SnapHead can be used to reset the IOContext to stop reading from a snapshot. +const SnapHead = SnapID(C.LIBRADOS_SNAP_HEAD) + +// SetReadSnap sets the snapshot from which reads are performed. +// Subsequent reads will return data as it was at the time of that snapshot. +// Pass SnapHead for no snapshot (i.e. normal operation). +// +// Implements: +// void rados_ioctx_snap_set_read(rados_ioctx_t io, rados_snap_t snap); +func (ioctx *IOContext) SetReadSnap(snapID SnapID) error { + if err := ioctx.validate(); err != nil { + return err + } + + C.rados_ioctx_snap_set_read(ioctx.ioctx, (C.rados_snap_t)(snapID)) + return nil +} diff --git a/vendor/github.com/ceph/go-ceph/rbd/callback_shims.go b/vendor/github.com/ceph/go-ceph/rbd/callback_shims.go deleted file mode 100644 index ab040e7dccb..00000000000 --- a/vendor/github.com/ceph/go-ceph/rbd/callback_shims.go +++ /dev/null @@ -1,13 +0,0 @@ -package rbd - -/* - -#include - -extern int diffIterateCallback(uint64_t ofs, size_t len, int exists, int index); - -int callDiffIterateCallback(uint64_t ofs, size_t len, int exists, int index) { - return diffIterateCallback(ofs, len, exists, index); -} -*/ -import "C" diff --git a/vendor/github.com/ceph/go-ceph/rbd/diff_iterate.go b/vendor/github.com/ceph/go-ceph/rbd/diff_iterate.go index 20cf9c4351e..b8fcadc798b 100644 --- a/vendor/github.com/ceph/go-ceph/rbd/diff_iterate.go +++ b/vendor/github.com/ceph/go-ceph/rbd/diff_iterate.go @@ -7,7 +7,7 @@ package rbd #include #include -extern int callDiffIterateCallback(uint64_t ofs, size_t len, int exists, int index); +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. @@ -16,9 +16,8 @@ static inline int wrap_rbd_diff_iterate2( const char *fromsnapname, uint64_t ofs, uint64_t len, uint8_t include_parent, uint8_t whole_object, - void *cb, - uintptr_t arg) { - return rbd_diff_iterate2(image, fromsnapname, ofs, len, include_parent, whole_object, cb, (void*)arg); + uintptr_t index) { + return rbd_diff_iterate2(image, fromsnapname, ofs, len, include_parent, whole_object, diffIterateCallback, (void*)index); } */ import "C" @@ -99,7 +98,7 @@ func (image *Image) DiffIterate(config DiffIterateConfig) error { return err } if config.Callback == nil { - return RBDError(C.EINVAL) + return rbdError(C.EINVAL) } var cSnapName *C.char @@ -118,7 +117,6 @@ func (image *Image) DiffIterate(config DiffIterateConfig) error { C.uint64_t(config.Length), C.uint8_t(config.IncludeParent), C.uint8_t(config.WholeObject), - C.callDiffIterateCallback, C.uintptr_t(cbIndex)) return getError(ret) @@ -126,9 +124,9 @@ func (image *Image) DiffIterate(config DiffIterateConfig) error { //export diffIterateCallback func diffIterateCallback( - offset C.uint64_t, length C.size_t, exists, index C.int) C.int { + offset C.uint64_t, length C.size_t, exists C.int, index unsafe.Pointer) C.int { - v := diffIterateCallbacks.Lookup(int(index)) + v := diffIterateCallbacks.Lookup(int(uintptr(index))) config := v.(DiffIterateConfig) return C.int(config.Callback( uint64(offset), uint64(length), int(exists), config.Data)) diff --git a/vendor/github.com/ceph/go-ceph/rbd/errors.go b/vendor/github.com/ceph/go-ceph/rbd/errors.go index 482d3059afe..5bfc0924840 100644 --- a/vendor/github.com/ceph/go-ceph/rbd/errors.go +++ b/vendor/github.com/ceph/go-ceph/rbd/errors.go @@ -7,24 +7,19 @@ import "C" import ( "errors" - "fmt" "github.com/ceph/go-ceph/internal/errutil" ) -// revive:disable:exported Temporarily live with stuttering +// rbdError represents an error condition returned from the librbd APIs. +type rbdError int -// RBDError represents an error condition returned from the librbd APIs. -type RBDError int - -// revive:enable:exported +func (e rbdError) Error() string { + return errutil.FormatErrorCode("rbd", int(e)) +} -func (e RBDError) Error() string { - errno, s := errutil.FormatErrno(int(e)) - if s == "" { - return fmt.Sprintf("rbd: ret=%d", errno) - } - return fmt.Sprintf("rbd: ret=%d, %s", errno, s) +func (e rbdError) ErrorCode() int { + return int(e) } func getError(err C.int) error { @@ -32,7 +27,7 @@ func getError(err C.int) error { if err == -C.ENOENT { return ErrNotFound } - return RBDError(err) + return rbdError(err) } return nil } @@ -79,5 +74,5 @@ var ( // Private errors: const ( - errRange = RBDError(-C.ERANGE) + errRange = rbdError(-C.ERANGE) ) diff --git a/vendor/github.com/ceph/go-ceph/rbd/features.go b/vendor/github.com/ceph/go-ceph/rbd/features.go index 44f845bb73e..363bda40155 100644 --- a/vendor/github.com/ceph/go-ceph/rbd/features.go +++ b/vendor/github.com/ceph/go-ceph/rbd/features.go @@ -152,7 +152,7 @@ func (image *Image) GetFeatures() (features uint64, err error) { } if ret := C.rbd_get_features(image.image, (*C.uint64_t)(&features)); ret < 0 { - return 0, RBDError(ret) + return 0, rbdError(ret) } return features, nil diff --git a/vendor/github.com/ceph/go-ceph/rbd/namespace_nautilus.go b/vendor/github.com/ceph/go-ceph/rbd/namespace_nautilus.go index fb78a9a3d6a..5b0e2018f73 100644 --- a/vendor/github.com/ceph/go-ceph/rbd/namespace_nautilus.go +++ b/vendor/github.com/ceph/go-ceph/rbd/namespace_nautilus.go @@ -13,9 +13,9 @@ package rbd import "C" import ( - "bytes" "unsafe" + "github.com/ceph/go-ceph/internal/cutil" "github.com/ceph/go-ceph/internal/retry" "github.com/ceph/go-ceph/rados" ) @@ -100,12 +100,7 @@ func NamespaceList(ioctx *rados.IOContext) (names []string, err error) { if err != nil { return nil, err } - tmpList := bytes.Split(buf[:cSize-1], []byte{0}) - for _, s := range tmpList { - if len(s) > 0 { - name := C.GoString((*C.char)(unsafe.Pointer(&s[0]))) - names = append(names, name) - } - } + + names = cutil.SplitSparseBuffer(buf[:cSize]) return names, nil } diff --git a/vendor/github.com/ceph/go-ceph/rbd/options_mimic.go b/vendor/github.com/ceph/go-ceph/rbd/options_mimic.go index 5ea1c5b2d7d..94f05bb3e29 100644 --- a/vendor/github.com/ceph/go-ceph/rbd/options_mimic.go +++ b/vendor/github.com/ceph/go-ceph/rbd/options_mimic.go @@ -9,4 +9,8 @@ const ( // ImageOptionFlatten is the representation of RBD_IMAGE_OPTION_FLATTEN // from librbd ImageOptionFlatten = C.RBD_IMAGE_OPTION_FLATTEN + + // ImageOptionCloneFormat is the representation of + // RBD_IMAGE_OPTION_CLONE_FORMAT from librbd + ImageOptionCloneFormat = C.RBD_IMAGE_OPTION_CLONE_FORMAT ) diff --git a/vendor/github.com/ceph/go-ceph/rbd/options_nautilus.go b/vendor/github.com/ceph/go-ceph/rbd/options_nautilus.go deleted file mode 100644 index e1d13c297c0..00000000000 --- a/vendor/github.com/ceph/go-ceph/rbd/options_nautilus.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build !luminous,!mimic - -package rbd - -// #include -import "C" - -const ( - // ImageOptionCloneFormat is the representation of - // RBD_IMAGE_OPTION_CLONE_FORMAT from librbd - ImageOptionCloneFormat = C.RBD_IMAGE_OPTION_CLONE_FORMAT -) diff --git a/vendor/github.com/ceph/go-ceph/rbd/pool_nautilus.go b/vendor/github.com/ceph/go-ceph/rbd/pool_nautilus.go index d436064d938..8fd18acb20e 100644 --- a/vendor/github.com/ceph/go-ceph/rbd/pool_nautilus.go +++ b/vendor/github.com/ceph/go-ceph/rbd/pool_nautilus.go @@ -84,3 +84,134 @@ func RemovePoolMetadata(ioctx *rados.IOContext, key string) error { ret := C.rbd_pool_metadata_remove(cephIoctx(ioctx), cKey) return getError(ret) } + +// PoolInit initializes a pool for use by rbd. +// This function does not create new pools, rather it prepares the pool +// to host rbd images. +// +// Implements: +// int rbd_pool_init(rados_ioctx_t io, bool force) +func PoolInit(ioctx *rados.IOContext, force bool) error { + if ioctx == nil { + return ErrNoIOContext + } + + ret := C.rbd_pool_init(cephIoctx(ioctx), C.bool(force)) + return getError(ret) +} + +// poolStats represents RBD pool stats variable. +type poolStats struct { + stats C.rbd_pool_stats_t +} + +// poolStatsCreate creates a new poolStats struct. +// +// Implements: +// void rbd_pool_stats_create(rbd_pool_stats_t *stats) +func poolStatsCreate() *poolStats { + poolstats := &poolStats{} + C.rbd_pool_stats_create(&poolstats.stats) + return poolstats +} + +// destroy a poolStats struct and free the associated resources. +// +// Implements: +// void rbd_pool_stats_destroy(rbd_pool_stats_t stats) +func (poolstats *poolStats) destroy() { + C.rbd_pool_stats_destroy(poolstats.stats) + + if poolstats.stats != nil { + poolstats.stats = nil + } +} + +// PoolStatOption represents a group of configurable pool stat options. +type PoolStatOption C.rbd_pool_stat_option_t + +const ( + // PoolStatOptionImages is the representation of + // RBD_POOL_STAT_OPTION_IMAGES from librbd. + PoolStatOptionImages = PoolStatOption(C.RBD_POOL_STAT_OPTION_IMAGES) + // PoolStatOptionImageProvisionedBytes is the representation of + // RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES from librbd. + PoolStatOptionImageProvisionedBytes = PoolStatOption(C.RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES) + // PoolStatOptionImageMaxProvisionedBytes is the representation of + // RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES from librbd. + PoolStatOptionImageMaxProvisionedBytes = PoolStatOption(C.RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES) + // PoolStatOptionImageSnapshots is the representation of + // RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS from librbd. + PoolStatOptionImageSnapshots = PoolStatOption(C.RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS) + // PoolStatOptionTrashImages is the representation of + // RBD_POOL_STAT_OPTION_TRASH_IMAGES from librbd. + PoolStatOptionTrashImages = PoolStatOption(C.RBD_POOL_STAT_OPTION_TRASH_IMAGES) + // PoolStatOptionTrashProvisionedBytes is the representation of + // RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES from librbd. + PoolStatOptionTrashProvisionedBytes = PoolStatOption(C.RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES) + // PoolStatOptionTrashMaxProvisionedBytes is the representation of + // RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES from librbd. + PoolStatOptionTrashMaxProvisionedBytes = PoolStatOption(C.RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES) + // PoolStatOptionTrashSnapshots is the representation of + // RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS from librbd. + PoolStatOptionTrashSnapshots = PoolStatOption(C.RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS) +) + +// addPoolStatOption adds the given PoolStatOption to PoolStats. +// +// Implements: +// int rbd_pool_stats_option_add_uint64(rbd_pool_stats_t stats, int stat_option, uint64_t* stat_val) +func (poolstats *poolStats) addPoolStatOption(option PoolStatOption, val *uint64) error { + ret := C.rbd_pool_stats_option_add_uint64( + poolstats.stats, + C.int(option), + (*C.uint64_t)(val)) + return getError(ret) +} + +// GetAllPoolStats returns a map of all PoolStatOption(s) to their respective values. +// +// Implements: +// int rbd_pool_stats_get(rados_ioctx_t io, rbd_pool_stats_t stats); +func GetAllPoolStats(ioctx *rados.IOContext) (map[PoolStatOption]uint64, error) { + var omap = make(map[PoolStatOption]uint64) + if ioctx == nil { + return omap, ErrNoIOContext + } + + poolstats := poolStatsCreate() + defer func() { + poolstats.destroy() + }() + + var keys [8]PoolStatOption + + keys[0] = PoolStatOptionImages + keys[1] = PoolStatOptionImageProvisionedBytes + keys[2] = PoolStatOptionImageMaxProvisionedBytes + keys[3] = PoolStatOptionImageSnapshots + keys[4] = PoolStatOptionTrashImages + keys[5] = PoolStatOptionTrashProvisionedBytes + keys[6] = PoolStatOptionTrashMaxProvisionedBytes + keys[7] = PoolStatOptionTrashSnapshots + + ovalArray := make([]uint64, len(keys)) + + // add option with the address where the respective value would be stored. + for i, key := range keys { + err := poolstats.addPoolStatOption(key, &ovalArray[i]) + if err != nil { + return omap, err + } + } + + ret := C.rbd_pool_stats_get(cephIoctx(ioctx), poolstats.stats) + if ret < 0 { + return omap, getError(ret) + } + + for j, key := range keys { + omap[key] = ovalArray[j] + } + return omap, nil +} diff --git a/vendor/github.com/ceph/go-ceph/rbd/rbd.go b/vendor/github.com/ceph/go-ceph/rbd/rbd.go index 76cc5be8ecb..b5f0648dbf1 100644 --- a/vendor/github.com/ceph/go-ceph/rbd/rbd.go +++ b/vendor/github.com/ceph/go-ceph/rbd/rbd.go @@ -11,13 +11,14 @@ package rbd import "C" import ( - "bytes" "errors" "io" "time" "unsafe" + "github.com/ceph/go-ceph/internal/cutil" "github.com/ceph/go-ceph/internal/retry" + ts "github.com/ceph/go-ceph/internal/timespec" "github.com/ceph/go-ceph/rados" ) @@ -45,6 +46,9 @@ const ( NoSnapshot = "" ) +// Timespec is a public type for the internal C 'struct timespec' +type Timespec ts.Timespec + // ImageInfo represents the status information for an image. type ImageInfo struct { Size uint64 @@ -52,8 +56,6 @@ type ImageInfo struct { Num_objs uint64 Order int Block_name_prefix string - Parent_pool int64 - Parent_name string } // SnapInfo represents the status information for a snapshot. @@ -91,18 +93,6 @@ type TrashInfo struct { DefermentEndTime time.Time // Date / time after which the trashed RBD may be permanently deleted. } -// -func split(buf []byte) (values []string) { - tmp := bytes.Split(buf[:len(buf)-1], []byte{0}) - for _, s := range tmp { - if len(s) > 0 { - go_s := C.GoString((*C.char)(unsafe.Pointer(&s[0]))) - values = append(values, go_s) - } - } - return values -} - // cephIoctx returns a ceph rados_ioctx_t given a go-ceph rados IOContext. func cephIoctx(radosIoctx *rados.IOContext) C.rados_ioctx_t { return C.rados_ioctx_t(radosIoctx.Pointer()) @@ -178,7 +168,7 @@ func Create(ioctx *rados.IOContext, name string, size uint64, order int, } if ret < 0 { - return nil, RBDError(ret) + return nil, rbdError(ret) } return &Image{ @@ -204,7 +194,7 @@ func Create2(ioctx *rados.IOContext, name string, size uint64, features uint64, ret = C.rbd_create2(cephIoctx(ioctx), c_name, C.uint64_t(size), C.uint64_t(features), &c_order) if ret < 0 { - return nil, RBDError(ret) + return nil, rbdError(ret) } return &Image{ @@ -233,7 +223,7 @@ func Create3(ioctx *rados.IOContext, name string, size uint64, features uint64, C.uint64_t(size), C.uint64_t(features), &c_order, C.uint64_t(stripe_unit), C.uint64_t(stripe_count)) if ret < 0 { - return nil, RBDError(ret) + return nil, rbdError(ret) } return &Image{ @@ -267,7 +257,7 @@ func (image *Image) Clone(snapname string, c_ioctx *rados.IOContext, c_name stri cephIoctx(c_ioctx), c_c_name, C.uint64_t(features), &c_order) if ret < 0 { - return nil, RBDError(ret) + return nil, rbdError(ret) } return &Image{ @@ -316,7 +306,7 @@ func (image *Image) Rename(destname string) error { defer C.free(unsafe.Pointer(c_srcname)) defer C.free(unsafe.Pointer(c_destname)) - err := RBDError(C.rbd_rename(cephIoctx(image.ioctx), + err := rbdError(C.rbd_rename(cephIoctx(image.ioctx), c_srcname, c_destname)) if err == 0 { image.name = destname @@ -377,7 +367,7 @@ func (image *Image) Close() error { } if ret := C.rbd_close(image.image); ret != 0 { - return RBDError(ret) + return rbdError(ret) } image.image = nil @@ -408,7 +398,7 @@ func (image *Image) Stat() (info *ImageInfo, err error) { var c_stat C.rbd_image_info_t if ret := C.rbd_stat(image.image, &c_stat, C.size_t(unsafe.Sizeof(info))); ret < 0 { - return info, RBDError(ret) + return info, rbdError(ret) } return &ImageInfo{ @@ -416,9 +406,7 @@ func (image *Image) Stat() (info *ImageInfo, err error) { Obj_size: uint64(c_stat.obj_size), Num_objs: uint64(c_stat.num_objs), Order: int(c_stat.order), - Block_name_prefix: C.GoString((*C.char)(&c_stat.block_name_prefix[0])), - Parent_pool: int64(c_stat.parent_pool), - Parent_name: C.GoString((*C.char)(&c_stat.parent_name[0]))}, nil + Block_name_prefix: C.GoString((*C.char)(&c_stat.block_name_prefix[0]))}, nil } // IsOldFormat returns true if the rbd image uses the old format. @@ -434,7 +422,7 @@ func (image *Image) IsOldFormat() (old_format bool, err error) { ret := C.rbd_get_old_format(image.image, &c_old_format) if ret < 0 { - return false, RBDError(ret) + return false, rbdError(ret) } return c_old_format != 0, nil @@ -450,7 +438,7 @@ func (image *Image) GetSize() (size uint64, err error) { } if ret := C.rbd_get_size(image.image, (*C.uint64_t)(&size)); ret < 0 { - return 0, RBDError(ret) + return 0, rbdError(ret) } return size, nil @@ -466,7 +454,7 @@ func (image *Image) GetStripeUnit() (stripe_unit uint64, err error) { } if ret := C.rbd_get_stripe_unit(image.image, (*C.uint64_t)(&stripe_unit)); ret < 0 { - return 0, RBDError(ret) + return 0, rbdError(ret) } return stripe_unit, nil @@ -482,7 +470,7 @@ func (image *Image) GetStripeCount() (stripe_count uint64, err error) { } if ret := C.rbd_get_stripe_count(image.image, (*C.uint64_t)(&stripe_count)); ret < 0 { - return 0, RBDError(ret) + return 0, rbdError(ret) } return stripe_count, nil @@ -499,7 +487,7 @@ func (image *Image) GetOverlap() (overlap uint64, err error) { } if ret := C.rbd_get_overlap(image.image, (*C.uint64_t)(&overlap)); ret < 0 { - return overlap, RBDError(ret) + return overlap, rbdError(ret) } return overlap, nil @@ -598,12 +586,12 @@ func (image *Image) ListLockers() (tag string, lockers []Locker, err error) { // but *0* is unexpected here because first rbd_list_lockers already // dealt with no locker case if int(c_locker_cnt) <= 0 { - return "", nil, RBDError(c_locker_cnt) + return "", nil, rbdError(c_locker_cnt) } - clients := split(clients_buf) - cookies := split(cookies_buf) - addrs := split(addrs_buf) + clients := cutil.SplitSparseBuffer(clients_buf) + cookies := cutil.SplitSparseBuffer(cookies_buf) + addrs := cutil.SplitSparseBuffer(addrs_buf) lockers = make([]Locker, c_locker_cnt) for i := 0; i < int(c_locker_cnt); i++ { @@ -704,7 +692,7 @@ func (image *Image) Read(data []byte) (int, error) { (*C.char)(unsafe.Pointer(&data[0])))) if ret < 0 { - return 0, RBDError(ret) + return 0, rbdError(ret) } image.offset += int64(ret) @@ -729,7 +717,7 @@ func (image *Image) Write(data []byte) (n int, err error) { } if ret != len(data) { - err = RBDError(-C.EPERM) + err = rbdError(-C.EPERM) } return ret, err @@ -767,7 +755,7 @@ func (image *Image) Discard(ofs uint64, length uint64) (int, error) { ret := C.rbd_discard(image.image, C.uint64_t(ofs), C.uint64_t(length)) if ret < 0 { - return 0, RBDError(ret) + return 0, rbdError(ret) } return int(ret), nil @@ -790,7 +778,7 @@ func (image *Image) ReadAt(data []byte, off int64) (int, error) { (*C.char)(unsafe.Pointer(&data[0])))) if ret < 0 { - return 0, RBDError(ret) + return 0, rbdError(ret) } if ret < len(data) { @@ -814,7 +802,7 @@ func (image *Image) WriteAt(data []byte, off int64) (n int, err error) { C.size_t(len(data)), (*C.char)(unsafe.Pointer(&data[0])))) if ret != len(data) { - err = RBDError(-C.EPERM) + err = rbdError(-C.EPERM) } return ret, err @@ -852,7 +840,7 @@ func (image *Image) GetSnapshotNames() (snaps []SnapInfo, err error) { ret = C.rbd_snap_list(image.image, &c_snaps[0], &c_max_snaps) if ret < 0 { - return nil, RBDError(ret) + return nil, rbdError(ret) } for i, s := range c_snaps { @@ -913,7 +901,7 @@ func (image *Image) SetMetadata(key string, value string) error { ret := C.rbd_metadata_set(image.image, c_key, c_value) if ret < 0 { - return RBDError(ret) + return rbdError(ret) } return nil @@ -933,7 +921,7 @@ func (image *Image) RemoveMetadata(key string) error { ret := C.rbd_metadata_remove(image.image, c_key) if ret < 0 { - return RBDError(ret) + return rbdError(ret) } return nil @@ -1205,7 +1193,7 @@ func CreateImage(ioctx *rados.IOContext, name string, size uint64, rio *ImageOpt return ErrNoName } if rio == nil { - return RBDError(C.EINVAL) + return rbdError(C.EINVAL) } c_name := C.CString(name) @@ -1244,7 +1232,7 @@ func CloneImage(ioctx *rados.IOContext, parentName, snapName string, destctx *rados.IOContext, name string, rio *ImageOptions) error { if rio == nil { - return RBDError(C.EINVAL) + return rbdError(C.EINVAL) } cParentName := C.CString(parentName) diff --git a/vendor/github.com/ceph/go-ceph/rbd/rbd_mimic.go b/vendor/github.com/ceph/go-ceph/rbd/rbd_mimic.go index d25ac74ec22..1c4a1238cec 100644 --- a/vendor/github.com/ceph/go-ceph/rbd/rbd_mimic.go +++ b/vendor/github.com/ceph/go-ceph/rbd/rbd_mimic.go @@ -12,9 +12,9 @@ package rbd import "C" import ( - "bytes" "unsafe" + "github.com/ceph/go-ceph/internal/cutil" "github.com/ceph/go-ceph/internal/retry" "github.com/ceph/go-ceph/rados" ) @@ -37,12 +37,6 @@ func GetImageNames(ioctx *rados.IOContext) (names []string, err error) { if err != nil { return nil, err } - tmp := bytes.Split(buf[:csize-1], []byte{0}) - for _, s := range tmp { - if len(s) > 0 { - name := C.GoString((*C.char)(unsafe.Pointer(&s[0]))) - names = append(names, name) - } - } + names = cutil.SplitSparseBuffer(buf[:csize]) return names, nil } diff --git a/vendor/github.com/ceph/go-ceph/rbd/rbd_nautilus.go b/vendor/github.com/ceph/go-ceph/rbd/rbd_nautilus.go index cf479a0a931..3ae2a485ba7 100644 --- a/vendor/github.com/ceph/go-ceph/rbd/rbd_nautilus.go +++ b/vendor/github.com/ceph/go-ceph/rbd/rbd_nautilus.go @@ -1,6 +1,7 @@ // +build !luminous,!mimic // -// Ceph Nautilus is the first release that includes rbd_list2(). +// Ceph Nautilus is the first release that includes rbd_list2() and +// rbd_get_create_timestamp(). package rbd @@ -14,6 +15,7 @@ import ( "unsafe" "github.com/ceph/go-ceph/internal/retry" + ts "github.com/ceph/go-ceph/internal/timespec" "github.com/ceph/go-ceph/rados" ) @@ -45,3 +47,57 @@ func GetImageNames(ioctx *rados.IOContext) ([]string, error) { } return names, nil } + +// GetCreateTimestamp returns the time the rbd image was created. +// +// Implements: +// int rbd_get_create_timestamp(rbd_image_t image, struct timespec *timestamp); +func (image *Image) GetCreateTimestamp() (Timespec, error) { + if err := image.validate(imageIsOpen); err != nil { + return Timespec{}, err + } + + var cts C.struct_timespec + + if ret := C.rbd_get_create_timestamp(image.image, &cts); ret < 0 { + return Timespec{}, getError(ret) + } + + return Timespec(ts.CStructToTimespec(ts.CTimespecPtr(&cts))), nil +} + +// GetAccessTimestamp returns the time the rbd image was last accessed. +// +// Implements: +// int rbd_get_access_timestamp(rbd_image_t image, struct timespec *timestamp); +func (image *Image) GetAccessTimestamp() (Timespec, error) { + if err := image.validate(imageIsOpen); err != nil { + return Timespec{}, err + } + + var cts C.struct_timespec + + if ret := C.rbd_get_access_timestamp(image.image, &cts); ret < 0 { + return Timespec{}, getError(ret) + } + + return Timespec(ts.CStructToTimespec(ts.CTimespecPtr(&cts))), nil +} + +// GetModifyTimestamp returns the time the rbd image was last modified. +// +// Implements: +// int rbd_get_modify_timestamp(rbd_image_t image, struct timespec *timestamp); +func (image *Image) GetModifyTimestamp() (Timespec, error) { + if err := image.validate(imageIsOpen); err != nil { + return Timespec{}, err + } + + var cts C.struct_timespec + + if ret := C.rbd_get_modify_timestamp(image.image, &cts); ret < 0 { + return Timespec{}, getError(ret) + } + + return Timespec(ts.CStructToTimespec(ts.CTimespecPtr(&cts))), nil +} diff --git a/vendor/github.com/ceph/go-ceph/rbd/snapshot.go b/vendor/github.com/ceph/go-ceph/rbd/snapshot.go index 0eddc56c75b..1f020f79fe8 100644 --- a/vendor/github.com/ceph/go-ceph/rbd/snapshot.go +++ b/vendor/github.com/ceph/go-ceph/rbd/snapshot.go @@ -30,7 +30,7 @@ func (image *Image) CreateSnapshot(snapname string) (*Snapshot, error) { ret := C.rbd_snap_create(image.image, c_snapname) if ret < 0 { - return nil, RBDError(ret) + return nil, rbdError(ret) } return &Snapshot{ @@ -139,7 +139,7 @@ func (snapshot *Snapshot) IsProtected() (bool, error) { ret := C.rbd_snap_is_protected(snapshot.image.image, c_snapname, &c_is_protected) if ret < 0 { - return false, RBDError(ret) + return false, rbdError(ret) } return c_is_protected != 0, nil diff --git a/vendor/github.com/ceph/go-ceph/rbd/snapshot_mimic.go b/vendor/github.com/ceph/go-ceph/rbd/snapshot_mimic.go index cdc3847300f..9c12d9f9c8d 100644 --- a/vendor/github.com/ceph/go-ceph/rbd/snapshot_mimic.go +++ b/vendor/github.com/ceph/go-ceph/rbd/snapshot_mimic.go @@ -12,8 +12,9 @@ package rbd import "C" import ( - "bytes" "unsafe" + + "github.com/ceph/go-ceph/internal/cutil" ) // GetParentInfo looks for the parent of the image and stores the pool, name @@ -40,7 +41,7 @@ func (image *Image) GetParentInfo(p_pool, p_name, p_snapname []byte) error { if ret == 0 { return nil } else { - return RBDError(ret) + return rbdError(ret) } } @@ -66,7 +67,7 @@ func (image *Image) ListChildren() (pools []string, images []string, err error) return nil, nil, nil } if ret < 0 && ret != -C.ERANGE { - return nil, nil, RBDError(ret) + return nil, nil, rbdError(ret) } pools_buf := make([]byte, c_pools_len) @@ -78,24 +79,10 @@ func (image *Image) ListChildren() (pools []string, images []string, err error) (*C.char)(unsafe.Pointer(&images_buf[0])), &c_images_len) if ret < 0 { - return nil, nil, RBDError(ret) - } - - tmp := bytes.Split(pools_buf[:c_pools_len-1], []byte{0}) - for _, s := range tmp { - if len(s) > 0 { - name := C.GoString((*C.char)(unsafe.Pointer(&s[0]))) - pools = append(pools, name) - } - } - - tmp = bytes.Split(images_buf[:c_images_len-1], []byte{0}) - for _, s := range tmp { - if len(s) > 0 { - name := C.GoString((*C.char)(unsafe.Pointer(&s[0]))) - images = append(images, name) - } + return nil, nil, rbdError(ret) } + pools = cutil.SplitSparseBuffer(pools_buf[:c_pools_len]) + images = cutil.SplitSparseBuffer(images_buf[:c_images_len]) return pools, images, nil } diff --git a/vendor/github.com/ceph/go-ceph/rbd/snapshot_namespace.go b/vendor/github.com/ceph/go-ceph/rbd/snapshot_namespace.go new file mode 100644 index 00000000000..a9e8d17539a --- /dev/null +++ b/vendor/github.com/ceph/go-ceph/rbd/snapshot_namespace.go @@ -0,0 +1,80 @@ +// +build !luminous +// +// Ceph Mimic introduced rbd_snap_get_namespace_type(). + +package rbd + +// #cgo LDFLAGS: -lrbd +// #include +import "C" + +import ( + "unsafe" + + "github.com/ceph/go-ceph/internal/retry" +) + +// SnapNamespaceType indicates the namespace to which the snapshot belongs to. +type SnapNamespaceType C.rbd_snap_namespace_type_t + +const ( + // SnapNamespaceTypeUser indicates that the snapshot belongs to user namespace. + SnapNamespaceTypeUser = SnapNamespaceType(C.RBD_SNAP_NAMESPACE_TYPE_USER) + + // SnapNamespaceTypeGroup indicates that the snapshot belongs to group namespace. + // Such snapshots will have associated group information. + SnapNamespaceTypeGroup = SnapNamespaceType(C.RBD_SNAP_NAMESPACE_TYPE_GROUP) + + // SnapNamespaceTypeTrash indicates that the snapshot belongs to trash namespace. + SnapNamespaceTypeTrash = SnapNamespaceType(C.RBD_SNAP_NAMESPACE_TYPE_TRASH) +) + +// GetSnapNamespaceType gets the type of namespace to which the snapshot belongs to, +// returns error on failure. +// +// Implements: +// int rbd_snap_get_namespace_type(rbd_image_t image, uint64_t snap_id, rbd_snap_namespace_type_t *namespace_type) +func (image *Image) GetSnapNamespaceType(snapID uint64) (SnapNamespaceType, error) { + var nsType SnapNamespaceType + + if err := image.validate(imageIsOpen); err != nil { + return nsType, err + } + + ret := C.rbd_snap_get_namespace_type(image.image, + C.uint64_t(snapID), + (*C.rbd_snap_namespace_type_t)(&nsType)) + return nsType, getError(ret) +} + +// GetSnapTrashNamespace returns the original name of the snapshot which was +// moved to the Trash. The caller should make sure that the snapshot ID passed in this +// function belongs to a snapshot already in the Trash. +// +// Implements: +// int rbd_snap_get_trash_namespace(rbd_image_t image, uint64_t snap_id, char *original_name, size_t max_length) +func (image *Image) GetSnapTrashNamespace(snapID uint64) (string, error) { + if err := image.validate(imageIsOpen); err != nil { + return "", err + } + + var ( + buf []byte + err error + ) + retry.WithSizes(4096, 262144, func(length int) retry.Hint { + cLength := C.size_t(length) + buf = make([]byte, cLength) + ret := C.rbd_snap_get_trash_namespace(image.image, + C.uint64_t(snapID), + (*C.char)(unsafe.Pointer(&buf[0])), + cLength) + err = getError(ret) + return retry.Size(int(cLength)).If(err == errRange) + }) + + if err != nil { + return "", err + } + return C.GoString((*C.char)(unsafe.Pointer(&buf[0]))), nil +} diff --git a/vendor/github.com/ceph/go-ceph/rbd/snapshot_nautilus.go b/vendor/github.com/ceph/go-ceph/rbd/snapshot_nautilus.go index 6018463e112..f0eed0cb4f7 100644 --- a/vendor/github.com/ceph/go-ceph/rbd/snapshot_nautilus.go +++ b/vendor/github.com/ceph/go-ceph/rbd/snapshot_nautilus.go @@ -32,7 +32,7 @@ func (image *Image) GetParentInfo(pool, name, snapname []byte) error { parentSnap := C.rbd_snap_spec_t{} ret := C.rbd_get_parent(image.image, &parentImage, &parentSnap) if ret != 0 { - return RBDError(ret) + return rbdError(ret) } defer C.rbd_linked_image_spec_cleanup(&parentImage) @@ -40,26 +40,26 @@ func (image *Image) GetParentInfo(pool, name, snapname []byte) error { strlen := int(C.strlen(parentImage.pool_name)) if len(pool) < strlen { - return RBDError(C.ERANGE) + return rbdError(C.ERANGE) } if copy(pool, C.GoString(parentImage.pool_name)) != strlen { - return RBDError(C.ERANGE) + return rbdError(C.ERANGE) } strlen = int(C.strlen(parentImage.image_name)) if len(name) < strlen { - return RBDError(C.ERANGE) + return rbdError(C.ERANGE) } if copy(name, C.GoString(parentImage.image_name)) != strlen { - return RBDError(C.ERANGE) + return rbdError(C.ERANGE) } strlen = int(C.strlen(parentSnap.name)) if len(snapname) < strlen { - return RBDError(C.ERANGE) + return rbdError(C.ERANGE) } if copy(snapname, C.GoString(parentSnap.name)) != strlen { - return RBDError(C.ERANGE) + return rbdError(C.ERANGE) } return nil diff --git a/vendor/github.com/ceph/go-ceph/rbd/watchers_mimic.go b/vendor/github.com/ceph/go-ceph/rbd/watchers_mimic.go index 198292a613c..e8c89783b1c 100644 --- a/vendor/github.com/ceph/go-ceph/rbd/watchers_mimic.go +++ b/vendor/github.com/ceph/go-ceph/rbd/watchers_mimic.go @@ -4,12 +4,30 @@ package rbd -// #cgo LDFLAGS: -lrbd -// #include -// #include +/* +#cgo LDFLAGS: -lrbd +#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" import ( + "unsafe" + + "github.com/ceph/go-ceph/internal/callbacks" "github.com/ceph/go-ceph/internal/retry" ) @@ -59,3 +77,76 @@ func (image *Image) ListWatchers() ([]ImageWatcher, error) { } return imageWatchers, nil } + +// watchCallbacks tracks the active callbacks for rbd watches +var watchCallbacks = callbacks.New() + +// WatchCallback defines the function signature needed for the UpdateWatch +// callback. +type WatchCallback func(interface{}) + +type watchCallbackCtx struct { + callback WatchCallback + data interface{} +} + +// Watch represents an ongoing image metadata watch. +type Watch struct { + image *Image + wcc watchCallbackCtx + handle C.uint64_t + cbIndex int +} + +// UpdateWatch updates the image object to watch metadata changes to the +// image, returning a Watch object. +// +// Implements: +// int rbd_update_watch(rbd_image_t image, uint64_t *handle, +// rbd_update_callback_t watch_cb, void *arg); +func (image *Image) UpdateWatch(cb WatchCallback, data interface{}) (*Watch, error) { + if err := image.validate(imageIsOpen); err != nil { + return nil, err + } + wcc := watchCallbackCtx{ + callback: cb, + data: data, + } + w := &Watch{ + image: image, + wcc: wcc, + cbIndex: watchCallbacks.Add(wcc), + } + + ret := C.wrap_rbd_update_watch( + image.image, + &w.handle, + C.uintptr_t(w.cbIndex)) + if ret != 0 { + return nil, getError(ret) + } + return w, nil +} + +// Unwatch un-registers the image watch. +// +// Implements: +// int rbd_update_unwatch(rbd_image_t image, uint64_t handle); +func (w *Watch) Unwatch() error { + if w.image == nil { + return ErrImageNotOpen + } + if err := w.image.validate(imageIsOpen); err != nil { + return err + } + ret := C.rbd_update_unwatch(w.image.image, w.handle) + watchCallbacks.Remove(w.cbIndex) + return getError(ret) +} + +//export imageWatchCallback +func imageWatchCallback(index unsafe.Pointer) { + v := watchCallbacks.Lookup(int(uintptr(index))) + wcc := v.(watchCallbackCtx) + wcc.callback(wcc.data) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index cb42f6262ba..164ac71f103 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -2,11 +2,12 @@ github.com/beorn7/perks/quantile # github.com/blang/semver v3.5.0+incompatible github.com/blang/semver -# github.com/ceph/go-ceph v0.4.0 +# github.com/ceph/go-ceph v0.5.0 github.com/ceph/go-ceph/internal/callbacks github.com/ceph/go-ceph/internal/cutil github.com/ceph/go-ceph/internal/errutil github.com/ceph/go-ceph/internal/retry +github.com/ceph/go-ceph/internal/timespec github.com/ceph/go-ceph/rados github.com/ceph/go-ceph/rbd # github.com/cespare/xxhash/v2 v2.1.1