diff --git a/go.mod b/go.mod
index e80c322848a..19ca5e5c76a 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
 	github.com/aws/aws-sdk-go v1.55.5
 	github.com/aws/aws-sdk-go-v2/service/sts v1.30.3
 	github.com/ceph/ceph-csi/api v0.0.0-00010101000000-000000000000
-	github.com/ceph/go-ceph v0.28.0
+	github.com/ceph/go-ceph v0.29.0
 	github.com/container-storage-interface/spec v1.10.0
 	github.com/csi-addons/spec v0.2.1-0.20240730084235-3958a5b17d24
 	github.com/gemalto/kmip-go v0.0.10
diff --git a/go.sum b/go.sum
index 34d0b90ed47..9f3179677b9 100644
--- a/go.sum
+++ b/go.sum
@@ -864,8 +864,8 @@ github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
-github.com/ceph/go-ceph v0.28.0 h1:ZjlDV9XiVmBQIe9bKbT5j2Ft/bse3Jm+Ui65yE/oFFU=
-github.com/ceph/go-ceph v0.28.0/go.mod h1:EwEITEDpuFCMnFrPLbV+/Vyi59jUihgCxBKvlTWGot0=
+github.com/ceph/go-ceph v0.29.0 h1:pJQY+++PyY2FMP0ffVaE7FbIdivemBPCu4MWr4S8CtI=
+github.com/ceph/go-ceph v0.29.0/go.mod h1:U/l216/AzIWrFe7ny+9cJ5Yjzyb5otrEGfdrU5VtCME=
 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.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
diff --git a/vendor/github.com/ceph/go-ceph/cephfs/admin/fs_quiesce.go b/vendor/github.com/ceph/go-ceph/cephfs/admin/fs_quiesce.go
index 3c93dcc8c26..d22dc2194f9 100644
--- a/vendor/github.com/ceph/go-ceph/cephfs/admin/fs_quiesce.go
+++ b/vendor/github.com/ceph/go-ceph/cephfs/admin/fs_quiesce.go
@@ -1,5 +1,3 @@
-//go:build ceph_preview
-
 package admin
 
 import "fmt"
