librbd: image demotion should record new demote journal event

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
This commit is contained in:
Jason Dillaman 2016-03-25 11:03:35 -04:00
parent 970a17368a
commit 04892961d2
3 changed files with 161 additions and 82 deletions

View File

@ -162,6 +162,7 @@ public:
template <typename I, typename J>
int open_journaler(I *image_ctx, J *journaler, bool *initialized,
cls::journal::Client *client,
journal::ImageClientMeta *client_meta,
journal::TagData *tag_data) {
C_SaferCond init_ctx;
@ -172,14 +173,13 @@ int open_journaler(I *image_ctx, J *journaler, bool *initialized,
return r;
}
cls::journal::Client client;
r = journaler->get_cached_client(Journal<ImageCtx>::IMAGE_CLIENT_ID, &client);
r = journaler->get_cached_client(Journal<ImageCtx>::IMAGE_CLIENT_ID, client);
if (r < 0) {
return r;
}
librbd::journal::ClientData client_data;
bufferlist::iterator bl_it = client.data.begin();
bufferlist::iterator bl_it = client->data.begin();
try {
::decode(client_data, bl_it);
} catch (const buffer::error &err) {
@ -207,6 +207,37 @@ int open_journaler(I *image_ctx, J *journaler, bool *initialized,
return 0;
}
template <typename J>
int allocate_journaler_tag(CephContext *cct, J *journaler,
const cls::journal::Client &client,
uint64_t tag_class,
const journal::TagData &prev_tag_data,
const std::string &mirror_uuid,
cls::journal::Tag *new_tag) {
journal::TagData tag_data;
if (!client.commit_position.object_positions.empty()) {
auto position = client.commit_position.object_positions.front();
tag_data.predecessor_commit_valid = true;
tag_data.predecessor_tag_tid = position.tag_tid;
tag_data.predecessor_entry_tid = position.entry_tid;
}
tag_data.predecessor_mirror_uuid = prev_tag_data.mirror_uuid;
tag_data.mirror_uuid = mirror_uuid;
bufferlist tag_bl;
::encode(tag_data, tag_bl);
C_SaferCond allocate_tag_ctx;
journaler->allocate_tag(tag_class, tag_bl, new_tag, &allocate_tag_ctx);
int r = allocate_tag_ctx.wait();
if (r < 0) {
lderr(cct) << "failed to allocate tag: " << cpp_strerror(r) << dendl;
return r;
}
return 0;
}
} // anonymous namespace
using util::create_async_context_callback;
@ -340,23 +371,14 @@ int Journal<I>::create(librados::IoCtx &io_ctx, const std::string &image_id,
return r;
}
// create tag class for this image's journal events
journal::TagData tag_data;
tag_data.mirror_uuid = (!non_primary ? LOCAL_MIRROR_UUID :
ORPHAN_MIRROR_UUID);
bufferlist tag_data_bl;
::encode(tag_data, tag_data_bl);
C_SaferCond tag_ctx;
cls::journal::Client client;
cls::journal::Tag tag;
journaler.allocate_tag(cls::journal::Tag::TAG_CLASS_NEW, tag_data_bl,
&tag, &tag_ctx);
r = tag_ctx.wait();
if (r < 0) {
lderr(cct) << "failed to allocate journal tag: " << cpp_strerror(r)
<< dendl;
}
journal::TagData tag_data;
std::string mirror_uuid = (!non_primary ? LOCAL_MIRROR_UUID :
ORPHAN_MIRROR_UUID);
r = allocate_journaler_tag(cct, &journaler, client,
cls::journal::Tag::TAG_CLASS_NEW,
tag_data, mirror_uuid, &tag);
bufferlist client_data;
::encode(journal::ClientData{journal::ImageClientMeta{tag.tag_class}},
@ -474,10 +496,11 @@ int Journal<I>::get_tag_owner(I *image_ctx, std::string *mirror_uuid) {
image_ctx->cct->_conf->rbd_journal_commit_age);
bool initialized;
cls::journal::Client client;
journal::ImageClientMeta client_meta;
journal::TagData tag_data;
int r = open_journaler(image_ctx, &journaler, &initialized, &client_meta,
&tag_data);
int r = open_journaler(image_ctx, &journaler, &initialized, &client,
&client_meta, &tag_data);
if (r >= 0) {
*mirror_uuid = tag_data.mirror_uuid;
}
@ -488,62 +511,6 @@ int Journal<I>::get_tag_owner(I *image_ctx, std::string *mirror_uuid) {
return r;
}
template <typename I>
int Journal<I>::allocate_tag(I *image_ctx, const std::string &mirror_uuid) {
CephContext *cct = image_ctx->cct;
ldout(cct, 20) << __func__ << ": mirror_uuid=" << mirror_uuid << dendl;
Journaler journaler(image_ctx->md_ctx, image_ctx->id, IMAGE_CLIENT_ID,
image_ctx->cct->_conf->rbd_journal_commit_age);
bool initialized;
journal::ImageClientMeta client_meta;
journal::TagData tag_data;
int r = open_journaler(image_ctx, &journaler, &initialized, &client_meta,
&tag_data);
BOOST_SCOPE_EXIT_ALL(&journaler, &initialized) {
if (initialized) {
journaler.shut_down();
}
};
if (r < 0) {
return r;
}
cls::journal::Client client;
r = journaler.get_cached_client(IMAGE_CLIENT_ID, &client);
if (r < 0) {
lderr(cct) << "failed to retrieve client" << cpp_strerror(r) << dendl;
return r;
}
if (!client.commit_position.object_positions.empty()) {
auto position = client.commit_position.object_positions.front();
tag_data.predecessor_commit_valid = true;
tag_data.predecessor_tag_tid = position.tag_tid;
tag_data.predecessor_entry_tid = position.entry_tid;
}
tag_data.predecessor_mirror_uuid = tag_data.mirror_uuid;
tag_data.mirror_uuid = mirror_uuid;
bufferlist tag_bl;
::encode(tag_data, tag_bl);
C_SaferCond allocate_tag_ctx;
cls::journal::Tag tag;
journaler.allocate_tag(client_meta.tag_class, tag_bl, &tag,
&allocate_tag_ctx);
r = allocate_tag_ctx.wait();
if (r < 0) {
lderr(cct) << "failed to allocate tag: " << cpp_strerror(r) << dendl;
return r;
}
return 0;
}
template <typename I>
int Journal<I>::request_resync(I *image_ctx) {
CephContext *cct = image_ctx->cct;
@ -553,10 +520,11 @@ int Journal<I>::request_resync(I *image_ctx) {
image_ctx->cct->_conf->rbd_journal_commit_age);
bool initialized;
cls::journal::Client client;
journal::ImageClientMeta client_meta;
journal::TagData tag_data;
int r = open_journaler(image_ctx, &journaler, &initialized, &client_meta,
&tag_data);
int r = open_journaler(image_ctx, &journaler, &initialized, &client,
&client_meta, &tag_data);
BOOST_SCOPE_EXIT_ALL(&journaler, &initialized) {
if (initialized) {
journaler.shut_down();
@ -584,6 +552,40 @@ int Journal<I>::request_resync(I *image_ctx) {
return 0;
}
template <typename I>
int Journal<I>::promote(I *image_ctx) {
CephContext *cct = image_ctx->cct;
ldout(cct, 20) << __func__ << dendl;
Journaler journaler(image_ctx->md_ctx, image_ctx->id, IMAGE_CLIENT_ID,
image_ctx->cct->_conf->rbd_journal_commit_age);
bool initialized;
cls::journal::Client client;
journal::ImageClientMeta client_meta;
journal::TagData tag_data;
int r = open_journaler(image_ctx, &journaler, &initialized, &client,
&client_meta, &tag_data);
BOOST_SCOPE_EXIT_ALL(&journaler, &initialized) {
if (initialized) {
journaler.shut_down();
}
};
if (r < 0) {
return r;
}
cls::journal::Tag new_tag;
r = allocate_journaler_tag(cct, &journaler, client, client_meta.tag_class,
tag_data, LOCAL_MIRROR_UUID, &new_tag);
if (r < 0) {
return r;
}
return 0;
}
template <typename I>
bool Journal<I>::is_journal_ready() const {
Mutex::Locker locker(m_lock);
@ -650,6 +652,65 @@ bool Journal<I>::is_tag_owner() const {
return (m_tag_data.mirror_uuid == LOCAL_MIRROR_UUID);
}
template <typename I>
int Journal<I>::demote() {
CephContext *cct = m_image_ctx.cct;
ldout(cct, 20) << __func__ << dendl;
Mutex::Locker locker(m_lock);
assert(m_journaler != nullptr && is_tag_owner());
cls::journal::Client client;
int r = m_journaler->get_cached_client(IMAGE_CLIENT_ID, &client);
if (r < 0) {
lderr(cct) << "failed to retrieve client: " << cpp_strerror(r) << dendl;
return r;
}
cls::journal::Tag new_tag;
r = allocate_journaler_tag(cct, m_journaler, client, m_tag_class,
m_tag_data, ORPHAN_MIRROR_UUID, &new_tag);
if (r < 0) {
return r;
}
bufferlist::iterator tag_data_bl_it = new_tag.data.begin();
r = C_DecodeTag::decode(&tag_data_bl_it, &m_tag_data);
if (r < 0) {
lderr(cct) << "failed to decode newly allocated tag" << dendl;
return r;
}
journal::EventEntry event_entry{journal::DemoteEvent{}};
bufferlist event_entry_bl;
::encode(event_entry, event_entry_bl);
m_tag_tid = new_tag.tid;
Future future = m_journaler->append(m_tag_tid, event_entry_bl);
C_SaferCond ctx;
future.flush(&ctx);
r = ctx.wait();
if (r < 0) {
lderr(cct) << "failed to append demotion journal event: " << cpp_strerror(r)
<< dendl;
return r;
}
m_journaler->committed(future);
C_SaferCond flush_ctx;
m_journaler->flush_commit_position(&flush_ctx);
r = flush_ctx.wait();
if (r < 0) {
lderr(cct) << "failed to flush demotion commit position: "
<< cpp_strerror(r) << dendl;
return r;
}
return 0;
}
template <typename I>
void Journal<I>::allocate_local_tag(Context *on_finish) {
CephContext *cct = m_image_ctx.cct;

View File

@ -101,8 +101,8 @@ public:
static int is_tag_owner(ImageCtxT *image_ctx, bool *is_tag_owner);
static int get_tag_owner(ImageCtxT *image_ctx, std::string *mirror_uuid);
static int allocate_tag(ImageCtxT *image_ctx, const std::string &mirror_uuid);
static int request_resync(ImageCtxT *image_ctx);
static int promote(ImageCtxT *image_ctx);
bool is_journal_ready() const;
bool is_journal_replaying() const;
@ -113,6 +113,8 @@ public:
void close(Context *on_finish);
bool is_tag_owner() const;
int demote();
void allocate_local_tag(Context *on_finish);
void allocate_tag(const std::string &mirror_uuid,
const std::string &predecessor_mirror_uuid,

View File

@ -2686,7 +2686,7 @@ remove_mirroring_image:
// TODO: need interlock with local rbd-mirror daemon to ensure it has stopped
// replay
r = Journal<>::allocate_tag(ictx, Journal<>::LOCAL_MIRROR_UUID);
r = Journal<>::promote(ictx);
if (r < 0) {
lderr(cct) << "failed to promote image: " << cpp_strerror(r)
<< dendl;
@ -2718,16 +2718,32 @@ remove_mirroring_image:
}
RWLock::RLocker owner_lock(ictx->owner_lock);
if (ictx->exclusive_lock == nullptr) {
lderr(cct) << "exclusive lock is not active" << dendl;
return -EINVAL;
}
C_SaferCond lock_ctx;
ictx->exclusive_lock->request_lock(&lock_ctx);
r = lock_ctx.wait();
if (r < 0) {
lderr(cct) << "failed to lock image: " << cpp_strerror(r) << dendl;
return r;
} else if (!ictx->exclusive_lock->is_lock_owner()) {
lderr(cct) << "failed to acquire exclusive lock" << dendl;
return -EROFS;
}
r = Journal<>::allocate_tag(ictx, Journal<>::ORPHAN_MIRROR_UUID);
RWLock::RLocker snap_locker(ictx->snap_lock);
if (ictx->journal == nullptr) {
lderr(cct) << "journal is not active" << dendl;
return -EINVAL;
} else if (!ictx->journal->is_tag_owner()) {
lderr(cct) << "image is not currently the primary" << dendl;
return -EINVAL;
}
r = ictx->journal->demote();
if (r < 0) {
lderr(cct) << "failed to demote image: " << cpp_strerror(r)
<< dendl;