template <typename I>
void DeepCopyRequest<I>::send() {
+ if (!m_src_image_ctx->data_ctx.is_valid()) {
+ lderr(m_cct) << "missing data pool for source image" << dendl;
+ finish(-ENODEV);
+ return;
+ }
+
+ if (!m_dst_image_ctx->data_ctx.is_valid()) {
+ lderr(m_cct) << "missing data pool for destination image" << dendl;
+ finish(-ENODEV);
+ return;
+ }
+
int r = validate_copy_points();
if (r < 0) {
finish(r);
delete[] format_string;
md_ctx.aio_flush();
- data_ctx.aio_flush();
+ if (data_ctx.is_valid()) {
+ data_ctx.aio_flush();
+ }
io_work_queue->drain();
delete io_object_dispatcher;
asok_hook = new LibrbdAdminSocketHook(this);
string pname = string("librbd-") + id + string("-") +
- data_ctx.get_pool_name() + string("-") + name;
+ md_ctx.get_pool_name() + string("-") + name;
if (!snap_name.empty()) {
pname += "-";
pname += snap_name;
asok_hook = nullptr;
}
- void ImageCtx::init_layout()
+ void ImageCtx::init_layout(int64_t pool_id)
{
if (stripe_unit == 0 || stripe_count == 0) {
stripe_unit = 1ull << order;
layout.stripe_unit = stripe_unit;
layout.stripe_count = stripe_count;
layout.object_size = 1ull << order;
- layout.pool_id = data_ctx.get_id(); // FIXME: pool id overflow?
+ layout.pool_id = pool_id; // FIXME: pool id overflow?
delete[] format_string;
size_t len = object_prefix.length() + 16;
snap_namespace = it->second.snap_namespace;
snap_name = it->second.name;
snap_exists = true;
- data_ctx.snap_set_read(snap_id);
+ if (data_ctx.is_valid()) {
+ data_ctx.snap_set_read(snap_id);
+ }
return 0;
}
return -ENOENT;
snap_namespace = {};
snap_name = "";
snap_exists = true;
- data_ctx.snap_set_read(snap_id);
+ if (data_ctx.is_valid()) {
+ data_ctx.snap_set_read(snap_id);
+ }
}
snap_t ImageCtx::get_snap_id(const cls::rbd::SnapshotNamespace& in_snap_namespace,
~ImageCtx();
void init();
void shutdown();
- void init_layout();
+ void init_layout(int64_t pool_id);
void perf_start(std::string name);
void perf_stop();
void set_read_flag(unsigned flag);
ldout(ictx->cct, 20) << "diff_iterate " << ictx << " off = " << off
<< " len = " << len << dendl;
+ if (!ictx->data_ctx.is_valid()) {
+ return -ENODEV;
+ }
+
// ensure previous writes are visible to listsnaps
C_SaferCond flush_ctx;
{
int DiffIterate<I>::execute() {
CephContext* cct = m_image_ctx.cct;
+ ceph_assert(m_image_ctx.data_ctx.is_valid());
+
librados::IoCtx head_ctx;
librados::snap_t from_snap_id = 0;
librados::snap_t end_snap_id;
} // anonymous namespace
+template <typename I>
+int64_t Image<I>::get_data_pool_id(I *ictx) {
+ if (ictx->data_ctx.is_valid()) {
+ return ictx->data_ctx.get_id();
+ }
+
+ int64_t pool_id;
+ int r = cls_client::get_data_pool(&ictx->md_ctx, ictx->header_oid, &pool_id);
+ if (r < 0) {
+ CephContext *cct = ictx->cct;
+ lderr(cct) << "error getting data pool ID: " << cpp_strerror(r) << dendl;
+ return r;
+ }
+
+ return pool_id;
+}
+
template <typename I>
int Image<I>::get_op_features(I *ictx, uint64_t *op_features) {
CephContext *cct = ictx->cct;
struct Image {
typedef std::map<std::string, std::string> ImageNameToIds;
+ static int64_t get_data_pool_id(ImageCtxT *ictx);
+
static int get_op_features(ImageCtxT *ictx, uint64_t *op_features);
static int list_images(librados::IoCtx& io_ctx,
return -ENOENT;
}
- GetGroupVisitor ggv = GetGroupVisitor(ictx->cct, &ictx->data_ctx, group_snap);
+ GetGroupVisitor ggv = GetGroupVisitor(ictx->cct, &ictx->md_ctx, group_snap);
r = boost::apply_visitor(ggv, snap_info->snap_namespace);
if (r < 0) {
return r;
: m_image_ctx(image_ctx),
m_cache_lock(util::unique_lock_name(
"librbd::cache::ObjectCacherObjectDispatch::cache_lock", this)) {
+ ceph_assert(m_image_ctx->data_ctx.is_valid());
}
template <typename I>
m_dst_image_ctx(dst_image_ctx), m_cct(dst_image_ctx->cct),
m_snap_map(snap_map), m_dst_object_number(dst_object_number),
m_flatten(flatten), m_on_finish(on_finish) {
+ ceph_assert(src_image_ctx->data_ctx.is_valid());
+ ceph_assert(dst_image_ctx->data_ctx.is_valid());
ceph_assert(!m_snap_map.empty());
m_src_async_op = new io::AsyncOperation();
*result = util::create_ioctx(m_image_ctx->md_ctx, "data pool", data_pool_id,
{}, &m_image_ctx->data_ctx);
if (*result < 0) {
- send_close_image(*result);
- return nullptr;
+ if (*result != -ENOENT) {
+ send_close_image(*result);
+ return nullptr;
+ }
+ m_image_ctx->data_ctx.close();
+ } else {
+ m_image_ctx->data_ctx.set_namespace(m_image_ctx->md_ctx.get_namespace());
}
- m_image_ctx->data_ctx.set_namespace(m_image_ctx->md_ctx.get_namespace());
+ } else {
+ data_pool_id = m_image_ctx->md_ctx.get_id();
}
- m_image_ctx->init_layout();
+ m_image_ctx->init_layout(data_pool_id);
send_refresh();
return nullptr;
}
template <typename I>
Context *OpenRequest<I>::send_init_cache(int *result) {
// cache is disabled or parent image context
- if (!m_image_ctx->cache || m_image_ctx->child != nullptr) {
+ if (!m_image_ctx->cache || m_image_ctx->child != nullptr ||
+ !m_image_ctx->data_ctx.is_valid()) {
return send_register_watch(result);
}
m_image_ctx.op_features = 0;
m_image_ctx.operations_disabled = false;
m_image_ctx.object_prefix = std::move(m_object_prefix);
- m_image_ctx.init_layout();
+ m_image_ctx.init_layout(m_image_ctx.md_ctx.get_id());
} else {
// HEAD revision doesn't have a defined overlap so it's only
// applicable to snapshots
if (m_refresh_parent != nullptr) {
m_refresh_parent->apply();
}
- m_image_ctx.data_ctx.selfmanaged_snap_set_write_ctx(m_image_ctx.snapc.seq,
- m_image_ctx.snaps);
+ if (m_image_ctx.data_ctx.is_valid()) {
+ m_image_ctx.data_ctx.selfmanaged_snap_set_write_ctx(m_image_ctx.snapc.seq,
+ m_image_ctx.snaps);
+ }
// handle dynamically enabled / disabled features
if (m_image_ctx.exclusive_lock != nullptr &&
return;
}
+ if (!m_image_ctx->data_ctx.is_valid()) {
+ detach_child();
+ return;
+ }
+
trim_image();
}
* PRE REMOVE IMAGE * * * |
* | * |
* v * |
- * TRIM IMAGE * * * * * |
+ * (skip if invalid data pool) TRIM IMAGE * * * * * |
* | * |
* v * |
* DETACH CHILD * |
m_trace(util::create_trace(*m_image_ctx, "copy-up", parent_trace)),
m_lock("CopyupRequest", false, false)
{
+ ceph_assert(m_image_ctx->data_ctx.is_valid());
m_async_op.start_op(*util::get_image_ctx(m_image_ctx));
}
return false;
}
+ if (!m_image_ctx.data_ctx.is_valid()) {
+ CephContext *cct = m_image_ctx.cct;
+ lderr(cct) << "missing data pool" << dendl;
+
+ c->get();
+ c->fail(-ENODEV);
+ return false;
+ }
+
m_in_flight_ios++;
return true;
}
: m_ictx(ictx), m_oid(oid), m_object_no(objectno), m_object_off(off),
m_object_len(len), m_snap_id(snap_id), m_completion(completion),
m_trace(util::create_trace(*ictx, "", trace)) {
+ ceph_assert(m_ictx->data_ctx.is_valid());
if (m_trace.valid()) {
m_trace.copy_name(trace_name + std::string(" ") + oid);
m_trace.event("start");
int64_t Image::get_data_pool_id()
{
ImageCtx *ictx = reinterpret_cast<ImageCtx *>(ctx);
- return ictx->data_ctx.get_id();
+ return librbd::api::Image<>::get_data_pool_id(ictx);
}
int Image::parent_info(string *parent_pool_name, string *parent_name,
extern "C" int64_t rbd_get_data_pool_id(rbd_image_t image)
{
librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx *>(image);
- return ictx->data_ctx.get_id();
+ return librbd::api::Image<>::get_data_pool_id(ictx);
}
extern "C" int rbd_get_parent_info(rbd_image_t image,
template <typename I>
void ObjectMapIterateRequest<I>::send() {
+ if (!m_image_ctx.data_ctx.is_valid()) {
+ this->async_complete(-ENODEV);
+ return;
+ }
+
send_verify_objects();
}
bool ObjectMapIterateRequest<I>::should_complete(int r) {
CephContext *cct = m_image_ctx.cct;
ldout(cct, 5) << this << " should_complete: " << " r=" << r << dendl;
+
+ if (r == -ENODEV) {
+ lderr(cct) << "missing data pool" << dendl;
+ return true;
+ }
+
if (r < 0) {
lderr(cct) << "object map operation encountered an error: "
<< cpp_strerror(r) << dendl;
template <typename I>
void SnapshotCreateRequest<I>::send_op() {
+ I &image_ctx = this->m_image_ctx;
+ CephContext *cct = image_ctx.cct;
+
+ if (!image_ctx.data_ctx.is_valid()) {
+ lderr(cct) << "missing data pool" << dendl;
+ this->async_complete(-ENODEV);
+ return;
+ }
+
send_suspend_requests();
}
void SnapshotRemoveRequest<I>::release_snap_id() {
I &image_ctx = this->m_image_ctx;
+ if (!image_ctx.data_ctx.is_valid()) {
+ remove_snap();
+ return;
+ }
+
CephContext *cct = image_ctx.cct;
ldout(cct, 5) << "snap_name=" << m_snap_name << ", "
<< "snap_id=" << m_snap_id << dendl;
ldout(m_cct, 20) << dendl;
+ if (!image_ctx.data_ctx.is_valid()) {
+ lderr(m_cct) << "missing data pool" << dendl;
+ return -ENODEV;
+ }
+
if (image_ctx.exclusive_lock != nullptr &&
!image_ctx.exclusive_lock->is_lock_owner()) {
ldout(m_cct, 1) << "lost exclusive lock during sparsify" << dendl;
template <typename I>
void TrimRequest<I>::send() {
+ I &image_ctx = this->m_image_ctx;
+ CephContext *cct = image_ctx.cct;
+
+ if (!image_ctx.data_ctx.is_valid()) {
+ lderr(cct) << "missing data pool" << dendl;
+ send_finish(-ENODEV);
+ return;
+ }
+
send_pre_trim();
}
}
void expect_init_layout(MockRefreshImageCtx &mock_image_ctx) {
- EXPECT_CALL(mock_image_ctx, init_layout());
+ EXPECT_CALL(mock_image_ctx, init_layout(_));
}
void expect_test_features(MockRefreshImageCtx &mock_image_ctx) {
ctx.wait();
}
- MOCK_METHOD0(init_layout, void());
+ MOCK_METHOD1(init_layout, void(int64_t));
MOCK_CONST_METHOD1(get_object_name, std::string(uint64_t));
MOCK_CONST_METHOD0(get_object_size, uint64_t());
ASSERT_EQ(0, ictx->data_ctx.stat(oid, &size, NULL));
ASSERT_EQ(0, ictx->data_ctx.read(oid, read_bl, 4096, 0));
}
+
+TEST_F(TestInternal, MissingDataPool) {
+ REQUIRE_FORMAT_V2();
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ ASSERT_EQ(0, snap_create(*ictx, "snap1"));
+ std::string header_oid = ictx->header_oid;
+ close_image(ictx);
+
+ // emulate non-existent data pool
+ int64_t pool_id = 1234;
+ std::string pool_name;
+ int r;
+ while ((r = _rados.pool_reverse_lookup(pool_id, &pool_name)) == 0) {
+ pool_id++;
+ }
+ ASSERT_EQ(r, -ENOENT);
+ bufferlist bl;
+ using ceph::encode;
+ encode(pool_id, bl);
+ ASSERT_EQ(0, m_ioctx.omap_set(header_oid, {{"data_pool_id", bl}}));
+
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ ASSERT_FALSE(ictx->data_ctx.is_valid());
+ ASSERT_EQ(pool_id, librbd::api::Image<>::get_data_pool_id(ictx));
+
+ librbd::image_info_t info;
+ ASSERT_EQ(0, librbd::info(ictx, info, sizeof(info)));
+
+ vector<librbd::snap_info_t> snaps;
+ EXPECT_EQ(0, librbd::snap_list(ictx, snaps));
+ EXPECT_EQ(1U, snaps.size());
+ EXPECT_EQ("snap1", snaps[0].name);
+
+ bufferptr read_ptr(256);
+ bufferlist read_bl;
+ read_bl.push_back(read_ptr);
+ librbd::io::ReadResult read_result{&read_bl};
+ ASSERT_EQ(-ENODEV,
+ ictx->io_work_queue->read(0, 256,
+ librbd::io::ReadResult{read_result}, 0));
+ ASSERT_EQ(-ENODEV,
+ ictx->io_work_queue->write(0, bl.length(), bufferlist{bl}, 0));
+ ASSERT_EQ(-ENODEV, ictx->io_work_queue->discard(0, 1, 256));
+ ASSERT_EQ(-ENODEV,
+ ictx->io_work_queue->writesame(0, bl.length(), bufferlist{bl}, 0));
+ uint64_t mismatch_off;
+ ASSERT_EQ(-ENODEV,
+ ictx->io_work_queue->compare_and_write(0, bl.length(),
+ bufferlist{bl},
+ bufferlist{bl},
+ &mismatch_off, 0));
+ ASSERT_EQ(-ENODEV, ictx->io_work_queue->flush());
+
+ ASSERT_EQ(-ENODEV, snap_create(*ictx, "snap2"));
+ ASSERT_EQ(0, ictx->operations->snap_remove(cls::rbd::UserSnapshotNamespace(),
+ "snap1"));
+
+ librbd::NoOpProgressContext no_op;
+ ASSERT_EQ(-ENODEV, ictx->operations->resize(0, true, no_op));
+
+ close_image(ictx);
+
+ ASSERT_EQ(0, librbd::api::Image<>::remove(m_ioctx, m_image_name, no_op));
+
+ ASSERT_EQ(0, create_image_pp(m_rbd, m_ioctx, m_image_name, m_image_size));
+}