diff --git a/vendor/github.com/ceph/go-ceph/internal/dlsym/dlsym.go b/vendor/github.com/ceph/go-ceph/internal/dlsym/dlsym.go
new file mode 100644
index 00000000000..9e5782c4d50
--- /dev/null
+++ b/vendor/github.com/ceph/go-ceph/internal/dlsym/dlsym.go
@@ -0,0 +1,41 @@
+package dlsym
+
+// #cgo LDFLAGS: -ldl
+//
+// #include <stdlib.h>
+// #include <dlfcn.h>
+//
+// #ifndef RTLD_DEFAULT /* from dlfcn.h */
+// #define RTLD_DEFAULT ((void *) 0)
+// #endif
+import "C"
+
+import (
+	"errors"
+	"fmt"
+	"unsafe"
+)
+
+// ErrUndefinedSymbol is returned by LookupSymbol when the requested symbol
+// could not be found.
+var ErrUndefinedSymbol = errors.New("symbol not found")
+
+// LookupSymbol resolves the named symbol from the already dynamically loaded
+// libraries. If the symbol is found, a pointer to it is returned, in case of a
+// failure, the message provided by dlerror() is included in the error message.
+func LookupSymbol(symbol string) (unsafe.Pointer, error) {
+	cSymName := C.CString(symbol)
+	defer C.free(unsafe.Pointer(cSymName))
+
+	// clear dlerror before looking up the symbol
+	C.dlerror()
+	// resolve the address of the symbol
+	sym := C.dlsym(C.RTLD_DEFAULT, cSymName)
+	e := C.dlerror()
+	dlerr := C.GoString(e)
+	if dlerr != "" {
+		return nil, fmt.Errorf("%w: %s", ErrUndefinedSymbol, dlerr)
+	}
+
+	return sym, nil
+}
diff --git a/vendor/github.com/ceph/go-ceph/rados/read_op_exec.go b/vendor/github.com/ceph/go-ceph/rados/read_op_exec.go
new file mode 100644
index 00000000000..44d6d18e81b
--- /dev/null
+++ b/vendor/github.com/ceph/go-ceph/rados/read_op_exec.go
@@ -0,0 +1,111 @@
+//go:build ceph_preview
+// +build ceph_preview
+
+package rados
+
+// #cgo LDFLAGS: -lrados
+// #include <stdlib.h>
+// #include <rados/librados.h>
+//
+import "C"
+
+import (
+	"runtime"
+	"unsafe"
+)
+
+// ReadOpExecStep - step for exec operation code.
+type ReadOpExecStep struct {
+	withoutFree
+
+	inBuffPtr     *C.char
+	inBuffLen     C.size_t
+	outBuffPtr    *C.char
+	outBuffLen    C.size_t
+	prval         C.int
+	canReadOutput bool
+}
+
+// newExecStepOp - init new *execStepOp.
+func newReadOpExecStep(in []byte) *ReadOpExecStep {
+	es := &ReadOpExecStep{
+		outBuffPtr: nil,
+		outBuffLen: 0,
+		prval:      0,
+	}
+
+	if len(in) > 0 {
+		es.inBuffPtr = (*C.char)(unsafe.Pointer(&in[0]))
+		es.inBuffLen = C.size_t(len(in))
+	}
+
+	runtime.SetFinalizer(es, func(es *ReadOpExecStep) {
+		if es != nil {
+			es.freeBuffer()
+			es = nil
+		}
+	})
+	return es
+}
+
+// freeBuffer - releases C allocated buffer. It is separated from es.free() because lifespan of C allocated buffer is
+// longer than lifespan of read operation.
+func (es *ReadOpExecStep) freeBuffer() {
+	if es.outBuffPtr != nil {
+		C.free(unsafe.Pointer(es.outBuffPtr))
+		es.outBuffPtr = nil
+		es.canReadOutput = false
+	}
+}
+
+// update - update state operation.
+func (es *ReadOpExecStep) update() error {
+	err := getError(es.prval)
+	es.canReadOutput = err == nil
+	return err
+}
+
+// Bytes returns the result of the executed command as a byte slice.
+func (es *ReadOpExecStep) Bytes() ([]byte, error) {
+	if !es.canReadOutput {
+		return nil, ErrOperationIncomplete
+	}
+
+	return C.GoBytes(unsafe.Pointer(es.outBuffPtr), C.int(es.outBuffLen)), nil
+}
+
+// Exec executes an OSD class method on an object.
+// See rados_exec() in the RADOS C api documentation for a general description.
+//
+// Implements:
+//
+//	void rados_read_op_exec(rados_read_op_t read_op,
+//	                        const char *cls,
+//	                        const char *method,
+//	                        const char *in_buf,
+//	                        size_t in_len,
+//	                        char **out_buf,
+//	                        size_t *out_len,
+//	                        int *prval);
+func (r *ReadOp) Exec(clsName, method string, in []byte) *ReadOpExecStep {
+	cClsName := C.CString(clsName)
+	defer C.free(unsafe.Pointer(cClsName))
+
+	cMethod := C.CString(method)
+	defer C.free(unsafe.Pointer(cMethod))
+
+	es := newReadOpExecStep(in)
+	r.steps = append(r.steps, es)
+	C.rados_read_op_exec(
+		r.op,
+		cClsName,
+		cMethod,
+		es.inBuffPtr,
+		es.inBuffLen,
+		&es.outBuffPtr,
+		&es.outBuffLen,
+		&es.prval,
+	)
+
+	return es
+}
diff --git a/vendor/github.com/ceph/go-ceph/rados/write_op_exec.go b/vendor/github.com/ceph/go-ceph/rados/write_op_exec.go
new file mode 100644
index 00000000000..8f7fc07f3a0
--- /dev/null
+++ b/vendor/github.com/ceph/go-ceph/rados/write_op_exec.go
@@ -0,0 +1,71 @@
+//go:build ceph_preview
+// +build ceph_preview
+
+package rados
+
+// #cgo LDFLAGS: -lrados
+// #include <stdlib.h>
+// #include <rados/librados.h>
+//
+import "C"
+
+import (
+	"unsafe"
+)
+
+// writeOpExecStep - exec step in write operation.
+type writeOpExecStep struct {
+	withoutFree
+
+	inBuffPtr *C.char
+	inBuffLen C.size_t
+	prval     C.int
+}
+
+// newWriteOpExecStep - init new *writeOpExecStep.
+func newWriteOpExecStep(in []byte) *writeOpExecStep {
+	es := &writeOpExecStep{
+		prval: 0,
+	}
+	if len(in) > 0 {
+		es.inBuffPtr = (*C.char)(unsafe.Pointer(&in[0]))
+		es.inBuffLen = C.size_t(len(in))
+	}
+
+	return es
+}
+
+// update - update state operation.
+func (es *writeOpExecStep) update() error {
+	return getError(es.prval)
+}
+
+// Exec executes an OSD class method on an object.
+// See rados_exec() in the RADOS C api documentation for a general description.
+//
+// Implements:
+//
+//	void rados_write_op_exec(rados_write_op_t write_op,
+//	                         const char *cls,
+//	                         const char *method,
+//	                         const char *in_buf,
+//	                         size_t in_len,
+//	                         int *prval)
+func (w *WriteOp) Exec(clsName, method string, in []byte) {
+	cClsName := C.CString(clsName)
+	defer C.free(unsafe.Pointer(cClsName))
+
+	cMethod := C.CString(method)
+	defer C.free(unsafe.Pointer(cMethod))
+
+	es := newWriteOpExecStep(in)
+	w.steps = append(w.steps, es)
+	C.rados_write_op_exec(
+		w.op,
+		cClsName,
+		cMethod,
+		es.inBuffPtr,
+		es.inBuffLen,
+		&es.prval,
+	)
+}
diff --git a/vendor/github.com/ceph/go-ceph/rbd/clone_image_by_id.go b/vendor/github.com/ceph/go-ceph/rbd/clone_image_by_id.go
new file mode 100644
index 00000000000..63cf552d9cc
--- /dev/null
+++ b/vendor/github.com/ceph/go-ceph/rbd/clone_image_by_id.go
@@ -0,0 +1,83 @@
+//go:build ceph_preview
+
+package rbd
+
+/*
+#cgo LDFLAGS: -lrbd
+#include <errno.h>
+#include <stdlib.h>
+#include <rados/librados.h>
+#include <rbd/librbd.h>
+
+// rbd_clone4_fn matches the rbd_clone4 function signature.
+typedef int(*rbd_clone4_fn)(rados_ioctx_t p_ioctx, const char *p_name,
+                            uint64_t p_snap_id, rados_ioctx_t c_ioctx,
+			    const char *c_name, rbd_image_options_t c_opts);
+
+// rbd_clone4_dlsym take *fn as rbd_clone4_fn and calls the dynamically loaded
+// rbd_clone4 function passed as 1st argument.
+static inline int rbd_clone4_dlsym(void *fn, rados_ioctx_t p_ioctx,
+				   const char *p_name, uint64_t p_snap_id,
+				   rados_ioctx_t c_ioctx, const char *c_name,
+                                   rbd_image_options_t c_opts) {
+  // cast function pointer fn to rbd_clone4 and call the function
+  return ((rbd_clone4_fn) fn)(p_ioctx, p_name, p_snap_id, c_ioctx, c_name, c_opts);
+}
+*/
+import "C"
+
+import (
+	"fmt"
+	"sync"
+	"unsafe"
+
+	"github.com/ceph/go-ceph/internal/dlsym"
+	"github.com/ceph/go-ceph/rados"
+)
+
+var (
+	rbdClone4Once sync.Once
+	rbdClone4     unsafe.Pointer
+	rbdClone4Err  error
+)
+
+// CloneImageByID creates a clone of the image from a snapshot with the given
+// ID in the provided io-context with the given name and image options.
+//
+// Implements:
+//
+//	int rbd_clone4(rados_ioctx_t p_ioctx, const char *p_name,
+//	               uint64_t p_snap_id, rados_ioctx_t c_ioctx,
+//	               const char *c_name, rbd_image_options_t c_opts);
+func CloneImageByID(ioctx *rados.IOContext, parentName string, snapID uint64,
+	destctx *rados.IOContext, name string, rio *ImageOptions) error {
+	if rio == nil {
+		return rbdError(C.EINVAL)
+	}
+
+	rbdClone4Once.Do(func() {
+		rbdClone4, rbdClone4Err = dlsym.LookupSymbol("rbd_clone4")
+	})
+
+	if rbdClone4Err != nil {
+		return fmt.Errorf("%w: %w", ErrNotImplemented, rbdClone4Err)
+	}
+
+	cParentName := C.CString(parentName)
+	defer C.free(unsafe.Pointer(cParentName))
+	cCloneName := C.CString(name)
+	defer C.free(unsafe.Pointer(cCloneName))
+
+	// call rbd_clone4_dlsym with the function pointer to rbd_clone4 as 1st
+	// argument
+	ret := C.rbd_clone4_dlsym(
+		rbdClone4,
+		cephIoctx(ioctx),
+		cParentName,
+		C.uint64_t(snapID),
+		cephIoctx(destctx),
+		cCloneName,
+		C.rbd_image_options_t(rio.options))
+
+	return getError(ret)
+}
diff --git a/vendor/github.com/ceph/go-ceph/rbd/errors.go b/vendor/github.com/ceph/go-ceph/rbd/errors.go
index 34693333f5a..4d98cce7c4e 100644
--- a/vendor/github.com/ceph/go-ceph/rbd/errors.go
+++ b/vendor/github.com/ceph/go-ceph/rbd/errors.go
@@ -75,6 +75,8 @@ var (
 const (
 	// ErrNotExist indicates a non-specific missing resource.
 	ErrNotExist = rbdError(-C.ENOENT)
+	// ErrNotImplemented indicates a function is not implemented in by librbd.
+	ErrNotImplemented = rbdError(-C.ENOSYS)
 )
 
 // Private errors:
diff --git a/vendor/github.com/ceph/go-ceph/rbd/snap_group_namespace.go b/vendor/github.com/ceph/go-ceph/rbd/snap_group_namespace.go
index 88f975d058b..f0bd765ead0 100644
--- a/vendor/github.com/ceph/go-ceph/rbd/snap_group_namespace.go
+++ b/vendor/github.com/ceph/go-ceph/rbd/snap_group_namespace.go
@@ -1,5 +1,3 @@
-//go:build ceph_preview
-
 package rbd
 
 // #cgo LDFLAGS: -lrbd
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 7ef495b0de0..5fd3181ee99 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -206,7 +206,7 @@ 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.28.0
+# github.com/ceph/go-ceph v0.29.0
 ## explicit; go 1.19
 github.com/ceph/go-ceph/cephfs
 github.com/ceph/go-ceph/cephfs/admin
@@ -216,6 +216,7 @@ github.com/ceph/go-ceph/common/commands
 github.com/ceph/go-ceph/internal/callbacks
 github.com/ceph/go-ceph/internal/commands
 github.com/ceph/go-ceph/internal/cutil
+github.com/ceph/go-ceph/internal/dlsym
 github.com/ceph/go-ceph/internal/errutil
 github.com/ceph/go-ceph/internal/log
 github.com/ceph/go-ceph/internal/retry