CEPH_RBD_API int rbd_snap_get_timestamp(rbd_image_t image, uint64_t snap_id, struct timespec *timestamp);
CEPH_RBD_API int rbd_snap_set(rbd_image_t image, const char *snapname);
+CEPH_RBD_API int rbd_snap_set_by_id(rbd_image_t image, uint64_t snap_id);
CEPH_RBD_API int rbd_snap_get_namespace_type(rbd_image_t image,
uint64_t snap_id,
int snap_unprotect(const char *snap_name);
int snap_is_protected(const char *snap_name, bool *is_protected);
int snap_set(const char *snap_name);
+ int snap_set_by_id(uint64_t snap_id);
int snap_rename(const char *srcname, const char *dstname);
int snap_get_limit(uint64_t *limit);
int snap_set_limit(uint64_t limit);
return 0;
}
+template <typename I>
+int Image<I>::snap_set(I *ictx,
+ const cls::rbd::SnapshotNamespace &snap_namespace,
+ const char *snap_name) {
+ ldout(ictx->cct, 20) << "snap_set " << ictx << " snap = "
+ << (snap_name ? snap_name : "NULL") << dendl;
+
+ // ignore return value, since we may be set to a non-existent
+ // snapshot and the user is trying to fix that
+ ictx->state->refresh_if_required();
+
+ uint64_t snap_id = CEPH_NOSNAP;
+ std::string name(snap_name == nullptr ? "" : snap_name);
+ if (!name.empty()) {
+ RWLock::RLocker snap_locker(ictx->snap_lock);
+ snap_id = ictx->get_snap_id(cls::rbd::UserSnapshotNamespace{},
+ snap_name);
+ if (snap_id == CEPH_NOSNAP) {
+ return -ENOENT;
+ }
+ }
+
+ return snap_set(ictx, snap_id);
+}
+
+template <typename I>
+int Image<I>::snap_set(I *ictx, uint64_t snap_id) {
+ ldout(ictx->cct, 20) << "snap_set " << ictx << " "
+ << "snap_id=" << snap_id << dendl;
+
+ // ignore return value, since we may be set to a non-existent
+ // snapshot and the user is trying to fix that
+ ictx->state->refresh_if_required();
+
+ C_SaferCond ctx;
+ ictx->state->snap_set(snap_id, &ctx);
+ int r = ctx.wait();
+ if (r < 0) {
+ if (r != -ENOENT) {
+ lderr(ictx->cct) << "failed to " << (snap_id == CEPH_NOSNAP ? "un" : "")
+ << "set snapshot: " << cpp_strerror(r) << dendl;
+ }
+ return r;
+ }
+
+ return 0;
+}
+
} // namespace api
} // namespace librbd
ProgressContext &prog_ctx);
static int deep_copy(ImageCtxT *src, ImageCtxT *dest,
ProgressContext &prog_ctx);
+
+ static int snap_set(ImageCtxT *ictx,
+ const cls::rbd::SnapshotNamespace &snap_namespace,
+ const char *snap_name);
+ static int snap_set(ImageCtxT *ictx, uint64_t snap_id);
+
};
} // namespace api
return r;
}
- int snap_set(ImageCtx *ictx,
- const cls::rbd::SnapshotNamespace &snap_namespace,
- const char *snap_name)
- {
- ldout(ictx->cct, 20) << "snap_set " << ictx << " snap = "
- << (snap_name ? snap_name : "NULL") << dendl;
-
- // ignore return value, since we may be set to a non-existent
- // snapshot and the user is trying to fix that
- ictx->state->refresh_if_required();
-
- uint64_t snap_id = CEPH_NOSNAP;
- std::string name(snap_name == nullptr ? "" : snap_name);
- if (!name.empty()) {
- RWLock::RLocker snap_locker(ictx->snap_lock);
- snap_id = ictx->get_snap_id(cls::rbd::UserSnapshotNamespace{},
- snap_name);
- if (snap_id == CEPH_NOSNAP) {
- return -ENOENT;
- }
- }
-
- C_SaferCond ctx;
- ictx->state->snap_set(snap_id, &ctx);
- int r = ctx.wait();
- if (r < 0) {
- if (r != -ENOENT) {
- lderr(ictx->cct) << "failed to " << (name.empty() ? "un" : "") << "set "
- << "snapshot: " << cpp_strerror(r) << dendl;
- }
- return r;
- }
-
- return 0;
- }
-
int list_lockers(ImageCtx *ictx,
std::list<locker_t> *lockers,
bool *exclusive,
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 cls::rbd::SnapshotNamespace &snap_namespace,
- const char *snap_name);
-
int list(librados::IoCtx& io_ctx, std::vector<std::string>& names);
int list_children(ImageCtx *ictx,
std::vector<child_info_t> *names);
{
ImageCtx *ictx = (ImageCtx *)ctx;
tracepoint(librbd, snap_set_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
- int r = librbd::snap_set(ictx, cls::rbd::UserSnapshotNamespace(), snap_name);
+ int r = librbd::api::Image<>::snap_set(
+ ictx, cls::rbd::UserSnapshotNamespace(), snap_name);
tracepoint(librbd, snap_set_exit, r);
return r;
}
+ int Image::snap_set_by_id(uint64_t snap_id)
+ {
+ ImageCtx *ictx = (ImageCtx *)ctx;
+ return librbd::api::Image<>::snap_set(ictx, snap_id);
+ }
+
ssize_t Image::read(uint64_t ofs, size_t len, bufferlist& bl)
{
ImageCtx *ictx = (ImageCtx *)ctx;
{
librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
tracepoint(librbd, snap_set_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
- int r = librbd::snap_set(ictx, cls::rbd::UserSnapshotNamespace(), snap_name);
+ int r = librbd::api::Image<>::snap_set(
+ ictx, cls::rbd::UserSnapshotNamespace(), snap_name);
tracepoint(librbd, snap_set_exit, r);
return r;
}
+extern "C" int rbd_snap_set_by_id(rbd_image_t image, uint64_t snap_id)
+{
+ librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
+ return librbd::api::Image<>::snap_set(ictx, snap_id);
+}
+
extern "C" ssize_t rbd_list_children(rbd_image_t image, char *pools,
size_t *pools_len, char *images,
size_t *images_len)
#include "librbd/ImageState.h"
#include "librbd/internal.h"
#include "librbd/Operations.h"
+#include "librbd/api/Image.h"
#include "librbd/deep_copy/ObjectCopyRequest.h"
#include "librbd/io/ImageRequestWQ.h"
#include "librbd/io/ReadResult.h"
std::cout << "comparing '" << snap_name << " (" << src_snap_id
<< " to " << dst_snap_id << ")" << std::endl;
- r = librbd::snap_set(m_src_image_ctx,
- cls::rbd::UserSnapshotNamespace(),
- snap_name.c_str());
+ r = librbd::api::Image<>::snap_set(m_src_image_ctx,
+ cls::rbd::UserSnapshotNamespace(),
+ snap_name.c_str());
if (r < 0) {
return r;
}
- r = librbd::snap_set(m_dst_image_ctx,
- cls::rbd::UserSnapshotNamespace(),
- snap_name.c_str());
+ r = librbd::api::Image<>::snap_set(m_dst_image_ctx,
+ cls::rbd::UserSnapshotNamespace(),
+ snap_name.c_str());
if (r < 0) {
return r;
}
}
}
- r = librbd::snap_set(m_src_image_ctx,
- cls::rbd::UserSnapshotNamespace(),
- nullptr);
+ r = librbd::api::Image<>::snap_set(m_src_image_ctx,
+ cls::rbd::UserSnapshotNamespace(),
+ nullptr);
if (r < 0) {
return r;
}
- r = librbd::snap_set(m_dst_image_ctx,
- cls::rbd::UserSnapshotNamespace(),
- nullptr);
+ r = librbd::api::Image<>::snap_set(m_dst_image_ctx,
+ cls::rbd::UserSnapshotNamespace(),
+ nullptr);
if (r < 0) {
return r;
}
#include "librbd/ImageState.h"
#include "librbd/internal.h"
#include "librbd/Operations.h"
+#include "librbd/api/Image.h"
#include "librbd/image/RefreshRequest.h"
#include "librbd/image/RefreshParentRequest.h"
#include "librbd/io/ImageDispatchSpec.h"
librbd::ImageCtx *ictx;
ASSERT_EQ(0, open_image(m_image_name, &ictx));
ASSERT_EQ(0, snap_create(*ictx, "snap"));
- ASSERT_EQ(0, librbd::snap_set(ictx, cls::rbd::UserSnapshotNamespace(), "snap"));
+ ASSERT_EQ(0, librbd::api::Image<>::snap_set(ictx,
+ cls::rbd::UserSnapshotNamespace(),
+ "snap"));
MockRefreshImageCtx mock_image_ctx(*ictx);
MockRefreshParentRequest mock_refresh_parent_request;
#include "test/librbd/test_support.h"
#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
#include "librbd/internal.h"
+#include "librbd/api/Image.h"
#include "librbd/object_map/InvalidateRequest.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
ASSERT_EQ(0, open_image(m_image_name, &ictx));
ASSERT_EQ(0, snap_create(*ictx, "snap1"));
- ASSERT_EQ(0, librbd::snap_set(ictx,
- cls::rbd::UserSnapshotNamespace(),
- "snap1"));
+ ASSERT_EQ(0, librbd::api::Image<>::snap_set(ictx,
+ cls::rbd::UserSnapshotNamespace(),
+ "snap1"));
C_SaferCond cond_ctx;
AsyncRequest<> *request = new InvalidateRequest<>(*ictx, ictx->snap_id, false,
#include "common/bit_vector.hpp"
#include "librbd/internal.h"
#include "librbd/ObjectMap.h"
+#include "librbd/api/Image.h"
#include "librbd/object_map/ResizeRequest.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
librbd::ImageCtx *ictx;
ASSERT_EQ(0, open_image(m_image_name, &ictx));
ASSERT_EQ(0, snap_create(*ictx, "snap1"));
- ASSERT_EQ(0, librbd::snap_set(ictx,
- cls::rbd::UserSnapshotNamespace(),
- "snap1"));
+ ASSERT_EQ(0, librbd::api::Image<>::snap_set(ictx,
+ cls::rbd::UserSnapshotNamespace(),
+ "snap1"));
uint64_t snap_id = ictx->snap_id;
expect_resize(ictx, snap_id, 0);
#include "librbd/internal.h"
#include "librbd/ObjectMap.h"
#include "librbd/Operations.h"
+#include "librbd/api/Image.h"
#include "librbd/object_map/UpdateRequest.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
librbd::ImageCtx *ictx;
ASSERT_EQ(0, open_image(m_image_name, &ictx));
ASSERT_EQ(0, snap_create(*ictx, "snap1"));
- ASSERT_EQ(0, librbd::snap_set(ictx,
- cls::rbd::UserSnapshotNamespace(),
- "snap1"));
+ ASSERT_EQ(0, librbd::api::Image<>::snap_set(ictx,
+ cls::rbd::UserSnapshotNamespace(),
+ "snap1"));
uint64_t snap_id = ictx->snap_id;
expect_update(ictx, snap_id, 0, 1, OBJECT_NONEXISTENT, OBJECT_EXISTS, 0);
src_snap_name = src_snaps[i].name.c_str();
dst_snap_name = dst_snaps[i].name.c_str();
}
- EXPECT_EQ(0, librbd::snap_set(m_src_ictx, cls::rbd::UserSnapshotNamespace(),
- src_snap_name));
- EXPECT_EQ(0, librbd::snap_set(m_dst_ictx, cls::rbd::UserSnapshotNamespace(),
- dst_snap_name));
+ EXPECT_EQ(0, librbd::api::Image<>::snap_set(
+ m_src_ictx, cls::rbd::UserSnapshotNamespace(),
+ src_snap_name));
+ EXPECT_EQ(0, librbd::api::Image<>::snap_set(
+ m_dst_ictx, cls::rbd::UserSnapshotNamespace(),
+ dst_snap_name));
uint64_t src_size, dst_size;
{
RWLock::RLocker src_locker(m_src_ictx->snap_lock);
#include "librbd/ObjectMap.h"
#include "librbd/Operations.h"
#include "librbd/api/DiffIterate.h"
+#include "librbd/api/Image.h"
#include "librbd/io/AioCompletion.h"
#include "librbd/io/ImageRequest.h"
#include "librbd/io/ImageRequestWQ.h"
librbd::ImageCtx *ictx;
ASSERT_EQ(0, open_image(m_image_name, &ictx));
- ASSERT_EQ(0, librbd::snap_set(ictx, cls::rbd::UserSnapshotNamespace(), "snap1"));
+ ASSERT_EQ(0, librbd::api::Image<>::snap_set(
+ ictx, cls::rbd::UserSnapshotNamespace(), "snap1"));
bool is_owner;
ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx, &is_owner));
for (std::list<std::string>::iterator it = snaps.begin();
it != snaps.end(); ++it) {
const char *snap_name = it->empty() ? NULL : it->c_str();
- ASSERT_EQ(0, librbd::snap_set(ictx2,
- cls::rbd::UserSnapshotNamespace(),
- snap_name));
+ ASSERT_EQ(0, librbd::api::Image<>::snap_set(
+ ictx2, cls::rbd::UserSnapshotNamespace(), snap_name));
ASSERT_EQ(256,
ictx2->io_work_queue->read(0, 256,
true, no_op));
ASSERT_EQ(0, ictx2->operations->resize(m_image_size - (2 << order) - 32,
true, no_op));
- ASSERT_EQ(0, librbd::snap_set(ictx2,
- cls::rbd::UserSnapshotNamespace(),
- "snap1"));
+ ASSERT_EQ(0, librbd::api::Image<>::snap_set(ictx2,
+ cls::rbd::UserSnapshotNamespace(),
+ "snap1"));
{
// hide the parent from the snapshot
ASSERT_EQ(static_cast<int>(m_image_size - 64),
ictx2->io_work_queue->discard(32, m_image_size - 64, false));
- ASSERT_EQ(0, librbd::snap_set(ictx2,
- cls::rbd::UserSnapshotNamespace(),
- "snap1"));
+ ASSERT_EQ(0, librbd::api::Image<>::snap_set(ictx2,
+ cls::rbd::UserSnapshotNamespace(),
+ "snap1"));
{
// hide the parent from the snapshot
librbd::io::ReadResult{read_result}, 0));
ASSERT_TRUE(write_full_bl.contents_equal(read_bl));
- ASSERT_EQ(0, librbd::snap_set(ictx2,
- cls::rbd::UserSnapshotNamespace(),
- "snap1"));
+ ASSERT_EQ(0, librbd::api::Image<>::snap_set(ictx2,
+ cls::rbd::UserSnapshotNamespace(),
+ "snap1"));
ASSERT_EQ((ssize_t)read_bl.length(),
ictx2->io_work_queue->read(0, read_bl.length(),
librbd::io::ReadResult{read_result}, 0));
ASSERT_EQ(0, io_ctx.write(oid, bl, 4096, 4096));
interval_set<uint64_t> diff;
- ASSERT_EQ(0, librbd::snap_set(ictx, cls::rbd::UserSnapshotNamespace(), "one"));
+ ASSERT_EQ(0, librbd::api::Image<>::snap_set(ictx,
+ cls::rbd::UserSnapshotNamespace(),
+ "one"));
ASSERT_EQ(0, librbd::api::DiffIterate<>::diff_iterate(
ictx, cls::rbd::UserSnapshotNamespace(), nullptr, 0, size, true, false,
iterate_cb, (void *)&diff));
ASSERT_EQ(0, image.close());
}
+TEST_F(TestLibRBD, TestSetSnapById) {
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx));
+
+ librbd::RBD rbd;
+ std::string name = get_temp_image_name();
+
+ uint64_t size = 1 << 18;
+ int order = 12;
+ ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order));
+
+ librbd::Image image;
+ ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), nullptr));
+ ASSERT_EQ(0, image.snap_create("snap"));
+
+ vector<librbd::snap_info_t> snaps;
+ ASSERT_EQ(0, image.snap_list(snaps));
+ ASSERT_EQ(1U, snaps.size());
+
+ ASSERT_EQ(0, image.snap_set_by_id(snaps[0].id));
+ ASSERT_EQ(0, image.snap_set_by_id(CEPH_NOSNAP));
+}
+
// poorman's assert()
namespace ceph {
void __ceph_assert_fail(const char *assertion, const char *file, int line,
#include "librbd/ImageState.h"
#include "librbd/Operations.h"
#include "librbd/internal.h"
+#include "librbd/api/Image.h"
#include "librbd/deep_copy/ImageCopyRequest.h"
#include "librbd/deep_copy/MetadataCopyRequest.h"
#include "librbd/deep_copy/SnapshotCopyRequest.h"
TEST_F(TestMockDeepCopyRequest, Snap) {
EXPECT_EQ(0, snap_create(*m_src_image_ctx, "copy"));
- EXPECT_EQ(0, librbd::snap_set(m_src_image_ctx,
- cls::rbd::UserSnapshotNamespace(), "copy"));
+ EXPECT_EQ(0, librbd::api::Image<>::snap_set(m_src_image_ctx,
+ cls::rbd::UserSnapshotNamespace(),
+ "copy"));
librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
#include "librbd/Journal.h"
#include "librbd/internal.h"
#include "librbd/Utils.h"
+#include "librbd/api/Image.h"
#include "librbd/api/Mirror.h"
#include "librbd/journal/DisabledPolicy.h"
#include "test/rbd_mirror/test_fixture.h"
cls::rbd::UserSnapshotNamespace(), "snap1"));
EXPECT_EQ(0, ictx->operations->snap_protect(
cls::rbd::UserSnapshotNamespace(), "snap1"));
- EXPECT_EQ(0, librbd::snap_set(ictx, cls::rbd::UserSnapshotNamespace(),
- "snap1"));
+ EXPECT_EQ(0, librbd::api::Image<>::snap_set(
+ ictx, cls::rbd::UserSnapshotNamespace(), "snap1"));
std::string clone_id = librbd::util::generate_image_id(m_local_io_ctx);
librbd::ImageOptions clone_opts;