]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: API: options on image create
authorMykola Golub <mgolub@mirantis.com>
Fri, 23 Oct 2015 09:38:08 +0000 (12:38 +0300)
committerMykola Golub <mgolub@mirantis.com>
Thu, 12 Nov 2015 19:43:49 +0000 (21:43 +0200)
Pass options as key/value configuration pairs on image create instead
of expanding rbd_create/rbd_clone/rbd_copy for every possible
configuration override.

Fixes: #13504
Signed-off-by: Mykola Golub <mgolub@mirantis.com>
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/internal.cc
src/librbd/internal.h
src/librbd/librbd.cc
src/pybind/rbd.py
src/tracing/librbd.tp

index 2eb3aa5e9542bfcbc68d09a19d5695ef82b9869b..ba64219d3be717d583672516f64409a4d124fc19 100644 (file)
@@ -52,6 +52,7 @@ extern "C" {
 
 typedef void *rbd_snap_t;
 typedef void *rbd_image_t;
+typedef void *rbd_image_options_t;
 
 typedef int (*librbd_progress_fn_t)(uint64_t offset, uint64_t total, void *ptr);
 
@@ -76,6 +77,30 @@ typedef struct {
 
 CEPH_RBD_API void rbd_version(int *major, int *minor, int *extra);
 
+/* image options */
+enum {
+  RBD_IMAGE_OPTION_FORMAT = 0,
+  RBD_IMAGE_OPTION_FEATURES = 1,
+  RBD_IMAGE_OPTION_ORDER = 2,
+  RBD_IMAGE_OPTION_STRIPE_UNIT = 3,
+  RBD_IMAGE_OPTION_STRIPE_COUNT = 4,
+};
+
+CEPH_RBD_API void rbd_image_options_create(rbd_image_options_t* opts);
+CEPH_RBD_API void rbd_image_options_destroy(rbd_image_options_t opts);
+CEPH_RBD_API int rbd_image_options_set_string(rbd_image_options_t opts,
+                                             int optname, const char* optval);
+CEPH_RBD_API int rbd_image_options_set_uint64(rbd_image_options_t opts,
+                                             int optname, uint64_t optval);
+CEPH_RBD_API int rbd_image_options_get_string(rbd_image_options_t opts,
+                                             int optname, char* optval,
+                                             size_t maxlen);
+CEPH_RBD_API int rbd_image_options_get_uint64(rbd_image_options_t opts,
+                                             int optname, uint64_t* optval);
+CEPH_RBD_API int rbd_image_options_unset(rbd_image_options_t opts, int optname);
+CEPH_RBD_API void rbd_image_options_clear(rbd_image_options_t opts);
+CEPH_RBD_API int rbd_image_options_is_empty(rbd_image_options_t opts);
+
 /* images */
 CEPH_RBD_API int rbd_list(rados_ioctx_t io, char *names, size_t *size);
 CEPH_RBD_API int rbd_create(rados_ioctx_t io, const char *name, uint64_t size,
@@ -102,6 +127,8 @@ CEPH_RBD_API int rbd_create2(rados_ioctx_t io, const char *name, uint64_t size,
 CEPH_RBD_API int rbd_create3(rados_ioctx_t io, const char *name, uint64_t size,
                             uint64_t features, int *order,
                             uint64_t stripe_unit, uint64_t stripe_count);
+CEPH_RBD_API int rbd_create4(rados_ioctx_t io, const char *name, uint64_t size,
+                            rbd_image_options_t opts);
 CEPH_RBD_API int rbd_clone(rados_ioctx_t p_ioctx, const char *p_name,
                           const char *p_snapname, rados_ioctx_t c_ioctx,
                           const char *c_name, uint64_t features, int *c_order);
@@ -109,6 +136,9 @@ CEPH_RBD_API int rbd_clone2(rados_ioctx_t p_ioctx, const char *p_name,
                            const char *p_snapname, rados_ioctx_t c_ioctx,
                            const char *c_name, uint64_t features, int *c_order,
                            uint64_t stripe_unit, int stripe_count);
+CEPH_RBD_API int rbd_clone3(rados_ioctx_t p_ioctx, const char *p_name,
+                           const char *p_snapname, rados_ioctx_t c_ioctx,
+                           const char *c_name, rbd_image_options_t c_opts);
 CEPH_RBD_API int rbd_remove(rados_ioctx_t io, const char *name);
 CEPH_RBD_API int rbd_remove_with_progress(rados_ioctx_t io, const char *name,
                                          librbd_progress_fn_t cb,
@@ -172,11 +202,18 @@ CEPH_RBD_API int rbd_rebuild_object_map(rbd_image_t image,
 CEPH_RBD_API int rbd_copy(rbd_image_t image, rados_ioctx_t dest_io_ctx,
                           const char *destname);
 CEPH_RBD_API int rbd_copy2(rbd_image_t src, rbd_image_t dest);
+CEPH_RBD_API int rbd_copy3(rbd_image_t src, rados_ioctx_t dest_io_ctx,
+                          const char *destname, rbd_image_options_t dest_opts);
 CEPH_RBD_API int rbd_copy_with_progress(rbd_image_t image, rados_ioctx_t dest_p,
                                         const char *destname,
                                         librbd_progress_fn_t cb, void *cbdata);
 CEPH_RBD_API int rbd_copy_with_progress2(rbd_image_t src, rbd_image_t dest,
                                         librbd_progress_fn_t cb, void *cbdata);
+CEPH_RBD_API int rbd_copy_with_progress3(rbd_image_t image,
+                                        rados_ioctx_t dest_p,
+                                        const char *destname,
+                                        rbd_image_options_t dest_opts,
+                                        librbd_progress_fn_t cb, void *cbdata);
 
 /* snapshots */
 CEPH_RBD_API int rbd_snap_list(rbd_image_t image, rbd_snap_info_t *snaps,
index 0c41b8e184a61175ae7855ba7c184cd050d7b696..a64ffa6b58ca697656dde18d281cf746255680bd 100644 (file)
@@ -29,6 +29,7 @@ namespace librbd {
   using librados::IoCtx;
 
   class Image;
+  class ImageOptions;
   typedef void *image_ctx_t;
   typedef void *completion_t;
   typedef void (*callback_t)(completion_t cb, void *arg);
@@ -86,12 +87,16 @@ public:
   int create3(IoCtx& io_ctx, const char *name, uint64_t size,
              uint64_t features, int *order,
              uint64_t stripe_unit, uint64_t stripe_count);
+  int create4(IoCtx& io_ctx, const char *name, uint64_t size,
+             ImageOptions& opts);
   int clone(IoCtx& p_ioctx, const char *p_name, const char *p_snapname,
               IoCtx& c_ioctx, const char *c_name, uint64_t features,
               int *c_order);
   int clone2(IoCtx& p_ioctx, const char *p_name, const char *p_snapname,
             IoCtx& c_ioctx, const char *c_name, uint64_t features,
             int *c_order, uint64_t stripe_unit, int stripe_count);
+  int clone3(IoCtx& p_ioctx, const char *p_name, const char *p_snapname,
+            IoCtx& c_ioctx, const char *c_name, ImageOptions& opts);
   int remove(IoCtx& io_ctx, const char *name);
   int remove_with_progress(IoCtx& io_ctx, const char *name, ProgressContext& pctx);
   int rename(IoCtx& src_io_ctx, const char *srcname, const char *destname);
@@ -102,6 +107,27 @@ private:
   const RBD& operator=(const RBD& rhs);
 };
 
+class CEPH_RBD_API ImageOptions {
+public:
+  ImageOptions();
+  ImageOptions(rbd_image_options_t opts);
+  ~ImageOptions();
+
+  int set(int optname, const std::string& optval);
+  int set(int optname, uint64_t optval);
+  int get(int optname, std::string* optval) const;
+  int get(int optname, uint64_t* optval) const;
+  int unset(int optname);
+  void clear();
+  bool empty() const;
+
+private:
+  friend class RBD;
+  friend class Image;
+
+  rbd_image_options_t opts;
+};
+
 class CEPH_RBD_API Image
 {
 public:
@@ -130,9 +156,12 @@ public:
 
   int copy(IoCtx& dest_io_ctx, const char *destname);
   int copy2(Image& dest);
+  int copy3(IoCtx& dest_io_ctx, const char *destname, ImageOptions& opts);
   int copy_with_progress(IoCtx& dest_io_ctx, const char *destname,
                         ProgressContext &prog_ctx);
   int copy_with_progress2(Image& dest, ProgressContext &prog_ctx);
+  int copy_with_progress3(IoCtx& dest_io_ctx, const char *destname,
+                         ImageOptions& opts, ProgressContext &prog_ctx);
 
   /* striping */
   uint64_t get_stripe_unit() const;
index 5ef44e1adb35cdd9c435e37c61c1208686540873..b61018d391d87f1944cbdd6482886501a04ddc87 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <boost/bind.hpp>
 #include <boost/scope_exit.hpp>
+#include <boost/variant.hpp>
 #include "include/assert.h"
 
 #define dout_subsys ceph_subsys_rbd
@@ -442,6 +443,156 @@ int invoke_async_request(ImageCtx *ictx, const std::string& request_type,
     return io_ctx.tmap_update(RBD_DIRECTORY, cmdbl);
   }
 
+  typedef boost::variant<std::string,uint64_t> image_option_value_t;
+  typedef std::map<int,image_option_value_t> image_options_t;
+  typedef std::shared_ptr<image_options_t> image_options_ref;
+
+  enum image_option_type_t {
+    STR,
+    UINT64,
+  };
+
+  const std::map<int, image_option_type_t> IMAGE_OPTIONS_TYPE_MAPPING = {
+    {RBD_IMAGE_OPTION_FORMAT, UINT64},
+    {RBD_IMAGE_OPTION_FEATURES, UINT64},
+    {RBD_IMAGE_OPTION_ORDER, UINT64},
+    {RBD_IMAGE_OPTION_STRIPE_UNIT, UINT64},
+    {RBD_IMAGE_OPTION_STRIPE_COUNT, UINT64},
+  };
+
+  void image_options_create(rbd_image_options_t* opts)
+  {
+    image_options_ref* opts_ = new image_options_ref(new image_options_t());
+
+    *opts = static_cast<rbd_image_options_t>(opts_);
+  }
+
+  void image_options_create_ref(rbd_image_options_t* opts,
+                               rbd_image_options_t orig)
+  {
+    image_options_ref* orig_ = static_cast<image_options_ref*>(orig);
+    image_options_ref* opts_ = new image_options_ref(*orig_);
+
+    *opts = static_cast<rbd_image_options_t>(opts_);
+  }
+
+  void image_options_destroy(rbd_image_options_t opts)
+  {
+    image_options_ref* opts_ = static_cast<image_options_ref*>(opts);
+
+    delete opts_;
+  }
+
+  int image_options_set(rbd_image_options_t opts, int optname,
+                       const std::string& optval)
+  {
+    image_options_ref* opts_ = static_cast<image_options_ref*>(opts);
+
+    std::map<int, image_option_type_t>::const_iterator i =
+      IMAGE_OPTIONS_TYPE_MAPPING.find(optname);
+
+    if (i == IMAGE_OPTIONS_TYPE_MAPPING.end() || i->second != STR) {
+      return -EINVAL;
+    }
+
+    (*opts_->get())[optname] = optval;
+    return 0;
+  }
+
+  int image_options_set(rbd_image_options_t opts, int optname, uint64_t optval)
+  {
+    image_options_ref* opts_ = static_cast<image_options_ref*>(opts);
+
+    std::map<int, image_option_type_t>::const_iterator i =
+      IMAGE_OPTIONS_TYPE_MAPPING.find(optname);
+
+    if (i == IMAGE_OPTIONS_TYPE_MAPPING.end() || i->second != UINT64) {
+      return -EINVAL;
+    }
+
+    (*opts_->get())[optname] = optval;
+    return 0;
+  }
+
+  int image_options_get(rbd_image_options_t opts, int optname,
+                       std::string* optval)
+  {
+    image_options_ref* opts_ = static_cast<image_options_ref*>(opts);
+
+    std::map<int, image_option_type_t>::const_iterator i =
+      IMAGE_OPTIONS_TYPE_MAPPING.find(optname);
+
+    if (i == IMAGE_OPTIONS_TYPE_MAPPING.end() || i->second != STR) {
+      return -EINVAL;
+    }
+
+    image_options_t::const_iterator j = (*opts_)->find(optname);
+
+    if (j == (*opts_)->end()) {
+      return -ENOENT;
+    }
+
+    *optval = boost::get<std::string>(j->second);
+    return 0;
+  }
+
+  int image_options_get(rbd_image_options_t opts, int optname, uint64_t* optval)
+  {
+    image_options_ref* opts_ = static_cast<image_options_ref*>(opts);
+
+    std::map<int, image_option_type_t>::const_iterator i =
+      IMAGE_OPTIONS_TYPE_MAPPING.find(optname);
+
+    if (i == IMAGE_OPTIONS_TYPE_MAPPING.end() || i->second != UINT64) {
+      return -EINVAL;
+    }
+
+    image_options_t::const_iterator j = (*opts_)->find(optname);
+
+    if (j == (*opts_)->end()) {
+      return -ENOENT;
+    }
+
+    *optval = boost::get<uint64_t>(j->second);
+    return 0;
+  }
+
+  int image_options_unset(rbd_image_options_t opts, int optname)
+  {
+    image_options_ref* opts_ = static_cast<image_options_ref*>(opts);
+
+    std::map<int, image_option_type_t>::const_iterator i =
+      IMAGE_OPTIONS_TYPE_MAPPING.find(optname);
+
+    if (i == IMAGE_OPTIONS_TYPE_MAPPING.end()) {
+      assert((*opts_)->find(optname) == (*opts_)->end());
+      return -EINVAL;
+    }
+
+    image_options_t::const_iterator j = (*opts_)->find(optname);
+
+    if (j == (*opts_)->end()) {
+      return -ENOENT;
+    }
+
+    (*opts_)->erase(j);
+    return 0;
+  }
+
+  void image_options_clear(rbd_image_options_t opts)
+  {
+    image_options_ref* opts_ = static_cast<image_options_ref*>(opts);
+
+    (*opts_)->clear();
+  }
+
+  bool image_options_is_empty(rbd_image_options_t opts)
+  {
+    image_options_ref* opts_ = static_cast<image_options_ref*>(opts);
+
+    return (*opts_)->empty();
+  }
+
   void rollback_object(ImageCtx *ictx, uint64_t snap_id, const string& oid,
                       SimpleThrottle& throttle)
   {
@@ -1229,15 +1380,59 @@ reprotect_and_return_err:
     if (!order)
       return -EINVAL;
 
+    uint64_t order_ = *order;
+    uint64_t format = old_format ? 1 : 2;
+    ImageOptions opts;
+    int r;
+
+    r = opts.set(RBD_IMAGE_OPTION_FORMAT, format);
+    assert(r == 0);
+    r = opts.set(RBD_IMAGE_OPTION_FEATURES, features);
+    assert(r == 0);
+    r = opts.set(RBD_IMAGE_OPTION_ORDER, order_);
+    assert(r == 0);
+    r = opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, stripe_unit);
+    assert(r == 0);
+    r = opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, stripe_count);
+    assert(r == 0);
+
+    r = create(io_ctx, imgname, size, opts);
+
+    int r1 = opts.get(RBD_IMAGE_OPTION_ORDER, &order_);
+    assert(r1 == 0);
+    *order = order_;
+
+    return r;
+  }
+
+  int create(IoCtx& io_ctx, const char *imgname, uint64_t size,
+            ImageOptions& opts)
+  {
     CephContext *cct = (CephContext *)io_ctx.cct();
+
+    uint64_t format = cct->_conf->rbd_default_format;
+    opts.get(RBD_IMAGE_OPTION_FORMAT, &format);
+    bool old_format = format == 1;
+
+    uint64_t features;
+    if (opts.get(RBD_IMAGE_OPTION_FEATURES, &features) != 0) {
+      features = old_format ? 0 : cct->_conf->rbd_default_features;
+    }
+    uint64_t stripe_unit = 0;
+    uint64_t stripe_count = 0;
+    opts.get(RBD_IMAGE_OPTION_STRIPE_UNIT, &stripe_unit);
+    opts.get(RBD_IMAGE_OPTION_STRIPE_COUNT, &stripe_count);
+
+    uint64_t order = 0;
+    opts.get(RBD_IMAGE_OPTION_ORDER, &order);
+
     ldout(cct, 20) << "create " << &io_ctx << " name = " << imgname
                   << " size = " << size << " old_format = " << old_format
-                  << " features = " << features << " order = " << *order
+                  << " features = " << features << " order = " << order
                   << " stripe_unit = " << stripe_unit
                   << " stripe_count = " << stripe_count
                   << dendl;
 
-
     if (features & ~RBD_FEATURES_ALL) {
       lderr(cct) << "librbd does not support requested features." << dendl;
       return -ENOSYS;
@@ -1254,12 +1449,12 @@ reprotect_and_return_err:
       return -EEXIST;
     }
 
-    if (!*order)
-      *order = cct->_conf->rbd_default_order;
-    if (!*order)
-      *order = RBD_DEFAULT_OBJ_ORDER;
+    if (!order)
+      order = cct->_conf->rbd_default_order;
+    if (!order)
+      order = RBD_DEFAULT_OBJ_ORDER;
 
-    if (*order > 25 || *order < 12) {
+    if (order > 25 || order < 12) {
       lderr(cct) << "order must be in the range [12, 25]" << dendl;
       return -EDOM;
     }
@@ -1275,7 +1470,7 @@ reprotect_and_return_err:
     }
 
     // normalize for default striping
-    if (stripe_unit == (1ull << *order) && stripe_count == 1) {
+    if (stripe_unit == (1ull << order) && stripe_count == 1) {
       stripe_unit = 0;
       stripe_count = 0;
     }
@@ -1289,21 +1484,43 @@ reprotect_and_return_err:
       return -EINVAL;
 
     if (old_format) {
-      if (stripe_unit && stripe_unit != (1ull << *order))
+      if (stripe_unit && stripe_unit != (1ull << order))
        return -EINVAL;
       if (stripe_count && stripe_count != 1)
        return -EINVAL;
 
-      return create_v1(io_ctx, imgname, bid, size, *order);
+      r = create_v1(io_ctx, imgname, bid, size, order);
     } else {
-      return create_v2(io_ctx, imgname, bid, size, *order, features,
-                      stripe_unit, stripe_count);
+      r = create_v2(io_ctx, imgname, bid, size, order, features, stripe_unit,
+                   stripe_count);
     }
+
+    int r1 = opts.set(RBD_IMAGE_OPTION_ORDER, order);
+    assert(r1 == 0);
+
+    return r;
   }
 
   /*
    * Parent may be in different pool, hence different IoCtx
    */
+  int clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
+           IoCtx& c_ioctx, const char *c_name, ImageOptions& c_opts)
+  {
+    int order = 0;
+    uint64_t features = 0;
+    uint64_t stripe_unit = 0;
+    uint64_t stripe_count = 0;
+    c_opts.get(RBD_IMAGE_OPTION_FEATURES, &features);
+    c_opts.get(RBD_IMAGE_OPTION_STRIPE_UNIT, &stripe_unit);
+    c_opts.get(RBD_IMAGE_OPTION_STRIPE_COUNT, &stripe_count);
+
+    int r = clone(p_ioctx, p_name, p_snap_name, c_ioctx, c_name, features,
+                 &order, stripe_unit, stripe_count);
+    c_opts.set(RBD_IMAGE_OPTION_ORDER, static_cast<uint64_t>(order));
+    return r;
+  }
+
   int clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
            IoCtx& c_ioctx, const char *c_name,
            uint64_t features, int *c_order,
@@ -2614,25 +2831,40 @@ reprotect_and_return_err:
   }
 
   int copy(ImageCtx *src, IoCtx& dest_md_ctx, const char *destname,
-          ProgressContext &prog_ctx)
+          ImageOptions& opts, ProgressContext &prog_ctx)
   {
     CephContext *cct = (CephContext *)dest_md_ctx.cct();
     ldout(cct, 20) << "copy " << src->name
                   << (src->snap_name.length() ? "@" + src->snap_name : "")
                   << " -> " << destname << dendl;
-    int order = src->order;
 
     src->snap_lock.get_read();
-    uint64_t src_features = src->features;
+    uint64_t features = src->features;
     uint64_t src_size = src->get_image_size(src->snap_id);
     src->snap_lock.put_read();
+    uint64_t stripe_unit = src->stripe_unit;
+    uint64_t stripe_count = src->stripe_count;
+    opts.get(RBD_IMAGE_OPTION_FEATURES, &features);
+    opts.get(RBD_IMAGE_OPTION_STRIPE_UNIT, &stripe_unit);
+    opts.get(RBD_IMAGE_OPTION_STRIPE_COUNT, &stripe_count);
+    int order = src->order;
+    uint64_t opt_order = 0;
+    if (opts.get(RBD_IMAGE_OPTION_ORDER, &opt_order)) {
+      order = opt_order;
+    }
+
+    if (features & ~RBD_FEATURES_ALL) {
+      lderr(cct) << "librbd does not support requested features" << dendl;
+      return -ENOSYS;
+    }
 
     int r = create(dest_md_ctx, destname, src_size, src->old_format,
-                  src_features, &order, src->stripe_unit, src->stripe_count);
+                  features, &order, stripe_unit, stripe_count);
     if (r < 0) {
       lderr(cct) << "header creation failed" << dendl;
       return r;
     }
+    opts.set(RBD_IMAGE_OPTION_ORDER, static_cast<uint64_t>(order));
 
     ImageCtx *dest = new librbd::ImageCtx(destname, "", NULL,
                                          dest_md_ctx, false);
index 4245b43f8108e0fdd29c63b4e5c776bf9962811e..3197c8e5d29dbce4fbd227e1c1df114ed4a412f6 100644 (file)
@@ -77,6 +77,21 @@ namespace librbd {
 
   bool has_parent(int64_t parent_pool_id, uint64_t off, uint64_t overlap);
 
+  void image_options_create(rbd_image_options_t* opts);
+  void image_options_create_ref(rbd_image_options_t* opts,
+                               rbd_image_options_t orig);
+  void image_options_destroy(rbd_image_options_t opts);
+  int image_options_set(rbd_image_options_t opts, int optname,
+                       const std::string& optval);
+  int image_options_set(rbd_image_options_t opts, int optname, uint64_t optval);
+  int image_options_get(rbd_image_options_t opts, int optname,
+                       std::string* optval);
+  int image_options_get(rbd_image_options_t opts, int optname,
+                       uint64_t* optval);
+  int image_options_unset(rbd_image_options_t opts, int optname);
+  void image_options_clear(rbd_image_options_t opts);
+  bool image_options_is_empty(rbd_image_options_t opts);
+
   int snap_set(ImageCtx *ictx, const char *snap_name);
   int list(librados::IoCtx& io_ctx, std::vector<std::string>& names);
   int list_children(ImageCtx *ictx,
@@ -86,10 +101,14 @@ namespace librbd {
   int create(librados::IoCtx& io_ctx, const char *imgname, uint64_t size,
             bool old_format, uint64_t features, int *order,
             uint64_t stripe_unit, uint64_t stripe_count);
+  int create(IoCtx& io_ctx, const char *imgname, uint64_t size,
+            ImageOptions& opts);
   int clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
            IoCtx& c_ioctx, const char *c_name,
            uint64_t features, int *c_order,
            uint64_t stripe_unit, int stripe_count);
+  int clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
+           IoCtx& c_ioctx, const char *c_name, ImageOptions& c_opts);
   int rename(librados::IoCtx& io_ctx, const char *srcname, const char *dstname);
   int info(ImageCtx *ictx, image_info_t& info, size_t image_size);
   int get_old_format(ImageCtx *ictx, uint8_t *old);
@@ -127,7 +146,7 @@ namespace librbd {
   int ictx_check(ImageCtx *ictx, bool owner_locked=false);
   int ictx_refresh(ImageCtx *ictx);
   int copy(ImageCtx *ictx, IoCtx& dest_md_ctx, const char *destname,
-          ProgressContext &prog_ctx);
+          ImageOptions& opts, ProgressContext &prog_ctx);
   int copy(ImageCtx *src, ImageCtx *dest, ProgressContext &prog_ctx);
 
   int open_parent(ImageCtx *ictx);
index 7f7ad40575fb193cb9f303ef6ad2295913618bb1..d3c4b02552ccfaff1a943bdeb0a6f6da76e0dd4b 100644 (file)
@@ -304,6 +304,16 @@ namespace librbd {
     return r;
   }
 
+  int RBD::create4(IoCtx& io_ctx, const char *name, uint64_t size,
+                  ImageOptions& opts)
+  {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+    tracepoint(librbd, create4_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, opts.opts);
+    int r = librbd::create(io_ctx, name, size, opts);
+    tracepoint(librbd, create4_exit, r);
+    return r;
+  }
+
   int RBD::clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
                 IoCtx& c_ioctx, const char *c_name, uint64_t features,
                 int *c_order)
@@ -328,6 +338,17 @@ namespace librbd {
     return r;
   }
 
+  int RBD::clone3(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
+                 IoCtx& c_ioctx, const char *c_name, ImageOptions& c_opts)
+  {
+    TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioctx));
+    tracepoint(librbd, clone3_enter, p_ioctx.get_pool_name().c_str(), p_ioctx.get_id(), p_name, p_snap_name, c_ioctx.get_pool_name().c_str(), c_ioctx.get_id(), c_name, c_opts.opts);
+    int r = librbd::clone(p_ioctx, p_name, p_snap_name, c_ioctx, c_name,
+                         c_opts);
+    tracepoint(librbd, clone3_exit, r);
+    return r;
+  }
+
   int RBD::remove(IoCtx& io_ctx, const char *name)
   {
     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
@@ -404,6 +425,60 @@ namespace librbd {
     delete this;
   }
 
+  /*
+    ImageOptions
+  */
+
+  ImageOptions::ImageOptions()
+  {
+    librbd::image_options_create(&opts);
+  }
+
+  ImageOptions::ImageOptions(rbd_image_options_t opts_)
+  {
+    librbd::image_options_create_ref(&opts, opts_);
+  }
+
+  ImageOptions::~ImageOptions()
+  {
+    librbd::image_options_destroy(opts);
+  }
+
+  int ImageOptions::set(int optname, const std::string& optval)
+  {
+    return librbd::image_options_set(opts, optname, optval);
+  }
+
+  int ImageOptions::set(int optname, uint64_t optval)
+  {
+    return librbd::image_options_set(opts, optname, optval);
+  }
+
+  int ImageOptions::get(int optname, std::string* optval) const
+  {
+    return librbd::image_options_get(opts, optname, optval);
+  }
+
+  int ImageOptions::get(int optname, uint64_t* optval) const
+  {
+    return librbd::image_options_get(opts, optname, optval);
+  }
+
+  int ImageOptions::unset(int optname)
+  {
+    return librbd::image_options_unset(opts, optname);
+  }
+
+  void ImageOptions::clear()
+  {
+    librbd::image_options_clear(opts);
+  }
+
+  bool ImageOptions::empty() const
+  {
+    return librbd::image_options_is_empty(opts);
+  }
+
   /*
     Image
   */
@@ -560,8 +635,9 @@ namespace librbd {
   {
     ImageCtx *ictx = (ImageCtx *)ctx;
     tracepoint(librbd, copy_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname);
+    ImageOptions opts;
     librbd::NoOpProgressContext prog_ctx;
-    int r = librbd::copy(ictx, dest_io_ctx, destname, prog_ctx);
+    int r = librbd::copy(ictx, dest_io_ctx, destname, opts, prog_ctx);
     tracepoint(librbd, copy_exit, r);
     return r;
   }
@@ -577,12 +653,23 @@ namespace librbd {
     return r;
   }
 
+  int Image::copy3(IoCtx& dest_io_ctx, const char *destname, ImageOptions& opts)
+  {
+    ImageCtx *ictx = (ImageCtx *)ctx;
+    tracepoint(librbd, copy3_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname, opts.opts);
+    librbd::NoOpProgressContext prog_ctx;
+    int r = librbd::copy(ictx, dest_io_ctx, destname, opts, prog_ctx);
+    tracepoint(librbd, copy3_exit, r);
+    return r;
+  }
+
   int Image::copy_with_progress(IoCtx& dest_io_ctx, const char *destname,
                                librbd::ProgressContext &pctx)
   {
     ImageCtx *ictx = (ImageCtx *)ctx;
     tracepoint(librbd, copy_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname);
-    int r = librbd::copy(ictx, dest_io_ctx, destname, pctx);
+    ImageOptions opts;
+    int r = librbd::copy(ictx, dest_io_ctx, destname, opts, pctx);
     tracepoint(librbd, copy_exit, r);
     return r;
   }
@@ -597,6 +684,17 @@ namespace librbd {
     return r;
   }
 
+  int Image::copy_with_progress3(IoCtx& dest_io_ctx, const char *destname,
+                                ImageOptions& opts,
+                                librbd::ProgressContext &pctx)
+  {
+    ImageCtx *ictx = (ImageCtx *)ctx;
+    tracepoint(librbd, copy3_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname, opts.opts);
+    int r = librbd::copy(ictx, dest_io_ctx, destname, opts, pctx);
+    tracepoint(librbd, copy3_exit, r);
+    return r;
+  }
+
   int Image::flatten()
   {
     ImageCtx *ictx = (ImageCtx *)ctx;
@@ -1053,6 +1151,69 @@ extern "C" void rbd_version(int *major, int *minor, int *extra)
     *extra = LIBRBD_VER_EXTRA;
 }
 
+extern "C" void rbd_image_options_create(rbd_image_options_t* opts)
+{
+  librbd::image_options_create(opts);
+}
+
+extern "C" void rbd_image_options_destroy(rbd_image_options_t opts)
+{
+  librbd::image_options_destroy(opts);
+}
+
+extern "C" int rbd_image_options_set_string(rbd_image_options_t opts, int optname,
+                                           const char* optval)
+{
+  return librbd::image_options_set(opts, optname, optval);
+}
+
+extern "C" int rbd_image_options_set_uint64(rbd_image_options_t opts, int optname,
+                                           uint64_t optval)
+{
+  return librbd::image_options_set(opts, optname, optval);
+}
+
+extern "C" int rbd_image_options_get_string(rbd_image_options_t opts, int optname,
+                                           char* optval, size_t maxlen)
+{
+  std::string optval_;
+
+  int r = librbd::image_options_get(opts, optname, &optval_);
+
+  if (r < 0) {
+    return r;
+  }
+
+  if (optval_.size() >= maxlen) {
+    return -E2BIG;
+  }
+
+  strncpy(optval, optval_.c_str(), maxlen);
+
+  return 0;
+}
+
+extern "C" int rbd_image_options_get_uint64(rbd_image_options_t opts, int optname,
+                                uint64_t* optval)
+{
+  return librbd::image_options_get(opts, optname, optval);
+}
+
+extern "C" int rbd_image_options_unset(rbd_image_options_t opts, int optname)
+{
+  return librbd::image_options_unset(opts, optname);
+}
+
+extern "C" void rbd_image_options_clear(rbd_image_options_t opts)
+{
+  librbd::image_options_clear(opts);
+}
+
+extern "C" int rbd_image_options_is_empty(rbd_image_options_t opts)
+{
+  return librbd::image_options_is_empty(opts);
+}
+
 /* images */
 extern "C" int rbd_list(rados_ioctx_t p, char *names, size_t *size)
 {
@@ -1135,6 +1296,19 @@ extern "C" int rbd_create3(rados_ioctx_t p, const char *name,
   return r;
 }
 
+extern "C" int rbd_create4(rados_ioctx_t p, const char *name,
+                          uint64_t size, rbd_image_options_t opts)
+{
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
+  tracepoint(librbd, create4_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, opts);
+  librbd::ImageOptions opts_(opts);
+  int r = librbd::create(io_ctx, name, size, opts_);
+  tracepoint(librbd, create4_exit, r);
+  return r;
+}
+
 extern "C" int rbd_clone(rados_ioctx_t p_ioctx, const char *p_name,
                         const char *p_snap_name, rados_ioctx_t c_ioctx,
                         const char *c_name, uint64_t features, int *c_order)
@@ -1166,6 +1340,21 @@ extern "C" int rbd_clone2(rados_ioctx_t p_ioctx, const char *p_name,
   return r;
 }
 
+extern "C" int rbd_clone3(rados_ioctx_t p_ioctx, const char *p_name,
+                         const char *p_snap_name, rados_ioctx_t c_ioctx,
+                         const char *c_name, rbd_image_options_t c_opts)
+{
+  librados::IoCtx p_ioc, c_ioc;
+  librados::IoCtx::from_rados_ioctx_t(p_ioctx, p_ioc);
+  librados::IoCtx::from_rados_ioctx_t(c_ioctx, c_ioc);
+  TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioc));
+  tracepoint(librbd, clone3_enter, p_ioc.get_pool_name().c_str(), p_ioc.get_id(), p_name, p_snap_name, c_ioc.get_pool_name().c_str(), c_ioc.get_id(), c_name, c_opts);
+  librbd::ImageOptions c_opts_(c_opts);
+  int r = librbd::clone(p_ioc, p_name, p_snap_name, c_ioc, c_name, c_opts_);
+  tracepoint(librbd, clone3_exit, r);
+  return r;
+}
+
 extern "C" int rbd_remove(rados_ioctx_t p, const char *name)
 {
   librados::IoCtx io_ctx;
@@ -1198,8 +1387,9 @@ extern "C" int rbd_copy(rbd_image_t image, rados_ioctx_t dest_p,
   librados::IoCtx dest_io_ctx;
   librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
   tracepoint(librbd, copy_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname);
+  librbd::ImageOptions opts;
   librbd::NoOpProgressContext prog_ctx;
-  int r = librbd::copy(ictx, dest_io_ctx, destname, prog_ctx);
+  int r = librbd::copy(ictx, dest_io_ctx, destname, opts, prog_ctx);
   tracepoint(librbd, copy_exit, r);
   return r;
 }
@@ -1215,6 +1405,20 @@ extern "C" int rbd_copy2(rbd_image_t srcp, rbd_image_t destp)
   return r;
 }
 
+extern "C" int rbd_copy3(rbd_image_t image, rados_ioctx_t dest_p,
+                        const char *destname, rbd_image_options_t c_opts)
+{
+  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+  librados::IoCtx dest_io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
+  tracepoint(librbd, copy3_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname, c_opts);
+  librbd::ImageOptions c_opts_(c_opts);
+  librbd::NoOpProgressContext prog_ctx;
+  int r = librbd::copy(ictx, dest_io_ctx, destname, c_opts_, prog_ctx);
+  tracepoint(librbd, copy3_exit, r);
+  return r;
+}
+
 extern "C" int rbd_copy_with_progress(rbd_image_t image, rados_ioctx_t dest_p,
                                      const char *destname,
                                      librbd_progress_fn_t fn, void *data)
@@ -1223,8 +1427,9 @@ extern "C" int rbd_copy_with_progress(rbd_image_t image, rados_ioctx_t dest_p,
   librados::IoCtx dest_io_ctx;
   librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
   tracepoint(librbd, copy_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname);
+  librbd::ImageOptions opts;
   librbd::CProgressContext prog_ctx(fn, data);
-  int ret = librbd::copy(ictx, dest_io_ctx, destname, prog_ctx);
+  int ret = librbd::copy(ictx, dest_io_ctx, destname, opts, prog_ctx);
   tracepoint(librbd, copy_exit, ret);
   return ret;
 }
@@ -1241,6 +1446,22 @@ extern "C" int rbd_copy_with_progress2(rbd_image_t srcp, rbd_image_t destp,
   return ret;
 }
 
+extern "C" int rbd_copy_with_progress3(rbd_image_t image, rados_ioctx_t dest_p,
+                                      const char *destname,
+                                      rbd_image_options_t dest_opts,
+                                      librbd_progress_fn_t fn, void *data)
+{
+  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+  librados::IoCtx dest_io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
+  tracepoint(librbd, copy_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname);
+  librbd::ImageOptions dest_opts_(dest_opts);
+  librbd::CProgressContext prog_ctx(fn, data);
+  int ret = librbd::copy(ictx, dest_io_ctx, destname, dest_opts_, prog_ctx);
+  tracepoint(librbd, copy_exit, ret);
+  return ret;
+}
+
 extern "C" int rbd_flatten(rbd_image_t image)
 {
   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
index 9b8664ca14c81c1fafa77b75a5c5289706e752f3..8ff074a9ff8945a8d3dbdb194aa8c5600dfe0fac 100644 (file)
@@ -65,6 +65,12 @@ RBD_FEATURES_SINGLE_CLIENT = (RBD_FEATURE_EXCLUSIVE_LOCK |
 
 RBD_FLAG_OBJECT_MAP_INVALID = 1
 
+RBD_IMAGE_OPTION_FORMAT = 0
+RBD_IMAGE_OPTION_FEATURES = 1
+RBD_IMAGE_OPTION_ORDER = 2
+RBD_IMAGE_OPTION_STRIPE_UNIT = 3
+RBD_IMAGE_OPTION_STRIPE_COUNT = 4
+
 
 class Error(Exception):
     pass
@@ -257,11 +263,37 @@ class RBD(object):
             if not hasattr(self.librbd, 'rbd_create2'):
                 raise FunctionNotSupported('installed version of librbd does'
                                            ' not support format 2 images')
+            has_create4 = hasattr(self.librbd, 'rbd_create4')
             has_create3 = hasattr(self.librbd, 'rbd_create3')
             if (stripe_unit != 0 or stripe_count != 0) and not has_create3:
                 raise FunctionNotSupported('installed version of librbd does'
                                            ' not support stripe unit or count')
-            if has_create3:
+            if has_create4:
+                format = old_format and 1 or 2
+                opts = c_void_p()
+                self.librbd.rbd_image_options_create(byref(opts))
+                self.librbd.rbd_image_options_set_uint64(opts,
+                                                         RBD_IMAGE_OPTION_FORMAT,
+                                                         c_uint64(format))
+                self.librbd.rbd_image_options_set_uint64(opts,
+                                                         RBD_IMAGE_OPTION_FEATURES,
+                                                         c_uint64(features))
+                self.librbd.rbd_image_options_set_uint64(opts,
+                                                         RBD_IMAGE_OPTION_ORDER,
+                                                         c_uint64(order))
+                self.librbd.rbd_image_options_set_uint64(opts,
+                                                         RBD_IMAGE_OPTION_STRIPE_UNIT,
+                                                         c_uint64(stripe_unit))
+                self.librbd.rbd_image_options_set_uint64(opts,
+                                                         RBD_IMAGE_OPTION_STRIPE_COUNT,
+                                                         c_uint64(stripe_count))
+                ret = self.librbd.rbd_create4(ioctx.io, c_char_p(name),
+                                              c_uint64(size), opts)
+                self.librbd.rbd_image_options_get_uint64(opts,
+                                                         RBD_IMAGE_OPTION_ORDER,
+                                                         byref(c_uint64(order)))
+                self.librbd.rbd_image_options_destroy(opts)
+            elif has_create3:
                 ret = self.librbd.rbd_create3(ioctx.io, c_char_p(name),
                                               c_uint64(size),
                                               c_uint64(features),
@@ -277,7 +309,7 @@ class RBD(object):
             raise make_ex(ret, 'error creating image')
 
     def clone(self, p_ioctx, p_name, p_snapname, c_ioctx, c_name,
-              features=0, order=None):
+              features=0, order=None, stripe_unit=0, stripe_count=0):
         """
         Clone a parent rbd snapshot into a COW sparse child.
 
@@ -295,6 +327,10 @@ class RBD(object):
         :type features: int
         :param order: the image is split into (2**order) byte objects
         :type order: int
+        :param stripe_unit: stripe unit in bytes (default 0 for object size)
+        :type stripe_unit: int
+        :param stripe_count: objects to stripe over before looping
+        :type stripe_count: int
         :raises: :class:`TypeError`
         :raises: :class:`InvalidArgument`
         :raises: :class:`ImageExists`
@@ -308,11 +344,39 @@ class RBD(object):
         if not isinstance(c_name, str):
             raise TypeError('child name must be a string')
 
-        ret = self.librbd.rbd_clone(p_ioctx.io, c_char_p(p_name),
-                                    c_char_p(p_snapname),
-                                    c_ioctx.io, c_char_p(c_name),
-                                    c_uint64(features),
-                                    byref(c_int(order)))
+        has_clone3 = hasattr(self.librbd, 'rbd_clone3')
+        if (stripe_unit != 0 or stripe_count != 0) and not has_clone3:
+            raise FunctionNotSupported('installed version of librbd does'
+                                       ' not support stripe unit or count')
+        if has_clone3:
+            opts = c_void_p()
+            self.librbd.rbd_image_options_create(byref(opts))
+            self.librbd.rbd_image_options_set_uint64(opts,
+                                                     RBD_IMAGE_OPTION_FEATURES,
+                                                     c_uint64(features))
+            self.librbd.rbd_image_options_set_uint64(opts,
+                                                     RBD_IMAGE_OPTION_ORDER,
+                                                     c_uint64(order))
+            self.librbd.rbd_image_options_set_uint64(opts,
+                                                     RBD_IMAGE_OPTION_STRIPE_UNIT,
+                                                     c_uint64(stripe_unit))
+            self.librbd.rbd_image_options_set_uint64(opts,
+                                                     RBD_IMAGE_OPTION_STRIPE_COUNT,
+                                                     c_uint64(stripe_count))
+            ret = self.librbd.rbd_clone3(p_ioctx.io, c_char_p(p_name),
+                                         c_char_p(p_snapname),
+                                         c_ioctx.io, c_char_p(c_name),
+                                         opts)
+            self.librbd.rbd_image_options_get_uint64(opts,
+                                                     RBD_IMAGE_OPTION_ORDER,
+                                                     byref(c_uint64(order)))
+            self.librbd.rbd_image_options_destroy(opts)
+        else:
+            ret = self.librbd.rbd_clone(p_ioctx.io, c_char_p(p_name),
+                                        c_char_p(p_snapname),
+                                        c_ioctx.io, c_char_p(c_name),
+                                        c_uint64(features),
+                                        byref(c_int(order)))
         if ret < 0:
             raise make_ex(ret, 'error creating clone')
 
@@ -632,7 +696,8 @@ class Image(object):
             raise make_ex(ret, 'error getting lock status for image' % (self.name))
         return owner.value == 1
 
-    def copy(self, dest_ioctx, dest_name):
+    def copy(self, dest_ioctx, dest_name, features=0, order=None, stripe_unit=0,
+             stripe_count=0):
         """
         Copy the image to another location.
 
@@ -640,11 +705,51 @@ class Image(object):
         :type dest_ioctx: :class:`rados.Ioctx`
         :param dest_name: the name of the copy
         :type dest_name: str
+        :param features: bitmask of features to enable; if set, must include layering
+        :type features: int
+        :param order: the image is split into (2**order) byte objects
+        :type order: int
+        :param stripe_unit: stripe unit in bytes (default 0 for object size)
+        :type stripe_unit: int
+        :param stripe_count: objects to stripe over before looping
+        :type stripe_count: int
+        :raises: :class:`TypeError`
+        :raises: :class:`InvalidArgument`
         :raises: :class:`ImageExists`
+        :raises: :class:`FunctionNotSupported`
+        :raises: :class:`ArgumentOutOfRange`
         """
+        if order is None:
+            order = 0
         if not isinstance(dest_name, str):
             raise TypeError('dest_name must be a string')
-        ret = self.librbd.rbd_copy(self.image, dest_ioctx.io, c_char_p(dest_name))
+        has_copy3 = hasattr(self.librbd, 'rbd_copy3')
+        if (stripe_unit != 0 or stripe_count != 0) and not has_copy3:
+            raise FunctionNotSupported('installed version of librbd does'
+                                       ' not support stripe unit or count')
+        if has_copy3:
+            opts = c_void_p()
+            self.librbd.rbd_image_options_create(byref(opts))
+            self.librbd.rbd_image_options_set_uint64(opts,
+                                                     RBD_IMAGE_OPTION_FEATURES,
+                                                     c_uint64(features))
+            self.librbd.rbd_image_options_set_uint64(opts,
+                                                     RBD_IMAGE_OPTION_ORDER,
+                                                     c_uint64(order))
+            self.librbd.rbd_image_options_set_uint64(opts,
+                                                     RBD_IMAGE_OPTION_STRIPE_UNIT,
+                                                     c_uint64(stripe_unit))
+            self.librbd.rbd_image_options_set_uint64(opts,
+                                                     RBD_IMAGE_OPTION_STRIPE_COUNT,
+                                                     c_uint64(stripe_count))
+            ret = self.librbd.rbd_copy3(self.image, dest_ioctx.io,
+                                        c_char_p(dest_name), opts)
+            self.librbd.rbd_image_options_get_uint64(opts,
+                                                     RBD_IMAGE_OPTION_ORDER,
+                                                     byref(c_uint64(order)))
+            self.librbd.rbd_image_options_destroy(opts)
+        else:
+            ret = self.librbd.rbd_copy(self.image, dest_ioctx.io, c_char_p(dest_name))
         if ret < 0:
             raise make_ex(ret, 'error copying image %s to %s' % (self.name, dest_name))
 
index 542084918e2fd03861b6ce4af62c36c93f62cff0..f6e1cb1b0bb2098962fa3e5010187b796319e1d1 100644 (file)
@@ -305,6 +305,29 @@ TRACEPOINT_EVENT(librbd, create3_exit,
     )
 )
 
+TRACEPOINT_EVENT(librbd, create4_enter,
+    TP_ARGS(
+        const char*, pool_name,
+        int64_t, id,
+        const char*, imgname,
+        uint64_t, size,
+        void*, opts),
+    TP_FIELDS(
+        ctf_string(pool_name, pool_name)
+        ctf_integer(int64_t, id, id)
+        ctf_string(imgname, imgname)
+        ctf_integer_hex(void*, opts, opts)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, create4_exit,
+    TP_ARGS(
+        int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
 TRACEPOINT_EVENT(librbd, remove_enter,
     TP_ARGS(
         const char*, pool_name,
@@ -671,6 +694,36 @@ TRACEPOINT_EVENT(librbd, copy2_exit,
     )
 )
 
+TRACEPOINT_EVENT(librbd, copy3_enter,
+    TP_ARGS(
+        void*, src_imagectx,
+        const char*, src_name,
+        const char*, src_snap_name,
+        char, src_read_only,
+        const char*, dst_pool_name,
+        uint64_t, dst_id,
+        const char*, dst_name,
+        void*, opts),
+    TP_FIELDS(
+        ctf_integer_hex(void*, src_imagectx, src_imagectx)
+        ctf_string(src_name, src_name)
+        ctf_string(src_snap_name, src_snap_name)
+        ctf_integer(char, src_read_only, src_read_only)
+        ctf_string(dst_pool_name, dst_pool_name)
+        ctf_integer(uint64_t, dst_id, dst_id)
+        ctf_string(dst_name, dst_name)
+        ctf_integer_hex(void*, opts, opts)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, copy3_exit,
+    TP_ARGS(
+        int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
 TRACEPOINT_EVENT(librbd, resize_enter,
     TP_ARGS(
         void*, imagectx,
@@ -874,6 +927,36 @@ TRACEPOINT_EVENT(librbd, clone2_exit,
     )
 )
 
+TRACEPOINT_EVENT(librbd, clone3_enter,
+    TP_ARGS(
+        const char*, parent_pool_name,
+        uint64_t, parent_id,
+        const char*, parent_name,
+        const char*, parent_snap_name,
+        const char*, child_pool_name,
+        uint64_t, child_id,
+        const char*, child_name,
+       void*, opts),
+    TP_FIELDS(
+        ctf_string(parent_pool_name, parent_pool_name)
+        ctf_integer(uint64_t, parent_id, parent_id)
+        ctf_string(parent_name, parent_name)
+        ctf_string(parent_snap_name, parent_snap_name)
+        ctf_string(child_pool_name, child_pool_name)
+        ctf_integer(uint64_t, child_id, child_id)
+        ctf_string(child_name, child_name)
+       ctf_integer_hex(void*, opts, opts)
+    )
+)
+
+TRACEPOINT_EVENT(librbd, clone3_exit,
+    TP_ARGS(
+        int, retval),
+    TP_FIELDS(
+        ctf_integer(int, retval, retval)
+    )
+)
+
 TRACEPOINT_EVENT(librbd, flatten_enter,
     TP_ARGS(
         void*, imagectx,