case MIGRATION_STATE_EXECUTED:
os << "executed";
break;
+ case MIGRATION_STATE_ABORTING:
+ os << "aborting";
+ break;
default:
os << "unknown (" << static_cast<uint32_t>(migration_state) << ")";
break;
MIGRATION_STATE_PREPARED = 2,
MIGRATION_STATE_EXECUTING = 3,
MIGRATION_STATE_EXECUTED = 4,
+ MIGRATION_STATE_ABORTING = 5,
};
inline void encode(const MigrationState &state, bufferlist& bl) {
RBD_IMAGE_MIGRATION_STATE_PREPARED = 2,
RBD_IMAGE_MIGRATION_STATE_EXECUTING = 3,
RBD_IMAGE_MIGRATION_STATE_EXECUTED = 4,
+ RBD_IMAGE_MIGRATION_STATE_ABORTING = 5,
} rbd_image_migration_state_t;
typedef struct {
ldout(m_cct, 1) << "failed to open destination image: " << cpp_strerror(r)
<< dendl;
} else {
- ldout(m_cct, 10) << "relinking children" << dendl;
+ BOOST_SCOPE_EXIT_TPL(&dst_image_ctx) {
+ if (dst_image_ctx != nullptr) {
+ dst_image_ctx->state->close();
+ }
+ } BOOST_SCOPE_EXIT_END;
+
+ std::list<obj_watch_t> watchers;
+ int flags = librbd::image::LIST_WATCHERS_FILTER_OUT_MY_INSTANCE |
+ librbd::image::LIST_WATCHERS_FILTER_OUT_MIRROR_INSTANCES;
+ C_SaferCond on_list_watchers;
+ auto list_watchers_request = librbd::image::ListWatchersRequest<I>::create(
+ *dst_image_ctx, flags, &watchers, &on_list_watchers);
+ list_watchers_request->send();
+ r = on_list_watchers.wait();
+ if (r < 0) {
+ lderr(m_cct) << "failed listing watchers:" << cpp_strerror(r) << dendl;
+ return r;
+ }
+ if (!watchers.empty()) {
+ lderr(m_cct) << "image has watchers - cannot abort migration" << dendl;
+ return -EBUSY;
+ }
+ // ensure destination image is now read-only
+ r = set_state(cls::rbd::MIGRATION_STATE_ABORTING, "");
+ if (r < 0) {
+ return r;
+ }
+
+ ldout(m_cct, 10) << "relinking children" << dendl;
r = relink_children(dst_image_ctx, m_src_image_ctx);
if (r < 0) {
return r;
ldout(m_cct, 10) << "removing dst image snapshots" << dendl;
- BOOST_SCOPE_EXIT_TPL(&dst_image_ctx) {
- if (dst_image_ctx != nullptr) {
- dst_image_ctx->state->close();
- }
- } BOOST_SCOPE_EXIT_END;
-
std::vector<librbd::snap_info_t> snaps;
r = snap_list(dst_image_ctx, snaps);
if (r < 0) {
<< m_dst_io_ctx.get_pool_name() << "/" << m_dst_image_name
<< " (" << m_dst_image_id << ")': " << cpp_strerror(r)
<< dendl;
- // not fatal
+ return r;
}
}
case cls::rbd::MIGRATION_HEADER_TYPE_DST:
ldout(cct, 1) << this << " " << __func__ << ": migrating from: "
<< m_migration_spec << dendl;
- if (m_migration_spec.state != cls::rbd::MIGRATION_STATE_PREPARED &&
- m_migration_spec.state != cls::rbd::MIGRATION_STATE_EXECUTING &&
- m_migration_spec.state != cls::rbd::MIGRATION_STATE_EXECUTED) {
+ switch (m_migration_spec.state) {
+ case cls::rbd::MIGRATION_STATE_PREPARING:
ldout(cct, 5) << this << " " << __func__ << ": current migration state: "
<< m_migration_spec.state << ", retrying" << dendl;
send();
return nullptr;
+ case cls::rbd::MIGRATION_STATE_PREPARED:
+ case cls::rbd::MIGRATION_STATE_EXECUTING:
+ case cls::rbd::MIGRATION_STATE_EXECUTED:
+ break;
+ case cls::rbd::MIGRATION_STATE_ABORTING:
+ if (!m_image_ctx.read_only) {
+ lderr(cct) << this << " " << __func__ << ": migration is being aborted"
+ << dendl;
+ *result = -EROFS;
+ return m_on_finish;
+ }
+ break;
+ default:
+ lderr(cct) << this << " " << __func__ << ": migration is in an "
+ << "unexpected state" << dendl;
+ *result = -EINVAL;
+ return m_on_finish;
}
break;
default:
m_image_ctx.operations_disabled = (
(m_op_features & ~RBD_OPERATION_FEATURES_ALL) != 0ULL);
m_image_ctx.group_spec = m_group_spec;
- if (get_migration_info(&m_image_ctx.parent_md,
- &m_image_ctx.migration_info)) {
+
+ bool migration_info_valid;
+ int r = get_migration_info(&m_image_ctx.parent_md,
+ &m_image_ctx.migration_info,
+ &migration_info_valid);
+ ceph_assert(r == 0); // validated in refresh parent step
+
+ if (migration_info_valid) {
for (auto it : m_image_ctx.migration_info.snap_map) {
migration_reverse_snap_seq[it.second.front()] = it.first;
}
int RefreshRequest<I>::get_parent_info(uint64_t snap_id,
ParentImageInfo *parent_md,
MigrationInfo *migration_info) {
- if (get_migration_info(parent_md, migration_info)) {
+ bool migration_info_valid;
+ int r = get_migration_info(parent_md, migration_info, &migration_info_valid);
+ if (r < 0) {
+ return r;
+ }
+
+ if (migration_info_valid) {
return 0;
} else if (snap_id == CEPH_NOSNAP) {
*parent_md = m_parent_md;
}
template <typename I>
-bool RefreshRequest<I>::get_migration_info(ParentImageInfo *parent_md,
- MigrationInfo *migration_info) {
+int RefreshRequest<I>::get_migration_info(ParentImageInfo *parent_md,
+ MigrationInfo *migration_info,
+ bool* migration_info_valid) {
+ CephContext *cct = m_image_ctx.cct;
if (m_migration_spec.header_type != cls::rbd::MIGRATION_HEADER_TYPE_DST ||
(m_migration_spec.state != cls::rbd::MIGRATION_STATE_PREPARED &&
- m_migration_spec.state != cls::rbd::MIGRATION_STATE_EXECUTING)) {
- ceph_assert(m_migration_spec.header_type ==
- cls::rbd::MIGRATION_HEADER_TYPE_SRC ||
- m_migration_spec.pool_id == -1 ||
- m_migration_spec.state == cls::rbd::MIGRATION_STATE_EXECUTED);
+ m_migration_spec.state != cls::rbd::MIGRATION_STATE_EXECUTING &&
+ m_migration_spec.state != cls::rbd::MIGRATION_STATE_ABORTING)) {
+ if (m_migration_spec.header_type != cls::rbd::MIGRATION_HEADER_TYPE_SRC &&
+ m_migration_spec.pool_id != -1 &&
+ m_migration_spec.state != cls::rbd::MIGRATION_STATE_EXECUTED) {
+ lderr(cct) << this << " " << __func__ << ": invalid migration spec"
+ << dendl;
+ return -EINVAL;
+ }
- return false;
+ *migration_info_valid = false;
+ return 0;
}
parent_md->spec.pool_id = m_migration_spec.pool_id;
*migration_info = {m_migration_spec.pool_id, m_migration_spec.pool_namespace,
m_migration_spec.image_name, m_migration_spec.image_id, {},
overlap, m_migration_spec.flatten};
+ *migration_info_valid = true;
deep_copy::util::compute_snap_map(m_image_ctx.cct, 0, CEPH_NOSNAP, {},
snap_seqs, &migration_info->snap_map);
- return true;
+ return 0;
}
} // namespace image
void apply();
int get_parent_info(uint64_t snap_id, ParentImageInfo *parent_md,
MigrationInfo *migration_info);
- bool get_migration_info(ParentImageInfo *parent_md,
- MigrationInfo *migration_info);
+ int get_migration_info(ParentImageInfo *parent_md,
+ MigrationInfo *migration_info,
+ bool* migration_info_valid);
};
} // namespace image
_RBD_IMAGE_MIGRATION_STATE_PREPARED "RBD_IMAGE_MIGRATION_STATE_PREPARED"
_RBD_IMAGE_MIGRATION_STATE_EXECUTING "RBD_IMAGE_MIGRATION_STATE_EXECUTING"
_RBD_IMAGE_MIGRATION_STATE_EXECUTED "RBD_IMAGE_MIGRATION_STATE_EXECUTED"
+ _RBD_IMAGE_MIGRATION_STATE_ABORTING "RBD_IMAGE_MIGRATION_STATE_ABORTING"
ctypedef struct rbd_image_migration_status_t:
int64_t source_pool_id
RBD_IMAGE_MIGRATION_STATE_PREPARED = _RBD_IMAGE_MIGRATION_STATE_PREPARED
RBD_IMAGE_MIGRATION_STATE_EXECUTING = _RBD_IMAGE_MIGRATION_STATE_EXECUTING
RBD_IMAGE_MIGRATION_STATE_EXECUTED = _RBD_IMAGE_MIGRATION_STATE_EXECUTED
+RBD_IMAGE_MIGRATION_STATE_ABORTING = _RBD_IMAGE_MIGRATION_STATE_ABORTING
RBD_CONFIG_SOURCE_CONFIG = _RBD_CONFIG_SOURCE_CONFIG
RBD_CONFIG_SOURCE_POOL = _RBD_CONFIG_SOURCE_POOL
migration_commit(m_ioctx, m_image_name);
}
+TEST_F(TestMigration, AbortInUseImage) {
+ migration_prepare(m_ioctx, m_image_name);
+ migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED);
+
+ librbd::NoOpProgressContext no_op;
+ EXPECT_EQ(-EBUSY, librbd::api::Migration<>::abort(m_ioctx, m_ictx->name,
+ no_op));
+}
+
TEST_F(TestMigration, CloneV1Parent)
{
const uint32_t CLONE_FORMAT = 1;
case RBD_IMAGE_MIGRATION_STATE_EXECUTED:
migration_state = "executed";
break;
+ case RBD_IMAGE_MIGRATION_STATE_ABORTING:
+ migration_state = "aborting";
+ break;
default:
migration_state = "unknown";
}