ldout(m_ictx->cct, 20) << "send " << this << " " << m_oid << " " << m_object_off << "~" << m_object_len << dendl;
// send read request to parent if the object doesn't exist locally
- {
- RWLock::RLocker l(m_ictx->md_lock);
- if (m_ictx->object_map != NULL &&
- !m_ictx->object_map->object_may_exist(m_object_no)) {
- complete(-ENOENT);
- return 0;
- }
+ if (!m_ictx->object_map.object_may_exist(m_object_no)) {
+ complete(-ENOENT);
+ return 0;
}
librados::AioCompletion *rados_completion =
bool lost_exclusive_lock = false;
{
RWLock::RLocker l(m_ictx->owner_lock);
- RWLock::RLocker l2(m_ictx->md_lock);
- if (m_ictx->object_map == NULL) {
+ if (!m_ictx->object_map.enabled()) {
return false;
}
m_state = LIBRBD_AIO_WRITE_PRE;
FunctionContext *ctx = new FunctionContext(
boost::bind(&AioRequest::complete, this, _1));
- if (!m_ictx->object_map->aio_update(m_object_no, new_state,
+ if (!m_ictx->object_map.aio_update(m_object_no, new_state,
current_state, ctx)) {
// no object map update required
return false;
<< m_object_off << "~" << m_object_len << dendl;
RWLock::RLocker l(m_ictx->owner_lock);
- RWLock::RLocker l2(m_ictx->md_lock);
- if (m_ictx->object_map == NULL || !post_object_map_update()) {
+ if (!m_ictx->object_map.enabled() || !post_object_map_update()) {
return true;
}
m_state = LIBRBD_AIO_WRITE_POST;
FunctionContext *ctx = new FunctionContext(
boost::bind(&AioRequest::complete, this, _1));
- if (!m_ictx->object_map->aio_update(m_object_no, OBJECT_NONEXISTENT,
+ if (!m_ictx->object_map.aio_update(m_object_no, OBJECT_NONEXISTENT,
OBJECT_PENDING, ctx)) {
// no object map update required
return true;
bool object_map_enabled = true;
{
RWLock::RLocker l(m_image_ctx.owner_lock);
- RWLock::RLocker l2(m_image_ctx.md_lock);
- if (m_image_ctx.object_map == NULL) {
+ if (!m_image_ctx.object_map.enabled()) {
object_map_enabled = false;
} else {
ldout(m_image_ctx.cct, 5) << this << " send_grow_object_map: "
ldout(m_image_ctx.cct, 1) << "lost exclusive lock during grow object map" << dendl;
lost_exclusive_lock = true;
} else {
- m_image_ctx.object_map->aio_resize(m_new_size, OBJECT_NONEXISTENT,
+ m_image_ctx.object_map.aio_resize(m_new_size, OBJECT_NONEXISTENT,
create_callback_context());
object_map_enabled = true;
}
bool lost_exclusive_lock = false;
{
RWLock::RLocker l(m_image_ctx.owner_lock);
- RWLock::RLocker l2(m_image_ctx.md_lock);
- if (m_image_ctx.object_map == NULL ||
+ if (!m_image_ctx.object_map.enabled() ||
m_new_size > m_original_size) {
return true;
}
ldout(m_image_ctx.cct, 1) << "lost exclusive lock during shrink object map" << dendl;
lost_exclusive_lock = true;
} else {
- m_image_ctx.object_map->aio_resize(m_new_size, OBJECT_NONEXISTENT,
+ m_image_ctx.object_map.aio_resize(m_new_size, OBJECT_NONEXISTENT,
create_callback_context());
}
}
}
virtual int send() {
- {
- RWLock::RLocker l(m_image_ctx.md_lock);
- if (m_image_ctx.object_map != NULL &&
- !m_image_ctx.object_map->object_may_exist(m_object_no)) {
- return 1;
- }
+ if (!m_image_ctx.object_map.object_may_exist(m_object_no)) {
+ return 1;
}
RWLock::RLocker l(m_image_ctx.owner_lock);
bool lost_exclusive_lock = false;
{
RWLock::RLocker l(m_image_ctx.owner_lock);
- RWLock::RLocker l2(m_image_ctx.md_lock);
- if (m_image_ctx.object_map == NULL) {
+ if (!m_image_ctx.object_map.enabled()) {
remove_objects = true;
} else {
ldout(m_image_ctx.cct, 5) << this << " send_pre_remove: "
lost_exclusive_lock = true;
} else {
// flag the objects as pending deletion
- if (!m_image_ctx.object_map->aio_update(m_delete_start, m_num_objects,
+ if (!m_image_ctx.object_map.aio_update(m_delete_start, m_num_objects,
OBJECT_PENDING, OBJECT_EXISTS,
create_callback_context())) {
remove_objects = true;
bool lost_exclusive_lock = false;
{
RWLock::RLocker l(m_image_ctx.owner_lock);
- RWLock::RLocker l2(m_image_ctx.md_lock);
- if (m_image_ctx.object_map == NULL) {
+ if (!m_image_ctx.object_map.enabled()) {
clean_boundary = true;
} else {
ldout(m_image_ctx.cct, 5) << this << " send_post_remove: "
ldout(m_image_ctx.cct, 1) << "lost exclusive lock during trim" << dendl;
} else {
// flag the pending objects as removed
- if (!m_image_ctx.object_map->aio_update(m_delete_start, m_num_objects,
+ if (!m_image_ctx.object_map.aio_update(m_delete_start, m_num_objects,
OBJECT_NONEXISTENT,
OBJECT_PENDING,
create_callback_context())) {
bool copyup = false;
{
RWLock::RLocker l(m_ictx->owner_lock);
- RWLock::RLocker l2(m_ictx->md_lock);
- if (m_ictx->object_map == NULL) {
+ if (!m_ictx->object_map.enabled()) {
copyup = true;
} else if (!m_ictx->image_watcher->is_lock_owner()) {
ldout(m_ictx->cct, 20) << "exclusive lock not held for copy-on-read"
return true;
} else {
m_state = STATE_OBJECT_MAP;
- if (!m_ictx->object_map->aio_update(m_object_no, OBJECT_EXISTS,
+ if (!m_ictx->object_map.aio_update(m_object_no, OBJECT_EXISTS,
boost::optional<uint8_t>(),
create_callback_context())) {
copyup = true;
object_cacher(NULL), writeback_handler(NULL), object_set(NULL),
readahead(),
total_bytes_read(0), copyup_finisher(NULL),
- object_map(NULL)
+ object_map(*this)
{
md_ctx.dup(p);
data_ctx.dup(p);
delete copyup_finisher;
copyup_finisher = NULL;
}
- delete object_map;
delete[] format_string;
}
snap_exists = true;
data_ctx.snap_set_read(snap_id);
- if (object_map != NULL) {
- object_map->refresh(in_snap_id);
+ if (object_map.enabled()) {
+ RWLock::WLocker l(object_map_lock);
+ object_map.refresh(in_snap_id);
}
return 0;
}
snap_exists = true;
data_ctx.snap_set_read(snap_id);
- if (object_map != NULL) {
- object_map->refresh(CEPH_NOSNAP);
+ if (object_map.enabled()) {
+ RWLock::WLocker l(object_map_lock);
+ object_map.refresh(CEPH_NOSNAP);
}
}
#include "cls/rbd/cls_rbd_client.h"
#include "librbd/LibrbdWriteback.h"
+#include "librbd/ObjectMap.h"
#include "librbd/SnapInfo.h"
#include "librbd/parent_types.h"
class AsyncOperation;
class CopyupRequest;
class ImageWatcher;
- class ObjectMap;
struct ImageCtx {
CephContext *cct;
RWLock snap_lock; // protects snapshot-related member variables, features, and flags
RWLock parent_lock; // protects parent_md and parent
Mutex refresh_lock; // protects refresh_seq and last_refresh
- RWLock object_map_lock; // protects object map updates
+ RWLock object_map_lock; // protects object map updates and object_map itself
Mutex async_ops_lock; // protects async_ops
Mutex copyup_list_lock; // protects copyup_waiting_list
xlist<AsyncOperation*> async_ops;
- ObjectMap *object_map;
+ ObjectMap object_map;
atomic_t async_request_seq;
bool test_features(uint64_t test_features) const;
int get_flags(librados::snap_t in_snap_id, uint64_t *flags) const;
bool test_flags(uint64_t test_flags) const;
+
const parent_info* get_parent_info(librados::snap_t in_snap_id) const;
int64_t get_parent_pool_id(librados::snap_t in_snap_id) const;
std::string get_parent_image_id(librados::snap_t in_snap_id) const;
m_owner_client_id = get_client_id();
}
- if (m_image_ctx.object_map != NULL) {
- r = m_image_ctx.object_map->lock();
+ if (m_image_ctx.object_map.enabled()) {
+ r = m_image_ctx.object_map.lock();
if (r < 0 && r != -ENOENT) {
unlock();
return r;
}
- m_image_ctx.object_map->refresh(CEPH_NOSNAP);
+ RWLock::RLocker l2(m_image_ctx.snap_lock);
+ RWLock::WLocker l3(m_image_ctx.object_map_lock);
+ m_image_ctx.object_map.refresh(CEPH_NOSNAP);
}
bufferlist bl;
return r;
}
- if (m_image_ctx.object_map != NULL) {
- m_image_ctx.object_map->unlock();
+ if (m_image_ctx.object_map.enabled()) {
+ m_image_ctx.object_map.unlock();
}
FunctionContext *ctx = new FunctionContext(
Context *req = new C_Request(m_ictx->cct, onfinish, &m_lock);
{
- RWLock::RLocker l(m_ictx->md_lock);
- if (m_ictx->object_map != NULL &&
- !m_ictx->object_map->object_may_exist(object_no)) {
+ if (!m_ictx->object_map.object_may_exist(object_no)) {
m_finisher->queue(req, -ENOENT);
return;
}
namespace librbd {
ObjectMap::ObjectMap(ImageCtx &image_ctx)
- : m_image_ctx(image_ctx)
+ : m_image_ctx(image_ctx), m_enabled(false)
{
}
return oid;
}
+bool ObjectMap::enabled() const
+{
+ RWLock::RLocker l(m_image_ctx.object_map_lock);
+ return m_enabled;
+}
+
int ObjectMap::lock()
{
if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP)) {
return 0;
}
+ {
+ RWLock::RLocker l(m_image_ctx.object_map_lock);
+ if (!m_enabled) {
+ return 0;
+ }
+ }
+
int r;
bool broke_lock = false;
CephContext *cct = m_image_ctx.cct;
}
RWLock::RLocker l(m_image_ctx.object_map_lock);
+ if (!m_enabled) {
+ return true;
+ }
assert(object_no < m_object_map.size());
bool exists = (m_object_map[object_no] == OBJECT_EXISTS ||
void ObjectMap::refresh(uint64_t snap_id)
{
assert(m_image_ctx.snap_lock.is_locked());
+ assert(m_image_ctx.object_map_lock.is_wlocked());
uint64_t features;
- m_image_ctx.get_features(m_image_ctx.snap_id, &features);
- if ((features & RBD_FEATURE_OBJECT_MAP) == 0) {
+ m_image_ctx.get_features(snap_id, &features);
+ if ((features & RBD_FEATURE_OBJECT_MAP) == 0 ||
+ (m_image_ctx.snap_id == snap_id && !m_image_ctx.snap_exists)) {
+ m_object_map.clear();
+ m_enabled = false;
return;
}
+ m_enabled = true;
CephContext *cct = m_image_ctx.cct;
ldout(cct, 10) << &m_image_ctx << " refreshing object map" << dendl;
- RWLock::WLocker l(m_image_ctx.object_map_lock);
std::string oid(object_map_name(m_image_ctx.id, snap_id));
int r = cls_client::object_map_load(&m_image_ctx.md_ctx, oid,
&m_object_map);
ldout(cct, 10) << &m_image_ctx << " rollback object map" << dendl;
RWLock::WLocker l(m_image_ctx.object_map_lock);
+ if (!m_enabled) {
+ return;
+ }
std::string snap_oid(object_map_name(m_image_ctx.id, snap_id));
bufferlist bl;
int r;
bufferlist bl;
- {
- RWLock::RLocker l(m_image_ctx.object_map_lock);
- std::string oid(object_map_name(m_image_ctx.id, CEPH_NOSNAP));
- r = m_image_ctx.md_ctx.read(oid, bl, 0, 0);
- if (r < 0) {
- lderr(cct) << "unable to load object map: " << cpp_strerror(r)
- << dendl;
- invalidate();
- }
+ RWLock::WLocker l(m_image_ctx.object_map_lock);
+ if (!m_enabled) {
+ return;
+ }
+ std::string oid(object_map_name(m_image_ctx.id, CEPH_NOSNAP));
+ r = m_image_ctx.md_ctx.read(oid, bl, 0, 0);
+ if (r < 0) {
+ lderr(cct) << "unable to load object map: " << cpp_strerror(r)
+ << dendl;
+ invalidate();
}
std::string snap_oid(object_map_name(m_image_ctx.id, snap_id));
void ObjectMap::invalidate() {
assert(m_image_ctx.snap_lock.is_wlocked());
+ assert(m_image_ctx.object_map_lock.is_wlocked());
uint64_t flags;
m_image_ctx.get_flags(m_image_ctx.snap_id, &flags);
if ((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0) {
}
{
- RWLock::RLocker l(m_image_ctx.md_lock);
RWLock::WLocker l2(m_image_ctx.object_map_lock);
- ObjectMap *object_map = m_image_ctx.object_map;
- if (object_map != NULL) {
- finish(object_map);
- }
+ finish(&m_image_ctx.object_map);
}
return true;
ldout(cct, 20) << "INVALIDATE" << dendl;
if (r < 0) {
lderr(cct) << "failed to invalidate object map: " << cpp_strerror(r)
- << dendl;
+ << dendl;
}
return true;
void rollback(uint64_t snap_id);
void snapshot(uint64_t snap_id);
+ bool enabled() const;
+
private:
class Request : public AsyncRequest {
ceph::BitVector<2> m_object_map;
+ bool m_enabled;
+
void invalidate();
};
{
RWLock::WLocker l(ictx->snap_lock);
- if (ictx->object_map != NULL) {
- ictx->object_map->rollback(snap_id);
- }
+ ictx->object_map.rollback(snap_id);
}
return 0;
}
}
}
- if (ictx->object_map != NULL) {
- r = ictx->md_ctx.remove(ObjectMap::object_map_name(ictx->id, snap_id));
- if (r < 0 && r != -ENOENT) {
- lderr(ictx->cct) << "snap_remove: failed to remove snapshot object map"
- << dendl;
- return 0;
- }
+ r = ictx->md_ctx.remove(ObjectMap::object_map_name(ictx->id, snap_id));
+ if (r < 0 && r != -ENOENT) {
+ lderr(ictx->cct) << "snap_remove: failed to remove snapshot object map"
+ << dendl;
+ return 0;
}
r = rm_snap(ictx, snap_name);
RWLock::WLocker l(ictx->snap_lock);
if (!ictx->old_format) {
- if (ictx->object_map != NULL) {
- ictx->object_map->snapshot(snap_id);
- }
+ ictx->object_map.snapshot(snap_id);
if (lock_owner) {
// immediately start using the new snap context if we
// own the exclusive lock
ictx->snap_exists = false;
}
- if ((ictx->features & RBD_FEATURE_OBJECT_MAP) == 0) {
- delete ictx->object_map;
- ictx->object_map = NULL;
- } else {
- ictx->object_map = new ObjectMap(*ictx);
- if (ictx->snap_exists) {
- ictx->object_map->refresh(ictx->snap_id);
- }
- }
+ RWLock::WLocker object_map_locker(ictx->object_map_lock);
+ ictx->object_map.refresh(ictx->snap_id);
ictx->data_ctx.selfmanaged_snap_set_write_ctx(ictx->snapc.seq, ictx->snaps);
} // release snap_lock