From: Douglas Fuller Date: Thu, 31 Mar 2016 15:45:41 +0000 (-0700) Subject: rbd: add rbd object-map check X-Git-Tag: v11.0.0~391^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=a100f02dba53fbfbbb16d87cbaf8ab9db84bbf7e;p=ceph.git rbd: add rbd object-map check Add a CLI option to verify the object map for an unmapped image for debugging purposes. Syntax: rbd object-map check This operation is not supported on currently mapped images. Any inconsistencies that could affect the correctness of future operations are noted and the object map (and fast diff state, if enabled) is invalidated. Inconsistencies that do not affect correctness will be emitted at debug level 1 or higher. Consolidate code path with object-map rebuild and remove newly unused code. Fixes: http://tracker.ceph.com/issues/14867 Signed-off-by: Douglas Fuller --- diff --git a/src/include/rbd/librbd.hpp b/src/include/rbd/librbd.hpp index e4c434ab490f..4ce59d82d534 100644 --- a/src/include/rbd/librbd.hpp +++ b/src/include/rbd/librbd.hpp @@ -204,6 +204,8 @@ public: /* object map feature */ int rebuild_object_map(ProgressContext &prog_ctx); + int check_object_map(ProgressContext &prog_ctx); + int copy(IoCtx& dest_io_ctx, const char *destname); int copy2(Image& dest); int copy3(IoCtx& dest_io_ctx, const char *destname, ImageOptions& opts); diff --git a/src/librbd/Makefile.am b/src/librbd/Makefile.am index 08c9738806ee..7b9416c0ca2f 100644 --- a/src/librbd/Makefile.am +++ b/src/librbd/Makefile.am @@ -55,6 +55,7 @@ librbd_internal_la_SOURCES = \ librbd/object_map/UpdateRequest.cc \ librbd/operation/FlattenRequest.cc \ librbd/operation/RebuildObjectMapRequest.cc \ + librbd/operation/ObjectMapIterate.cc \ librbd/operation/RenameRequest.cc \ librbd/operation/Request.cc \ librbd/operation/ResizeRequest.cc \ @@ -145,6 +146,7 @@ noinst_HEADERS += \ librbd/object_map/UpdateRequest.h \ librbd/operation/FlattenRequest.h \ librbd/operation/RebuildObjectMapRequest.h \ + librbd/operation/ObjectMapIterate.h \ librbd/operation/RenameRequest.h \ librbd/operation/Request.h \ librbd/operation/ResizeRequest.h \ diff --git a/src/librbd/Operations.cc b/src/librbd/Operations.cc index c523b912680d..9c7ea32ad443 100644 --- a/src/librbd/Operations.cc +++ b/src/librbd/Operations.cc @@ -13,6 +13,7 @@ #include "librbd/Utils.h" #include "librbd/operation/FlattenRequest.h" #include "librbd/operation/RebuildObjectMapRequest.h" +#include "librbd/operation/ObjectMapIterate.h" #include "librbd/operation/RenameRequest.h" #include "librbd/operation/ResizeRequest.h" #include "librbd/operation/SnapshotCreateRequest.h" @@ -274,6 +275,18 @@ struct C_InvokeAsyncRequest : public Context { } }; +template +bool needs_invalidate(I& image_ctx, uint64_t object_no, + uint8_t current_state, uint8_t new_state) { + if ( (current_state == OBJECT_EXISTS || + current_state == OBJECT_EXISTS_CLEAN) && + (new_state == OBJECT_NONEXISTENT || + new_state == OBJECT_PENDING)) { + return false; + } + return true; +} + } // anonymous namespace template @@ -423,6 +436,48 @@ void Operations::execute_rebuild_object_map(ProgressContext &prog_ctx, req->send(); } +template +int Operations::check_object_map(ProgressContext &prog_ctx) { + CephContext *cct = m_image_ctx.cct; + ldout(cct, 5) << this << " " << __func__ << dendl; + int r = m_image_ctx.state->refresh_if_required(); + if (r < 0) { + return r; + } + + r = invoke_async_request("check object map", true, + boost::bind(&Operations::check_object_map, this, + boost::ref(prog_ctx), _1), + [] (Context *c) { c->complete(-EOPNOTSUPP); }); + + return r; +} + +template +void Operations::object_map_iterate(ProgressContext &prog_ctx, + operation::ObjectIterateWork handle_mismatch, + Context *on_finish) { + assert(m_image_ctx.owner_lock.is_locked()); + assert(m_image_ctx.exclusive_lock == nullptr || + m_image_ctx.exclusive_lock->is_lock_owner()); + + if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP)) { + on_finish->complete(-EINVAL); + return; + } + + operation::ObjectMapIterateRequest *req = + new operation::ObjectMapIterateRequest(m_image_ctx, on_finish, + prog_ctx, handle_mismatch); + req->send(); +} + +template +void Operations::check_object_map(ProgressContext &prog_ctx, + Context *on_finish) { + object_map_iterate(prog_ctx, needs_invalidate, on_finish); +} + template int Operations::rename(const char *dstname) { CephContext *cct = m_image_ctx.cct; diff --git a/src/librbd/Operations.h b/src/librbd/Operations.h index 95af4dcf1e96..a6fc91b7912a 100644 --- a/src/librbd/Operations.h +++ b/src/librbd/Operations.h @@ -5,6 +5,7 @@ #define CEPH_LIBRBD_OPERATIONS_H #include "include/int_types.h" +#include "librbd/operation/ObjectMapIterate.h" #include #include #include @@ -28,6 +29,13 @@ public: void execute_rebuild_object_map(ProgressContext &prog_ctx, Context *on_finish); + int check_object_map(ProgressContext &prog_ctx); + void check_object_map(ProgressContext &prog_ctx, Context *on_finish); + + void object_map_iterate(ProgressContext &prog_ctx, + operation::ObjectIterateWork handle_mismatch, + Context* on_finish); + int rename(const char *dstname); void execute_rename(const char *dstname, Context *on_finish); diff --git a/src/librbd/librbd.cc b/src/librbd/librbd.cc index 2cb5132ed24b..eb6df2a85db0 100644 --- a/src/librbd/librbd.cc +++ b/src/librbd/librbd.cc @@ -713,6 +713,12 @@ namespace librbd { return ictx->operations->rebuild_object_map(prog_ctx); } + int Image::check_object_map(ProgressContext &prog_ctx) + { + ImageCtx *ictx = reinterpret_cast(ctx); + return ictx->operations->check_object_map(prog_ctx); + } + int Image::copy(IoCtx& dest_io_ctx, const char *destname) { ImageCtx *ictx = (ImageCtx *)ctx; diff --git a/src/librbd/operation/ObjectMapIterate.cc b/src/librbd/operation/ObjectMapIterate.cc new file mode 100644 index 000000000000..87fab84465e9 --- /dev/null +++ b/src/librbd/operation/ObjectMapIterate.cc @@ -0,0 +1,293 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "librbd/operation/ObjectMapIterate.h" +#include "common/dout.h" +#include "common/errno.h" +#include "librbd/AsyncObjectThrottle.h" +#include "librbd/ExclusiveLock.h" +#include "librbd/ImageCtx.h" +#include "librbd/ImageWatcher.h" +#include "librbd/internal.h" +#include "librbd/ObjectMap.h" +#include "librbd/operation/ResizeRequest.h" +#include "librbd/object_map/InvalidateRequest.h" +#include "librbd/Utils.h" +#include +#include + +#define dout_subsys ceph_subsys_rbd +#undef dout_prefix +#define dout_prefix *_dout << "librbd::ObjectMapIterateRequest: " + +namespace librbd { +namespace operation { + +namespace { + +template +class C_VerifyObjectCallback : public C_AsyncObjectThrottle { +public: + C_VerifyObjectCallback(AsyncObjectThrottle &throttle, I *image_ctx, + uint64_t snap_id, uint64_t object_no, + ObjectIterateWork handle_mismatch, + std::atomic_flag *invalidate) + : C_AsyncObjectThrottle(throttle, *image_ctx), + m_snap_id(snap_id), m_object_no(object_no), + m_oid(image_ctx->get_object_name(m_object_no)), + m_handle_mismatch(handle_mismatch), + m_invalidate(invalidate) + { + m_io_ctx.dup(image_ctx->md_ctx); + m_io_ctx.snap_set_read(CEPH_SNAPDIR); + } + + virtual void complete(int r) { + I &image_ctx = this->m_image_ctx; + if (should_complete(r)) { + ldout(image_ctx.cct, 20) << m_oid << " C_VerifyObjectCallback completed " + << dendl; + this->finish(r); + delete this; + } + } + + virtual int send() { + send_list_snaps(); + return 0; + } + +private: + librados::IoCtx m_io_ctx; + uint64_t m_snap_id; + uint64_t m_object_no; + std::string m_oid; + ObjectIterateWork m_handle_mismatch; + std::atomic_flag *m_invalidate; + + librados::snap_set_t m_snap_set; + int m_snap_list_ret; + + bool should_complete(int r) { + I &image_ctx = this->m_image_ctx; + CephContext *cct = image_ctx.cct; + if (r == 0) { + r = m_snap_list_ret; + } + if (r < 0 && r != -ENOENT) { + lderr(cct) << m_oid << " C_VerifyObjectCallback::should_complete: " + << "encountered an error: " << cpp_strerror(r) << dendl; + return true; + } + + ldout(cct, 20) << m_oid << " C_VerifyObjectCallback::should_complete: " + << " r=" + << r << dendl; + return object_map_action(get_object_state()); + } + + void send_list_snaps() { + I &image_ctx = this->m_image_ctx; + assert(image_ctx.owner_lock.is_locked()); + ldout(image_ctx.cct, 5) << m_oid + << " C_VerifyObjectCallback::send_list_snaps" + << dendl; + + librados::ObjectReadOperation op; + op.list_snaps(&m_snap_set, &m_snap_list_ret); + + librados::AioCompletion *comp = util::create_rados_safe_callback(this); + int r = m_io_ctx.aio_operate(m_oid, comp, &op, NULL); + assert(r == 0); + comp->release(); + } + + uint8_t get_object_state() { + I &image_ctx = this->m_image_ctx; + RWLock::RLocker snap_locker(image_ctx.snap_lock); + for (std::vector::const_iterator r = + m_snap_set.clones.begin(); r != m_snap_set.clones.end(); ++r) { + librados::snap_t from_snap_id; + librados::snap_t to_snap_id; + if (r->cloneid == librados::SNAP_HEAD) { + from_snap_id = next_valid_snap_id(m_snap_set.seq + 1); + to_snap_id = librados::SNAP_HEAD; + } else { + from_snap_id = next_valid_snap_id(r->snaps[0]); + to_snap_id = r->snaps[r->snaps.size()-1]; + } + + if (to_snap_id < m_snap_id) { + continue; + } else if (m_snap_id < from_snap_id) { + break; + } + + if ((image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0 && + from_snap_id != m_snap_id) { + return OBJECT_EXISTS_CLEAN; + } + return OBJECT_EXISTS; + } + return OBJECT_NONEXISTENT; + } + + uint64_t next_valid_snap_id(uint64_t snap_id) { + I &image_ctx = this->m_image_ctx; + assert(image_ctx.snap_lock.is_locked()); + + std::map::iterator it = + image_ctx.snap_info.lower_bound(snap_id); + if (it == image_ctx.snap_info.end()) { + return CEPH_NOSNAP; + } + return it->first; + } + + bool object_map_action(uint8_t new_state) { + I &image_ctx = this->m_image_ctx; + CephContext *cct = image_ctx.cct; + RWLock::RLocker owner_locker(image_ctx.owner_lock); + + // should have been canceled prior to releasing lock + assert(image_ctx.exclusive_lock == nullptr || + image_ctx.exclusive_lock->is_lock_owner()); + + RWLock::RLocker snap_locker(image_ctx.snap_lock); + assert(image_ctx.object_map != nullptr); + + RWLock::WLocker l(image_ctx.object_map_lock); + uint8_t state = (*image_ctx.object_map)[m_object_no]; + + ldout(cct, 10) << "C_VerifyObjectCallback::object_map_action" + << " object " << image_ctx.get_object_name(m_object_no) + << " state " << (int)state + << " new_state " << (int)new_state << dendl; + + if (state != new_state) { + int r = 0; + + assert(m_handle_mismatch); + r = m_handle_mismatch(image_ctx, m_object_no, state, new_state); + if (r) { + lderr(cct) << "object map error: object " + << image_ctx.get_object_name(m_object_no) + << " marked as " << (int)state << ", but should be " + << (int)new_state << dendl; + m_invalidate->test_and_set(); + } else { + ldout(cct, 1) << "object map inconsistent: object " + << image_ctx.get_object_name(m_object_no) + << " marked as " << (int)state << ", but should be " + << (int)new_state << dendl; + } + } + + return true; + } +}; + +} // anonymous namespace + +template +void ObjectMapIterateRequest::send() { + send_verify_objects(); +} + +template +bool ObjectMapIterateRequest::should_complete(int r) { + CephContext *cct = m_image_ctx.cct; + ldout(cct, 5) << this << " should_complete: " << " r=" << r << dendl; + + RWLock::RLocker owner_lock(m_image_ctx.owner_lock); + switch (m_state) { + case STATE_VERIFY_OBJECTS: + if (m_invalidate.test_and_set()) { + send_invalidate_object_map(); + } else if (r == 0) { + return true; + } + break; + + case STATE_INVALIDATE_OBJECT_MAP: + if (r == 0) { + return true; + } + break; + + default: + assert(false); + break; + } + + if (r < 0) { + lderr(cct) << "object map operation encountered an error: " + << cpp_strerror(r) + << dendl; + return true; + } + + return false; +} + +template +void ObjectMapIterateRequest::send_verify_objects() { + assert(m_image_ctx.owner_lock.is_locked()); + CephContext *cct = m_image_ctx.cct; + + uint64_t snap_id; + uint64_t num_objects; + { + RWLock::RLocker l(m_image_ctx.snap_lock); + snap_id = m_image_ctx.snap_id; + num_objects = Striper::get_num_objects(m_image_ctx.layout, + m_image_ctx.get_image_size(snap_id)); + } + ldout(cct, 5) << this << " send_verify_objects" << dendl; + + m_state = STATE_VERIFY_OBJECTS; + + typename AsyncObjectThrottle::ContextFactory context_factory( + boost::lambda::bind(boost::lambda::new_ptr >(), + boost::lambda::_1, &m_image_ctx, snap_id, + boost::lambda::_2, m_handle_mismatch, &m_invalidate)); + AsyncObjectThrottle *throttle = new AsyncObjectThrottle( + this, m_image_ctx, context_factory, this->create_callback_context(), + &m_prog_ctx, 0, num_objects); + throttle->start_ops(cct->_conf->rbd_concurrent_management_ops); +} + +template +uint64_t ObjectMapIterateRequest::get_image_size() const { + assert(m_image_ctx.snap_lock.is_locked()); + if (m_image_ctx.snap_id == CEPH_NOSNAP) { + if (!m_image_ctx.resize_reqs.empty()) { + return m_image_ctx.resize_reqs.front()->get_image_size(); + } else { + return m_image_ctx.size; + } + } + return m_image_ctx.get_image_size(m_image_ctx.snap_id); +} + +template +void ObjectMapIterateRequest::send_invalidate_object_map() { + CephContext *cct = m_image_ctx.cct; + + ldout(cct, 5) << this << " send_invalidate_object_map" << dendl; + m_state = STATE_INVALIDATE_OBJECT_MAP; + + object_map::InvalidateRequest*req = + object_map::InvalidateRequest::create(m_image_ctx, m_image_ctx.snap_id, + true, + this->create_callback_context()); + + assert(m_image_ctx.owner_lock.is_locked()); + RWLock::WLocker snap_locker(m_image_ctx.snap_lock); + req->send(); +} + +} // namespace operation +} // namespace librbd + +template class librbd::operation::ObjectMapIterateRequest; diff --git a/src/librbd/operation/ObjectMapIterate.h b/src/librbd/operation/ObjectMapIterate.h new file mode 100644 index 000000000000..cc2dc3432f78 --- /dev/null +++ b/src/librbd/operation/ObjectMapIterate.h @@ -0,0 +1,66 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +#ifndef CEPH_LIBRBD_OPERATION_OBJECT_MAP_ITERATE_H +#define CEPH_LIBRBD_OPERATION_OBJECT_MAP_ITERATE_H + +#include +#include + +#include "include/int_types.h" +#include "include/rbd/object_map_types.h" +#include "librbd/AsyncRequest.h" + +namespace librbd { + +class ImageCtx; +class ProgressContext; + +namespace operation { + +template +using ObjectIterateWork = bool(*)(ImageCtxT &image_ctx, + uint64_t object_no, + uint8_t current_state, + uint8_t new_state); + +template +class ObjectMapIterateRequest : public AsyncRequest { +public: + ObjectMapIterateRequest(ImageCtxT &image_ctx, Context *on_finish, + ProgressContext &prog_ctx, + ObjectIterateWork handle_mismatch) + : AsyncRequest(image_ctx, on_finish), m_image_ctx(image_ctx), + m_prog_ctx(prog_ctx), m_handle_mismatch(handle_mismatch), + m_invalidate(ATOMIC_FLAG_INIT) + { + } + + virtual void send(); + +protected: + virtual bool should_complete(int r); + +private: + enum State { + STATE_VERIFY_OBJECTS, + STATE_INVALIDATE_OBJECT_MAP + }; + + ImageCtxT &m_image_ctx; + ProgressContext &m_prog_ctx; + ObjectIterateWork m_handle_mismatch; + std::atomic_flag m_invalidate; + State m_state; + + void send_verify_objects(); + void send_invalidate_object_map(); + + uint64_t get_image_size() const; +}; + +} // namespace operation +} // namespace librbd + +extern template class librbd::operation::ObjectMapIterateRequest; + +#endif diff --git a/src/librbd/operation/RebuildObjectMapRequest.cc b/src/librbd/operation/RebuildObjectMapRequest.cc index da2e744ce904..aa65618b60ae 100644 --- a/src/librbd/operation/RebuildObjectMapRequest.cc +++ b/src/librbd/operation/RebuildObjectMapRequest.cc @@ -12,6 +12,7 @@ #include "librbd/ObjectMap.h" #include "librbd/operation/ResizeRequest.h" #include "librbd/operation/TrimRequest.h" +#include "librbd/operation/ObjectMapIterate.h" #include "librbd/Utils.h" #include #include @@ -23,152 +24,6 @@ namespace librbd { namespace operation { -namespace { - -template -class C_VerifyObject : public C_AsyncObjectThrottle { -public: - C_VerifyObject(AsyncObjectThrottle &throttle, I *image_ctx, - uint64_t snap_id, uint64_t object_no) - : C_AsyncObjectThrottle(throttle, *image_ctx), m_snap_id(snap_id), - m_object_no(object_no), - m_oid(image_ctx->get_object_name(m_object_no)), - m_snap_list_ret(0) - { - m_io_ctx.dup(image_ctx->md_ctx); - m_io_ctx.snap_set_read(CEPH_SNAPDIR); - } - - virtual void complete(int r) { - I &image_ctx = this->m_image_ctx; - if (should_complete(r)) { - ldout(image_ctx.cct, 20) << m_oid << " C_VerifyObject completed " - << dendl; - this->finish(r); - delete this; - } - } - - virtual int send() { - send_list_snaps(); - return 0; - } - -private: - librados::IoCtx m_io_ctx; - uint64_t m_snap_id; - uint64_t m_object_no; - std::string m_oid; - - librados::snap_set_t m_snap_set; - int m_snap_list_ret; - - bool should_complete(int r) { - I &image_ctx = this->m_image_ctx; - CephContext *cct = image_ctx.cct; - if (r == 0) { - r = m_snap_list_ret; - } - if (r < 0 && r != -ENOENT) { - lderr(cct) << m_oid << " C_VerifyObject::should_complete: " - << "encountered an error: " << cpp_strerror(r) << dendl; - return true; - } - - ldout(cct, 20) << m_oid << " C_VerifyObject::should_complete: " << " r=" - << r << dendl; - return update_object_map(get_object_state()); - } - - void send_list_snaps() { - I &image_ctx = this->m_image_ctx; - assert(image_ctx.owner_lock.is_locked()); - ldout(image_ctx.cct, 5) << m_oid << " C_VerifyObject::send_list_snaps" - << dendl; - - librados::ObjectReadOperation op; - op.list_snaps(&m_snap_set, &m_snap_list_ret); - - librados::AioCompletion *comp = util::create_rados_safe_callback(this); - int r = m_io_ctx.aio_operate(m_oid, comp, &op, NULL); - assert(r == 0); - comp->release(); - } - - uint8_t get_object_state() { - I &image_ctx = this->m_image_ctx; - RWLock::RLocker snap_locker(image_ctx.snap_lock); - for (std::vector::const_iterator r = - m_snap_set.clones.begin(); r != m_snap_set.clones.end(); ++r) { - librados::snap_t from_snap_id; - librados::snap_t to_snap_id; - if (r->cloneid == librados::SNAP_HEAD) { - from_snap_id = next_valid_snap_id(m_snap_set.seq + 1); - to_snap_id = librados::SNAP_HEAD; - } else { - from_snap_id = next_valid_snap_id(r->snaps[0]); - to_snap_id = r->snaps[r->snaps.size()-1]; - } - - if (to_snap_id < m_snap_id) { - continue; - } else if (m_snap_id < from_snap_id) { - break; - } - - if ((image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0 && - from_snap_id != m_snap_id) { - return OBJECT_EXISTS_CLEAN; - } - return OBJECT_EXISTS; - } - return OBJECT_NONEXISTENT; - } - - uint64_t next_valid_snap_id(uint64_t snap_id) { - I &image_ctx = this->m_image_ctx; - assert(image_ctx.snap_lock.is_locked()); - - std::map::iterator it = - image_ctx.snap_info.lower_bound(snap_id); - if (it == image_ctx.snap_info.end()) { - return CEPH_NOSNAP; - } - return it->first; - } - - bool update_object_map(uint8_t new_state) { - I &image_ctx = this->m_image_ctx; - RWLock::RLocker owner_locker(image_ctx.owner_lock); - CephContext *cct = image_ctx.cct; - - // should have been canceled prior to releasing lock - assert(image_ctx.exclusive_lock == nullptr || - image_ctx.exclusive_lock->is_lock_owner()); - - RWLock::RLocker snap_locker(image_ctx.snap_lock); - assert(image_ctx.object_map != nullptr); - - RWLock::WLocker l(image_ctx.object_map_lock); - uint8_t state = (*image_ctx.object_map)[m_object_no]; - if (state == OBJECT_EXISTS && new_state == OBJECT_NONEXISTENT && - m_snap_id == CEPH_NOSNAP) { - // might be writing object to OSD concurrently - new_state = state; - } - - if (new_state != state) { - ldout(cct, 15) << m_oid << " C_VerifyObject::update_object_map " - << static_cast(state) << "->" - << static_cast(new_state) << dendl; - (*image_ctx.object_map)[m_object_no] = new_state; - } - return true; - } -}; - -} // anonymous namespace - template void RebuildObjectMapRequest::send() { send_resize_object_map(); @@ -294,34 +149,42 @@ void RebuildObjectMapRequest::send_trim_image() { } template -void RebuildObjectMapRequest::send_verify_objects() { - assert(m_image_ctx.owner_lock.is_locked()); - CephContext *cct = m_image_ctx.cct; +bool update_object_map(I& image_ctx, uint64_t object_no, uint8_t current_state, + uint8_t new_state) { + CephContext *cct = image_ctx.cct; + uint64_t snap_id = image_ctx.snap_id; - uint64_t snap_id; - uint64_t num_objects; - { - RWLock::RLocker l(m_image_ctx.snap_lock); - snap_id = m_image_ctx.snap_id; - num_objects = Striper::get_num_objects(m_image_ctx.layout, - m_image_ctx.get_image_size(snap_id)); + uint8_t state = (*image_ctx.object_map)[object_no]; + if (state == OBJECT_EXISTS && new_state == OBJECT_NONEXISTENT && + snap_id == CEPH_NOSNAP) { + // might be writing object to OSD concurrently + new_state = state; } - if (num_objects == 0) { - send_save_object_map(); - return; + if (new_state != state) { + ldout(cct, 15) << image_ctx.get_object_name(object_no) + << " rebuild updating object map " + << static_cast(state) << "->" + << static_cast(new_state) << dendl; + (*image_ctx.object_map)[object_no] = new_state; } + return false; +} + +template +void RebuildObjectMapRequest::send_verify_objects() { + assert(m_image_ctx.owner_lock.is_locked()); + CephContext *cct = m_image_ctx.cct; m_state = STATE_VERIFY_OBJECTS; ldout(cct, 5) << this << " send_verify_objects" << dendl; - typename AsyncObjectThrottle::ContextFactory context_factory( - boost::lambda::bind(boost::lambda::new_ptr >(), - boost::lambda::_1, &m_image_ctx, snap_id, boost::lambda::_2)); - AsyncObjectThrottle *throttle = new AsyncObjectThrottle( - this, m_image_ctx, context_factory, this->create_callback_context(), - &m_prog_ctx, 0, num_objects); - throttle->start_ops(cct->_conf->rbd_concurrent_management_ops); + ObjectMapIterateRequest *req = + new ObjectMapIterateRequest(m_image_ctx, + this->create_callback_context(), + m_prog_ctx, update_object_map); + + req->send(); } template diff --git a/src/test/librbd/test_librbd.cc b/src/test/librbd/test_librbd.cc index c3754610b12d..0a84c868cd0a 100644 --- a/src/test/librbd/test_librbd.cc +++ b/src/test/librbd/test_librbd.cc @@ -3669,6 +3669,71 @@ TEST_F(TestLibRBD, RebuildNewObjectMap) rados_ioctx_destroy(ioctx); } +TEST_F(TestLibRBD, CheckObjectMap) +{ + REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); + + 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 << 20; + int order = 18; + ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order)); + + PrintProgress prog_ctx; + bufferlist bl1; + bufferlist bl2; + bl1.append("foo"); + { + librbd::Image image; + ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL)); + + uint64_t features; + ASSERT_EQ(0, image.features(&features)); + + ASSERT_EQ(bl1.length(), image.write(0, bl1.length(), bl1)); + + ASSERT_EQ(0, image.snap_create("snap1")); + ASSERT_EQ(bl1.length(), image.write(1<()); + if (r < 0) { + std::cerr << "rbd: checking object map failed: " << cpp_strerror(r) + << std::endl; + return r; + } + return 0; +} + +Shell::Action action_rebuild( {"object-map", "rebuild"}, {}, "Rebuild an invalid object map.", "", - &get_arguments, &execute); + &get_rebuild_arguments, &execute_rebuild); +Shell::Action action_check( + {"object-map", "check"}, {}, "Verify the object map is correct.", "", + &get_check_arguments, &execute_check); } // namespace object_map } // namespace action