#include "librbd/ImageCtx.h"
#include "librbd/ImageState.h"
#include "librbd/internal.h"
-#include "librbd/Operations.h"
#include "librbd/TaskFinisher.h"
#include "librbd/Types.h"
#include "librbd/Utils.h"
}
}
+template <typename I>
+bool ImageWatcher<I>::handle_operation_request(
+ const AsyncRequestId& async_request_id,
+ exclusive_lock::OperationRequestType request_type, Operation operation,
+ std::function<void(ProgressContext &prog_ctx, Context*)> execute,
+ C_NotifyAck *ack_ctx) {
+ std::shared_lock owner_locker{m_image_ctx.owner_lock};
+
+ if (m_image_ctx.exclusive_lock != nullptr) {
+ int r = 0;
+ if (m_image_ctx.exclusive_lock->accept_request(request_type, &r)) {
+ bool new_request;
+ Context *ctx;
+ ProgressContext *prog_ctx;
+ bool complete;
+ if (async_request_id) {
+ r = prepare_async_request(async_request_id, &new_request, &ctx,
+ &prog_ctx);
+ encode(ResponseMessage(r), ack_ctx->out);
+ complete = true;
+ } else {
+ new_request = true;
+ ctx = new C_ResponseMessage(ack_ctx);
+ prog_ctx = &m_no_op_prog_ctx;
+ complete = false;
+ }
+ if (r == 0 && new_request) {
+ ctx = new LambdaContext(
+ [this, operation, ctx](int r) {
+ m_image_ctx.operations->finish_op(operation, r);
+ ctx->complete(r);
+ });
+ ctx = new LambdaContext(
+ [this, execute, prog_ctx, ctx](int r) {
+ if (r < 0) {
+ ctx->complete(r);
+ return;
+ }
+ std::shared_lock l{m_image_ctx.owner_lock};
+ execute(*prog_ctx, ctx);
+ });
+ m_image_ctx.operations->start_op(operation, ctx);
+ }
+ return complete;
+ } else if (r < 0) {
+ encode(ResponseMessage(r), ack_ctx->out);
+ }
+ }
+ return true;
+}
+
template <typename I>
bool ImageWatcher<I>::handle_payload(const HeaderUpdatePayload &payload,
C_NotifyAck *ack_ctx) {
template <typename I>
bool ImageWatcher<I>::handle_payload(const FlattenPayload &payload,
C_NotifyAck *ack_ctx) {
+ ldout(m_image_ctx.cct, 10) << this << " remote flatten request: "
+ << payload.async_request_id << dendl;
- std::shared_lock l{m_image_ctx.owner_lock};
- if (m_image_ctx.exclusive_lock != nullptr) {
- int r;
- if (m_image_ctx.exclusive_lock->accept_request(
- exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
- bool new_request;
- Context *ctx;
- ProgressContext *prog_ctx;
- r = prepare_async_request(payload.async_request_id, &new_request,
- &ctx, &prog_ctx);
- if (r == 0 && new_request) {
- ldout(m_image_ctx.cct, 10) << this << " remote flatten request: "
- << payload.async_request_id << dendl;
- m_image_ctx.operations->execute_flatten(*prog_ctx, ctx);
- }
-
- encode(ResponseMessage(r), ack_ctx->out);
- } else if (r < 0) {
- encode(ResponseMessage(r), ack_ctx->out);
- }
- }
- return true;
+ return handle_operation_request(
+ payload.async_request_id, exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ OPERATION_FLATTEN, std::bind(&Operations<I>::execute_flatten,
+ m_image_ctx.operations,
+ std::placeholders::_1,
+ std::placeholders::_2),
+ ack_ctx);
}
template <typename I>
bool ImageWatcher<I>::handle_payload(const ResizePayload &payload,
C_NotifyAck *ack_ctx) {
- std::shared_lock l{m_image_ctx.owner_lock};
- if (m_image_ctx.exclusive_lock != nullptr) {
- int r;
- if (m_image_ctx.exclusive_lock->accept_request(
- exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
- bool new_request;
- Context *ctx;
- ProgressContext *prog_ctx;
- r = prepare_async_request(payload.async_request_id, &new_request,
- &ctx, &prog_ctx);
- if (r == 0 && new_request) {
- ldout(m_image_ctx.cct, 10) << this << " remote resize request: "
- << payload.async_request_id << " "
- << payload.size << " "
- << payload.allow_shrink << dendl;
- m_image_ctx.operations->execute_resize(payload.size, payload.allow_shrink, *prog_ctx, ctx, 0);
- }
+ ldout(m_image_ctx.cct, 10) << this << " remote resize request: "
+ << payload.async_request_id << " "
+ << payload.size << " "
+ << payload.allow_shrink << dendl;
- encode(ResponseMessage(r), ack_ctx->out);
- } else if (r < 0) {
- encode(ResponseMessage(r), ack_ctx->out);
- }
- }
- return true;
+ return handle_operation_request(
+ payload.async_request_id, exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ OPERATION_RESIZE, std::bind(&Operations<I>::execute_resize,
+ m_image_ctx.operations, payload.size,
+ payload.allow_shrink, std::placeholders::_1,
+ std::placeholders::_2, 0), ack_ctx);
}
template <typename I>
bool ImageWatcher<I>::handle_payload(const SnapCreatePayload &payload,
C_NotifyAck *ack_ctx) {
- std::shared_lock l{m_image_ctx.owner_lock};
- if (m_image_ctx.exclusive_lock != nullptr) {
- int r;
- auto request_type = exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL;
-
- // rbd-mirror needs to accept forced promotion orphan snap create requests
- auto mirror_ns = boost::get<cls::rbd::MirrorSnapshotNamespace>(
- &payload.snap_namespace);
- if (mirror_ns != nullptr && mirror_ns->is_orphan()) {
- request_type = exclusive_lock::OPERATION_REQUEST_TYPE_FORCE_PROMOTION;
- }
-
- if (m_image_ctx.exclusive_lock->accept_request(request_type, &r)) {
- bool new_request;
- Context *ctx;
- ProgressContext *prog_ctx;
- bool complete;
- if (payload.async_request_id) {
- r = prepare_async_request(payload.async_request_id, &new_request,
- &ctx, &prog_ctx);
- encode(ResponseMessage(r), ack_ctx->out);
- complete = true;
- } else {
- new_request = true;
- prog_ctx = &m_no_op_prog_ctx;
- ctx = new C_ResponseMessage(ack_ctx);
- complete = false;
- }
- if (r == 0 && new_request) {
- ldout(m_image_ctx.cct, 10) << this << " remote snap_create request: "
- << payload.async_request_id << " "
- << payload.snap_namespace << " "
- << payload.snap_name << " "
- << payload.flags << dendl;
-
- m_image_ctx.operations->execute_snap_create(payload.snap_namespace,
- payload.snap_name,
- ctx, 0, payload.flags,
- *prog_ctx);
- }
- return complete;
- } else if (r < 0) {
- encode(ResponseMessage(r), ack_ctx->out);
- }
+ ldout(m_image_ctx.cct, 10) << this << " remote snap_create request: "
+ << payload.async_request_id << " "
+ << payload.snap_namespace << " "
+ << payload.snap_name << " "
+ << payload.flags << dendl;
+
+ auto request_type = exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL;
+
+ // rbd-mirror needs to accept forced promotion orphan snap create requests
+ auto mirror_ns = boost::get<cls::rbd::MirrorSnapshotNamespace>(
+ &payload.snap_namespace);
+ if (mirror_ns != nullptr && mirror_ns->is_orphan()) {
+ request_type = exclusive_lock::OPERATION_REQUEST_TYPE_FORCE_PROMOTION;
}
- return true;
+
+ return handle_operation_request(
+ payload.async_request_id, request_type,
+ OPERATION_SNAP_CREATE, std::bind(&Operations<I>::execute_snap_create,
+ m_image_ctx.operations,
+ payload.snap_namespace,
+ payload.snap_name, std::placeholders::_2,
+ 0, payload.flags, std::placeholders::_1),
+ ack_ctx);
}
template <typename I>
bool ImageWatcher<I>::handle_payload(const SnapRenamePayload &payload,
C_NotifyAck *ack_ctx) {
- std::shared_lock l{m_image_ctx.owner_lock};
- if (m_image_ctx.exclusive_lock != nullptr) {
- int r;
- if (m_image_ctx.exclusive_lock->accept_request(
- exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
- bool new_request;
- Context *ctx;
- bool complete;
- if (payload.async_request_id) {
- r = prepare_async_request(payload.async_request_id, &new_request,
- &ctx, nullptr);
- encode(ResponseMessage(r), ack_ctx->out);
- complete = true;
- } else {
- new_request = true;
- ctx = new C_ResponseMessage(ack_ctx);
- complete = false;
- }
- if (r == 0 && new_request) {
- ldout(m_image_ctx.cct, 10) << this << " remote snap_rename request: "
- << payload.snap_id << " to "
- << payload.snap_name << dendl;
+ ldout(m_image_ctx.cct, 10) << this << " remote snap_rename request: "
+ << payload.async_request_id << " "
+ << payload.snap_id << " to "
+ << payload.snap_name << dendl;
- m_image_ctx.operations->execute_snap_rename(payload.snap_id,
- payload.snap_name, ctx);
- }
- return complete;
- } else if (r < 0) {
- encode(ResponseMessage(r), ack_ctx->out);
- }
- }
- return true;
+ return handle_operation_request(
+ payload.async_request_id, exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ OPERATION_SNAP_RENAME, std::bind(&Operations<I>::execute_snap_rename,
+ m_image_ctx.operations, payload.snap_id,
+ payload.snap_name,
+ std::placeholders::_2), ack_ctx);
}
template <typename I>
bool ImageWatcher<I>::handle_payload(const SnapRemovePayload &payload,
C_NotifyAck *ack_ctx) {
- std::shared_lock l{m_image_ctx.owner_lock};
- if (m_image_ctx.exclusive_lock != nullptr) {
- auto request_type = exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL;
- if (cls::rbd::get_snap_namespace_type(payload.snap_namespace) ==
- cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH) {
- request_type = exclusive_lock::OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE;
- }
- int r;
- if (m_image_ctx.exclusive_lock->accept_request(request_type, &r)) {
- bool new_request;
- Context *ctx;
- bool complete;
- if (payload.async_request_id) {
- r = prepare_async_request(payload.async_request_id, &new_request,
- &ctx, nullptr);
- encode(ResponseMessage(r), ack_ctx->out);
- complete = true;
- } else {
- new_request = true;
- ctx = new C_ResponseMessage(ack_ctx);
- complete = false;
- }
- if (r == 0 && new_request) {
- ldout(m_image_ctx.cct, 10) << this << " remote snap_remove request: "
- << payload.snap_name << dendl;
+ ldout(m_image_ctx.cct, 10) << this << " remote snap_remove request: "
+ << payload.snap_name << dendl;
- m_image_ctx.operations->execute_snap_remove(payload.snap_namespace,
- payload.snap_name, ctx);
- }
- return complete;
- } else if (r < 0) {
- encode(ResponseMessage(r), ack_ctx->out);
- }
+ auto request_type = exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL;
+ if (cls::rbd::get_snap_namespace_type(payload.snap_namespace) ==
+ cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH) {
+ request_type = exclusive_lock::OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE;
}
- return true;
+
+ return handle_operation_request(
+ payload.async_request_id, request_type, OPERATION_SNAP_REMOVE,
+ std::bind(&Operations<I>::execute_snap_remove, m_image_ctx.operations,
+ payload.snap_namespace, payload.snap_name,
+ std::placeholders::_2), ack_ctx);
}
template <typename I>
bool ImageWatcher<I>::handle_payload(const SnapProtectPayload& payload,
C_NotifyAck *ack_ctx) {
- std::shared_lock owner_locker{m_image_ctx.owner_lock};
- if (m_image_ctx.exclusive_lock != nullptr) {
- int r;
- if (m_image_ctx.exclusive_lock->accept_request(
- exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
- bool new_request;
- Context *ctx;
- bool complete;
- if (payload.async_request_id) {
- r = prepare_async_request(payload.async_request_id, &new_request,
- &ctx, nullptr);
- encode(ResponseMessage(r), ack_ctx->out);
- complete = true;
- } else {
- new_request = true;
- ctx = new C_ResponseMessage(ack_ctx);
- complete = false;
- }
- if (r == 0 && new_request) {
- ldout(m_image_ctx.cct, 10) << this << " remote snap_protect request: "
- << payload.snap_name << dendl;
+ ldout(m_image_ctx.cct, 10) << this << " remote snap_protect request: "
+ << payload.async_request_id << " "
+ << payload.snap_name << dendl;
- m_image_ctx.operations->execute_snap_protect(payload.snap_namespace,
- payload.snap_name, ctx);
- }
- return complete;
- } else if (r < 0) {
- encode(ResponseMessage(r), ack_ctx->out);
- }
- }
- return true;
+ return handle_operation_request(
+ payload.async_request_id, exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ OPERATION_SNAP_PROTECT, std::bind(&Operations<I>::execute_snap_protect,
+ m_image_ctx.operations,
+ payload.snap_namespace,
+ payload.snap_name,
+ std::placeholders::_2), ack_ctx);
}
template <typename I>
bool ImageWatcher<I>::handle_payload(const SnapUnprotectPayload& payload,
C_NotifyAck *ack_ctx) {
- std::shared_lock owner_locker{m_image_ctx.owner_lock};
- if (m_image_ctx.exclusive_lock != nullptr) {
- int r;
- if (m_image_ctx.exclusive_lock->accept_request(
- exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
- bool new_request;
- Context *ctx;
- bool complete;
- if (payload.async_request_id) {
- r = prepare_async_request(payload.async_request_id, &new_request,
- &ctx, nullptr);
- encode(ResponseMessage(r), ack_ctx->out);
- complete = true;
- } else {
- new_request = true;
- ctx = new C_ResponseMessage(ack_ctx);
- complete = false;
- }
- if (r == 0 && new_request) {
- ldout(m_image_ctx.cct, 10) << this << " remote snap_unprotect request: "
- << payload.snap_name << dendl;
+ ldout(m_image_ctx.cct, 10) << this << " remote snap_unprotect request: "
+ << payload.async_request_id << " "
+ << payload.snap_name << dendl;
- m_image_ctx.operations->execute_snap_unprotect(payload.snap_namespace,
- payload.snap_name, ctx);
- }
- return complete;
- } else if (r < 0) {
- encode(ResponseMessage(r), ack_ctx->out);
- }
- }
- return true;
+ return handle_operation_request(
+ payload.async_request_id, exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ OPERATION_SNAP_UNPROTECT, std::bind(&Operations<I>::execute_snap_unprotect,
+ m_image_ctx.operations,
+ payload.snap_namespace,
+ payload.snap_name,
+ std::placeholders::_2), ack_ctx);
}
template <typename I>
bool ImageWatcher<I>::handle_payload(const RebuildObjectMapPayload& payload,
C_NotifyAck *ack_ctx) {
- std::shared_lock l{m_image_ctx.owner_lock};
- if (m_image_ctx.exclusive_lock != nullptr) {
- int r;
- if (m_image_ctx.exclusive_lock->accept_request(
- exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
- bool new_request;
- Context *ctx;
- ProgressContext *prog_ctx;
- r = prepare_async_request(payload.async_request_id, &new_request,
- &ctx, &prog_ctx);
- if (r == 0 && new_request) {
- ldout(m_image_ctx.cct, 10) << this
- << " remote rebuild object map request: "
- << payload.async_request_id << dendl;
- m_image_ctx.operations->execute_rebuild_object_map(*prog_ctx, ctx);
- }
+ ldout(m_image_ctx.cct, 10) << this << " remote rebuild object map request: "
+ << payload.async_request_id << dendl;
- encode(ResponseMessage(r), ack_ctx->out);
- } else if (r < 0) {
- encode(ResponseMessage(r), ack_ctx->out);
- }
- }
- return true;
+ return handle_operation_request(
+ payload.async_request_id, exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ OPERATION_REBUILD_OBJECT_MAP,
+ std::bind(&Operations<I>::execute_rebuild_object_map,
+ m_image_ctx.operations, std::placeholders::_1,
+ std::placeholders::_2), ack_ctx);
}
template <typename I>
bool ImageWatcher<I>::handle_payload(const RenamePayload& payload,
C_NotifyAck *ack_ctx) {
- std::shared_lock owner_locker{m_image_ctx.owner_lock};
- if (m_image_ctx.exclusive_lock != nullptr) {
- int r;
- if (m_image_ctx.exclusive_lock->accept_request(
- exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
- bool new_request;
- Context *ctx;
- bool complete;
- if (payload.async_request_id) {
- r = prepare_async_request(payload.async_request_id, &new_request,
- &ctx, nullptr);
- encode(ResponseMessage(r), ack_ctx->out);
- complete = true;
- } else {
- new_request = true;
- ctx = new C_ResponseMessage(ack_ctx);
- complete = false;
- }
- if (r == 0 && new_request) {
- ldout(m_image_ctx.cct, 10) << this << " remote rename request: "
- << payload.image_name << dendl;
+ ldout(m_image_ctx.cct, 10) << this << " remote rename request: "
+ << payload.async_request_id << " "
+ << payload.image_name << dendl;
- m_image_ctx.operations->execute_rename(payload.image_name, ctx);
- }
- return complete;
- } else if (r < 0) {
- encode(ResponseMessage(r), ack_ctx->out);
- }
- }
- return true;
+ return handle_operation_request(
+ payload.async_request_id, exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ OPERATION_RENAME, std::bind(&Operations<I>::execute_rename,
+ m_image_ctx.operations, payload.image_name,
+ std::placeholders::_2), ack_ctx);
}
template <typename I>
bool ImageWatcher<I>::handle_payload(const UpdateFeaturesPayload& payload,
C_NotifyAck *ack_ctx) {
- std::shared_lock owner_locker{m_image_ctx.owner_lock};
- if (m_image_ctx.exclusive_lock != nullptr) {
- int r;
- if (m_image_ctx.exclusive_lock->accept_request(
- exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
- bool new_request;
- Context *ctx;
- bool complete;
- if (payload.async_request_id) {
- r = prepare_async_request(payload.async_request_id, &new_request,
- &ctx, nullptr);
- encode(ResponseMessage(r), ack_ctx->out);
- complete = true;
- } else {
- new_request = true;
- ctx = new C_ResponseMessage(ack_ctx);
- complete = false;
- }
- if (r == 0 && new_request) {
- ldout(m_image_ctx.cct, 10) << this << " remote update_features request: "
- << payload.features << " "
- << (payload.enabled ? "enabled" : "disabled")
- << dendl;
-
- m_image_ctx.operations->execute_update_features(payload.features,
- payload.enabled, ctx,
- 0);
- }
- return complete;
- } else if (r < 0) {
- encode(ResponseMessage(r), ack_ctx->out);
- }
- }
- return true;
+ ldout(m_image_ctx.cct, 10) << this << " remote update_features request: "
+ << payload.async_request_id << " "
+ << payload.features << " "
+ << (payload.enabled ? "enabled" : "disabled")
+ << dendl;
+
+ return handle_operation_request(
+ payload.async_request_id, exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ OPERATION_UPDATE_FEATURES,
+ std::bind(&Operations<I>::execute_update_features, m_image_ctx.operations,
+ payload.features, payload.enabled, std::placeholders::_2, 0),
+ ack_ctx);
}
template <typename I>
bool ImageWatcher<I>::handle_payload(const MigratePayload &payload,
C_NotifyAck *ack_ctx) {
+ ldout(m_image_ctx.cct, 10) << this << " remote migrate request: "
+ << payload.async_request_id << dendl;
- std::shared_lock l{m_image_ctx.owner_lock};
- if (m_image_ctx.exclusive_lock != nullptr) {
- int r;
- if (m_image_ctx.exclusive_lock->accept_request(
- exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
- bool new_request;
- Context *ctx;
- ProgressContext *prog_ctx;
- r = prepare_async_request(payload.async_request_id, &new_request,
- &ctx, &prog_ctx);
- if (r == 0 && new_request) {
- ldout(m_image_ctx.cct, 10) << this << " remote migrate request: "
- << payload.async_request_id << dendl;
- m_image_ctx.operations->execute_migrate(*prog_ctx, ctx);
- }
-
- encode(ResponseMessage(r), ack_ctx->out);
- } else if (r < 0) {
- encode(ResponseMessage(r), ack_ctx->out);
- }
- }
- return true;
+ return handle_operation_request(
+ payload.async_request_id, exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ OPERATION_MIGRATE, std::bind(&Operations<I>::execute_migrate,
+ m_image_ctx.operations,
+ std::placeholders::_1,
+ std::placeholders::_2), ack_ctx);
}
template <typename I>
bool ImageWatcher<I>::handle_payload(const SparsifyPayload &payload,
C_NotifyAck *ack_ctx) {
- std::shared_lock l{m_image_ctx.owner_lock};
- if (m_image_ctx.exclusive_lock != nullptr) {
- int r;
- if (m_image_ctx.exclusive_lock->accept_request(
- exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
- bool new_request;
- Context *ctx;
- ProgressContext *prog_ctx;
- r = prepare_async_request(payload.async_request_id, &new_request,
- &ctx, &prog_ctx);
- if (r == 0 && new_request) {
- ldout(m_image_ctx.cct, 10) << this << " remote sparsify request: "
- << payload.async_request_id << dendl;
- m_image_ctx.operations->execute_sparsify(payload.sparse_size, *prog_ctx,
- ctx);
- }
+ ldout(m_image_ctx.cct, 10) << this << " remote sparsify request: "
+ << payload.async_request_id << dendl;
- encode(ResponseMessage(r), ack_ctx->out);
- } else if (r < 0) {
- encode(ResponseMessage(r), ack_ctx->out);
- }
+ return handle_operation_request(
+ payload.async_request_id, exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ OPERATION_SPARSIFY, std::bind(&Operations<I>::execute_sparsify,
+ m_image_ctx.operations,
+ payload.sparse_size, std::placeholders::_1,
+ std::placeholders::_2), ack_ctx);
+}
+
+template <typename I>
+bool ImageWatcher<I>::handle_payload(const MetadataUpdatePayload &payload,
+ C_NotifyAck *ack_ctx) {
+ if (payload.value) {
+ ldout(m_image_ctx.cct, 10) << this << " remote metadata_set request: "
+ << payload.async_request_id << " "
+ << "key=" << payload.key << ", value="
+ << *payload.value << dendl;
+
+ return handle_operation_request(
+ payload.async_request_id,
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ OPERATION_METADATA_UPDATE,
+ std::bind(&Operations<I>::execute_metadata_set,
+ m_image_ctx.operations, payload.key, *payload.value,
+ std::placeholders::_2),
+ ack_ctx);
+ } else {
+ ldout(m_image_ctx.cct, 10) << this << " remote metadata_remove request: "
+ << payload.async_request_id << " "
+ << "key=" << payload.key << dendl;
+
+ return handle_operation_request(
+ payload.async_request_id,
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
+ OPERATION_METADATA_UPDATE,
+ std::bind(&Operations<I>::execute_metadata_remove,
+ m_image_ctx.operations, payload.key, std::placeholders::_2),
+ ack_ctx);
}
- return true;
}
template <typename I>
return true;
}
-template <typename I>
-bool ImageWatcher<I>::handle_payload(const MetadataUpdatePayload &payload,
- C_NotifyAck *ack_ctx) {
- std::shared_lock l{m_image_ctx.owner_lock};
- if (m_image_ctx.exclusive_lock != nullptr) {
- int r;
- if (m_image_ctx.exclusive_lock->accept_request(
- exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, &r)) {
- bool new_request;
- Context *ctx;
- bool complete;
- if (payload.async_request_id) {
- r = prepare_async_request(payload.async_request_id, &new_request,
- &ctx, nullptr);
- encode(ResponseMessage(r), ack_ctx->out);
- complete = true;
- } else {
- new_request = true;
- ctx = new C_ResponseMessage(ack_ctx);
- complete = false;
- }
- if (r == 0 && new_request) {
- if (payload.value) {
- ldout(m_image_ctx.cct, 10) << this << " remote metadata_set request: "
- << "key=" << payload.key << ", value="
- << *payload.value << dendl;
-
- m_image_ctx.operations->execute_metadata_set(payload.key,
- *payload.value, ctx);
- } else {
- ldout(m_image_ctx.cct, 10) << this << " remote metadata_remove request: "
- << "key=" << payload.key << dendl;
-
- m_image_ctx.operations->execute_metadata_remove(payload.key, ctx);
- }
- }
- return complete;
- } else if (r < 0) {
- encode(ResponseMessage(r), ack_ctx->out);
- }
- }
- return true;
-}
-
template <typename I>
bool ImageWatcher<I>::handle_payload(const UnknownPayload &payload,
C_NotifyAck *ack_ctx) {
namespace {
+std::ostream &operator<<(std::ostream &out, const Operation &op) {
+ switch (op) {
+ case OPERATION_CHECK_OBJECT_MAP:
+ out << "check object map";
+ break;
+ case OPERATION_FLATTEN:
+ out << "flatten";
+ break;
+ case OPERATION_METADATA_UPDATE:
+ out << "metadata update";
+ break;
+ case OPERATION_MIGRATE:
+ out << "migrate";
+ break;
+ case OPERATION_REBUILD_OBJECT_MAP:
+ out << "rebuild object map";
+ break;
+ case OPERATION_RENAME:
+ out << "rename";
+ break;
+ case OPERATION_RESIZE:
+ out << "resize";
+ break;
+ case OPERATION_SNAP_CREATE:
+ out << "snap create";
+ break;
+ case OPERATION_SNAP_PROTECT:
+ out << "snap protect";
+ break;
+ case OPERATION_SNAP_REMOVE:
+ out << "snap remove";
+ break;
+ case OPERATION_SNAP_RENAME:
+ out << "snap rename";
+ break;
+ case OPERATION_SNAP_ROLLBACK:
+ out << "snap rollback";
+ break;
+ case OPERATION_SNAP_UNPROTECT:
+ out << "snap unprotect";
+ break;
+ case OPERATION_SPARSIFY:
+ out << "sparsify";
+ break;
+ case OPERATION_UPDATE_FEATURES:
+ out << "update features";
+ break;
+ default:
+ ceph_abort();
+ break;
+ }
+ return out;
+}
+
template <typename I>
struct C_NotifyUpdate : public Context {
I &image_ctx;
*/
I &image_ctx;
- std::string name;
+ Operation operation;
exclusive_lock::OperationRequestType request_type;
bool permit_snapshot;
boost::function<void(Context*)> local;
Context *on_finish;
bool request_lock = false;
- C_InvokeAsyncRequest(I &image_ctx, const std::string& name,
+ C_InvokeAsyncRequest(I &image_ctx, Operation operation,
exclusive_lock::OperationRequestType request_type,
bool permit_snapshot,
const boost::function<void(Context*)>& local,
const boost::function<void(Context*)>& remote,
const std::set<int> &filter_error_codes,
Context *on_finish)
- : image_ctx(image_ctx), name(name), request_type(request_type),
+ : image_ctx(image_ctx), operation(operation), request_type(request_type),
permit_snapshot(permit_snapshot), local(local), remote(remote),
filter_error_codes(filter_error_codes), on_finish(on_finish) {
}
ldout(cct, 20) << __func__ << ": r=" << r << dendl;
if (r == -EOPNOTSUPP) {
- ldout(cct, 5) << name << " not supported by current lock owner" << dendl;
+ ldout(cct, 5) << operation << " not supported by current lock owner"
+ << dendl;
request_lock = true;
send_refresh_image();
return;
return;
}
- ldout(cct, 5) << name << " timed out notifying lock owner" << dendl;
+ ldout(cct, 5) << operation << " timed out notifying lock owner" << dendl;
send_refresh_image();
}
void send_local_request() {
- ceph_assert(ceph_mutex_is_locked(image_ctx.owner_lock));
+ auto ctx = new LambdaContext(
+ [this](int r) {
+ if (r == -ERESTART) {
+ image_ctx.operations->finish_op(operation, r);
+ send_refresh_image();
+ return;
+ }
+ execute_local_request();
+ });
+
+ image_ctx.operations->start_op(operation, ctx);
+ }
+
+ void execute_local_request() {
+ std::shared_lock owner_locker{image_ctx.owner_lock};
CephContext *cct = image_ctx.cct;
ldout(cct, 20) << __func__ << dendl;
CephContext *cct = image_ctx.cct;
ldout(cct, 20) << __func__ << ": r=" << r << dendl;
+ image_ctx.operations->finish_op(operation, r);
+
if (r == -ERESTART) {
send_refresh_image();
return;
template <typename I>
Operations<I>::Operations(I &image_ctx)
- : m_image_ctx(image_ctx), m_async_request_seq(0) {
+ : m_image_ctx(image_ctx), m_async_request_seq(0),
+ m_queue_lock(ceph::make_mutex(
+ util::unique_lock_name("librbd::Operations::m_queue_lock",
+ this))) {
+}
+
+template <typename I>
+void Operations<I>::start_op(Operation op, Context *ctx) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << __func__ << ": " << op << " " << ctx << dendl;
+
+ ctx = util::create_async_context_callback(
+ m_image_ctx, new LambdaContext(
+ [this, op, ctx](int r) {
+ if (r == 0) {
+ std::shared_lock owner_locker{m_image_ctx.owner_lock};
+ std::shared_lock image_locker{m_image_ctx.image_lock};
+
+ if (m_image_ctx.exclusive_lock != nullptr &&
+ (!m_image_ctx.exclusive_lock->is_lock_owner())) {
+ ldout(m_image_ctx.cct, 20) << "lock owner lost, restarting" << dendl;
+ r = -ERESTART;
+ }
+ }
+
+ ldout(m_image_ctx.cct, 20) << "start " << op << " " << ctx << dendl;
+ ctx->complete(r);
+ }));
+
+ std::unique_lock locker{m_queue_lock};
+ if (!m_in_flight_ops.insert(op).second) {
+ ldout(cct, 20) << __func__ << ": " << op << " in flight" << dendl;
+ m_queued_ops[op].push_back(ctx);
+ return;
+ }
+
+ ctx->complete(0);
+}
+
+template <typename I>
+void Operations<I>::finish_op(Operation op, int r) {
+ CephContext *cct = m_image_ctx.cct;
+ ldout(cct, 20) << __func__ << ": " << op << " r=" << r << dendl;
+
+ std::unique_lock locker{m_queue_lock};
+ auto &queue = m_queued_ops[op];
+ if (queue.empty()) {
+ m_in_flight_ops.erase(op);
+ return;
+ }
+
+ auto ctx = queue.front();
+ queue.pop_front();
+ // propagate -ERESTART through all the queue
+ ctx->complete(r == -ERESTART ? r : 0);
}
template <typename I>
}
uint64_t request_id = ++m_async_request_seq;
- r = invoke_async_request("flatten",
+ r = invoke_async_request(OPERATION_FLATTEN,
exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
false,
boost::bind(&Operations<I>::execute_flatten, this,
}
uint64_t request_id = ++m_async_request_seq;
- r = invoke_async_request("rebuild object map",
+ r = invoke_async_request(OPERATION_REBUILD_OBJECT_MAP,
exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, true,
boost::bind(&Operations<I>::execute_rebuild_object_map,
this, boost::ref(prog_ctx), _1),
return r;
}
- r = invoke_async_request("check object map",
+ r = invoke_async_request(OPERATION_CHECK_OBJECT_MAP,
exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, true,
boost::bind(&Operations<I>::check_object_map, this,
boost::ref(prog_ctx), _1),
if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
uint64_t request_id = ++m_async_request_seq;
- r = invoke_async_request("rename",
+ r = invoke_async_request(OPERATION_RENAME,
exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
true,
boost::bind(&Operations<I>::execute_rename, this,
}
uint64_t request_id = ++m_async_request_seq;
- r = invoke_async_request("resize",
+ r = invoke_async_request(OPERATION_RESIZE,
exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
false,
boost::bind(&Operations<I>::execute_resize, this,
uint64_t request_id = ++m_async_request_seq;
C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(
- m_image_ctx, "snap_create", exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
- true,
+ m_image_ctx, OPERATION_SNAP_CREATE,
+ exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL, true,
boost::bind(&Operations<I>::execute_snap_create, this, snap_namespace, snap_name,
_1, 0, flags, boost::ref(prog_ctx)),
boost::bind(&ImageWatcher<I>::notify_snap_create, m_image_ctx.image_watcher,
return r;
}
- execute_snap_rollback(snap_namespace, snap_name, prog_ctx, &cond_ctx);
+ Context *ctx = new LambdaContext(
+ [this, ctx=&cond_ctx](int r) {
+ m_image_ctx.operations->finish_op(OPERATION_SNAP_ROLLBACK, r);
+ ctx->complete(r);
+ });
+ ctx = new LambdaContext(
+ [this, snap_namespace, snap_name, &prog_ctx, ctx](int r) {
+ if (r < 0) {
+ ctx->complete(r);
+ return;
+ }
+ std::shared_lock l{m_image_ctx.owner_lock};
+ execute_snap_rollback(snap_namespace, snap_name, prog_ctx, ctx);
+ });
+
+ m_image_ctx.operations->start_op(OPERATION_SNAP_ROLLBACK, ctx);
}
r = cond_ctx.wait();
request_type = exclusive_lock::OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE;
}
C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(
- m_image_ctx, "snap_remove", request_type, true,
+ m_image_ctx, OPERATION_SNAP_REMOVE, request_type, true,
boost::bind(&Operations<I>::execute_snap_remove, this, snap_namespace,
snap_name, _1),
boost::bind(&ImageWatcher<I>::notify_snap_remove,
if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
uint64_t request_id = ++m_async_request_seq;
- r = invoke_async_request("snap_rename",
+ r = invoke_async_request(OPERATION_SNAP_RENAME,
exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
true,
boost::bind(&Operations<I>::execute_snap_rename,
if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
uint64_t request_id = ++m_async_request_seq;
- r = invoke_async_request("snap_protect",
+ r = invoke_async_request(OPERATION_SNAP_PROTECT,
exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
true,
boost::bind(&Operations<I>::execute_snap_protect,
if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
uint64_t request_id = ++m_async_request_seq;
- r = invoke_async_request("snap_unprotect",
+ r = invoke_async_request(OPERATION_SNAP_UNPROTECT,
exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
true,
boost::bind(&Operations<I>::execute_snap_unprotect,
r = cond_ctx.wait();
} else {
uint64_t request_id = ++m_async_request_seq;
- r = invoke_async_request("update_features",
+ r = invoke_async_request(OPERATION_UPDATE_FEATURES,
exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
false,
boost::bind(&Operations<I>::execute_update_features,
}
uint64_t request_id = ++m_async_request_seq;
- r = invoke_async_request("metadata_set",
+ r = invoke_async_request(OPERATION_METADATA_UPDATE,
exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
false,
boost::bind(&Operations<I>::execute_metadata_set,
return r;
uint64_t request_id = ++m_async_request_seq;
- r = invoke_async_request("metadata_remove",
+ r = invoke_async_request(OPERATION_METADATA_UPDATE,
exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
false,
boost::bind(&Operations<I>::execute_metadata_remove,
}
uint64_t request_id = ++m_async_request_seq;
- r = invoke_async_request("migrate",
+ r = invoke_async_request(OPERATION_MIGRATE,
exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
false,
boost::bind(&Operations<I>::execute_migrate, this,
}
uint64_t request_id = ++m_async_request_seq;
- int r = invoke_async_request("sparsify",
+ int r = invoke_async_request(OPERATION_SPARSIFY,
exclusive_lock::OPERATION_REQUEST_TYPE_GENERAL,
false,
boost::bind(&Operations<I>::execute_sparsify,
template <typename I>
int Operations<I>::invoke_async_request(
- const std::string& name, exclusive_lock::OperationRequestType request_type,
+ Operation op, exclusive_lock::OperationRequestType request_type,
bool permit_snapshot, const boost::function<void(Context*)>& local_request,
const boost::function<void(Context*)>& remote_request) {
C_SaferCond ctx;
- C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(m_image_ctx, name,
+ C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(m_image_ctx, op,
request_type,
permit_snapshot,
local_request,