diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index 8b4ea9e10ec..545e603e884 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -418,10 +418,20 @@ namespace librbd { for (std::list::const_iterator it = pools.begin(); it != pools.end(); ++it) { + int64_t pool_id = rados.pool_lookup(it->c_str()); + int64_t base_tier; + int r = rados.pool_get_base_tier(pool_id, &base_tier); + if (r < 0) { + return r; + } + if (base_tier != pool_id) { + // pool is a cache; skip it + continue; + } IoCtx ioctx; rados.ioctx_create(it->c_str(), ioctx); set image_ids; - int r = cls_client::get_children(&ioctx, RBD_CHILDREN, + r = cls_client::get_children(&ioctx, RBD_CHILDREN, parent_spec, image_ids); if (r < 0 && r != -ENOENT) { lderr(cct) << "Error reading list of children from pool " << *it @@ -637,6 +647,16 @@ namespace librbd { rados.pool_list(pools); std::set children; for (std::list::const_iterator it = pools.begin(); it != pools.end(); ++it) { + int64_t pool_id = rados.pool_lookup(it->c_str()); + int64_t base_tier; + r = rados.pool_get_base_tier(pool_id, &base_tier); + if (r < 0) { + return r; + } + if (base_tier != pool_id) { + // pool is a cache; skip it + continue; + } IoCtx pool_ioctx; r = rados.ioctx_create(it->c_str(), pool_ioctx); if (r < 0) { diff --git a/src/test/librbd/test_librbd.cc b/src/test/librbd/test_librbd.cc index 6a61f3fe3a4..3f565660ac3 100644 --- a/src/test/librbd/test_librbd.cc +++ b/src/test/librbd/test_librbd.cc @@ -1330,6 +1330,124 @@ TEST(LibRBD, ListChildren) ASSERT_EQ(0, destroy_one_pool(pool_name2, &cluster)); } +TEST(LibRBD, ListChildrenTiered) +{ + rados_t cluster; + string pool_name1 = get_temp_pool_name(); + ASSERT_EQ("", create_one_pool(pool_name1, &cluster)); + string pool_name2 = get_temp_pool_name(); + ASSERT_EQ("", create_one_pool(pool_name2, &cluster)); + string pool_name3 = get_temp_pool_name(); + ASSERT_EQ("", create_one_pool(pool_name3, &cluster)); + + std::string cmdstr = "{\"prefix\": \"osd tier add\", \"pool\": \"" + + pool_name1 + "\", \"tierpool\":\"" + pool_name3 + "\", \"force_nonempty\":\"\"}"; + char *cmd[1]; + cmd[0] = (char *)cmdstr.c_str(); + ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0)); + + cmdstr = "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + + pool_name3 + "\", \"mode\":\"writeback\"}"; + cmd[0] = (char *)cmdstr.c_str(); + ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0)); + + cmdstr = "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + + pool_name1 + "\", \"overlaypool\":\"" + pool_name3 + "\"}"; + cmd[0] = (char *)cmdstr.c_str(); + ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0)); + + EXPECT_EQ(0, rados_wait_for_latest_osdmap(cluster)); + + rados_ioctx_t ioctx1, ioctx2; + rados_ioctx_create(cluster, pool_name1.c_str(), &ioctx1); + rados_ioctx_create(cluster, pool_name2.c_str(), &ioctx2); + + int features = RBD_FEATURE_LAYERING; + rbd_image_t parent; + int order = 0; + + // make a parent to clone from + ASSERT_EQ(0, create_image_full(ioctx1, "parent", 4<<20, &order, + false, features)); + ASSERT_EQ(0, rbd_open(ioctx1, "parent", &parent, NULL)); + // create a snapshot, reopen as the parent we're interested in + ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap")); + ASSERT_EQ(0, rbd_snap_set(parent, "parent_snap")); + ASSERT_EQ(0, rbd_snap_protect(parent, "parent_snap")); + + ASSERT_EQ(0, rbd_close(parent)); + ASSERT_EQ(0, rbd_open(ioctx1, "parent", &parent, "parent_snap")); + + ASSERT_EQ(0, rbd_clone(ioctx1, "parent", "parent_snap", ioctx2, "child1", + features, &order)); + test_list_children(parent, 1, pool_name2.c_str(), "child1"); + + ASSERT_EQ(0, rbd_clone(ioctx1, "parent", "parent_snap", ioctx1, "child2", + features, &order)); + test_list_children(parent, 2, pool_name2.c_str(), "child1", + pool_name1.c_str(), "child2"); + + // read from the cache to populate it + rbd_image_t tier_image; + ASSERT_EQ(0, rbd_open(ioctx1, "child2", &tier_image, NULL)); + size_t len = 4 * 1024 * 1024; + char* buf = (char*)malloc(len); + ssize_t size = rbd_read(tier_image, 0, len, buf); + ASSERT_GT(size, 0); + free(buf); + ASSERT_EQ(0, rbd_close(tier_image)); + + ASSERT_EQ(0, rbd_clone(ioctx1, "parent", "parent_snap", ioctx2, "child3", + features, &order)); + test_list_children(parent, 3, pool_name2.c_str(), "child1", + pool_name1.c_str(), "child2", + pool_name2.c_str(), "child3"); + + ASSERT_EQ(0, rbd_clone(ioctx1, "parent", "parent_snap", ioctx2, "child4", + features, &order)); + test_list_children(parent, 4, pool_name2.c_str(), "child1", + pool_name1.c_str(), "child2", + pool_name2.c_str(), "child3", + pool_name2.c_str(), "child4"); + + ASSERT_EQ(0, rbd_remove(ioctx2, "child1")); + test_list_children(parent, 3, + pool_name1.c_str(), "child2", + pool_name2.c_str(), "child3", + pool_name2.c_str(), "child4"); + + ASSERT_EQ(0, rbd_remove(ioctx2, "child3")); + test_list_children(parent, 2, + pool_name1.c_str(), "child2", + pool_name2.c_str(), "child4"); + + ASSERT_EQ(0, rbd_remove(ioctx2, "child4")); + test_list_children(parent, 1, + pool_name1.c_str(), "child2"); + + ASSERT_EQ(0, rbd_remove(ioctx1, "child2")); + test_list_children(parent, 0); + + ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap")); + ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap")); + ASSERT_EQ(0, rbd_close(parent)); + ASSERT_EQ(0, rbd_remove(ioctx1, "parent")); + rados_ioctx_destroy(ioctx1); + rados_ioctx_destroy(ioctx2); + // destroy_one_pool also closes the cluster; do this one step at a time + cmdstr = "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + + pool_name1 + "\"}"; + cmd[0] = (char *)cmdstr.c_str(); + ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0)); + cmdstr = "{\"prefix\": \"osd tier remove\", \"pool\": \"" + + pool_name1 + "\", \"tierpool\":\"" + pool_name3 + "\"}"; + cmd[0] = (char *)cmdstr.c_str(); + ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, NULL, 0, NULL, 0)); + ASSERT_EQ(0, rados_pool_delete(cluster, pool_name3.c_str())); + ASSERT_EQ(0, rados_pool_delete(cluster, pool_name1.c_str())); + ASSERT_EQ(0, destroy_one_pool(pool_name2, &cluster)); +} + TEST(LibRBD, LockingPP) { librados::Rados rados;