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 = Snapshot<I>::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_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;
}
librados::Rados rados(m_image_ctx.md_ctx);
int8_t require_osd_release;
- int r = rados.get_min_compatible_osd(&require_osd_release);
+ r = rados.get_min_compatible_osd(&require_osd_release);
if (r == 0 && require_osd_release >= CEPH_RELEASE_OCTOPUS) {
m_image_ctx.enable_sparse_copyup = true;
}
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