]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
Add struct parent_spec
authorDan Mick <dan.mick@inktank.com>
Sat, 11 Aug 2012 02:31:38 +0000 (19:31 -0700)
committerDan Mick <dan.mick@inktank.com>
Sat, 18 Aug 2012 01:31:51 +0000 (18:31 -0700)
Holds poolid,imageid,snapid triple identifying parent
Allows for equality comparison of parents

src/librbd/ImageCtx.cc
src/librbd/cls_rbd_client.cc
src/librbd/cls_rbd_client.h
src/librbd/internal.cc
src/test/rbd/test_cls_rbd.cc

index bde095e9922b2a2da45b12a8dc65bcde2733a497..ab4eda57b1fb82c3ff6a2665bc3b1ea7e112a57e 100644 (file)
@@ -287,7 +287,7 @@ namespace librbd {
     assert(snap_lock.is_locked());
     assert(parent_lock.is_locked());
     if (in_snap_id == CEPH_NOSNAP) {
-      return parent_md.pool_id;
+      return parent_md.spec.pool_id;
     }
     string in_snap_name;
     int r = get_snap_name(in_snap_id, &in_snap_name);
@@ -296,7 +296,7 @@ namespace librbd {
     map<string, SnapInfo>::const_iterator p = snaps_by_name.find(in_snap_name);
     if (p == snaps_by_name.end())
       return -1;
-    return p->second.parent.pool_id;
+    return p->second.parent.spec.pool_id;
   }
 
   string ImageCtx::get_parent_image_id(snap_t in_snap_id) const
@@ -304,7 +304,7 @@ namespace librbd {
     assert(snap_lock.is_locked());
     assert(parent_lock.is_locked());
     if (in_snap_id == CEPH_NOSNAP) {
-      return parent_md.image_id;
+      return parent_md.spec.image_id;
     }
     string in_snap_name;
     int r = get_snap_name(in_snap_id, &in_snap_name);
@@ -313,7 +313,7 @@ namespace librbd {
     map<string, SnapInfo>::const_iterator p = snaps_by_name.find(in_snap_name);
     if (p == snaps_by_name.end())
       return "";
-    return p->second.parent.image_id;
+    return p->second.parent.spec.image_id;
   }
 
   uint64_t ImageCtx::get_parent_snap_id(snap_t in_snap_id) const
@@ -321,7 +321,7 @@ namespace librbd {
     assert(snap_lock.is_locked());
     assert(parent_lock.is_locked());
     if (in_snap_id == CEPH_NOSNAP) {
-      return parent_md.snap_id;
+      return parent_md.spec.snap_id;
     }
     string in_snap_name;
     int r = get_snap_name(in_snap_id, &in_snap_name);
@@ -330,7 +330,7 @@ namespace librbd {
     map<string, SnapInfo>::const_iterator p = snaps_by_name.find(in_snap_name);
     if (p == snaps_by_name.end())
       return CEPH_NOSNAP;
-    return p->second.parent.snap_id;
+    return p->second.parent.spec.snap_id;
   }
 
   int ImageCtx::get_parent_overlap(snap_t in_snap_id, uint64_t *overlap) const
index d0e78637803eb85036de7bdc875066a6728f91fd..5c9e9db3e5d9546d4b6df0bc4f0d3e421186501e 100644 (file)
@@ -91,9 +91,9 @@ namespace librbd {
        ::decode(*lockers, iter);
        ::decode(*exclusive_lock, iter);
        // get_parent
-       ::decode(parent->pool_id, iter);
-       ::decode(parent->image_id, iter);
-       ::decode(parent->snap_id, iter);
+       ::decode(parent->spec.pool_id, iter);
+       ::decode(parent->spec.image_id, iter);
+       ::decode(parent->spec.snap_id, iter);
        ::decode(parent->overlap, iter);
       } catch (const buffer::error &err) {
        return -EBADMSG;
@@ -184,8 +184,7 @@ namespace librbd {
     }
 
     int get_parent(librados::IoCtx *ioctx, const std::string &oid,
-                  snapid_t snap_id, int64_t *parent_pool,
-                  string *parent_image, snapid_t *parent_snap_id,
+                  snapid_t snap_id, parent_spec *pspec, 
                   uint64_t *parent_overlap)
     {
       bufferlist inbl, outbl;
@@ -197,9 +196,9 @@ namespace librbd {
 
       try {
        bufferlist::iterator iter = outbl.begin();
-       ::decode(*parent_pool, iter);
-       ::decode(*parent_image, iter);
-       ::decode(*parent_snap_id, iter);
+       ::decode(pspec->pool_id, iter);
+       ::decode(pspec->image_id, iter);
+       ::decode(pspec->snap_id, iter);
        ::decode(*parent_overlap, iter);
       } catch (const buffer::error &err) {
        return -EBADMSG;
@@ -209,13 +208,12 @@ namespace librbd {
     }
 
     int set_parent(librados::IoCtx *ioctx, const std::string &oid,
-                  int64_t parent_pool, const string& parent_image,
-                  snapid_t parent_snap_id, uint64_t parent_overlap)
+                  parent_spec pspec, uint64_t parent_overlap)
     {
       bufferlist inbl, outbl;
-      ::encode(parent_pool, inbl);
-      ::encode(parent_image, inbl);
-      ::encode(parent_snap_id, inbl);
+      ::encode(pspec.pool_id, inbl);
+      ::encode(pspec.image_id, inbl);
+      ::encode(pspec.snap_id, inbl);
       ::encode(parent_overlap, inbl);
 
       return ioctx->exec(oid, "rbd", "set_parent", inbl, outbl);
@@ -228,39 +226,36 @@ namespace librbd {
     }
 
     int add_child(librados::IoCtx *ioctx, const std::string &oid,
-                 uint64_t p_poolid, const std::string &p_imageid,
-                 snapid_t p_snapid, const std::string &c_imageid)
+                 parent_spec pspec, const std::string &c_imageid)
     {
       bufferlist in, out;
-      ::encode(p_poolid, in);
-      ::encode(p_imageid, in);
-      ::encode(p_snapid, in);
+      ::encode(pspec.pool_id, in);
+      ::encode(pspec.image_id, in);
+      ::encode(pspec.snap_id, in);
       ::encode(c_imageid, in);
 
       return ioctx->exec(oid, "rbd", "add_child", in, out);
     }
 
     int remove_child(librados::IoCtx *ioctx, const std::string &oid,
-                    uint64_t p_poolid, const std::string &p_imageid,
-                    snapid_t p_snapid, const std::string &c_imageid)
+                    parent_spec pspec, const std::string &c_imageid)
     {
       bufferlist in, out;
-      ::encode(p_poolid, in);
-      ::encode(p_imageid, in);
-      ::encode(p_snapid, in);
+      ::encode(pspec.pool_id, in);
+      ::encode(pspec.image_id, in);
+      ::encode(pspec.snap_id, in);
       ::encode(c_imageid, in);
 
       return ioctx->exec(oid, "rbd", "remove_child", in, out);
     }
 
     int get_children(librados::IoCtx *ioctx, const std::string &oid,
-                    uint64_t p_poolid, const std::string &p_imageid,
-                    snapid_t p_snapid, set<string>& children)
+                    parent_spec pspec, set<string>& children)
     {
       bufferlist in, out;
-      ::encode(p_poolid, in);
-      ::encode(p_imageid, in);
-      ::encode(p_snapid, in);
+      ::encode(pspec.pool_id, in);
+      ::encode(pspec.image_id, in);
+      ::encode(pspec.snap_id, in);
 
       int r = ioctx->exec(oid, "rbd", "get_children", in, out);
       if (r < 0)
@@ -365,9 +360,9 @@ namespace librbd {
          ::decode((*features)[i], iter);
          ::decode(incompat_features, iter);
          // get_parent
-         ::decode((*parents)[i].pool_id, iter);
-         ::decode((*parents)[i].image_id, iter);
-         ::decode((*parents)[i].snap_id, iter);
+         ::decode((*parents)[i].spec.pool_id, iter);
+         ::decode((*parents)[i].spec.image_id, iter);
+         ::decode((*parents)[i].spec.snap_id, iter);
          ::decode((*parents)[i].overlap, iter);
        }
       } catch (const buffer::error &err) {
index 285ed3739616bd200b7174f6f7de353a99b01942..51c1c3a06cf8328494ec26d9ab6cfdde166a38f4 100644 (file)
 
 namespace librbd {
   namespace cls_client {
-
-    struct parent_info {
+    struct parent_spec {
       int64_t pool_id;
       string image_id;
       snapid_t snap_id;
+      parent_spec() : pool_id(-1), snap_id(CEPH_NOSNAP) {}
+      parent_spec(uint64_t pool_id, string image_id, snapid_t snap_id) :
+       pool_id(pool_id), image_id(image_id), snap_id(snap_id) {}
+      bool operator==(const parent_spec &other) {
+       return ((this->pool_id == other.pool_id) &&
+               (this->image_id == other.image_id) &&
+               (this->snap_id == other.snap_id));
+      }
+      bool operator!=(const parent_spec &other) {
+       return !(*this == other);
+      }
+    };
+
+    struct parent_info {
+      struct parent_spec spec;
       uint64_t overlap;
-      parent_info() : pool_id(-1), snap_id(CEPH_NOSNAP), overlap(0) {}
+      parent_info() : overlap(0) {}
     };
 
     // high-level interface to the header
@@ -49,22 +63,17 @@ namespace librbd {
     int set_size(librados::IoCtx *ioctx, const std::string &oid,
                 uint64_t size);
     int get_parent(librados::IoCtx *ioctx, const std::string &oid,
-                  snapid_t snap_id, int64_t *parent_pool,
-                  std::string *parent_image, snapid_t *parent_snap_id,
+                  snapid_t snap_id, parent_spec *pspec,
                   uint64_t *parent_overlap);
     int set_parent(librados::IoCtx *ioctx, const std::string &oid,
-                  int64_t parent_pool, const std::string& parent_image,
-                  snapid_t parent_snap_id, uint64_t parent_overlap);
+                  parent_spec pspec, uint64_t parent_overlap);
     int remove_parent(librados::IoCtx *ioctx, const std::string &oid);
     int add_child(librados::IoCtx *ioctx, const std::string &oid,
-                 uint64_t p_poolid, const std::string &p_imageid,
-                 snapid_t p_snapid, const std::string &c_imageid);
+                 parent_spec pspec, const std::string &c_imageid);
     int remove_child(librados::IoCtx *ioctx, const std::string &oid,
-                    uint64_t p_poolid, const std::string &p_imageid,
-                    snapid_t p_snapid, const std::string &c_imageid);
+                    parent_spec pspec, const std::string &c_imageid);
     int get_children(librados::IoCtx *ioctx, const std::string &oid,
-                    uint64_t p_poolid, const std::string &p_imageid,
-                    snapid_t p_snapid, set<string>& children);
+                    parent_spec pspec, set<string>& children);
     int snapshot_add(librados::IoCtx *ioctx, const std::string &oid,
                     snapid_t snap_id, const std::string &snap_name);
     int snapshot_remove(librados::IoCtx *ioctx, const std::string &oid,
index 20b13c5567612d26c1d1d5dd2ea255b8c292790c..07c7ce0761e584f286f1d8dd220d34e587f62ae8 100644 (file)
@@ -428,17 +428,15 @@ namespace librbd {
     // that could be because the parent was flattened before the snapshots
     // were removed.  In any case, this is now the time we should
     // remove the child from the child list.
-    if (ictx->snaps.size() == 1 && (ictx->parent_md.pool_id == -1)) {
+    if (ictx->snaps.size() == 1 && (ictx->parent_md.spec.pool_id == -1)) {
       SnapInfo *snapinfo;
       Mutex::Locker l(ictx->snap_lock);
       r = ictx->get_snapinfo(snap_id, &snapinfo);
       if (r < 0)
        return r;
-      if (snapinfo->parent.pool_id != -1) {
+      if (snapinfo->parent.spec.pool_id != -1) {
        r = cls_client::remove_child(&ictx->md_ctx, RBD_CHILDREN,
-                                    snapinfo->parent.pool_id,
-                                    snapinfo->parent.image_id,
-                                    snapinfo->parent.snap_id, ictx->id);
+                                    snapinfo->parent.spec, ictx->id);
        if (r < 0)
          return r;
       }
@@ -622,6 +620,9 @@ namespace librbd {
       order = p_imctx->order;
     }
 
+    cls_client::parent_spec pspec(p_ioctx.get_id(), p_imctx->id,
+                                 p_imctx->snap_id);
+
     int remove_r;
     librbd::NoOpProgressContext no_op;
     ImageCtx *c_imctx = NULL;
@@ -631,9 +632,6 @@ namespace librbd {
       goto err_close_parent;
     }
 
-    int64_t p_poolid;
-    p_poolid = p_ioctx.get_id();
-
     c_imctx = new ImageCtx(c_name, "", NULL, c_ioctx);
     r = open_image(c_imctx, true);
     if (r < 0) {
@@ -641,15 +639,13 @@ namespace librbd {
       goto err_remove;
     }
 
-    r = cls_client::set_parent(&c_ioctx, c_imctx->header_oid, p_poolid,
-                              p_imctx->id, p_imctx->snap_id, size);
+    r = cls_client::set_parent(&c_ioctx, c_imctx->header_oid, pspec, size);
     if (r < 0) {
       lderr(cct) << "couldn't set parent: " << r << dendl;
       goto err_close_child;
     }
 
-    r = cls_client::add_child(&c_ioctx, RBD_CHILDREN, p_poolid, p_imctx->id,
-                             p_imctx->snap_id, c_imctx->id);
+    r = cls_client::add_child(&c_ioctx, RBD_CHILDREN, pspec, c_imctx->id);
     if (r < 0) {
       lderr(cct) << "couldn't add child: " << r << dendl;
       goto err_close_child;
@@ -915,12 +911,13 @@ namespace librbd {
        return r;
       }
       parent_info = &(snapinfo->parent);
-      if (parent_info->pool_id == -1)
+      if (parent_info->spec.pool_id == -1)
        return 0;
     }
     if (parent_pool_name) {
       Rados rados(ictx->md_ctx);
-      r = rados.pool_reverse_lookup(parent_info->pool_id, parent_pool_name);
+      r = rados.pool_reverse_lookup(parent_info->spec.pool_id,
+                                   parent_pool_name);
       if (r < 0) {
        lderr(ictx->cct) << "error looking up pool name" << cpp_strerror(r)
                         << dendl;
@@ -929,7 +926,8 @@ namespace librbd {
 
     if (parent_snap_name) {
       Mutex::Locker l(ictx->parent->snap_lock);
-      r = ictx->parent->get_snap_name(parent_info->snap_id, parent_snap_name);
+      r = ictx->parent->get_snap_name(parent_info->spec.snap_id,
+                                     parent_snap_name);
       if (r < 0) {
        lderr(ictx->cct) << "error finding parent snap name: "
                         << cpp_strerror(r) << dendl;
@@ -939,7 +937,7 @@ namespace librbd {
 
     if (parent_name) {
       r = cls_client::dir_get_name(&ictx->parent->md_ctx, RBD_DIRECTORY,
-                                  parent_info->image_id, parent_name);
+                                  parent_info->spec.image_id, parent_name);
       if (r < 0) {
        lderr(ictx->cct) << "error getting parent image name: "
                         << cpp_strerror(r) << dendl;
@@ -982,12 +980,10 @@ namespace librbd {
       ictx->parent_lock.Unlock();
       close_image(ictx);
 
-      if (parent_info.pool_id != -1) {
+      if (parent_info.spec.pool_id != -1) {
        ldout(cct, 2) << "removing child from children list..." << dendl;
        int r = cls_client::remove_child(&io_ctx, RBD_CHILDREN,
-                                        parent_info.pool_id,
-                                        parent_info.image_id,
-                                        parent_info.snap_id, id);
+                                        parent_info.spec, id);
        if (r < 0) {
          lderr(cct) << "error removing child from children list" << dendl;
          return r;
@@ -1627,7 +1623,7 @@ namespace librbd {
     Mutex::Locker l2(ictx->snap_lock);
     Mutex::Locker l3(ictx->parent_lock);
     // can't flatten a non-clone
-    if (ictx->parent_md.pool_id == -1) {
+    if (ictx->parent_md.spec.pool_id == -1) {
       lderr(ictx->cct) << "image has no parent" << dendl;
       return -EINVAL;
     }
@@ -1675,9 +1671,7 @@ namespace librbd {
     if (ictx->snaps.empty()) {
       ldout(ictx->cct, 2) << "removing child from children list..." << dendl;
       int r = cls_client::remove_child(&ictx->md_ctx, RBD_CHILDREN,
-                                      ictx->parent_md.pool_id,
-                                      ictx->parent_md.image_id,
-                                      ictx->parent_md.snap_id, ictx->id);
+                                      ictx->parent_md.spec, ictx->id);
       if (r < 0) {
        lderr(ictx->cct) << "error removing child from children list" << dendl;
        return r;
index b9427758e4c7ecbdb72a884bd379c0ade7b82228..d4f9990f4344f3859ffada88e550f54f452e686d 100644 (file)
@@ -46,6 +46,7 @@ using ::librbd::cls_client::dir_add_image;
 using ::librbd::cls_client::dir_remove_image;
 using ::librbd::cls_client::dir_rename_image;
 using ::librbd::cls_client::parent_info;
+using ::librbd::cls_client::parent_spec;
 
 static char *random_buf(size_t len)
 {
@@ -153,18 +154,16 @@ TEST(cls_rbd, add_remove_child)
   string oid = "rbd_children_test";
   ASSERT_EQ(0, ioctx.create(oid, true));
 
-  string parent_image = "parent_id";
   string snapname = "parent_snap";
   snapid_t snapid(10);
+  string parent_image = "parent_id";
   string child_image = "child_id";
-  uint64_t poolid = ioctx.get_id();
   set<string>children;
+  parent_spec pspec(ioctx.get_id(), parent_image, snapid);
 
   // nonexistent children cannot be listed or removed
-  ASSERT_EQ(-ENOENT, get_children(&ioctx, oid, poolid, parent_image, snapid,
-           children));
-  ASSERT_EQ(-ENOENT, remove_child(&ioctx, oid, poolid, parent_image, snapid,
-           child_image));
+  ASSERT_EQ(-ENOENT, get_children(&ioctx, oid, pspec, children));
+  ASSERT_EQ(-ENOENT, remove_child(&ioctx, oid, pspec, child_image));
 
   // make a parent with a snapshot
   ASSERT_EQ(0, create_image(&ioctx, parent_image, 2<<20, 0,
@@ -172,15 +171,12 @@ TEST(cls_rbd, add_remove_child)
   ASSERT_EQ(0, snapshot_add(&ioctx, parent_image, snapid, snapname));
 
   // add, verify it showed up
-  ASSERT_EQ(0, add_child(&ioctx, oid, poolid, parent_image, snapid,
-            child_image));
-  ASSERT_EQ(0, get_children(&ioctx, oid, poolid, parent_image, snapid,
-           children));
+  ASSERT_EQ(0, add_child(&ioctx, oid, pspec, child_image));
+  ASSERT_EQ(0, get_children(&ioctx, oid, pspec, children));
   bool found = (children.find(child_image) != children.end());
   ASSERT_EQ(found, true);
 
-  ASSERT_EQ(0, remove_child(&ioctx, oid, poolid, parent_image, snapid,
-           child_image));
+  ASSERT_EQ(0, remove_child(&ioctx, oid, pspec, child_image));
   ioctx.close();
   ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados));
 }
@@ -536,147 +532,146 @@ TEST(cls_rbd, parents)
   ASSERT_EQ("", create_one_pool_pp(pool_name, rados));
   ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx));
 
-  int64_t pool;
-  string parent;
-  snapid_t snapid;
+  parent_spec pspec;
   uint64_t size;
 
-  ASSERT_EQ(-ENOENT, get_parent(&ioctx, "doesnotexist", CEPH_NOSNAP, &pool, &parent, &snapid, &size));
+  ASSERT_EQ(-ENOENT, get_parent(&ioctx, "doesnotexist", CEPH_NOSNAP, &pspec, &size));
 
   // old image should fail
   ASSERT_EQ(0, create_image(&ioctx, "old", 33<<20, 22, 0, "old_blk."));
-  ASSERT_EQ(-ENOEXEC, get_parent(&ioctx, "old", CEPH_NOSNAP, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(-ENOEXEC, set_parent(&ioctx, "old", -1, "parent", 3, 10<<20));
+  pspec = parent_spec(-1, "parent", 3);
+  ASSERT_EQ(-ENOEXEC, set_parent(&ioctx, "old", parent_spec(-1, "parent", 3), 10<<20));
   ASSERT_EQ(-ENOEXEC, remove_parent(&ioctx, "old"));
 
   // new image will work
   ASSERT_EQ(0, create_image(&ioctx, "foo", 33<<20, 22, RBD_FEATURE_LAYERING, "foo."));
 
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(-1, pool);
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", 123, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(-1, pool);
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pspec, &size));
+  ASSERT_EQ(-1, pspec.pool_id);
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", 123, &pspec, &size));
+  ASSERT_EQ(-1, pspec.pool_id);
 
-  ASSERT_EQ(-EINVAL, set_parent(&ioctx, "foo", -1, "parent", 3, 10<<20));
-  ASSERT_EQ(-EINVAL, set_parent(&ioctx, "foo", 1, "", 3, 10<<20));
-  ASSERT_EQ(-EINVAL, set_parent(&ioctx, "foo", 1, "parent", CEPH_NOSNAP, 10<<20));
-  ASSERT_EQ(-EINVAL, set_parent(&ioctx, "foo", 1, "parent", 3, 0));
+  ASSERT_EQ(-EINVAL, set_parent(&ioctx, "foo", parent_spec(-1, "parent", 3), 10<<20));
+  ASSERT_EQ(-EINVAL, set_parent(&ioctx, "foo", parent_spec(1, "", 3), 10<<20));
+  ASSERT_EQ(-EINVAL, set_parent(&ioctx, "foo", parent_spec(1, "parent", CEPH_NOSNAP), 10<<20));
+  ASSERT_EQ(-EINVAL, set_parent(&ioctx, "foo", parent_spec(1, "parent", 3), 0));
 
-  ASSERT_EQ(0, set_parent(&ioctx, "foo", 1, "parent", 3, 10<<20));
-  ASSERT_EQ(-EEXIST, set_parent(&ioctx, "foo", 1, "parent", 3, 10<<20));
-  ASSERT_EQ(-EEXIST, set_parent(&ioctx, "foo", 2, "parent", 34, 10<<20));
+  pspec = parent_spec(1, "parent", 3);
+  ASSERT_EQ(0, set_parent(&ioctx, "foo", pspec, 10<<20));
+  ASSERT_EQ(-EEXIST, set_parent(&ioctx, "foo", pspec, 10<<20));
+  ASSERT_EQ(-EEXIST, set_parent(&ioctx, "foo", parent_spec(2, "parent", 34), 10<<20));
 
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 1);
-  ASSERT_EQ(parent, "parent");
-  ASSERT_EQ(snapid, snapid_t(3));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 1);
+  ASSERT_EQ(pspec.image_id, "parent");
+  ASSERT_EQ(pspec.snap_id, snapid_t(3));
 
   ASSERT_EQ(0, remove_parent(&ioctx, "foo"));
   ASSERT_EQ(-ENOENT, remove_parent(&ioctx, "foo"));
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(-1, pool);
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pspec, &size));
+  ASSERT_EQ(-1, pspec.pool_id);
 
   // snapshots
-  ASSERT_EQ(0, set_parent(&ioctx, "foo", 1, "parent", 3, 10<<20));
+  ASSERT_EQ(0, set_parent(&ioctx, "foo", parent_spec(1, "parent", 3), 10<<20));
   ASSERT_EQ(0, snapshot_add(&ioctx, "foo", 10, "snap1"));
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", 10, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 1);
-  ASSERT_EQ(parent, "parent");
-  ASSERT_EQ(snapid, snapid_t(3));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", 10, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 1);
+  ASSERT_EQ(pspec.image_id, "parent");
+  ASSERT_EQ(pspec.snap_id, snapid_t(3));
   ASSERT_EQ(size, 10ull<<20);
 
   ASSERT_EQ(0, remove_parent(&ioctx, "foo"));
-  ASSERT_EQ(0, set_parent(&ioctx, "foo", 4, "parent2", 6, 5<<20));
+  ASSERT_EQ(0, set_parent(&ioctx, "foo", parent_spec(4, "parent2", 6), 5<<20));
   ASSERT_EQ(0, snapshot_add(&ioctx, "foo", 11, "snap2"));
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", 10, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 1);
-  ASSERT_EQ(parent, "parent");
-  ASSERT_EQ(snapid, snapid_t(3));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", 10, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 1);
+  ASSERT_EQ(pspec.image_id, "parent");
+  ASSERT_EQ(pspec.snap_id, snapid_t(3));
   ASSERT_EQ(size, 10ull<<20);
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", 11, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 4);
-  ASSERT_EQ(parent, "parent2");
-  ASSERT_EQ(snapid, snapid_t(6));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", 11, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 4);
+  ASSERT_EQ(pspec.image_id, "parent2");
+  ASSERT_EQ(pspec.snap_id, snapid_t(6));
   ASSERT_EQ(size, 5ull<<20);
 
   ASSERT_EQ(0, remove_parent(&ioctx, "foo"));
   ASSERT_EQ(0, snapshot_add(&ioctx, "foo", 12, "snap3"));
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", 10, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 1);
-  ASSERT_EQ(parent, "parent");
-  ASSERT_EQ(snapid, snapid_t(3));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", 10, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 1);
+  ASSERT_EQ(pspec.image_id, "parent");
+  ASSERT_EQ(pspec.snap_id, snapid_t(3));
   ASSERT_EQ(size, 10ull<<20);
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", 11, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 4);
-  ASSERT_EQ(parent, "parent2");
-  ASSERT_EQ(snapid, snapid_t(6));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", 11, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 4);
+  ASSERT_EQ(pspec.image_id, "parent2");
+  ASSERT_EQ(pspec.snap_id, snapid_t(6));
   ASSERT_EQ(size, 5ull<<20);
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", 12, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(-1, pool);
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", 12, &pspec, &size));
+  ASSERT_EQ(-1, pspec.pool_id);
 
   // make sure set_parent takes min of our size and parent's size
-  ASSERT_EQ(0, set_parent(&ioctx, "foo", 1, "parent", 3, 1<<20));
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 1);
-  ASSERT_EQ(parent, "parent");
-  ASSERT_EQ(snapid, snapid_t(3));
+  ASSERT_EQ(0, set_parent(&ioctx, "foo", parent_spec(1, "parent", 3), 1<<20));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 1);
+  ASSERT_EQ(pspec.image_id, "parent");
+  ASSERT_EQ(pspec.snap_id, snapid_t(3));
   ASSERT_EQ(size, 1ull<<20);
   ASSERT_EQ(0, remove_parent(&ioctx, "foo"));
 
-  ASSERT_EQ(0, set_parent(&ioctx, "foo", 1, "parent", 3, 100<<20));
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 1);
-  ASSERT_EQ(parent, "parent");
-  ASSERT_EQ(snapid, snapid_t(3));
+  ASSERT_EQ(0, set_parent(&ioctx, "foo", parent_spec(1, "parent", 3), 100<<20));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 1);
+  ASSERT_EQ(pspec.image_id, "parent");
+  ASSERT_EQ(pspec.snap_id, snapid_t(3));
   ASSERT_EQ(size, 33ull<<20);
   ASSERT_EQ(0, remove_parent(&ioctx, "foo"));
 
   // make sure resize adjust parent overlap
-  ASSERT_EQ(0, set_parent(&ioctx, "foo", 1, "parent", 3, 10<<20));
+  ASSERT_EQ(0, set_parent(&ioctx, "foo", parent_spec(1, "parent", 3), 10<<20));
 
   ASSERT_EQ(0, snapshot_add(&ioctx, "foo", 14, "snap4"));
   ASSERT_EQ(0, set_size(&ioctx, "foo", 3 << 20));
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 1);
-  ASSERT_EQ(parent, "parent");
-  ASSERT_EQ(snapid, snapid_t(3));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 1);
+  ASSERT_EQ(pspec.image_id, "parent");
+  ASSERT_EQ(pspec.snap_id, snapid_t(3));
   ASSERT_EQ(size, 3ull<<20);
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", 14, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 1);
-  ASSERT_EQ(parent, "parent");
-  ASSERT_EQ(snapid, snapid_t(3));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", 14, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 1);
+  ASSERT_EQ(pspec.image_id, "parent");
+  ASSERT_EQ(pspec.snap_id, snapid_t(3));
   ASSERT_EQ(size, 10ull<<20);
 
   ASSERT_EQ(0, snapshot_add(&ioctx, "foo", 15, "snap5"));
   ASSERT_EQ(0, set_size(&ioctx, "foo", 30 << 20));
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 1);
-  ASSERT_EQ(parent, "parent");
-  ASSERT_EQ(snapid, snapid_t(3));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 1);
+  ASSERT_EQ(pspec.image_id, "parent");
+  ASSERT_EQ(pspec.snap_id, snapid_t(3));
   ASSERT_EQ(size, 3ull<<20);
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", 14, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 1);
-  ASSERT_EQ(parent, "parent");
-  ASSERT_EQ(snapid, snapid_t(3));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", 14, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 1);
+  ASSERT_EQ(pspec.image_id, "parent");
+  ASSERT_EQ(pspec.snap_id, snapid_t(3));
   ASSERT_EQ(size, 10ull<<20);
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", 15, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 1);
-  ASSERT_EQ(parent, "parent");
-  ASSERT_EQ(snapid, snapid_t(3));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", 15, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 1);
+  ASSERT_EQ(pspec.image_id, "parent");
+  ASSERT_EQ(pspec.snap_id, snapid_t(3));
   ASSERT_EQ(size, 3ull<<20);
 
   ASSERT_EQ(0, set_size(&ioctx, "foo", 2 << 20));
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 1);
-  ASSERT_EQ(parent, "parent");
-  ASSERT_EQ(snapid, snapid_t(3));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 1);
+  ASSERT_EQ(pspec.image_id, "parent");
+  ASSERT_EQ(pspec.snap_id, snapid_t(3));
   ASSERT_EQ(size, 2ull<<20);
 
   ASSERT_EQ(0, snapshot_add(&ioctx, "foo", 16, "snap6"));
-  ASSERT_EQ(0, get_parent(&ioctx, "foo", 16, &pool, &parent, &snapid, &size));
-  ASSERT_EQ(pool, 1);
-  ASSERT_EQ(parent, "parent");
-  ASSERT_EQ(snapid, snapid_t(3));
+  ASSERT_EQ(0, get_parent(&ioctx, "foo", 16, &pspec, &size));
+  ASSERT_EQ(pspec.pool_id, 1);
+  ASSERT_EQ(pspec.image_id, "parent");
+  ASSERT_EQ(pspec.snap_id, snapid_t(3));
   ASSERT_EQ(size, 2ull<<20);
 
   ioctx.close();