]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/image/RefreshRequest.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / librbd / image / RefreshRequest.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
11fdf7f2 4#include "include/ceph_assert.h"
b32b8144 5
7c673cae
FG
6#include "librbd/image/RefreshRequest.h"
7#include "common/dout.h"
8#include "common/errno.h"
9#include "cls/lock/cls_lock_client.h"
10#include "cls/rbd/cls_rbd_client.h"
11#include "librbd/ExclusiveLock.h"
12#include "librbd/ImageCtx.h"
11fdf7f2 13#include "librbd/ImageWatcher.h"
7c673cae
FG
14#include "librbd/Journal.h"
15#include "librbd/ObjectMap.h"
16#include "librbd/Utils.h"
11fdf7f2 17#include "librbd/deep_copy/Utils.h"
9f95a23c 18#include "librbd/image/GetMetadataRequest.h"
7c673cae 19#include "librbd/image/RefreshParentRequest.h"
11fdf7f2
TL
20#include "librbd/io/AioCompletion.h"
21#include "librbd/io/ImageDispatchSpec.h"
7c673cae
FG
22#include "librbd/io/ImageRequestWQ.h"
23#include "librbd/journal/Policy.h"
24
25#define dout_subsys ceph_subsys_rbd
26#undef dout_prefix
27#define dout_prefix *_dout << "librbd::image::RefreshRequest: "
28
29namespace librbd {
30namespace image {
31
32using util::create_rados_callback;
33using util::create_async_context_callback;
34using util::create_context_callback;
35
36template <typename I>
37RefreshRequest<I>::RefreshRequest(I &image_ctx, bool acquiring_lock,
38 bool skip_open_parent, Context *on_finish)
39 : m_image_ctx(image_ctx), m_acquiring_lock(acquiring_lock),
40 m_skip_open_parent_image(skip_open_parent),
41 m_on_finish(create_async_context_callback(m_image_ctx, on_finish)),
42 m_error_result(0), m_flush_aio(false), m_exclusive_lock(nullptr),
43 m_object_map(nullptr), m_journal(nullptr), m_refresh_parent(nullptr) {
11fdf7f2
TL
44 m_pool_metadata_io_ctx.dup(image_ctx.md_ctx);
45 m_pool_metadata_io_ctx.set_namespace("");
7c673cae
FG
46}
47
48template <typename I>
49RefreshRequest<I>::~RefreshRequest() {
50 // these require state machine to close
11fdf7f2
TL
51 ceph_assert(m_exclusive_lock == nullptr);
52 ceph_assert(m_object_map == nullptr);
53 ceph_assert(m_journal == nullptr);
54 ceph_assert(m_refresh_parent == nullptr);
55 ceph_assert(!m_blocked_writes);
7c673cae
FG
56}
57
58template <typename I>
59void RefreshRequest<I>::send() {
60 if (m_image_ctx.old_format) {
61 send_v1_read_header();
62 } else {
63 send_v2_get_mutable_metadata();
64 }
65}
66
11fdf7f2
TL
67template <typename I>
68void RefreshRequest<I>::send_get_migration_header() {
69 if (m_image_ctx.ignore_migrating) {
70 if (m_image_ctx.old_format) {
71 send_v1_get_snapshots();
72 } else {
73 send_v2_get_metadata();
74 }
75 return;
76 }
77
78 CephContext *cct = m_image_ctx.cct;
79 ldout(cct, 10) << this << " " << __func__ << dendl;
80
81 librados::ObjectReadOperation op;
82 cls_client::migration_get_start(&op);
83
84 using klass = RefreshRequest<I>;
85 librados::AioCompletion *comp =
86 create_rados_callback<klass, &klass::handle_get_migration_header>(this);
87 m_out_bl.clear();
88 m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
89 &m_out_bl);
90 comp->release();
91}
92
93template <typename I>
94Context *RefreshRequest<I>::handle_get_migration_header(int *result) {
95 CephContext *cct = m_image_ctx.cct;
96 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
97
98 if (*result == 0) {
99 auto it = m_out_bl.cbegin();
100 *result = cls_client::migration_get_finish(&it, &m_migration_spec);
101 } else if (*result == -ENOENT) {
102 ldout(cct, 5) << this << " " << __func__ << ": no migration header found"
103 << ", retrying" << dendl;
104 send();
105 return nullptr;
106 }
107
108 if (*result < 0) {
109 lderr(cct) << "failed to retrieve migration header: "
110 << cpp_strerror(*result) << dendl;
111 return m_on_finish;
112 }
113
114 switch(m_migration_spec.header_type) {
115 case cls::rbd::MIGRATION_HEADER_TYPE_SRC:
9f95a23c 116 if (!m_read_only) {
11fdf7f2
TL
117 lderr(cct) << "image being migrated" << dendl;
118 *result = -EROFS;
119 return m_on_finish;
120 }
121 ldout(cct, 1) << this << " " << __func__ << ": migrating to: "
122 << m_migration_spec << dendl;
123 break;
124 case cls::rbd::MIGRATION_HEADER_TYPE_DST:
125 ldout(cct, 1) << this << " " << __func__ << ": migrating from: "
126 << m_migration_spec << dendl;
127 if (m_migration_spec.state != cls::rbd::MIGRATION_STATE_PREPARED &&
128 m_migration_spec.state != cls::rbd::MIGRATION_STATE_EXECUTING &&
129 m_migration_spec.state != cls::rbd::MIGRATION_STATE_EXECUTED) {
130 ldout(cct, 5) << this << " " << __func__ << ": current migration state: "
131 << m_migration_spec.state << ", retrying" << dendl;
132 send();
133 return nullptr;
134 }
135 break;
136 default:
137 ldout(cct, 1) << this << " " << __func__ << ": migration type "
138 << m_migration_spec.header_type << dendl;
139 *result = -EBADMSG;
140 return m_on_finish;
141 }
142
143 if (m_image_ctx.old_format) {
144 send_v1_get_snapshots();
145 } else {
146 send_v2_get_metadata();
147 }
148 return nullptr;
149}
150
7c673cae
FG
151template <typename I>
152void RefreshRequest<I>::send_v1_read_header() {
153 CephContext *cct = m_image_ctx.cct;
154 ldout(cct, 10) << this << " " << __func__ << dendl;
155
156 librados::ObjectReadOperation op;
157 op.read(0, 0, nullptr, nullptr);
158
159 using klass = RefreshRequest<I>;
160 librados::AioCompletion *comp = create_rados_callback<
161 klass, &klass::handle_v1_read_header>(this);
162 m_out_bl.clear();
163 int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
164 &m_out_bl);
11fdf7f2 165 ceph_assert(r == 0);
7c673cae
FG
166 comp->release();
167}
168
169template <typename I>
170Context *RefreshRequest<I>::handle_v1_read_header(int *result) {
171 CephContext *cct = m_image_ctx.cct;
172 ldout(cct, 10) << this << " " << __func__ << ": " << "r=" << *result << dendl;
173
174 rbd_obj_header_ondisk v1_header;
11fdf7f2 175 bool migrating = false;
7c673cae
FG
176 if (*result < 0) {
177 return m_on_finish;
178 } else if (m_out_bl.length() < sizeof(v1_header)) {
179 lderr(cct) << "v1 header too small" << dendl;
180 *result = -EIO;
181 return m_on_finish;
182 } else if (memcmp(RBD_HEADER_TEXT, m_out_bl.c_str(),
183 sizeof(RBD_HEADER_TEXT)) != 0) {
11fdf7f2
TL
184 if (memcmp(RBD_MIGRATE_HEADER_TEXT, m_out_bl.c_str(),
185 sizeof(RBD_MIGRATE_HEADER_TEXT)) == 0) {
186 ldout(cct, 1) << this << " " << __func__ << ": migration v1 header detected"
187 << dendl;
188 migrating = true;
189 } else {
190 lderr(cct) << "unrecognized v1 header" << dendl;
191 *result = -ENXIO;
192 return m_on_finish;
193 }
7c673cae
FG
194 }
195
9f95a23c
TL
196 {
197 std::shared_lock image_locker{m_image_ctx.image_lock};
198 m_read_only = m_image_ctx.read_only;
199 m_read_only_flags = m_image_ctx.read_only_flags;
200 }
201
7c673cae
FG
202 memcpy(&v1_header, m_out_bl.c_str(), sizeof(v1_header));
203 m_order = v1_header.options.order;
204 m_size = v1_header.image_size;
205 m_object_prefix = v1_header.block_name;
11fdf7f2
TL
206 if (migrating) {
207 send_get_migration_header();
208 } else {
209 send_v1_get_snapshots();
210 }
7c673cae
FG
211 return nullptr;
212}
213
214template <typename I>
215void RefreshRequest<I>::send_v1_get_snapshots() {
216 CephContext *cct = m_image_ctx.cct;
217 ldout(cct, 10) << this << " " << __func__ << dendl;
218
219 librados::ObjectReadOperation op;
220 cls_client::old_snapshot_list_start(&op);
221
222 using klass = RefreshRequest<I>;
223 librados::AioCompletion *comp = create_rados_callback<
224 klass, &klass::handle_v1_get_snapshots>(this);
225 m_out_bl.clear();
226 int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
227 &m_out_bl);
11fdf7f2 228 ceph_assert(r == 0);
7c673cae
FG
229 comp->release();
230}
231
232template <typename I>
233Context *RefreshRequest<I>::handle_v1_get_snapshots(int *result) {
234 CephContext *cct = m_image_ctx.cct;
235 ldout(cct, 10) << this << " " << __func__ << ": " << "r=" << *result << dendl;
236
11fdf7f2
TL
237 std::vector<std::string> snap_names;
238 std::vector<uint64_t> snap_sizes;
7c673cae 239 if (*result == 0) {
11fdf7f2
TL
240 auto it = m_out_bl.cbegin();
241 *result = cls_client::old_snapshot_list_finish(&it, &snap_names,
242 &snap_sizes, &m_snapc);
7c673cae
FG
243 }
244
245 if (*result < 0) {
246 lderr(cct) << "failed to retrieve v1 snapshots: " << cpp_strerror(*result)
247 << dendl;
248 return m_on_finish;
249 }
250
251 if (!m_snapc.is_valid()) {
252 lderr(cct) << "v1 image snap context is invalid" << dendl;
253 *result = -EIO;
254 return m_on_finish;
255 }
256
11fdf7f2
TL
257 m_snap_infos.clear();
258 for (size_t i = 0; i < m_snapc.snaps.size(); ++i) {
259 m_snap_infos.push_back({m_snapc.snaps[i],
260 {cls::rbd::UserSnapshotNamespace{}},
261 snap_names[i], snap_sizes[i], {}, 0});
262 }
7c673cae
FG
263
264 send_v1_get_locks();
265 return nullptr;
266}
267
268template <typename I>
269void RefreshRequest<I>::send_v1_get_locks() {
270 CephContext *cct = m_image_ctx.cct;
271 ldout(cct, 10) << this << " " << __func__ << dendl;
272
273 librados::ObjectReadOperation op;
274 rados::cls::lock::get_lock_info_start(&op, RBD_LOCK_NAME);
275
276 using klass = RefreshRequest<I>;
277 librados::AioCompletion *comp = create_rados_callback<
278 klass, &klass::handle_v1_get_locks>(this);
279 m_out_bl.clear();
280 int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
281 &m_out_bl);
11fdf7f2 282 ceph_assert(r == 0);
7c673cae
FG
283 comp->release();
284}
285
286template <typename I>
287Context *RefreshRequest<I>::handle_v1_get_locks(int *result) {
288 CephContext *cct = m_image_ctx.cct;
289 ldout(cct, 10) << this << " " << __func__ << ": "
290 << "r=" << *result << dendl;
291
11fdf7f2
TL
292 if (*result == 0) {
293 auto it = m_out_bl.cbegin();
7c673cae
FG
294 ClsLockType lock_type;
295 *result = rados::cls::lock::get_lock_info_finish(&it, &m_lockers,
296 &lock_type, &m_lock_tag);
297 if (*result == 0) {
298 m_exclusive_locked = (lock_type == LOCK_EXCLUSIVE);
299 }
300 }
301 if (*result < 0) {
302 lderr(cct) << "failed to retrieve locks: " << cpp_strerror(*result)
303 << dendl;
304 return m_on_finish;
305 }
306
307 send_v1_apply();
308 return nullptr;
309}
310
311template <typename I>
312void RefreshRequest<I>::send_v1_apply() {
313 CephContext *cct = m_image_ctx.cct;
314 ldout(cct, 10) << this << " " << __func__ << dendl;
315
316 // ensure we are not in a rados callback when applying updates
317 using klass = RefreshRequest<I>;
318 Context *ctx = create_context_callback<
319 klass, &klass::handle_v1_apply>(this);
320 m_image_ctx.op_work_queue->queue(ctx, 0);
321}
322
323template <typename I>
324Context *RefreshRequest<I>::handle_v1_apply(int *result) {
325 CephContext *cct = m_image_ctx.cct;
326 ldout(cct, 10) << this << " " << __func__ << dendl;
327
328 apply();
329 return send_flush_aio();
330}
331
332template <typename I>
333void RefreshRequest<I>::send_v2_get_mutable_metadata() {
334 CephContext *cct = m_image_ctx.cct;
335 ldout(cct, 10) << this << " " << __func__ << dendl;
336
337 uint64_t snap_id;
338 {
9f95a23c 339 std::shared_lock image_locker{m_image_ctx.image_lock};
7c673cae 340 snap_id = m_image_ctx.snap_id;
9f95a23c
TL
341 m_read_only = m_image_ctx.read_only;
342 m_read_only_flags = m_image_ctx.read_only_flags;
7c673cae
FG
343 }
344
9f95a23c
TL
345 // mask out the non-primary read-only flag since its state can change
346 bool read_only = (
347 ((m_read_only_flags & ~IMAGE_READ_ONLY_FLAG_NON_PRIMARY) != 0) ||
348 (snap_id != CEPH_NOSNAP));
7c673cae 349 librados::ObjectReadOperation op;
11fdf7f2
TL
350 cls_client::get_size_start(&op, CEPH_NOSNAP);
351 cls_client::get_features_start(&op, read_only);
352 cls_client::get_flags_start(&op, CEPH_NOSNAP);
353 cls_client::get_snapcontext_start(&op);
354 rados::cls::lock::get_lock_info_start(&op, RBD_LOCK_NAME);
7c673cae
FG
355
356 using klass = RefreshRequest<I>;
357 librados::AioCompletion *comp = create_rados_callback<
358 klass, &klass::handle_v2_get_mutable_metadata>(this);
359 m_out_bl.clear();
360 int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
361 &m_out_bl);
11fdf7f2 362 ceph_assert(r == 0);
7c673cae
FG
363 comp->release();
364}
365
366template <typename I>
367Context *RefreshRequest<I>::handle_v2_get_mutable_metadata(int *result) {
368 CephContext *cct = m_image_ctx.cct;
369 ldout(cct, 10) << this << " " << __func__ << ": "
370 << "r=" << *result << dendl;
371
11fdf7f2
TL
372 auto it = m_out_bl.cbegin();
373 if (*result >= 0) {
374 uint8_t order;
375 *result = cls_client::get_size_finish(&it, &m_size, &order);
376 }
377
378 if (*result >= 0) {
379 *result = cls_client::get_features_finish(&it, &m_features,
380 &m_incompatible_features);
381 }
382
383 if (*result >= 0) {
384 *result = cls_client::get_flags_finish(&it, &m_flags);
385 }
386
387 if (*result >= 0) {
388 *result = cls_client::get_snapcontext_finish(&it, &m_snapc);
389 }
390
391 if (*result >= 0) {
392 ClsLockType lock_type = LOCK_NONE;
393 *result = rados::cls::lock::get_lock_info_finish(&it, &m_lockers,
394 &lock_type, &m_lock_tag);
395 if (*result == 0) {
396 m_exclusive_locked = (lock_type == LOCK_EXCLUSIVE);
397 }
7c673cae 398 }
11fdf7f2 399
7c673cae
FG
400 if (*result < 0) {
401 lderr(cct) << "failed to retrieve mutable metadata: "
402 << cpp_strerror(*result) << dendl;
403 return m_on_finish;
404 }
405
406 uint64_t unsupported = m_incompatible_features & ~RBD_FEATURES_ALL;
407 if (unsupported != 0ULL) {
408 lderr(cct) << "Image uses unsupported features: " << unsupported << dendl;
409 *result = -ENOSYS;
410 return m_on_finish;
411 }
412
413 if (!m_snapc.is_valid()) {
414 lderr(cct) << "image snap context is invalid!" << dendl;
415 *result = -EIO;
416 return m_on_finish;
417 }
418
419 if (m_acquiring_lock && (m_features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) {
420 ldout(cct, 5) << "ignoring dynamically disabled exclusive lock" << dendl;
421 m_features |= RBD_FEATURE_EXCLUSIVE_LOCK;
422 m_incomplete_update = true;
423 }
424
9f95a23c
TL
425 if (((m_incompatible_features & RBD_FEATURE_NON_PRIMARY) != 0U) &&
426 ((m_read_only_flags & IMAGE_READ_ONLY_FLAG_NON_PRIMARY) == 0U) &&
427 ((m_image_ctx.read_only_mask & IMAGE_READ_ONLY_FLAG_NON_PRIMARY) != 0U)) {
428 // implies we opened a non-primary image in R/W mode
429 ldout(cct, 5) << "adding non-primary read-only image flag" << dendl;
430 m_read_only_flags |= IMAGE_READ_ONLY_FLAG_NON_PRIMARY;
431 } else if ((((m_incompatible_features & RBD_FEATURE_NON_PRIMARY) == 0U) ||
432 ((m_image_ctx.read_only_mask &
433 IMAGE_READ_ONLY_FLAG_NON_PRIMARY) == 0U)) &&
434 ((m_read_only_flags & IMAGE_READ_ONLY_FLAG_NON_PRIMARY) != 0U)) {
435 ldout(cct, 5) << "removing non-primary read-only image flag" << dendl;
436 m_read_only_flags &= ~IMAGE_READ_ONLY_FLAG_NON_PRIMARY;
437 }
438 m_read_only = (m_read_only_flags != 0U);
439
11fdf7f2
TL
440 send_v2_get_parent();
441 return nullptr;
442}
443
444template <typename I>
445void RefreshRequest<I>::send_v2_get_parent() {
446 // NOTE: remove support when Mimic is EOLed
447 CephContext *cct = m_image_ctx.cct;
448 ldout(cct, 10) << this << " " << __func__ << ": legacy=" << m_legacy_parent
449 << dendl;
450
451 librados::ObjectReadOperation op;
452 if (!m_legacy_parent) {
453 cls_client::parent_get_start(&op);
454 cls_client::parent_overlap_get_start(&op, CEPH_NOSNAP);
455 } else {
456 cls_client::get_parent_start(&op, CEPH_NOSNAP);
457 }
458
459 auto aio_comp = create_rados_callback<
460 RefreshRequest<I>, &RefreshRequest<I>::handle_v2_get_parent>(this);
461 m_out_bl.clear();
462 m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, aio_comp, &op,
463 &m_out_bl);
464 aio_comp->release();
465}
466
467template <typename I>
468Context *RefreshRequest<I>::handle_v2_get_parent(int *result) {
469 // NOTE: remove support when Mimic is EOLed
470 CephContext *cct = m_image_ctx.cct;
471 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
472
473 auto it = m_out_bl.cbegin();
474 if (!m_legacy_parent) {
475 if (*result == 0) {
476 *result = cls_client::parent_get_finish(&it, &m_parent_md.spec);
477 }
478
479 std::optional<uint64_t> parent_overlap;
480 if (*result == 0) {
481 *result = cls_client::parent_overlap_get_finish(&it, &parent_overlap);
482 }
483
484 if (*result == 0 && parent_overlap) {
485 m_parent_md.overlap = *parent_overlap;
486 m_head_parent_overlap = true;
487 }
488 } else if (*result == 0) {
489 *result = cls_client::get_parent_finish(&it, &m_parent_md.spec,
490 &m_parent_md.overlap);
491 m_head_parent_overlap = true;
492 }
493
494 if (*result == -EOPNOTSUPP && !m_legacy_parent) {
495 ldout(cct, 10) << "retrying using legacy parent method" << dendl;
496 m_legacy_parent = true;
497 send_v2_get_parent();
498 return nullptr;
499 } if (*result < 0) {
500 lderr(cct) << "failed to retrieve parent: " << cpp_strerror(*result)
501 << dendl;
502 return m_on_finish;
503 }
504
505 if ((m_features & RBD_FEATURE_MIGRATING) != 0) {
506 ldout(cct, 1) << "migrating feature set" << dendl;
507 send_get_migration_header();
508 return nullptr;
509 }
510
b32b8144
FG
511 send_v2_get_metadata();
512 return nullptr;
513}
514
515template <typename I>
516void RefreshRequest<I>::send_v2_get_metadata() {
517 CephContext *cct = m_image_ctx.cct;
9f95a23c 518 ldout(cct, 10) << this << " " << __func__ << dendl;
b32b8144 519
9f95a23c
TL
520 auto ctx = create_context_callback<
521 RefreshRequest<I>, &RefreshRequest<I>::handle_v2_get_metadata>(this);
522 auto req = GetMetadataRequest<I>::create(
523 m_image_ctx.md_ctx, m_image_ctx.header_oid, true,
524 ImageCtx::METADATA_CONF_PREFIX, ImageCtx::METADATA_CONF_PREFIX, 0U,
525 &m_metadata, ctx);
526 req->send();
b32b8144
FG
527}
528
529template <typename I>
530Context *RefreshRequest<I>::handle_v2_get_metadata(int *result) {
531 CephContext *cct = m_image_ctx.cct;
532 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
533
11fdf7f2 534 if (*result < 0) {
b32b8144
FG
535 lderr(cct) << "failed to retrieve metadata: " << cpp_strerror(*result)
536 << dendl;
537 return m_on_finish;
538 }
539
11fdf7f2 540 send_v2_get_pool_metadata();
7c673cae
FG
541 return nullptr;
542}
543
544template <typename I>
11fdf7f2 545void RefreshRequest<I>::send_v2_get_pool_metadata() {
7c673cae 546 CephContext *cct = m_image_ctx.cct;
9f95a23c 547 ldout(cct, 10) << this << " " << __func__ << dendl;
7c673cae 548
9f95a23c
TL
549 auto ctx = create_context_callback<
550 RefreshRequest<I>, &RefreshRequest<I>::handle_v2_get_pool_metadata>(this);
551 auto req = GetMetadataRequest<I>::create(
552 m_pool_metadata_io_ctx, RBD_INFO, true, ImageCtx::METADATA_CONF_PREFIX,
553 ImageCtx::METADATA_CONF_PREFIX, 0U, &m_metadata, ctx);
554 req->send();
7c673cae
FG
555}
556
557template <typename I>
11fdf7f2 558Context *RefreshRequest<I>::handle_v2_get_pool_metadata(int *result) {
7c673cae 559 CephContext *cct = m_image_ctx.cct;
11fdf7f2 560 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
7c673cae 561
9f95a23c 562 if (*result < 0) {
11fdf7f2 563 lderr(cct) << "failed to retrieve pool metadata: " << cpp_strerror(*result)
7c673cae
FG
564 << dendl;
565 return m_on_finish;
566 }
567
11fdf7f2
TL
568 bool thread_safe = m_image_ctx.image_watcher->is_unregistered();
569 m_image_ctx.apply_metadata(m_metadata, thread_safe);
570
571 send_v2_get_op_features();
7c673cae
FG
572 return nullptr;
573}
574
575template <typename I>
11fdf7f2
TL
576void RefreshRequest<I>::send_v2_get_op_features() {
577 if ((m_features & RBD_FEATURE_OPERATIONS) == 0LL) {
578 send_v2_get_group();
579 return;
580 }
581
7c673cae
FG
582 CephContext *cct = m_image_ctx.cct;
583 ldout(cct, 10) << this << " " << __func__ << dendl;
584
585 librados::ObjectReadOperation op;
11fdf7f2 586 cls_client::op_features_get_start(&op);
7c673cae 587
7c673cae 588 librados::AioCompletion *comp = create_rados_callback<
11fdf7f2 589 RefreshRequest<I>, &RefreshRequest<I>::handle_v2_get_op_features>(this);
7c673cae
FG
590 m_out_bl.clear();
591 int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
592 &m_out_bl);
11fdf7f2 593 ceph_assert(r == 0);
7c673cae
FG
594 comp->release();
595}
596
597template <typename I>
11fdf7f2 598Context *RefreshRequest<I>::handle_v2_get_op_features(int *result) {
7c673cae
FG
599 CephContext *cct = m_image_ctx.cct;
600 ldout(cct, 10) << this << " " << __func__ << ": "
601 << "r=" << *result << dendl;
602
11fdf7f2
TL
603 // -EOPNOTSUPP handler not required since feature bit implies OSD
604 // supports the method
7c673cae 605 if (*result == 0) {
11fdf7f2
TL
606 auto it = m_out_bl.cbegin();
607 cls_client::op_features_get_finish(&it, &m_op_features);
7c673cae 608 } else if (*result < 0) {
11fdf7f2 609 lderr(cct) << "failed to retrieve op features: " << cpp_strerror(*result)
7c673cae
FG
610 << dendl;
611 return m_on_finish;
612 }
613
11fdf7f2 614 send_v2_get_group();
7c673cae
FG
615 return nullptr;
616}
617
618template <typename I>
11fdf7f2 619void RefreshRequest<I>::send_v2_get_group() {
7c673cae
FG
620 CephContext *cct = m_image_ctx.cct;
621 ldout(cct, 10) << this << " " << __func__ << dendl;
622
623 librados::ObjectReadOperation op;
11fdf7f2 624 cls_client::image_group_get_start(&op);
7c673cae
FG
625
626 using klass = RefreshRequest<I>;
627 librados::AioCompletion *comp = create_rados_callback<
11fdf7f2 628 klass, &klass::handle_v2_get_group>(this);
7c673cae
FG
629 m_out_bl.clear();
630 int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
631 &m_out_bl);
11fdf7f2 632 ceph_assert(r == 0);
7c673cae
FG
633 comp->release();
634}
635
636template <typename I>
11fdf7f2 637Context *RefreshRequest<I>::handle_v2_get_group(int *result) {
7c673cae
FG
638 CephContext *cct = m_image_ctx.cct;
639 ldout(cct, 10) << this << " " << __func__ << ": "
640 << "r=" << *result << dendl;
641
642 if (*result == 0) {
11fdf7f2
TL
643 auto it = m_out_bl.cbegin();
644 cls_client::image_group_get_finish(&it, &m_group_spec);
7c673cae 645 }
9f95a23c 646 if (*result < 0) {
11fdf7f2 647 lderr(cct) << "failed to retrieve group: " << cpp_strerror(*result)
7c673cae
FG
648 << dendl;
649 return m_on_finish;
650 }
651
11fdf7f2 652 send_v2_get_snapshots();
7c673cae
FG
653 return nullptr;
654}
655
656template <typename I>
11fdf7f2
TL
657void RefreshRequest<I>::send_v2_get_snapshots() {
658 m_snap_infos.resize(m_snapc.snaps.size());
659 m_snap_flags.resize(m_snapc.snaps.size());
660 m_snap_parents.resize(m_snapc.snaps.size());
661 m_snap_protection.resize(m_snapc.snaps.size());
662
663 if (m_snapc.snaps.empty()) {
664 send_v2_refresh_parent();
665 return;
666 }
667
7c673cae
FG
668 CephContext *cct = m_image_ctx.cct;
669 ldout(cct, 10) << this << " " << __func__ << dendl;
670
671 librados::ObjectReadOperation op;
11fdf7f2 672 for (auto snap_id : m_snapc.snaps) {
9f95a23c 673 if (m_legacy_snapshot) {
11fdf7f2
TL
674 /// NOTE: remove after Luminous is retired
675 cls_client::get_snapshot_name_start(&op, snap_id);
676 cls_client::get_size_start(&op, snap_id);
9f95a23c 677 cls_client::get_snapshot_timestamp_start(&op, snap_id);
11fdf7f2
TL
678 } else {
679 cls_client::snapshot_get_start(&op, snap_id);
680 }
681
682 if (m_legacy_parent) {
683 cls_client::get_parent_start(&op, snap_id);
684 } else {
685 cls_client::parent_overlap_get_start(&op, snap_id);
686 }
687
688 cls_client::get_flags_start(&op, snap_id);
689 cls_client::get_protection_status_start(&op, snap_id);
690 }
7c673cae
FG
691
692 using klass = RefreshRequest<I>;
693 librados::AioCompletion *comp = create_rados_callback<
11fdf7f2 694 klass, &klass::handle_v2_get_snapshots>(this);
7c673cae
FG
695 m_out_bl.clear();
696 int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
11fdf7f2
TL
697 &m_out_bl);
698 ceph_assert(r == 0);
7c673cae
FG
699 comp->release();
700}
701
702template <typename I>
11fdf7f2 703Context *RefreshRequest<I>::handle_v2_get_snapshots(int *result) {
7c673cae
FG
704 CephContext *cct = m_image_ctx.cct;
705 ldout(cct, 10) << this << " " << __func__ << ": " << "r=" << *result << dendl;
706
11fdf7f2
TL
707 auto it = m_out_bl.cbegin();
708 for (size_t i = 0; i < m_snapc.snaps.size(); ++i) {
9f95a23c 709 if (m_legacy_snapshot) {
11fdf7f2
TL
710 /// NOTE: remove after Luminous is retired
711 std::string snap_name;
712 if (*result >= 0) {
713 *result = cls_client::get_snapshot_name_finish(&it, &snap_name);
714 }
7c673cae 715
11fdf7f2
TL
716 uint64_t snap_size;
717 if (*result >= 0) {
718 uint8_t order;
719 *result = cls_client::get_size_finish(&it, &snap_size, &order);
720 }
7c673cae 721
11fdf7f2 722 utime_t snap_timestamp;
9f95a23c 723 if (*result >= 0) {
11fdf7f2
TL
724 *result = cls_client::get_snapshot_timestamp_finish(&it,
725 &snap_timestamp);
726 }
7c673cae 727
11fdf7f2
TL
728 if (*result >= 0) {
729 m_snap_infos[i] = {m_snapc.snaps[i],
730 {cls::rbd::UserSnapshotNamespace{}},
731 snap_name, snap_size, snap_timestamp, 0};
732 }
733 } else if (*result >= 0) {
734 *result = cls_client::snapshot_get_finish(&it, &m_snap_infos[i]);
735 }
7c673cae 736
11fdf7f2
TL
737 if (*result == 0) {
738 if (m_legacy_parent) {
739 *result = cls_client::get_parent_finish(&it, &m_snap_parents[i].spec,
740 &m_snap_parents[i].overlap);
741 } else {
742 std::optional<uint64_t> parent_overlap;
743 *result = cls_client::parent_overlap_get_finish(&it, &parent_overlap);
744 if (*result == 0 && parent_overlap && m_parent_md.spec.pool_id > -1) {
745 m_snap_parents[i].spec = m_parent_md.spec;
746 m_snap_parents[i].overlap = *parent_overlap;
747 }
748 }
749 }
7c673cae 750
11fdf7f2
TL
751 if (*result >= 0) {
752 *result = cls_client::get_flags_finish(&it, &m_snap_flags[i]);
753 }
7c673cae 754
11fdf7f2
TL
755 if (*result >= 0) {
756 *result = cls_client::get_protection_status_finish(
757 &it, &m_snap_protection[i]);
758 }
759
760 if (*result < 0) {
761 break;
762 }
7c673cae 763 }
11fdf7f2 764
7c673cae
FG
765 if (*result == -ENOENT) {
766 ldout(cct, 10) << "out-of-sync snapshot state detected" << dendl;
767 send_v2_get_mutable_metadata();
768 return nullptr;
9f95a23c 769 } else if (!m_legacy_snapshot && *result == -EOPNOTSUPP) {
11fdf7f2 770 ldout(cct, 10) << "retrying using legacy snapshot methods" << dendl;
9f95a23c 771 m_legacy_snapshot = true;
11fdf7f2
TL
772 send_v2_get_snapshots();
773 return nullptr;
7c673cae
FG
774 } else if (*result < 0) {
775 lderr(cct) << "failed to retrieve snapshots: " << cpp_strerror(*result)
776 << dendl;
777 return m_on_finish;
778 }
779
780 send_v2_refresh_parent();
781 return nullptr;
782}
783
784template <typename I>
785void RefreshRequest<I>::send_v2_refresh_parent() {
786 {
9f95a23c 787 std::shared_lock image_locker{m_image_ctx.image_lock};
7c673cae 788
11fdf7f2
TL
789 ParentImageInfo parent_md;
790 MigrationInfo migration_info;
791 int r = get_parent_info(m_image_ctx.snap_id, &parent_md, &migration_info);
7c673cae 792 if (!m_skip_open_parent_image && (r < 0 ||
11fdf7f2
TL
793 RefreshParentRequest<I>::is_refresh_required(m_image_ctx, parent_md,
794 migration_info))) {
7c673cae
FG
795 CephContext *cct = m_image_ctx.cct;
796 ldout(cct, 10) << this << " " << __func__ << dendl;
797
798 using klass = RefreshRequest<I>;
799 Context *ctx = create_context_callback<
800 klass, &klass::handle_v2_refresh_parent>(this);
801 m_refresh_parent = RefreshParentRequest<I>::create(
11fdf7f2 802 m_image_ctx, parent_md, migration_info, ctx);
7c673cae
FG
803 }
804 }
805
806 if (m_refresh_parent != nullptr) {
807 m_refresh_parent->send();
808 } else {
809 send_v2_init_exclusive_lock();
810 }
811}
812
813template <typename I>
814Context *RefreshRequest<I>::handle_v2_refresh_parent(int *result) {
815 CephContext *cct = m_image_ctx.cct;
816 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
817
818 if (*result < 0) {
819 lderr(cct) << "failed to refresh parent image: " << cpp_strerror(*result)
820 << dendl;
821 save_result(result);
822 send_v2_apply();
823 return nullptr;
824 }
825
826 send_v2_init_exclusive_lock();
827 return nullptr;
828}
829
830template <typename I>
831void RefreshRequest<I>::send_v2_init_exclusive_lock() {
832 if ((m_features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0 ||
9f95a23c 833 m_read_only || !m_image_ctx.snap_name.empty() ||
7c673cae
FG
834 m_image_ctx.exclusive_lock != nullptr) {
835 send_v2_open_object_map();
836 return;
837 }
838
839 // implies exclusive lock dynamically enabled or image open in-progress
840 CephContext *cct = m_image_ctx.cct;
841 ldout(cct, 10) << this << " " << __func__ << dendl;
842
843 // TODO need safe shut down
844 m_exclusive_lock = m_image_ctx.create_exclusive_lock();
845
846 using klass = RefreshRequest<I>;
847 Context *ctx = create_context_callback<
848 klass, &klass::handle_v2_init_exclusive_lock>(this);
849
9f95a23c 850 std::shared_lock owner_locker{m_image_ctx.owner_lock};
7c673cae
FG
851 m_exclusive_lock->init(m_features, ctx);
852}
853
854template <typename I>
855Context *RefreshRequest<I>::handle_v2_init_exclusive_lock(int *result) {
856 CephContext *cct = m_image_ctx.cct;
857 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
858
859 if (*result < 0) {
860 lderr(cct) << "failed to initialize exclusive lock: "
861 << cpp_strerror(*result) << dendl;
862 save_result(result);
863 }
864
865 // object map and journal will be opened when exclusive lock is
866 // acquired (if features are enabled)
867 send_v2_apply();
868 return nullptr;
869}
870
871template <typename I>
872void RefreshRequest<I>::send_v2_open_journal() {
873 bool journal_disabled = (
874 (m_features & RBD_FEATURE_JOURNALING) == 0 ||
9f95a23c 875 m_read_only ||
7c673cae
FG
876 !m_image_ctx.snap_name.empty() ||
877 m_image_ctx.journal != nullptr ||
878 m_image_ctx.exclusive_lock == nullptr ||
879 !m_image_ctx.exclusive_lock->is_lock_owner());
880 bool journal_disabled_by_policy;
881 {
9f95a23c 882 std::shared_lock image_locker{m_image_ctx.image_lock};
7c673cae
FG
883 journal_disabled_by_policy = (
884 !journal_disabled &&
885 m_image_ctx.get_journal_policy()->journal_disabled());
886 }
887
888 if (journal_disabled || journal_disabled_by_policy) {
889 // journal dynamically enabled -- doesn't own exclusive lock
890 if ((m_features & RBD_FEATURE_JOURNALING) != 0 &&
891 !journal_disabled_by_policy &&
892 m_image_ctx.exclusive_lock != nullptr &&
893 m_image_ctx.journal == nullptr) {
224ce89b
WB
894 m_image_ctx.io_work_queue->set_require_lock(librbd::io::DIRECTION_BOTH,
895 true);
7c673cae
FG
896 }
897 send_v2_block_writes();
898 return;
899 }
900
901 // implies journal dynamically enabled since ExclusiveLock will init
902 // the journal upon acquiring the lock
903 CephContext *cct = m_image_ctx.cct;
904 ldout(cct, 10) << this << " " << __func__ << dendl;
905
906 using klass = RefreshRequest<I>;
907 Context *ctx = create_context_callback<
908 klass, &klass::handle_v2_open_journal>(this);
909
910 // TODO need safe close
911 m_journal = m_image_ctx.create_journal();
912 m_journal->open(ctx);
913}
914
915template <typename I>
916Context *RefreshRequest<I>::handle_v2_open_journal(int *result) {
917 CephContext *cct = m_image_ctx.cct;
918 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
919
920 if (*result < 0) {
921 lderr(cct) << "failed to initialize journal: " << cpp_strerror(*result)
922 << dendl;
923 save_result(result);
924 }
925
926 send_v2_block_writes();
927 return nullptr;
928}
929
930template <typename I>
931void RefreshRequest<I>::send_v2_block_writes() {
932 bool disabled_journaling = false;
933 {
9f95a23c 934 std::shared_lock image_locker{m_image_ctx.image_lock};
7c673cae
FG
935 disabled_journaling = ((m_features & RBD_FEATURE_EXCLUSIVE_LOCK) != 0 &&
936 (m_features & RBD_FEATURE_JOURNALING) == 0 &&
937 m_image_ctx.journal != nullptr);
938 }
939
940 if (!disabled_journaling) {
941 send_v2_apply();
942 return;
943 }
944
945 CephContext *cct = m_image_ctx.cct;
946 ldout(cct, 10) << this << " " << __func__ << dendl;
947
948 // we need to block writes temporarily to avoid in-flight journal
949 // writes
950 m_blocked_writes = true;
951 Context *ctx = create_context_callback<
952 RefreshRequest<I>, &RefreshRequest<I>::handle_v2_block_writes>(this);
953
9f95a23c 954 std::shared_lock owner_locker{m_image_ctx.owner_lock};
7c673cae
FG
955 m_image_ctx.io_work_queue->block_writes(ctx);
956}
957
958template <typename I>
959Context *RefreshRequest<I>::handle_v2_block_writes(int *result) {
960 CephContext *cct = m_image_ctx.cct;
961 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
962
963 if (*result < 0) {
964 lderr(cct) << "failed to block writes: " << cpp_strerror(*result)
965 << dendl;
966 save_result(result);
967 }
968 send_v2_apply();
969 return nullptr;
970}
971
972template <typename I>
973void RefreshRequest<I>::send_v2_open_object_map() {
974 if ((m_features & RBD_FEATURE_OBJECT_MAP) == 0 ||
975 m_image_ctx.object_map != nullptr ||
976 (m_image_ctx.snap_name.empty() &&
9f95a23c 977 (m_read_only ||
7c673cae
FG
978 m_image_ctx.exclusive_lock == nullptr ||
979 !m_image_ctx.exclusive_lock->is_lock_owner()))) {
980 send_v2_open_journal();
981 return;
982 }
983
984 // implies object map dynamically enabled or image open in-progress
985 // since SetSnapRequest loads the object map for a snapshot and
986 // ExclusiveLock loads the object map for HEAD
987 CephContext *cct = m_image_ctx.cct;
988 ldout(cct, 10) << this << " " << __func__ << dendl;
989
990 if (m_image_ctx.snap_name.empty()) {
991 m_object_map = m_image_ctx.create_object_map(CEPH_NOSNAP);
992 } else {
11fdf7f2
TL
993 for (size_t snap_idx = 0; snap_idx < m_snap_infos.size(); ++snap_idx) {
994 if (m_snap_infos[snap_idx].name == m_image_ctx.snap_name) {
7c673cae
FG
995 m_object_map = m_image_ctx.create_object_map(
996 m_snapc.snaps[snap_idx].val);
997 break;
998 }
999 }
1000
1001 if (m_object_map == nullptr) {
1002 lderr(cct) << "failed to locate snapshot: " << m_image_ctx.snap_name
1003 << dendl;
1004 send_v2_open_journal();
1005 return;
1006 }
1007 }
1008
1009 using klass = RefreshRequest<I>;
1010 Context *ctx = create_context_callback<
1011 klass, &klass::handle_v2_open_object_map>(this);
1012 m_object_map->open(ctx);
1013}
1014
1015template <typename I>
1016Context *RefreshRequest<I>::handle_v2_open_object_map(int *result) {
1017 CephContext *cct = m_image_ctx.cct;
1018 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
1019
1020 if (*result < 0) {
1021 lderr(cct) << "failed to open object map: " << cpp_strerror(*result)
1022 << dendl;
9f95a23c 1023 m_object_map->put();
7c673cae 1024 m_object_map = nullptr;
11fdf7f2
TL
1025
1026 if (*result != -EFBIG) {
1027 save_result(result);
1028 }
7c673cae
FG
1029 }
1030
1031 send_v2_open_journal();
1032 return nullptr;
1033}
1034
1035template <typename I>
1036void RefreshRequest<I>::send_v2_apply() {
1037 CephContext *cct = m_image_ctx.cct;
1038 ldout(cct, 10) << this << " " << __func__ << dendl;
1039
1040 // ensure we are not in a rados callback when applying updates
1041 using klass = RefreshRequest<I>;
1042 Context *ctx = create_context_callback<
1043 klass, &klass::handle_v2_apply>(this);
1044 m_image_ctx.op_work_queue->queue(ctx, 0);
1045}
1046
1047template <typename I>
1048Context *RefreshRequest<I>::handle_v2_apply(int *result) {
1049 CephContext *cct = m_image_ctx.cct;
1050 ldout(cct, 10) << this << " " << __func__ << dendl;
1051
1052 apply();
1053
1054 return send_v2_finalize_refresh_parent();
1055}
1056
1057template <typename I>
1058Context *RefreshRequest<I>::send_v2_finalize_refresh_parent() {
1059 if (m_refresh_parent == nullptr) {
1060 return send_v2_shut_down_exclusive_lock();
1061 }
1062
1063 CephContext *cct = m_image_ctx.cct;
1064 ldout(cct, 10) << this << " " << __func__ << dendl;
1065
1066 using klass = RefreshRequest<I>;
1067 Context *ctx = create_context_callback<
1068 klass, &klass::handle_v2_finalize_refresh_parent>(this);
1069 m_refresh_parent->finalize(ctx);
1070 return nullptr;
1071}
1072
1073template <typename I>
1074Context *RefreshRequest<I>::handle_v2_finalize_refresh_parent(int *result) {
1075 CephContext *cct = m_image_ctx.cct;
1076 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
1077
11fdf7f2 1078 ceph_assert(m_refresh_parent != nullptr);
7c673cae
FG
1079 delete m_refresh_parent;
1080 m_refresh_parent = nullptr;
1081
1082 return send_v2_shut_down_exclusive_lock();
1083}
1084
1085template <typename I>
1086Context *RefreshRequest<I>::send_v2_shut_down_exclusive_lock() {
1087 if (m_exclusive_lock == nullptr) {
1088 return send_v2_close_journal();
1089 }
1090
1091 CephContext *cct = m_image_ctx.cct;
1092 ldout(cct, 10) << this << " " << __func__ << dendl;
1093
1094 // exclusive lock feature was dynamically disabled. in-flight IO will be
1095 // flushed and in-flight requests will be canceled before releasing lock
1096 using klass = RefreshRequest<I>;
1097 Context *ctx = create_context_callback<
1098 klass, &klass::handle_v2_shut_down_exclusive_lock>(this);
1099 m_exclusive_lock->shut_down(ctx);
1100 return nullptr;
1101}
1102
1103template <typename I>
1104Context *RefreshRequest<I>::handle_v2_shut_down_exclusive_lock(int *result) {
1105 CephContext *cct = m_image_ctx.cct;
1106 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
1107
1108 if (*result < 0) {
1109 lderr(cct) << "failed to shut down exclusive lock: "
1110 << cpp_strerror(*result) << dendl;
1111 save_result(result);
1112 }
1113
1114 {
9f95a23c 1115 std::unique_lock owner_locker{m_image_ctx.owner_lock};
11fdf7f2 1116 ceph_assert(m_image_ctx.exclusive_lock == nullptr);
7c673cae
FG
1117 }
1118
11fdf7f2 1119 ceph_assert(m_exclusive_lock != nullptr);
9f95a23c 1120 m_exclusive_lock->put();
7c673cae
FG
1121 m_exclusive_lock = nullptr;
1122
1123 return send_v2_close_journal();
1124}
1125
1126template <typename I>
1127Context *RefreshRequest<I>::send_v2_close_journal() {
1128 if (m_journal == nullptr) {
1129 return send_v2_close_object_map();
1130 }
1131
1132 CephContext *cct = m_image_ctx.cct;
1133 ldout(cct, 10) << this << " " << __func__ << dendl;
1134
1135 // journal feature was dynamically disabled
1136 using klass = RefreshRequest<I>;
1137 Context *ctx = create_context_callback<
1138 klass, &klass::handle_v2_close_journal>(this);
1139 m_journal->close(ctx);
1140 return nullptr;
1141}
1142
1143template <typename I>
1144Context *RefreshRequest<I>::handle_v2_close_journal(int *result) {
1145 CephContext *cct = m_image_ctx.cct;
1146 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
1147
1148 if (*result < 0) {
1149 save_result(result);
1150 lderr(cct) << "failed to close journal: " << cpp_strerror(*result)
1151 << dendl;
1152 }
1153
11fdf7f2 1154 ceph_assert(m_journal != nullptr);
9f95a23c 1155 m_journal->put();
7c673cae
FG
1156 m_journal = nullptr;
1157
11fdf7f2 1158 ceph_assert(m_blocked_writes);
7c673cae
FG
1159 m_blocked_writes = false;
1160
1161 m_image_ctx.io_work_queue->unblock_writes();
1162 return send_v2_close_object_map();
1163}
1164
1165template <typename I>
1166Context *RefreshRequest<I>::send_v2_close_object_map() {
1167 if (m_object_map == nullptr) {
1168 return send_flush_aio();
1169 }
1170
1171 CephContext *cct = m_image_ctx.cct;
1172 ldout(cct, 10) << this << " " << __func__ << dendl;
1173
1174 // object map was dynamically disabled
1175 using klass = RefreshRequest<I>;
1176 Context *ctx = create_context_callback<
1177 klass, &klass::handle_v2_close_object_map>(this);
1178 m_object_map->close(ctx);
1179 return nullptr;
1180}
1181
1182template <typename I>
1183Context *RefreshRequest<I>::handle_v2_close_object_map(int *result) {
1184 CephContext *cct = m_image_ctx.cct;
1185 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
1186
11fdf7f2
TL
1187 if (*result < 0) {
1188 lderr(cct) << "failed to close object map: " << cpp_strerror(*result)
1189 << dendl;
1190 }
1191
1192 ceph_assert(m_object_map != nullptr);
9f95a23c
TL
1193
1194 m_object_map->put();
7c673cae
FG
1195 m_object_map = nullptr;
1196
1197 return send_flush_aio();
1198}
1199
1200template <typename I>
1201Context *RefreshRequest<I>::send_flush_aio() {
1202 if (m_incomplete_update && m_error_result == 0) {
1203 // if this was a partial refresh, notify ImageState
1204 m_error_result = -ERESTART;
1205 }
1206
1207 if (m_flush_aio) {
1208 CephContext *cct = m_image_ctx.cct;
1209 ldout(cct, 10) << this << " " << __func__ << dendl;
1210
9f95a23c 1211 std::shared_lock owner_locker{m_image_ctx.owner_lock};
11fdf7f2
TL
1212 auto ctx = create_context_callback<
1213 RefreshRequest<I>, &RefreshRequest<I>::handle_flush_aio>(this);
494da23a 1214 auto aio_comp = io::AioCompletion::create_and_start(
11fdf7f2
TL
1215 ctx, util::get_image_ctx(&m_image_ctx), io::AIO_TYPE_FLUSH);
1216 auto req = io::ImageDispatchSpec<I>::create_flush_request(
1217 m_image_ctx, aio_comp, io::FLUSH_SOURCE_INTERNAL, {});
1218 req->send();
1219 delete req;
7c673cae
FG
1220 return nullptr;
1221 } else if (m_error_result < 0) {
1222 // propagate saved error back to caller
1223 Context *ctx = create_context_callback<
1224 RefreshRequest<I>, &RefreshRequest<I>::handle_error>(this);
1225 m_image_ctx.op_work_queue->queue(ctx, 0);
1226 return nullptr;
1227 }
1228
1229 return m_on_finish;
1230}
1231
1232template <typename I>
1233Context *RefreshRequest<I>::handle_flush_aio(int *result) {
1234 CephContext *cct = m_image_ctx.cct;
1235 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
1236
1237 if (*result < 0) {
1238 lderr(cct) << "failed to flush pending AIO: " << cpp_strerror(*result)
1239 << dendl;
1240 }
1241
1242 return handle_error(result);
1243}
1244
1245template <typename I>
1246Context *RefreshRequest<I>::handle_error(int *result) {
1247 if (m_error_result < 0) {
1248 *result = m_error_result;
1249
1250 CephContext *cct = m_image_ctx.cct;
1251 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
1252 }
1253 return m_on_finish;
1254}
1255
1256template <typename I>
1257void RefreshRequest<I>::apply() {
1258 CephContext *cct = m_image_ctx.cct;
1259 ldout(cct, 20) << this << " " << __func__ << dendl;
1260
9f95a23c 1261 std::scoped_lock locker{m_image_ctx.owner_lock, m_image_ctx.image_lock};
7c673cae 1262
9f95a23c
TL
1263 m_image_ctx.read_only_flags = m_read_only_flags;
1264 m_image_ctx.read_only = m_read_only;
1265 m_image_ctx.size = m_size;
1266 m_image_ctx.lockers = m_lockers;
1267 m_image_ctx.lock_tag = m_lock_tag;
1268 m_image_ctx.exclusive_locked = m_exclusive_locked;
7c673cae 1269
9f95a23c 1270 std::map<uint64_t, uint64_t> migration_reverse_snap_seq;
7c673cae 1271
9f95a23c
TL
1272 if (m_image_ctx.old_format) {
1273 m_image_ctx.order = m_order;
1274 m_image_ctx.features = 0;
1275 m_image_ctx.flags = 0;
1276 m_image_ctx.op_features = 0;
1277 m_image_ctx.operations_disabled = false;
1278 m_image_ctx.object_prefix = std::move(m_object_prefix);
1279 m_image_ctx.init_layout(m_image_ctx.md_ctx.get_id());
1280 } else {
1281 // HEAD revision doesn't have a defined overlap so it's only
1282 // applicable to snapshots
1283 if (!m_head_parent_overlap) {
1284 m_parent_md = {};
1285 }
11fdf7f2 1286
9f95a23c
TL
1287 m_image_ctx.features = m_features;
1288 m_image_ctx.flags = m_flags;
1289 m_image_ctx.op_features = m_op_features;
1290 m_image_ctx.operations_disabled = (
1291 (m_op_features & ~RBD_OPERATION_FEATURES_ALL) != 0ULL);
1292 m_image_ctx.group_spec = m_group_spec;
1293 if (get_migration_info(&m_image_ctx.parent_md,
1294 &m_image_ctx.migration_info)) {
1295 for (auto it : m_image_ctx.migration_info.snap_map) {
1296 migration_reverse_snap_seq[it.second.front()] = it.first;
11fdf7f2 1297 }
9f95a23c
TL
1298 } else {
1299 m_image_ctx.parent_md = m_parent_md;
1300 m_image_ctx.migration_info = {};
1301 }
11fdf7f2 1302
9f95a23c
TL
1303 librados::Rados rados(m_image_ctx.md_ctx);
1304 int8_t require_osd_release;
1305 int r = rados.get_min_compatible_osd(&require_osd_release);
1306 if (r == 0 && require_osd_release >= CEPH_RELEASE_OCTOPUS) {
1307 m_image_ctx.enable_sparse_copyup = true;
7c673cae 1308 }
9f95a23c 1309 }
7c673cae 1310
9f95a23c
TL
1311 for (size_t i = 0; i < m_snapc.snaps.size(); ++i) {
1312 std::vector<librados::snap_t>::const_iterator it = std::find(
1313 m_image_ctx.snaps.begin(), m_image_ctx.snaps.end(),
1314 m_snapc.snaps[i].val);
1315 if (it == m_image_ctx.snaps.end()) {
1316 m_flush_aio = true;
1317 ldout(cct, 20) << "new snapshot id=" << m_snapc.snaps[i].val
1318 << " name=" << m_snap_infos[i].name
1319 << " size=" << m_snap_infos[i].image_size
1320 << dendl;
7c673cae 1321 }
9f95a23c 1322 }
7c673cae 1323
9f95a23c
TL
1324 m_image_ctx.snaps.clear();
1325 m_image_ctx.snap_info.clear();
1326 m_image_ctx.snap_ids.clear();
1327 auto overlap = m_image_ctx.parent_md.overlap;
1328 for (size_t i = 0; i < m_snapc.snaps.size(); ++i) {
1329 uint64_t flags = m_image_ctx.old_format ? 0 : m_snap_flags[i];
1330 uint8_t protection_status = m_image_ctx.old_format ?
1331 static_cast<uint8_t>(RBD_PROTECTION_STATUS_UNPROTECTED) :
1332 m_snap_protection[i];
1333 ParentImageInfo parent;
1334 if (!m_image_ctx.old_format) {
1335 if (!m_image_ctx.migration_info.empty()) {
1336 parent = m_image_ctx.parent_md;
1337 auto it = migration_reverse_snap_seq.find(m_snapc.snaps[i].val);
1338 if (it != migration_reverse_snap_seq.end()) {
1339 parent.spec.snap_id = it->second;
1340 parent.overlap = m_snap_infos[i].image_size;
11fdf7f2 1341 } else {
9f95a23c
TL
1342 overlap = std::min(overlap, m_snap_infos[i].image_size);
1343 parent.overlap = overlap;
11fdf7f2 1344 }
9f95a23c
TL
1345 } else {
1346 parent = m_snap_parents[i];
7c673cae 1347 }
7c673cae 1348 }
9f95a23c
TL
1349 m_image_ctx.add_snap(m_snap_infos[i].snapshot_namespace,
1350 m_snap_infos[i].name, m_snapc.snaps[i].val,
1351 m_snap_infos[i].image_size, parent,
1352 protection_status, flags,
1353 m_snap_infos[i].timestamp);
1354 }
1355 m_image_ctx.parent_md.overlap = std::min(overlap, m_image_ctx.size);
1356 m_image_ctx.snapc = m_snapc;
7c673cae 1357
9f95a23c
TL
1358 if (m_image_ctx.snap_id != CEPH_NOSNAP &&
1359 m_image_ctx.get_snap_id(m_image_ctx.snap_namespace,
1360 m_image_ctx.snap_name) != m_image_ctx.snap_id) {
1361 lderr(cct) << "tried to read from a snapshot that no longer exists: "
1362 << m_image_ctx.snap_name << dendl;
1363 m_image_ctx.snap_exists = false;
1364 }
7c673cae 1365
9f95a23c
TL
1366 if (m_refresh_parent != nullptr) {
1367 m_refresh_parent->apply();
1368 }
1369 if (m_image_ctx.data_ctx.is_valid()) {
1370 m_image_ctx.data_ctx.selfmanaged_snap_set_write_ctx(m_image_ctx.snapc.seq,
1371 m_image_ctx.snaps);
1372 }
1373
1374 // handle dynamically enabled / disabled features
1375 if (m_image_ctx.exclusive_lock != nullptr &&
1376 !m_image_ctx.test_features(RBD_FEATURE_EXCLUSIVE_LOCK,
1377 m_image_ctx.image_lock)) {
1378 // disabling exclusive lock will automatically handle closing
1379 // object map and journaling
1380 ceph_assert(m_exclusive_lock == nullptr);
1381 m_exclusive_lock = m_image_ctx.exclusive_lock;
1382 } else {
1383 if (m_exclusive_lock != nullptr) {
1384 ceph_assert(m_image_ctx.exclusive_lock == nullptr);
1385 std::swap(m_exclusive_lock, m_image_ctx.exclusive_lock);
1386 }
1387 if (!m_image_ctx.test_features(RBD_FEATURE_JOURNALING,
1388 m_image_ctx.image_lock)) {
1389 if (!m_image_ctx.clone_copy_on_read && m_image_ctx.journal != nullptr) {
1390 m_image_ctx.io_work_queue->set_require_lock(io::DIRECTION_READ,
1391 false);
7c673cae 1392 }
9f95a23c
TL
1393 std::swap(m_journal, m_image_ctx.journal);
1394 } else if (m_journal != nullptr) {
1395 std::swap(m_journal, m_image_ctx.journal);
1396 }
1397 if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
1398 m_image_ctx.image_lock) ||
1399 m_object_map != nullptr) {
1400 std::swap(m_object_map, m_image_ctx.object_map);
7c673cae
FG
1401 }
1402 }
1403}
1404
1405template <typename I>
1406int RefreshRequest<I>::get_parent_info(uint64_t snap_id,
11fdf7f2
TL
1407 ParentImageInfo *parent_md,
1408 MigrationInfo *migration_info) {
1409 if (get_migration_info(parent_md, migration_info)) {
1410 return 0;
1411 } else if (snap_id == CEPH_NOSNAP) {
7c673cae 1412 *parent_md = m_parent_md;
11fdf7f2 1413 *migration_info = {};
7c673cae
FG
1414 return 0;
1415 } else {
1416 for (size_t i = 0; i < m_snapc.snaps.size(); ++i) {
1417 if (m_snapc.snaps[i].val == snap_id) {
1418 *parent_md = m_snap_parents[i];
11fdf7f2 1419 *migration_info = {};
7c673cae
FG
1420 return 0;
1421 }
1422 }
1423 }
1424 return -ENOENT;
1425}
1426
11fdf7f2
TL
1427template <typename I>
1428bool RefreshRequest<I>::get_migration_info(ParentImageInfo *parent_md,
1429 MigrationInfo *migration_info) {
1430 if (m_migration_spec.header_type != cls::rbd::MIGRATION_HEADER_TYPE_DST ||
1431 (m_migration_spec.state != cls::rbd::MIGRATION_STATE_PREPARED &&
1432 m_migration_spec.state != cls::rbd::MIGRATION_STATE_EXECUTING)) {
1433 ceph_assert(m_migration_spec.header_type ==
1434 cls::rbd::MIGRATION_HEADER_TYPE_SRC ||
1435 m_migration_spec.pool_id == -1 ||
1436 m_migration_spec.state == cls::rbd::MIGRATION_STATE_EXECUTED);
1437
1438 return false;
1439 }
1440
1441 parent_md->spec.pool_id = m_migration_spec.pool_id;
1442 parent_md->spec.pool_namespace = m_migration_spec.pool_namespace;
1443 parent_md->spec.image_id = m_migration_spec.image_id;
1444 parent_md->spec.snap_id = CEPH_NOSNAP;
1445 parent_md->overlap = std::min(m_size, m_migration_spec.overlap);
1446
1447 auto snap_seqs = m_migration_spec.snap_seqs;
1448 // If new snapshots have been created on destination image after
1449 // migration stared, map the source CEPH_NOSNAP to the earliest of
1450 // these snapshots.
1451 snapid_t snap_id = snap_seqs.empty() ? 0 : snap_seqs.rbegin()->second;
1452 auto it = std::upper_bound(m_snapc.snaps.rbegin(), m_snapc.snaps.rend(),
1453 snap_id);
1454 if (it != m_snapc.snaps.rend()) {
1455 snap_seqs[CEPH_NOSNAP] = *it;
1456 } else {
1457 snap_seqs[CEPH_NOSNAP] = CEPH_NOSNAP;
1458 }
1459
1460 std::set<uint64_t> snap_ids;
1461 for (auto& it : snap_seqs) {
1462 snap_ids.insert(it.second);
1463 }
1464 uint64_t overlap = snap_ids.find(CEPH_NOSNAP) != snap_ids.end() ?
1465 parent_md->overlap : 0;
1466 for (size_t i = 0; i < m_snapc.snaps.size(); ++i) {
1467 if (snap_ids.find(m_snapc.snaps[i].val) != snap_ids.end()) {
1468 overlap = std::max(overlap, m_snap_infos[i].image_size);
1469 }
1470 }
1471
1472 *migration_info = {m_migration_spec.pool_id, m_migration_spec.pool_namespace,
1473 m_migration_spec.image_name, m_migration_spec.image_id, {},
1474 overlap, m_migration_spec.flatten};
1475
9f95a23c
TL
1476 deep_copy::util::compute_snap_map(m_image_ctx.cct, 0, CEPH_NOSNAP, {},
1477 snap_seqs, &migration_info->snap_map);
11fdf7f2
TL
1478 return true;
1479}
1480
7c673cae
FG
1481} // namespace image
1482} // namespace librbd
1483
1484template class librbd::image::RefreshRequest<librbd::ImageCtx>;