#include "common/Mutex.h"
#include "common/RWLock.h"
+#include "librbd/AioObjectRequest.h"
#include "librbd/AioCompletion.h"
#include "librbd/AioImageRequest.h"
+#include "librbd/CopyupRequest.h"
#include "librbd/ExclusiveLock.h"
#include "librbd/ImageCtx.h"
#include "librbd/ImageWatcher.h"
#include "librbd/internal.h"
-
-#include "librbd/AioObjectRequest.h"
-#include "librbd/CopyupRequest.h"
+#include "librbd/ObjectMap.h"
#include "librbd/Utils.h"
#include <boost/bind.hpp>
<< m_object_off << "~" << m_object_len << dendl;
// send read request to parent if the object doesn't exist locally
- if (!m_ictx->object_map.object_may_exist(m_object_no)) {
+ bool non_existent = false;
+ {
+ RWLock::RLocker snap_locker(m_ictx->snap_lock);
+ non_existent = (m_ictx->object_map != nullptr &&
+ !m_ictx->object_map->object_may_exist(m_object_no));
+ }
+ if (non_existent) {
complete(-ENOENT);
return;
}
void AbstractAioObjectWrite::send_pre() {
assert(m_ictx->owner_lock.is_locked());
- m_object_exist = m_ictx->object_map.object_may_exist(m_object_no);
bool write = false;
{
RWLock::RLocker snap_lock(m_ictx->snap_lock);
- if (!m_ictx->object_map.enabled()) {
+ if (m_ictx->object_map == nullptr) {
+ m_object_exist = true;
write = true;
} else {
// should have been flushed prior to releasing lock
assert(m_ictx->exclusive_lock->is_lock_owner());
+ m_object_exist = m_ictx->object_map->object_may_exist(m_object_no);
+
ldout(m_ictx->cct, 20) << "send_pre " << this << " " << m_oid << " "
<< m_object_off << "~" << m_object_len << dendl;
m_state = LIBRBD_AIO_WRITE_PRE;
pre_object_map_update(&new_state);
RWLock::WLocker object_map_locker(m_ictx->object_map_lock);
- if (m_ictx->object_map[m_object_no] != new_state) {
+ if ((*m_ictx->object_map)[m_object_no] != new_state) {
Context *ctx = util::create_context_callback<AioObjectRequest>(this);
- bool updated = m_ictx->object_map.aio_update(m_object_no, new_state,
- current_state, ctx);
+ bool updated = m_ictx->object_map->aio_update(m_object_no, new_state,
+ current_state, ctx);
assert(updated);
} else {
write = true;
bool AbstractAioObjectWrite::send_post() {
RWLock::RLocker owner_locker(m_ictx->owner_lock);
RWLock::RLocker snap_locker(m_ictx->snap_lock);
- if (!m_ictx->object_map.enabled() || !post_object_map_update()) {
+ if (m_ictx->object_map == nullptr || !post_object_map_update()) {
return true;
}
m_state = LIBRBD_AIO_WRITE_POST;
RWLock::WLocker object_map_locker(m_ictx->object_map_lock);
- uint8_t current_state = m_ictx->object_map[m_object_no];
+ uint8_t current_state = (*m_ictx->object_map)[m_object_no];
if (current_state != OBJECT_PENDING ||
current_state == OBJECT_NONEXISTENT) {
return true;
}
Context *ctx = util::create_context_callback<AioObjectRequest>(this);
- bool updated = m_ictx->object_map.aio_update(m_object_no,
- OBJECT_NONEXISTENT,
- OBJECT_PENDING, ctx);
+ bool updated = m_ictx->object_map->aio_update(m_object_no,
+ OBJECT_NONEXISTENT,
+ OBJECT_PENDING, ctx);
assert(updated);
return false;
}
}
void AioObjectWrite::add_write_ops(librados::ObjectWriteOperation *wr) {
- if (m_ictx->enable_alloc_hint && !m_ictx->object_map.object_may_exist(m_object_no))
+ RWLock::RLocker snap_locker(m_ictx->snap_lock);
+ if (m_ictx->enable_alloc_hint &&
+ (m_ictx->object_map == nullptr ||
+ !m_ictx->object_map->object_may_exist(m_object_no))) {
wr->set_alloc_hint(m_ictx->get_object_size(), m_ictx->get_object_size());
+ }
+
if (m_object_off == 0 && m_object_len == m_ictx->get_object_size()) {
wr->write_full(m_write_data);
} else {
RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
RWLock::WLocker object_map_locker(m_image_ctx.object_map_lock);
assert(m_image_ctx.exclusive_lock->is_lock_owner());
- bool sent = m_image_ctx.object_map.aio_update(m_object_no, OBJECT_EXISTS,
- boost::optional<uint8_t>(),
- this);
+ assert(m_image_ctx.object_map != nullptr);
+ bool sent = m_image_ctx.object_map->aio_update(m_object_no, OBJECT_EXISTS,
+ boost::optional<uint8_t>(),
+ this);
return (sent ? 0 : 1);
}
RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
RWLock::RLocker object_map_locker(m_image_ctx.object_map_lock);
- m_image_ctx.object_map.aio_update(snap_id, m_object_no, m_object_no + 1,
- state, boost::optional<uint8_t>(), this);
+ if (m_image_ctx.object_map == nullptr) {
+ return 1;
+ }
+
+ m_image_ctx.object_map->aio_update(snap_id, m_object_no, m_object_no + 1,
+ state, boost::optional<uint8_t>(), this);
return 0;
}
{
RWLock::RLocker owner_locker(m_ictx->owner_lock);
RWLock::RLocker snap_locker(m_ictx->snap_lock);
- if (m_ictx->object_map.enabled()) {
+ if (m_ictx->object_map != nullptr) {
bool copy_on_read = m_pending_requests.empty();
if (!m_ictx->exclusive_lock->is_lock_owner()) {
ldout(m_ictx->cct, 20) << "exclusive lock not held for copyup request"
}
RWLock::WLocker object_map_locker(m_ictx->object_map_lock);
- if (copy_on_read && m_ictx->object_map[m_object_no] != OBJECT_EXISTS) {
+ if (copy_on_read &&
+ (*m_ictx->object_map)[m_object_no] != OBJECT_EXISTS) {
// CoW already updates the HEAD object map
m_snap_ids.push_back(CEPH_NOSNAP);
}
#include "librbd/DiffIterate.h"
#include "librbd/ImageCtx.h"
#include "librbd/internal.h"
+#include "librbd/ObjectMap.h"
#include "librbd/Utils.h"
#include "include/rados/librados.hpp"
#include "include/interval_set.h"
readahead(),
total_bytes_read(0), copyup_finisher(NULL),
exclusive_lock(nullptr),
- object_map(*this), object_map_ptr(nullptr), aio_work_queue(NULL), op_work_queue(NULL),
+ object_map(nullptr), aio_work_queue(NULL), op_work_queue(NULL),
refresh_in_progress(false), asok_hook(new LibrbdAdminSocketHook(this))
{
md_ctx.dup(p);
snap_name = in_snap_name;
snap_exists = true;
data_ctx.snap_set_read(snap_id);
- object_map.refresh(in_snap_id);
return 0;
}
return -ENOENT;
snap_name = "";
snap_exists = true;
data_ctx.snap_set_read(snap_id);
- object_map.refresh(CEPH_NOSNAP);
}
snap_t ImageCtx::get_snap_id(string in_snap_name) const
#include "cls/rbd/cls_rbd_client.h"
#include "librbd/AsyncRequest.h"
#include "librbd/LibrbdWriteback.h"
-#include "librbd/ObjectMap.h"
#include "librbd/SnapInfo.h"
#include "librbd/parent_types.h"
class ImageWatcher;
class Journal;
class LibrbdAdminSocketHook;
+ class ObjectMap;
namespace operation {
template <typename> class ResizeRequest;
// lock_tag
// lockers
Mutex cache_lock; // used as client_lock for the ObjectCacher
- RWLock snap_lock; // protects snapshot-related member variables, features, and flags
+ RWLock snap_lock; // protects snapshot-related member variables,
+ // features (and associated helper classes), 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 and object_map itself
ExclusiveLock<ImageCtx> *exclusive_lock;
- ObjectMap object_map; // TODO
- ObjectMap *object_map_ptr;
+ ObjectMap *object_map;
atomic_t async_request_seq;
&m_lock);
{
- if (!m_ictx->object_map.object_may_exist(object_no)) {
+ RWLock::RLocker snap_locker(m_ictx->snap_lock);
+ if (m_ictx->object_map != nullptr &&
+ !m_ictx->object_map->object_may_exist(object_no)) {
m_finisher->queue(req, -ENOENT);
return;
}
} // anonymous namespace
ObjectMap::ObjectMap(ImageCtx &image_ctx)
- : m_image_ctx(image_ctx), m_snap_id(CEPH_NOSNAP), m_enabled(false)
+ : m_image_ctx(image_ctx), m_snap_id(CEPH_NOSNAP)
{
}
return m_object_map[object_no];
}
-bool ObjectMap::enabled() const
-{
- RWLock::RLocker l(m_image_ctx.object_map_lock);
- return m_enabled;
-}
-
-bool ObjectMap::enabled(const RWLock &object_map_lock) const {
- assert(m_image_ctx.object_map_lock.is_locked());
- 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;
- }
- }
-
bool broke_lock = false;
CephContext *cct = m_image_ctx.cct;
std::string oid(object_map_name(m_image_ctx.id, CEPH_NOSNAP));
}
RWLock::RLocker l(m_image_ctx.object_map_lock);
- if (!m_enabled) {
- return true;
- }
uint8_t state = (*this)[object_no];
bool exists = (state != OBJECT_NONEXISTENT);
ldout(m_image_ctx.cct, 20) << &m_image_ctx << " object_may_exist: "
RWLock::WLocker l(m_image_ctx.object_map_lock);
m_snap_id = snap_id;
- if ((m_image_ctx.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;
std::string oid(object_map_name(m_image_ctx.id, snap_id));
ldout(cct, 10) << &m_image_ctx << " refreshing object map: "
void ObjectMap::rollback(uint64_t snap_id, Context *on_finish) {
assert(m_image_ctx.snap_lock.is_locked());
assert(m_image_ctx.object_map_lock.is_wlocked());
- assert(m_enabled);
object_map::SnapshotRollbackRequest *req =
new object_map::SnapshotRollbackRequest(m_image_ctx, snap_id, on_finish);
void snapshot_add(uint64_t snap_id, Context *on_finish);
void snapshot_remove(uint64_t snap_id, Context *on_finish);
- bool enabled() const;
- bool enabled(const RWLock &object_map_lock) const;
-
private:
ImageCtx &m_image_ctx;
ceph::BitVector<2> m_object_map;
uint64_t m_snap_id;
- bool m_enabled;
void invalidate(uint64_t snap_id, bool force);
};
void ReleaseRequest<I>::send_unlock_object_map() {
{
RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
- std::swap(m_object_map, m_image_ctx.object_map_ptr);
+ std::swap(m_object_map, m_image_ctx.object_map);
}
if (m_object_map == nullptr) {
std::string m_cookie;
Context *m_on_finish;
- decltype(m_image_ctx.object_map_ptr) m_object_map;
+ decltype(m_image_ctx.object_map) m_object_map;
decltype(m_image_ctx.journal) m_journal;
void send_cancel_op_requests();
}
std::swap(m_exclusive_lock, m_image_ctx.exclusive_lock);
- std::swap(m_object_map, m_image_ctx.object_map_ptr);
+ std::swap(m_object_map, m_image_ctx.object_map);
return 0;
}
ictx->snap_exists = false;
}
- ictx->object_map.refresh(ictx->snap_id);
+ // TODO handle by new async refresh state machine
+ //ictx->object_map.refresh(ictx->snap_id);
ictx->data_ctx.selfmanaged_snap_set_write_ctx(ictx->snapc.seq, ictx->snaps);
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];
+ 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
ldout(cct, 15) << m_oid << " C_VerifyObject::update_object_map "
<< static_cast<uint32_t>(state) << "->"
<< static_cast<uint32_t>(new_state) << dendl;
- image_ctx.object_map[m_object_no] = new_state;
+ (*image_ctx.object_map)[m_object_no] = new_state;
}
return true;
}
assert(m_image_ctx.owner_lock.is_locked());
CephContext *cct = m_image_ctx.cct;
- uint64_t num_objects;
- uint64_t size;
- {
- RWLock::RLocker l(m_image_ctx.snap_lock);
- size = get_image_size();
- num_objects = Striper::get_num_objects(m_image_ctx.layout, size);
- }
+ m_image_ctx.snap_lock.get_read();
+ assert(m_image_ctx.object_map != nullptr);
+
+ uint64_t size = get_image_size();
+ uint64_t num_objects = Striper::get_num_objects(m_image_ctx.layout, size);
- if (m_image_ctx.object_map.size() == num_objects) {
+ if (m_image_ctx.object_map->size() == num_objects) {
+ m_image_ctx.snap_lock.put_read();
send_verify_objects();
return;
}
// should have been canceled prior to releasing lock
assert(m_image_ctx.exclusive_lock == nullptr ||
m_image_ctx.exclusive_lock->is_lock_owner());
- m_image_ctx.object_map.aio_resize(size, OBJECT_NONEXISTENT,
- this->create_callback_context());
+
+ m_image_ctx.object_map->aio_resize(size, OBJECT_NONEXISTENT,
+ this->create_callback_context());
+ m_image_ctx.snap_lock.put_read();
}
template <typename I>
uint64_t orig_size;
{
RWLock::RLocker l(m_image_ctx.snap_lock);
+ assert(m_image_ctx.object_map != nullptr);
+
new_size = get_image_size();
orig_size = m_image_ctx.get_object_size() *
- m_image_ctx.object_map.size();
+ m_image_ctx.object_map->size();
}
TrimRequest<I> *req = new TrimRequest<I>(m_image_ctx,
this->create_callback_context(),
// should have been canceled prior to releasing lock
assert(m_image_ctx.exclusive_lock == nullptr ||
m_image_ctx.exclusive_lock->is_lock_owner());
- m_image_ctx.object_map.aio_save(this->create_callback_context());
+
+ RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
+ assert(m_image_ctx.object_map != nullptr);
+ m_image_ctx.object_map->aio_save(this->create_callback_context());
}
template <typename I>
void ResizeRequest<I>::send_grow_object_map() {
I &image_ctx = this->m_image_ctx;
assert(image_ctx.owner_lock.is_locked());
- if (!image_ctx.object_map.enabled()) {
+
+ image_ctx.snap_lock.get_read();
+ if (image_ctx.object_map == nullptr) {
+ image_ctx.snap_lock.put_read();
send_update_header();
return;
}
assert(image_ctx.exclusive_lock == nullptr ||
image_ctx.exclusive_lock->is_lock_owner());
- image_ctx.object_map.aio_resize(m_new_size, OBJECT_NONEXISTENT,
- this->create_callback_context());
+ image_ctx.object_map->aio_resize(m_new_size, OBJECT_NONEXISTENT,
+ this->create_callback_context());
+ image_ctx.snap_lock.put_read();
}
template <typename I>
bool ResizeRequest<I>::send_shrink_object_map() {
I &image_ctx = this->m_image_ctx;
assert(image_ctx.owner_lock.is_locked());
- if (!image_ctx.object_map.enabled() || m_new_size > m_original_size) {
+
+ image_ctx.snap_lock.get_read();
+ if (image_ctx.object_map == nullptr || m_new_size > m_original_size) {
+ image_ctx.snap_lock.put_read();
return true;
}
assert(image_ctx.exclusive_lock == nullptr ||
image_ctx.exclusive_lock->is_lock_owner());
- image_ctx.object_map.aio_resize(m_new_size, OBJECT_NONEXISTENT,
- this->create_callback_context());
+ image_ctx.object_map->aio_resize(m_new_size, OBJECT_NONEXISTENT,
+ this->create_callback_context());
+ image_ctx.snap_lock.put_read();
return false;
}
{
RWLock::RLocker snap_locker(image_ctx.snap_lock);
RWLock::RLocker object_map_lock(image_ctx.object_map_lock);
- if (image_ctx.object_map.enabled(image_ctx.object_map_lock)) {
+ if (image_ctx.object_map != nullptr) {
CephContext *cct = image_ctx.cct;
ldout(cct, 5) << this << " " << __func__ << dendl;
m_state = STATE_CREATE_OBJECT_MAP;
- image_ctx.object_map.snapshot_add(m_snap_id,
- this->create_callback_context());
+ image_ctx.object_map->snapshot_add(m_snap_id,
+ this->create_callback_context());
return false;
}
}
{
RWLock::WLocker snap_locker(image_ctx.snap_lock);
RWLock::RLocker object_map_locker(image_ctx.object_map_lock);
- if (image_ctx.object_map.enabled(image_ctx.object_map_lock)) {
+ if (image_ctx.object_map != nullptr) {
CephContext *cct = image_ctx.cct;
ldout(cct, 5) << this << " " << __func__ << dendl;
m_state = STATE_REMOVE_OBJECT_MAP;
- image_ctx.object_map.snapshot_remove(
+ image_ctx.object_map->snapshot_remove(
m_snap_id, this->create_callback_context());
return;
}
{
RWLock::RLocker snap_locker(image_ctx.snap_lock);
RWLock::WLocker object_map_lock(image_ctx.object_map_lock);
- if (image_ctx.object_map.enabled(image_ctx.object_map_lock)) {
+ if (image_ctx.object_map != nullptr) {
CephContext *cct = image_ctx.cct;
ldout(cct, 5) << this << " " << __func__ << dendl;
m_state = STATE_ROLLBACK_OBJECT_MAP;
- image_ctx.object_map.rollback(m_snap_id, this->create_callback_context());
+ image_ctx.object_map->rollback(m_snap_id,
+ this->create_callback_context());
return;
}
}
assert(image_ctx.owner_lock.is_locked());
assert(image_ctx.exclusive_lock == nullptr ||
image_ctx.exclusive_lock->is_lock_owner());
- if (!image_ctx.object_map.object_may_exist(m_object_no)) {
- return 1;
+
+ {
+ RWLock::RLocker snap_locker(image_ctx.snap_lock);
+ if (image_ctx.object_map != nullptr &&
+ !image_ctx.object_map->object_may_exist(m_object_no)) {
+ return 1;
+ }
}
string oid = image_ctx.get_object_name(m_object_no);
bool remove_objects = false;
{
RWLock::RLocker snap_locker(image_ctx.snap_lock);
- if (!image_ctx.object_map.enabled()) {
+ if (image_ctx.object_map == nullptr) {
remove_objects = true;
} else {
ldout(image_ctx.cct, 5) << this << " send_pre_remove: "
// flag the objects as pending deletion
Context *ctx = this->create_callback_context();
RWLock::WLocker object_map_locker(image_ctx.object_map_lock);
- if (!image_ctx.object_map.aio_update(m_delete_start, m_num_objects,
- OBJECT_PENDING, OBJECT_EXISTS,
- ctx)) {
+ if (!image_ctx.object_map->aio_update(m_delete_start, m_num_objects,
+ OBJECT_PENDING, OBJECT_EXISTS,
+ ctx)) {
delete ctx;
remove_objects = true;
}
bool clean_boundary = false;
{
RWLock::RLocker snap_locker(image_ctx.snap_lock);
- if (!image_ctx.object_map.enabled()) {
+ if (image_ctx.object_map == nullptr) {
clean_boundary = true;
} else {
ldout(image_ctx.cct, 5) << this << " send_post_remove: "
// flag the pending objects as removed
Context *ctx = this->create_callback_context();
RWLock::WLocker object_map_locker(image_ctx.object_map_lock);
- if (!image_ctx.object_map.aio_update(m_delete_start, m_num_objects,
- OBJECT_NONEXISTENT,
- OBJECT_PENDING, ctx)) {
+ if (!image_ctx.object_map->aio_update(m_delete_start, m_num_objects,
+ OBJECT_NONEXISTENT,
+ OBJECT_PENDING, ctx)) {
delete ctx;
clean_boundary = true;
}