-
Notifications
You must be signed in to change notification settings - Fork 5.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
librbd: generalized copy deep function
(mostly taken from rbd-mirror image sync) Signed-off-by: Mykola Golub <mgolub@mirantis.com>
- Loading branch information
Mykola Golub
committed
Aug 28, 2017
1 parent
c9b6dfc
commit e595c5b
Showing
15 changed files
with
3,000 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,282 @@ | ||
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- | ||
// vim: ts=8 sw=2 smarttab | ||
|
||
#include "CopyRequest.h" | ||
#include "common/errno.h" | ||
#include "librbd/ExclusiveLock.h" | ||
#include "librbd/ImageCtx.h" | ||
#include "librbd/ObjectMap.h" | ||
#include "librbd/Utils.h" | ||
#include "librbd/image_copy/ImageCopyRequest.h" | ||
#include "librbd/image_copy/SnapshotCopyRequest.h" | ||
#include "librbd/operation/SnapshotRemoveRequest.h" | ||
|
||
#define dout_context g_ceph_context | ||
#define dout_subsys ceph_subsys_rbd | ||
#undef dout_prefix | ||
#define dout_prefix *_dout << "librbd::image::CopyRequest: " \ | ||
<< this << " " << __func__ << ": " | ||
|
||
namespace librbd { | ||
|
||
namespace image { | ||
|
||
using namespace librbd::image_copy; | ||
|
||
using librbd::util::create_context_callback; | ||
using librbd::util::unique_lock_name; | ||
|
||
template <typename I> | ||
CopyRequest<I>::CopyRequest(I *src_image_ctx, I *dst_image_ctx, | ||
ContextWQ *work_queue, ProgressContext *prog_ctx, | ||
Context *on_finish) | ||
: RefCountedObject(dst_image_ctx->cct, 1), m_src_image_ctx(src_image_ctx), | ||
m_dst_image_ctx(dst_image_ctx), m_cct(dst_image_ctx->cct), | ||
m_work_queue(work_queue), m_prog_ctx(prog_ctx), m_on_finish(on_finish), | ||
m_lock(unique_lock_name("CopyRequest::m_lock", this)) { | ||
} | ||
|
||
template <typename I> | ||
CopyRequest<I>::~CopyRequest() { | ||
assert(m_snapshot_copy_request == nullptr); | ||
assert(m_image_copy_request == nullptr); | ||
} | ||
|
||
template <typename I> | ||
void CopyRequest<I>::send() { | ||
send_copy_snapshots(); | ||
} | ||
|
||
template <typename I> | ||
void CopyRequest<I>::cancel() { | ||
Mutex::Locker locker(m_lock); | ||
|
||
ldout(m_cct, 20) << dendl; | ||
|
||
m_canceled = true; | ||
|
||
if (m_snapshot_copy_request != nullptr) { | ||
m_snapshot_copy_request->cancel(); | ||
} | ||
|
||
if (m_image_copy_request != nullptr) { | ||
m_image_copy_request->cancel(); | ||
} | ||
} | ||
|
||
template <typename I> | ||
void CopyRequest<I>::send_copy_snapshots() { | ||
m_lock.Lock(); | ||
if (m_canceled) { | ||
m_lock.Unlock(); | ||
finish(-ECANCELED); | ||
return; | ||
} | ||
|
||
ldout(m_cct, 20) << dendl; | ||
|
||
Context *ctx = create_context_callback< | ||
CopyRequest<I>, &CopyRequest<I>::handle_copy_snapshots>(this); | ||
m_snapshot_copy_request = SnapshotCopyRequest<I>::create( | ||
m_src_image_ctx, m_dst_image_ctx, m_work_queue, &m_snap_seqs, ctx); | ||
m_snapshot_copy_request->get(); | ||
m_lock.Unlock(); | ||
|
||
m_snapshot_copy_request->send(); | ||
} | ||
|
||
template <typename I> | ||
void CopyRequest<I>::handle_copy_snapshots(int r) { | ||
ldout(m_cct, 20) << "r=" << r << dendl; | ||
|
||
{ | ||
Mutex::Locker locker(m_lock); | ||
m_snapshot_copy_request->put(); | ||
m_snapshot_copy_request = nullptr; | ||
if (r == 0 && m_canceled) { | ||
r = -ECANCELED; | ||
} | ||
} | ||
|
||
if (r == -ECANCELED) { | ||
ldout(m_cct, 10) << "snapshot copy canceled" << dendl; | ||
finish(r); | ||
return; | ||
} else if (r < 0) { | ||
lderr(m_cct) << "failed to copy snapshot metadata: " << cpp_strerror(r) << dendl; | ||
finish(r); | ||
return; | ||
} | ||
|
||
send_copy_image(); | ||
} | ||
|
||
template <typename I> | ||
void CopyRequest<I>::send_copy_image() { | ||
m_lock.Lock(); | ||
if (m_canceled) { | ||
m_lock.Unlock(); | ||
finish(-ECANCELED); | ||
return; | ||
} | ||
|
||
ldout(m_cct, 20) << dendl; | ||
|
||
Context *ctx = create_context_callback< | ||
CopyRequest<I>, &CopyRequest<I>::handle_copy_image>(this); | ||
m_image_copy_request = ImageCopyRequest<I>::create( | ||
m_src_image_ctx, m_dst_image_ctx, m_snap_seqs, m_prog_ctx, ctx); | ||
m_image_copy_request->get(); | ||
m_lock.Unlock(); | ||
|
||
m_image_copy_request->send(); | ||
} | ||
|
||
template <typename I> | ||
void CopyRequest<I>::handle_copy_image(int r) { | ||
ldout(m_cct, 20) << "r=" << r << dendl; | ||
|
||
{ | ||
Mutex::Locker locker(m_lock); | ||
m_image_copy_request->put(); | ||
m_image_copy_request = nullptr; | ||
if (r == 0 && m_canceled) { | ||
r = -ECANCELED; | ||
} | ||
} | ||
|
||
if (r == -ECANCELED) { | ||
ldout(m_cct, 10) << "image copy canceled" << dendl; | ||
finish(r); | ||
return; | ||
} else if (r < 0) { | ||
lderr(m_cct) << "failed to copy image: " << cpp_strerror(r) << dendl; | ||
finish(r); | ||
return; | ||
} | ||
|
||
send_copy_object_map(); | ||
} | ||
|
||
template <typename I> | ||
void CopyRequest<I>::send_copy_object_map() { | ||
std::string copy_snap_name; | ||
{ | ||
RWLock::RLocker snap_locker(m_src_image_ctx->snap_lock); | ||
assert(m_src_image_ctx->snap_id != CEPH_NOSNAP); | ||
copy_snap_name = m_src_image_ctx->snap_name; | ||
auto snap_id_it = m_dst_image_ctx->snap_ids.find( | ||
{cls::rbd::UserSnapshotNamespace(), copy_snap_name}); | ||
assert(snap_id_it != m_dst_image_ctx->snap_ids.end()); | ||
m_copy_snap_id = snap_id_it->second; | ||
} | ||
|
||
m_dst_image_ctx->owner_lock.get_read(); | ||
m_dst_image_ctx->snap_lock.get_read(); | ||
if (!m_dst_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP, | ||
m_dst_image_ctx->snap_lock)) { | ||
m_dst_image_ctx->snap_lock.put_read(); | ||
m_dst_image_ctx->owner_lock.put_read(); | ||
send_remove_copy_snapshot(); | ||
return; | ||
} | ||
|
||
assert(m_dst_image_ctx->object_map != nullptr); | ||
assert(!copy_snap_name.empty()); | ||
|
||
ldout(m_cct, 20) << dendl; | ||
|
||
Context *finish_op_ctx = nullptr; | ||
if (m_dst_image_ctx->exclusive_lock != nullptr) { | ||
finish_op_ctx = m_dst_image_ctx->exclusive_lock->start_op(); | ||
} | ||
if (finish_op_ctx == nullptr) { | ||
lderr(m_cct) << "lost exclusive lock" << dendl; | ||
m_dst_image_ctx->snap_lock.put_read(); | ||
m_dst_image_ctx->owner_lock.put_read(); | ||
finish(-EROFS); | ||
return; | ||
} | ||
|
||
// rollback the object map (copy snapshot object map to HEAD) | ||
RWLock::WLocker object_map_locker(m_dst_image_ctx->object_map_lock); | ||
auto ctx = new FunctionContext([this, finish_op_ctx](int r) { | ||
handle_copy_object_map(r); | ||
finish_op_ctx->complete(0); | ||
}); | ||
m_dst_image_ctx->object_map->rollback(m_copy_snap_id, ctx); | ||
m_dst_image_ctx->snap_lock.put_read(); | ||
m_dst_image_ctx->owner_lock.put_read(); | ||
} | ||
|
||
template <typename I> | ||
void CopyRequest<I>::handle_copy_object_map(int r) { | ||
ldout(m_cct, 20) << dendl; | ||
|
||
assert(r == 0); | ||
send_refresh_object_map(); | ||
} | ||
|
||
template <typename I> | ||
void CopyRequest<I>::send_refresh_object_map() { | ||
ldout(m_cct, 20) << dendl; | ||
|
||
Context *ctx = create_context_callback< | ||
CopyRequest<I>, &CopyRequest<I>::handle_refresh_object_map>(this); | ||
m_object_map = m_dst_image_ctx->create_object_map(CEPH_NOSNAP); | ||
m_object_map->open(ctx); | ||
} | ||
|
||
template <typename I> | ||
void CopyRequest<I>::handle_refresh_object_map(int r) { | ||
ldout(m_cct, 20) << "r=" << r << dendl; | ||
|
||
assert(r == 0); | ||
{ | ||
RWLock::WLocker snap_locker(m_dst_image_ctx->snap_lock); | ||
std::swap(m_dst_image_ctx->object_map, m_object_map); | ||
} | ||
delete m_object_map; | ||
|
||
send_remove_copy_snapshot(); | ||
} | ||
|
||
template <typename I> | ||
void CopyRequest<I>::send_remove_copy_snapshot() { | ||
ldout(m_cct, 20) << dendl; | ||
|
||
RWLock::RLocker owner_lock(m_dst_image_ctx->owner_lock); | ||
|
||
Context *ctx = create_context_callback< | ||
CopyRequest<I>, &CopyRequest<I>::handle_remove_copy_snapshot>(this); | ||
|
||
auto req = new operation::SnapshotRemoveRequest<I>( | ||
*m_dst_image_ctx, ctx, cls::rbd::UserSnapshotNamespace(), "", | ||
m_copy_snap_id); | ||
req->send(); | ||
} | ||
|
||
template <typename I> | ||
void CopyRequest<I>::handle_remove_copy_snapshot(int r) { | ||
ldout(m_cct, 20) << "r=" << r << dendl; | ||
|
||
if (r < 0) { | ||
lderr(m_cct) << "failed to remove copy snapshot: " << cpp_strerror(r) | ||
<< dendl; | ||
} | ||
|
||
finish(r); | ||
} | ||
|
||
template <typename I> | ||
void CopyRequest<I>::finish(int r) { | ||
ldout(m_cct, 20) << "r=" << r << dendl; | ||
|
||
m_on_finish->complete(r); | ||
put(); | ||
} | ||
|
||
} // namespace image | ||
} // namespace librbd | ||
|
||
template class librbd::image::CopyRequest<librbd::ImageCtx>; |
Oops, something went wrong.