1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/image/RefreshRequest.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "cls/lock/cls_lock_client.h"
8 #include "cls/rbd/cls_rbd_client.h"
9 #include "librbd/ExclusiveLock.h"
10 #include "librbd/ImageCtx.h"
11 #include "librbd/Journal.h"
12 #include "librbd/ObjectMap.h"
13 #include "librbd/Utils.h"
14 #include "librbd/image/RefreshParentRequest.h"
15 #include "librbd/io/ImageRequestWQ.h"
16 #include "librbd/journal/Policy.h"
18 #define dout_subsys ceph_subsys_rbd
20 #define dout_prefix *_dout << "librbd::image::RefreshRequest: "
25 using util::create_rados_callback
;
26 using util::create_async_context_callback
;
27 using util::create_context_callback
;
30 RefreshRequest
<I
>::RefreshRequest(I
&image_ctx
, bool acquiring_lock
,
31 bool skip_open_parent
, Context
*on_finish
)
32 : m_image_ctx(image_ctx
), m_acquiring_lock(acquiring_lock
),
33 m_skip_open_parent_image(skip_open_parent
),
34 m_on_finish(create_async_context_callback(m_image_ctx
, on_finish
)),
35 m_error_result(0), m_flush_aio(false), m_exclusive_lock(nullptr),
36 m_object_map(nullptr), m_journal(nullptr), m_refresh_parent(nullptr) {
40 RefreshRequest
<I
>::~RefreshRequest() {
41 // these require state machine to close
42 assert(m_exclusive_lock
== nullptr);
43 assert(m_object_map
== nullptr);
44 assert(m_journal
== nullptr);
45 assert(m_refresh_parent
== nullptr);
46 assert(!m_blocked_writes
);
50 void RefreshRequest
<I
>::send() {
51 if (m_image_ctx
.old_format
) {
52 send_v1_read_header();
54 send_v2_get_mutable_metadata();
59 void RefreshRequest
<I
>::send_v1_read_header() {
60 CephContext
*cct
= m_image_ctx
.cct
;
61 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
63 librados::ObjectReadOperation op
;
64 op
.read(0, 0, nullptr, nullptr);
66 using klass
= RefreshRequest
<I
>;
67 librados::AioCompletion
*comp
= create_rados_callback
<
68 klass
, &klass::handle_v1_read_header
>(this);
70 int r
= m_image_ctx
.md_ctx
.aio_operate(m_image_ctx
.header_oid
, comp
, &op
,
77 Context
*RefreshRequest
<I
>::handle_v1_read_header(int *result
) {
78 CephContext
*cct
= m_image_ctx
.cct
;
79 ldout(cct
, 10) << this << " " << __func__
<< ": " << "r=" << *result
<< dendl
;
81 rbd_obj_header_ondisk v1_header
;
84 } else if (m_out_bl
.length() < sizeof(v1_header
)) {
85 lderr(cct
) << "v1 header too small" << dendl
;
88 } else if (memcmp(RBD_HEADER_TEXT
, m_out_bl
.c_str(),
89 sizeof(RBD_HEADER_TEXT
)) != 0) {
90 lderr(cct
) << "unrecognized v1 header" << dendl
;
95 memcpy(&v1_header
, m_out_bl
.c_str(), sizeof(v1_header
));
96 m_order
= v1_header
.options
.order
;
97 m_size
= v1_header
.image_size
;
98 m_object_prefix
= v1_header
.block_name
;
99 send_v1_get_snapshots();
103 template <typename I
>
104 void RefreshRequest
<I
>::send_v1_get_snapshots() {
105 CephContext
*cct
= m_image_ctx
.cct
;
106 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
108 librados::ObjectReadOperation op
;
109 cls_client::old_snapshot_list_start(&op
);
111 using klass
= RefreshRequest
<I
>;
112 librados::AioCompletion
*comp
= create_rados_callback
<
113 klass
, &klass::handle_v1_get_snapshots
>(this);
115 int r
= m_image_ctx
.md_ctx
.aio_operate(m_image_ctx
.header_oid
, comp
, &op
,
121 template <typename I
>
122 Context
*RefreshRequest
<I
>::handle_v1_get_snapshots(int *result
) {
123 CephContext
*cct
= m_image_ctx
.cct
;
124 ldout(cct
, 10) << this << " " << __func__
<< ": " << "r=" << *result
<< dendl
;
127 bufferlist::iterator it
= m_out_bl
.begin();
128 *result
= cls_client::old_snapshot_list_finish(
129 &it
, &m_snap_names
, &m_snap_sizes
, &m_snapc
);
133 lderr(cct
) << "failed to retrieve v1 snapshots: " << cpp_strerror(*result
)
138 if (!m_snapc
.is_valid()) {
139 lderr(cct
) << "v1 image snap context is invalid" << dendl
;
144 //m_snap_namespaces = {m_snap_names.size(), cls::rbd::UserSnapshotNamespace()};
145 m_snap_namespaces
= std::vector
<cls::rbd::SnapshotNamespace
>(
147 cls::rbd::UserSnapshotNamespace());
149 m_snap_timestamps
= std::vector
<utime_t
>(m_snap_names
.size(), utime_t());
155 template <typename I
>
156 void RefreshRequest
<I
>::send_v1_get_locks() {
157 CephContext
*cct
= m_image_ctx
.cct
;
158 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
160 librados::ObjectReadOperation op
;
161 rados::cls::lock::get_lock_info_start(&op
, RBD_LOCK_NAME
);
163 using klass
= RefreshRequest
<I
>;
164 librados::AioCompletion
*comp
= create_rados_callback
<
165 klass
, &klass::handle_v1_get_locks
>(this);
167 int r
= m_image_ctx
.md_ctx
.aio_operate(m_image_ctx
.header_oid
, comp
, &op
,
173 template <typename I
>
174 Context
*RefreshRequest
<I
>::handle_v1_get_locks(int *result
) {
175 CephContext
*cct
= m_image_ctx
.cct
;
176 ldout(cct
, 10) << this << " " << __func__
<< ": "
177 << "r=" << *result
<< dendl
;
179 // If EOPNOTSUPP, treat image as if there are no locks (we can't
181 if (*result
== -EOPNOTSUPP
) {
183 } else if (*result
== 0) {
184 bufferlist::iterator it
= m_out_bl
.begin();
185 ClsLockType lock_type
;
186 *result
= rados::cls::lock::get_lock_info_finish(&it
, &m_lockers
,
187 &lock_type
, &m_lock_tag
);
189 m_exclusive_locked
= (lock_type
== LOCK_EXCLUSIVE
);
193 lderr(cct
) << "failed to retrieve locks: " << cpp_strerror(*result
)
202 template <typename I
>
203 void RefreshRequest
<I
>::send_v1_apply() {
204 CephContext
*cct
= m_image_ctx
.cct
;
205 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
207 // ensure we are not in a rados callback when applying updates
208 using klass
= RefreshRequest
<I
>;
209 Context
*ctx
= create_context_callback
<
210 klass
, &klass::handle_v1_apply
>(this);
211 m_image_ctx
.op_work_queue
->queue(ctx
, 0);
214 template <typename I
>
215 Context
*RefreshRequest
<I
>::handle_v1_apply(int *result
) {
216 CephContext
*cct
= m_image_ctx
.cct
;
217 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
220 return send_flush_aio();
223 template <typename I
>
224 void RefreshRequest
<I
>::send_v2_get_mutable_metadata() {
225 CephContext
*cct
= m_image_ctx
.cct
;
226 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
230 RWLock::RLocker
snap_locker(m_image_ctx
.snap_lock
);
231 snap_id
= m_image_ctx
.snap_id
;
234 bool read_only
= m_image_ctx
.read_only
|| snap_id
!= CEPH_NOSNAP
;
235 librados::ObjectReadOperation op
;
236 cls_client::get_mutable_metadata_start(&op
, read_only
);
238 using klass
= RefreshRequest
<I
>;
239 librados::AioCompletion
*comp
= create_rados_callback
<
240 klass
, &klass::handle_v2_get_mutable_metadata
>(this);
242 int r
= m_image_ctx
.md_ctx
.aio_operate(m_image_ctx
.header_oid
, comp
, &op
,
248 template <typename I
>
249 Context
*RefreshRequest
<I
>::handle_v2_get_mutable_metadata(int *result
) {
250 CephContext
*cct
= m_image_ctx
.cct
;
251 ldout(cct
, 10) << this << " " << __func__
<< ": "
252 << "r=" << *result
<< dendl
;
255 bufferlist::iterator it
= m_out_bl
.begin();
256 *result
= cls_client::get_mutable_metadata_finish(&it
, &m_size
, &m_features
,
257 &m_incompatible_features
,
260 &m_lock_tag
, &m_snapc
,
264 lderr(cct
) << "failed to retrieve mutable metadata: "
265 << cpp_strerror(*result
) << dendl
;
269 uint64_t unsupported
= m_incompatible_features
& ~RBD_FEATURES_ALL
;
270 if (unsupported
!= 0ULL) {
271 lderr(cct
) << "Image uses unsupported features: " << unsupported
<< dendl
;
276 if (!m_snapc
.is_valid()) {
277 lderr(cct
) << "image snap context is invalid!" << dendl
;
282 if (m_acquiring_lock
&& (m_features
& RBD_FEATURE_EXCLUSIVE_LOCK
) == 0) {
283 ldout(cct
, 5) << "ignoring dynamically disabled exclusive lock" << dendl
;
284 m_features
|= RBD_FEATURE_EXCLUSIVE_LOCK
;
285 m_incomplete_update
= true;
292 template <typename I
>
293 void RefreshRequest
<I
>::send_v2_get_flags() {
294 CephContext
*cct
= m_image_ctx
.cct
;
295 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
297 librados::ObjectReadOperation op
;
298 cls_client::get_flags_start(&op
, m_snapc
.snaps
);
300 using klass
= RefreshRequest
<I
>;
301 librados::AioCompletion
*comp
= create_rados_callback
<
302 klass
, &klass::handle_v2_get_flags
>(this);
304 int r
= m_image_ctx
.md_ctx
.aio_operate(m_image_ctx
.header_oid
, comp
, &op
,
310 template <typename I
>
311 Context
*RefreshRequest
<I
>::handle_v2_get_flags(int *result
) {
312 CephContext
*cct
= m_image_ctx
.cct
;
313 ldout(cct
, 10) << this << " " << __func__
<< ": "
314 << "r=" << *result
<< dendl
;
317 bufferlist::iterator it
= m_out_bl
.begin();
318 cls_client::get_flags_finish(&it
, &m_flags
, m_snapc
.snaps
, &m_snap_flags
);
320 if (*result
== -EOPNOTSUPP
) {
321 // Older OSD doesn't support RBD flags, need to assume the worst
323 ldout(cct
, 10) << "OSD does not support RBD flags, disabling object map "
324 << "optimizations" << dendl
;
325 m_flags
= RBD_FLAG_OBJECT_MAP_INVALID
;
326 if ((m_features
& RBD_FEATURE_FAST_DIFF
) != 0) {
327 m_flags
|= RBD_FLAG_FAST_DIFF_INVALID
;
330 std::vector
<uint64_t> default_flags(m_snapc
.snaps
.size(), m_flags
);
331 m_snap_flags
= std::move(default_flags
);
332 } else if (*result
== -ENOENT
) {
333 ldout(cct
, 10) << "out-of-sync snapshot state detected" << dendl
;
334 send_v2_get_mutable_metadata();
336 } else if (*result
< 0) {
337 lderr(cct
) << "failed to retrieve flags: " << cpp_strerror(*result
)
346 template <typename I
>
347 void RefreshRequest
<I
>::send_v2_get_group() {
348 CephContext
*cct
= m_image_ctx
.cct
;
349 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
351 librados::ObjectReadOperation op
;
352 cls_client::image_get_group_start(&op
);
354 using klass
= RefreshRequest
<I
>;
355 librados::AioCompletion
*comp
= create_rados_callback
<
356 klass
, &klass::handle_v2_get_group
>(this);
358 int r
= m_image_ctx
.md_ctx
.aio_operate(m_image_ctx
.header_oid
, comp
, &op
,
364 template <typename I
>
365 Context
*RefreshRequest
<I
>::handle_v2_get_group(int *result
) {
366 CephContext
*cct
= m_image_ctx
.cct
;
367 ldout(cct
, 10) << this << " " << __func__
<< ": "
368 << "r=" << *result
<< dendl
;
371 bufferlist::iterator it
= m_out_bl
.begin();
372 cls_client::image_get_group_finish(&it
, &m_group_spec
);
374 if (*result
== -EOPNOTSUPP
) {
375 // Older OSD doesn't support RBD groups
377 ldout(cct
, 10) << "OSD does not support consistency groups" << dendl
;
378 } else if (*result
< 0) {
379 lderr(cct
) << "failed to retrieve group: " << cpp_strerror(*result
)
384 send_v2_get_snapshots();
388 template <typename I
>
389 void RefreshRequest
<I
>::send_v2_get_snapshots() {
390 if (m_snapc
.snaps
.empty()) {
391 m_snap_names
.clear();
392 m_snap_namespaces
.clear();
393 m_snap_sizes
.clear();
394 m_snap_parents
.clear();
395 m_snap_protection
.clear();
396 m_snap_timestamps
.clear();
397 send_v2_refresh_parent();
401 CephContext
*cct
= m_image_ctx
.cct
;
402 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
404 librados::ObjectReadOperation op
;
405 cls_client::snapshot_list_start(&op
, m_snapc
.snaps
);
407 using klass
= RefreshRequest
<I
>;
408 librados::AioCompletion
*comp
= create_rados_callback
<
409 klass
, &klass::handle_v2_get_snapshots
>(this);
411 int r
= m_image_ctx
.md_ctx
.aio_operate(m_image_ctx
.header_oid
, comp
, &op
,
417 template <typename I
>
418 Context
*RefreshRequest
<I
>::handle_v2_get_snapshots(int *result
) {
419 CephContext
*cct
= m_image_ctx
.cct
;
420 ldout(cct
, 10) << this << " " << __func__
<< ": "
421 << "r=" << *result
<< dendl
;
424 bufferlist::iterator it
= m_out_bl
.begin();
425 *result
= cls_client::snapshot_list_finish(&it
, m_snapc
.snaps
,
431 if (*result
== -ENOENT
) {
432 ldout(cct
, 10) << "out-of-sync snapshot state detected" << dendl
;
433 send_v2_get_mutable_metadata();
435 } else if (*result
< 0) {
436 lderr(cct
) << "failed to retrieve snapshots: " << cpp_strerror(*result
)
441 send_v2_get_snap_timestamps();
445 template <typename I
>
446 void RefreshRequest
<I
>::send_v2_get_snap_timestamps() {
447 CephContext
*cct
= m_image_ctx
.cct
;
448 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
450 librados::ObjectReadOperation op
;
451 cls_client::snapshot_timestamp_list_start(&op
, m_snapc
.snaps
);
453 using klass
= RefreshRequest
<I
>;
454 librados::AioCompletion
*comp
= create_rados_callback
<
455 klass
, &klass::handle_v2_get_snap_timestamps
>(this);
457 int r
= m_image_ctx
.md_ctx
.aio_operate(m_image_ctx
.header_oid
, comp
, &op
,
463 template <typename I
>
464 Context
*RefreshRequest
<I
>::handle_v2_get_snap_timestamps(int *result
) {
465 CephContext
*cct
= m_image_ctx
.cct
;
466 ldout(cct
, 10) << this << " " << __func__
<< ": " << "r=" << *result
<< dendl
;
469 bufferlist::iterator it
= m_out_bl
.begin();
470 *result
= cls_client::snapshot_timestamp_list_finish(&it
, m_snapc
.snaps
, &m_snap_timestamps
);
472 if (*result
== -ENOENT
) {
473 ldout(cct
, 10) << "out-of-sync snapshot state detected" << dendl
;
474 send_v2_get_mutable_metadata();
476 } else if (*result
== -EOPNOTSUPP
) {
477 m_snap_timestamps
= std::vector
<utime_t
>(m_snap_names
.size(), utime_t());
478 // Ignore it means no snap timestamps are available
479 } else if (*result
< 0) {
480 lderr(cct
) << "failed to retrieve snapshots: " << cpp_strerror(*result
)
485 send_v2_get_snap_namespaces();
489 template <typename I
>
490 void RefreshRequest
<I
>::send_v2_get_snap_namespaces() {
491 CephContext
*cct
= m_image_ctx
.cct
;
492 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
494 librados::ObjectReadOperation op
;
495 cls_client::snapshot_namespace_list_start(&op
, m_snapc
.snaps
);
497 using klass
= RefreshRequest
<I
>;
498 librados::AioCompletion
*comp
= create_rados_callback
<
499 klass
, &klass::handle_v2_get_snap_namespaces
>(this);
501 int r
= m_image_ctx
.md_ctx
.aio_operate(m_image_ctx
.header_oid
, comp
, &op
,
507 template <typename I
>
508 Context
*RefreshRequest
<I
>::handle_v2_get_snap_namespaces(int *result
) {
509 CephContext
*cct
= m_image_ctx
.cct
;
510 ldout(cct
, 10) << this << " " << __func__
<< ": "
511 << "r=" << *result
<< dendl
;
514 bufferlist::iterator it
= m_out_bl
.begin();
515 *result
= cls_client::snapshot_namespace_list_finish(&it
, m_snapc
.snaps
,
518 if (*result
== -ENOENT
) {
519 ldout(cct
, 10) << "out-of-sync snapshot state detected" << dendl
;
520 send_v2_get_mutable_metadata();
522 } else if (*result
== -EOPNOTSUPP
) {
523 m_snap_namespaces
= std::vector
524 <cls::rbd::SnapshotNamespace
>(
526 cls::rbd::UserSnapshotNamespace());
527 // Ignore it means no snap namespaces are available
528 } else if (*result
< 0) {
529 lderr(cct
) << "failed to retrieve snapshots: " << cpp_strerror(*result
)
534 send_v2_refresh_parent();
538 template <typename I
>
539 void RefreshRequest
<I
>::send_v2_refresh_parent() {
541 RWLock::RLocker
snap_locker(m_image_ctx
.snap_lock
);
542 RWLock::RLocker
parent_locker(m_image_ctx
.parent_lock
);
544 ParentInfo parent_md
;
545 int r
= get_parent_info(m_image_ctx
.snap_id
, &parent_md
);
546 if (!m_skip_open_parent_image
&& (r
< 0 ||
547 RefreshParentRequest
<I
>::is_refresh_required(m_image_ctx
, parent_md
))) {
548 CephContext
*cct
= m_image_ctx
.cct
;
549 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
551 using klass
= RefreshRequest
<I
>;
552 Context
*ctx
= create_context_callback
<
553 klass
, &klass::handle_v2_refresh_parent
>(this);
554 m_refresh_parent
= RefreshParentRequest
<I
>::create(
555 m_image_ctx
, parent_md
, ctx
);
559 if (m_refresh_parent
!= nullptr) {
560 m_refresh_parent
->send();
562 send_v2_init_exclusive_lock();
566 template <typename I
>
567 Context
*RefreshRequest
<I
>::handle_v2_refresh_parent(int *result
) {
568 CephContext
*cct
= m_image_ctx
.cct
;
569 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
572 lderr(cct
) << "failed to refresh parent image: " << cpp_strerror(*result
)
579 send_v2_init_exclusive_lock();
583 template <typename I
>
584 void RefreshRequest
<I
>::send_v2_init_exclusive_lock() {
585 if ((m_features
& RBD_FEATURE_EXCLUSIVE_LOCK
) == 0 ||
586 m_image_ctx
.read_only
|| !m_image_ctx
.snap_name
.empty() ||
587 m_image_ctx
.exclusive_lock
!= nullptr) {
588 send_v2_open_object_map();
592 // implies exclusive lock dynamically enabled or image open in-progress
593 CephContext
*cct
= m_image_ctx
.cct
;
594 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
596 // TODO need safe shut down
597 m_exclusive_lock
= m_image_ctx
.create_exclusive_lock();
599 using klass
= RefreshRequest
<I
>;
600 Context
*ctx
= create_context_callback
<
601 klass
, &klass::handle_v2_init_exclusive_lock
>(this);
603 RWLock::RLocker
owner_locker(m_image_ctx
.owner_lock
);
604 m_exclusive_lock
->init(m_features
, ctx
);
607 template <typename I
>
608 Context
*RefreshRequest
<I
>::handle_v2_init_exclusive_lock(int *result
) {
609 CephContext
*cct
= m_image_ctx
.cct
;
610 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
613 lderr(cct
) << "failed to initialize exclusive lock: "
614 << cpp_strerror(*result
) << dendl
;
618 // object map and journal will be opened when exclusive lock is
619 // acquired (if features are enabled)
624 template <typename I
>
625 void RefreshRequest
<I
>::send_v2_open_journal() {
626 bool journal_disabled
= (
627 (m_features
& RBD_FEATURE_JOURNALING
) == 0 ||
628 m_image_ctx
.read_only
||
629 !m_image_ctx
.snap_name
.empty() ||
630 m_image_ctx
.journal
!= nullptr ||
631 m_image_ctx
.exclusive_lock
== nullptr ||
632 !m_image_ctx
.exclusive_lock
->is_lock_owner());
633 bool journal_disabled_by_policy
;
635 RWLock::RLocker
snap_locker(m_image_ctx
.snap_lock
);
636 journal_disabled_by_policy
= (
638 m_image_ctx
.get_journal_policy()->journal_disabled());
641 if (journal_disabled
|| journal_disabled_by_policy
) {
642 // journal dynamically enabled -- doesn't own exclusive lock
643 if ((m_features
& RBD_FEATURE_JOURNALING
) != 0 &&
644 !journal_disabled_by_policy
&&
645 m_image_ctx
.exclusive_lock
!= nullptr &&
646 m_image_ctx
.journal
== nullptr) {
647 m_image_ctx
.io_work_queue
->set_require_lock(librbd::io::DIRECTION_BOTH
,
650 send_v2_block_writes();
654 // implies journal dynamically enabled since ExclusiveLock will init
655 // the journal upon acquiring the lock
656 CephContext
*cct
= m_image_ctx
.cct
;
657 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
659 using klass
= RefreshRequest
<I
>;
660 Context
*ctx
= create_context_callback
<
661 klass
, &klass::handle_v2_open_journal
>(this);
663 // TODO need safe close
664 m_journal
= m_image_ctx
.create_journal();
665 m_journal
->open(ctx
);
668 template <typename I
>
669 Context
*RefreshRequest
<I
>::handle_v2_open_journal(int *result
) {
670 CephContext
*cct
= m_image_ctx
.cct
;
671 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
674 lderr(cct
) << "failed to initialize journal: " << cpp_strerror(*result
)
679 send_v2_block_writes();
683 template <typename I
>
684 void RefreshRequest
<I
>::send_v2_block_writes() {
685 bool disabled_journaling
= false;
687 RWLock::RLocker
snap_locker(m_image_ctx
.snap_lock
);
688 disabled_journaling
= ((m_features
& RBD_FEATURE_EXCLUSIVE_LOCK
) != 0 &&
689 (m_features
& RBD_FEATURE_JOURNALING
) == 0 &&
690 m_image_ctx
.journal
!= nullptr);
693 if (!disabled_journaling
) {
698 CephContext
*cct
= m_image_ctx
.cct
;
699 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
701 // we need to block writes temporarily to avoid in-flight journal
703 m_blocked_writes
= true;
704 Context
*ctx
= create_context_callback
<
705 RefreshRequest
<I
>, &RefreshRequest
<I
>::handle_v2_block_writes
>(this);
707 RWLock::RLocker
owner_locker(m_image_ctx
.owner_lock
);
708 m_image_ctx
.io_work_queue
->block_writes(ctx
);
711 template <typename I
>
712 Context
*RefreshRequest
<I
>::handle_v2_block_writes(int *result
) {
713 CephContext
*cct
= m_image_ctx
.cct
;
714 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
717 lderr(cct
) << "failed to block writes: " << cpp_strerror(*result
)
725 template <typename I
>
726 void RefreshRequest
<I
>::send_v2_open_object_map() {
727 if ((m_features
& RBD_FEATURE_OBJECT_MAP
) == 0 ||
728 m_image_ctx
.object_map
!= nullptr ||
729 (m_image_ctx
.snap_name
.empty() &&
730 (m_image_ctx
.read_only
||
731 m_image_ctx
.exclusive_lock
== nullptr ||
732 !m_image_ctx
.exclusive_lock
->is_lock_owner()))) {
733 send_v2_open_journal();
737 // implies object map dynamically enabled or image open in-progress
738 // since SetSnapRequest loads the object map for a snapshot and
739 // ExclusiveLock loads the object map for HEAD
740 CephContext
*cct
= m_image_ctx
.cct
;
741 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
743 if (m_image_ctx
.snap_name
.empty()) {
744 m_object_map
= m_image_ctx
.create_object_map(CEPH_NOSNAP
);
746 for (size_t snap_idx
= 0; snap_idx
< m_snap_names
.size(); ++snap_idx
) {
747 if (m_snap_names
[snap_idx
] == m_image_ctx
.snap_name
) {
748 m_object_map
= m_image_ctx
.create_object_map(
749 m_snapc
.snaps
[snap_idx
].val
);
754 if (m_object_map
== nullptr) {
755 lderr(cct
) << "failed to locate snapshot: " << m_image_ctx
.snap_name
757 send_v2_open_journal();
762 using klass
= RefreshRequest
<I
>;
763 Context
*ctx
= create_context_callback
<
764 klass
, &klass::handle_v2_open_object_map
>(this);
765 m_object_map
->open(ctx
);
768 template <typename I
>
769 Context
*RefreshRequest
<I
>::handle_v2_open_object_map(int *result
) {
770 CephContext
*cct
= m_image_ctx
.cct
;
771 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
774 lderr(cct
) << "failed to open object map: " << cpp_strerror(*result
)
777 m_object_map
= nullptr;
780 send_v2_open_journal();
784 template <typename I
>
785 void RefreshRequest
<I
>::send_v2_apply() {
786 CephContext
*cct
= m_image_ctx
.cct
;
787 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
789 // ensure we are not in a rados callback when applying updates
790 using klass
= RefreshRequest
<I
>;
791 Context
*ctx
= create_context_callback
<
792 klass
, &klass::handle_v2_apply
>(this);
793 m_image_ctx
.op_work_queue
->queue(ctx
, 0);
796 template <typename I
>
797 Context
*RefreshRequest
<I
>::handle_v2_apply(int *result
) {
798 CephContext
*cct
= m_image_ctx
.cct
;
799 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
803 return send_v2_finalize_refresh_parent();
806 template <typename I
>
807 Context
*RefreshRequest
<I
>::send_v2_finalize_refresh_parent() {
808 if (m_refresh_parent
== nullptr) {
809 return send_v2_shut_down_exclusive_lock();
812 CephContext
*cct
= m_image_ctx
.cct
;
813 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
815 using klass
= RefreshRequest
<I
>;
816 Context
*ctx
= create_context_callback
<
817 klass
, &klass::handle_v2_finalize_refresh_parent
>(this);
818 m_refresh_parent
->finalize(ctx
);
822 template <typename I
>
823 Context
*RefreshRequest
<I
>::handle_v2_finalize_refresh_parent(int *result
) {
824 CephContext
*cct
= m_image_ctx
.cct
;
825 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
827 assert(m_refresh_parent
!= nullptr);
828 delete m_refresh_parent
;
829 m_refresh_parent
= nullptr;
831 return send_v2_shut_down_exclusive_lock();
834 template <typename I
>
835 Context
*RefreshRequest
<I
>::send_v2_shut_down_exclusive_lock() {
836 if (m_exclusive_lock
== nullptr) {
837 return send_v2_close_journal();
840 CephContext
*cct
= m_image_ctx
.cct
;
841 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
843 // exclusive lock feature was dynamically disabled. in-flight IO will be
844 // flushed and in-flight requests will be canceled before releasing lock
845 using klass
= RefreshRequest
<I
>;
846 Context
*ctx
= create_context_callback
<
847 klass
, &klass::handle_v2_shut_down_exclusive_lock
>(this);
848 m_exclusive_lock
->shut_down(ctx
);
852 template <typename I
>
853 Context
*RefreshRequest
<I
>::handle_v2_shut_down_exclusive_lock(int *result
) {
854 CephContext
*cct
= m_image_ctx
.cct
;
855 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
858 lderr(cct
) << "failed to shut down exclusive lock: "
859 << cpp_strerror(*result
) << dendl
;
864 RWLock::WLocker
owner_locker(m_image_ctx
.owner_lock
);
865 assert(m_image_ctx
.exclusive_lock
== nullptr);
868 assert(m_exclusive_lock
!= nullptr);
869 delete m_exclusive_lock
;
870 m_exclusive_lock
= nullptr;
872 return send_v2_close_journal();
875 template <typename I
>
876 Context
*RefreshRequest
<I
>::send_v2_close_journal() {
877 if (m_journal
== nullptr) {
878 return send_v2_close_object_map();
881 CephContext
*cct
= m_image_ctx
.cct
;
882 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
884 // journal feature was dynamically disabled
885 using klass
= RefreshRequest
<I
>;
886 Context
*ctx
= create_context_callback
<
887 klass
, &klass::handle_v2_close_journal
>(this);
888 m_journal
->close(ctx
);
892 template <typename I
>
893 Context
*RefreshRequest
<I
>::handle_v2_close_journal(int *result
) {
894 CephContext
*cct
= m_image_ctx
.cct
;
895 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
899 lderr(cct
) << "failed to close journal: " << cpp_strerror(*result
)
903 assert(m_journal
!= nullptr);
907 assert(m_blocked_writes
);
908 m_blocked_writes
= false;
910 m_image_ctx
.io_work_queue
->unblock_writes();
911 return send_v2_close_object_map();
914 template <typename I
>
915 Context
*RefreshRequest
<I
>::send_v2_close_object_map() {
916 if (m_object_map
== nullptr) {
917 return send_flush_aio();
920 CephContext
*cct
= m_image_ctx
.cct
;
921 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
923 // object map was dynamically disabled
924 using klass
= RefreshRequest
<I
>;
925 Context
*ctx
= create_context_callback
<
926 klass
, &klass::handle_v2_close_object_map
>(this);
927 m_object_map
->close(ctx
);
931 template <typename I
>
932 Context
*RefreshRequest
<I
>::handle_v2_close_object_map(int *result
) {
933 CephContext
*cct
= m_image_ctx
.cct
;
934 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
936 assert(*result
== 0);
937 assert(m_object_map
!= nullptr);
939 m_object_map
= nullptr;
941 return send_flush_aio();
944 template <typename I
>
945 Context
*RefreshRequest
<I
>::send_flush_aio() {
946 if (m_incomplete_update
&& m_error_result
== 0) {
947 // if this was a partial refresh, notify ImageState
948 m_error_result
= -ERESTART
;
952 CephContext
*cct
= m_image_ctx
.cct
;
953 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
955 RWLock::RLocker
owner_lock(m_image_ctx
.owner_lock
);
956 using klass
= RefreshRequest
<I
>;
957 Context
*ctx
= create_context_callback
<
958 klass
, &klass::handle_flush_aio
>(this);
959 m_image_ctx
.flush(ctx
);
961 } else if (m_error_result
< 0) {
962 // propagate saved error back to caller
963 Context
*ctx
= create_context_callback
<
964 RefreshRequest
<I
>, &RefreshRequest
<I
>::handle_error
>(this);
965 m_image_ctx
.op_work_queue
->queue(ctx
, 0);
972 template <typename I
>
973 Context
*RefreshRequest
<I
>::handle_flush_aio(int *result
) {
974 CephContext
*cct
= m_image_ctx
.cct
;
975 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
978 lderr(cct
) << "failed to flush pending AIO: " << cpp_strerror(*result
)
982 return handle_error(result
);
985 template <typename I
>
986 Context
*RefreshRequest
<I
>::handle_error(int *result
) {
987 if (m_error_result
< 0) {
988 *result
= m_error_result
;
990 CephContext
*cct
= m_image_ctx
.cct
;
991 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
996 template <typename I
>
997 void RefreshRequest
<I
>::apply() {
998 CephContext
*cct
= m_image_ctx
.cct
;
999 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
1001 RWLock::WLocker
owner_locker(m_image_ctx
.owner_lock
);
1002 RWLock::WLocker
md_locker(m_image_ctx
.md_lock
);
1005 Mutex::Locker
cache_locker(m_image_ctx
.cache_lock
);
1006 RWLock::WLocker
snap_locker(m_image_ctx
.snap_lock
);
1007 RWLock::WLocker
parent_locker(m_image_ctx
.parent_lock
);
1009 m_image_ctx
.size
= m_size
;
1010 m_image_ctx
.lockers
= m_lockers
;
1011 m_image_ctx
.lock_tag
= m_lock_tag
;
1012 m_image_ctx
.exclusive_locked
= m_exclusive_locked
;
1014 if (m_image_ctx
.old_format
) {
1015 m_image_ctx
.order
= m_order
;
1016 m_image_ctx
.features
= 0;
1017 m_image_ctx
.flags
= 0;
1018 m_image_ctx
.object_prefix
= std::move(m_object_prefix
);
1019 m_image_ctx
.init_layout();
1021 m_image_ctx
.features
= m_features
;
1022 m_image_ctx
.flags
= m_flags
;
1023 m_image_ctx
.group_spec
= m_group_spec
;
1024 m_image_ctx
.parent_md
= m_parent_md
;
1027 for (size_t i
= 0; i
< m_snapc
.snaps
.size(); ++i
) {
1028 std::vector
<librados::snap_t
>::const_iterator it
= std::find(
1029 m_image_ctx
.snaps
.begin(), m_image_ctx
.snaps
.end(),
1030 m_snapc
.snaps
[i
].val
);
1031 if (it
== m_image_ctx
.snaps
.end()) {
1033 ldout(cct
, 20) << "new snapshot id=" << m_snapc
.snaps
[i
].val
1034 << " name=" << m_snap_names
[i
]
1035 << " size=" << m_snap_sizes
[i
]
1040 m_image_ctx
.snaps
.clear();
1041 m_image_ctx
.snap_info
.clear();
1042 m_image_ctx
.snap_ids
.clear();
1043 for (size_t i
= 0; i
< m_snapc
.snaps
.size(); ++i
) {
1044 uint64_t flags
= m_image_ctx
.old_format
? 0 : m_snap_flags
[i
];
1045 uint8_t protection_status
= m_image_ctx
.old_format
?
1046 static_cast<uint8_t>(RBD_PROTECTION_STATUS_UNPROTECTED
) :
1047 m_snap_protection
[i
];
1049 if (!m_image_ctx
.old_format
) {
1050 parent
= m_snap_parents
[i
];
1053 m_image_ctx
.add_snap(m_snap_namespaces
[i
], m_snap_names
[i
],
1054 m_snapc
.snaps
[i
].val
, m_snap_sizes
[i
], parent
,
1055 protection_status
, flags
, m_snap_timestamps
[i
]);
1057 m_image_ctx
.snapc
= m_snapc
;
1059 if (m_image_ctx
.snap_id
!= CEPH_NOSNAP
&&
1060 m_image_ctx
.get_snap_id(m_image_ctx
.snap_namespace
,
1061 m_image_ctx
.snap_name
) != m_image_ctx
.snap_id
) {
1062 lderr(cct
) << "tried to read from a snapshot that no longer exists: "
1063 << m_image_ctx
.snap_name
<< dendl
;
1064 m_image_ctx
.snap_exists
= false;
1067 if (m_refresh_parent
!= nullptr) {
1068 m_refresh_parent
->apply();
1070 m_image_ctx
.data_ctx
.selfmanaged_snap_set_write_ctx(m_image_ctx
.snapc
.seq
,
1073 // handle dynamically enabled / disabled features
1074 if (m_image_ctx
.exclusive_lock
!= nullptr &&
1075 !m_image_ctx
.test_features(RBD_FEATURE_EXCLUSIVE_LOCK
,
1076 m_image_ctx
.snap_lock
)) {
1077 // disabling exclusive lock will automatically handle closing
1078 // object map and journaling
1079 assert(m_exclusive_lock
== nullptr);
1080 m_exclusive_lock
= m_image_ctx
.exclusive_lock
;
1082 if (m_exclusive_lock
!= nullptr) {
1083 assert(m_image_ctx
.exclusive_lock
== nullptr);
1084 std::swap(m_exclusive_lock
, m_image_ctx
.exclusive_lock
);
1086 if (!m_image_ctx
.test_features(RBD_FEATURE_JOURNALING
,
1087 m_image_ctx
.snap_lock
)) {
1088 if (!m_image_ctx
.clone_copy_on_read
&& m_image_ctx
.journal
!= nullptr) {
1089 m_image_ctx
.io_work_queue
->set_require_lock(io::DIRECTION_READ
,
1092 std::swap(m_journal
, m_image_ctx
.journal
);
1093 } else if (m_journal
!= nullptr) {
1094 std::swap(m_journal
, m_image_ctx
.journal
);
1096 if (!m_image_ctx
.test_features(RBD_FEATURE_OBJECT_MAP
,
1097 m_image_ctx
.snap_lock
) ||
1098 m_object_map
!= nullptr) {
1099 std::swap(m_object_map
, m_image_ctx
.object_map
);
1105 template <typename I
>
1106 int RefreshRequest
<I
>::get_parent_info(uint64_t snap_id
,
1107 ParentInfo
*parent_md
) {
1108 if (snap_id
== CEPH_NOSNAP
) {
1109 *parent_md
= m_parent_md
;
1112 for (size_t i
= 0; i
< m_snapc
.snaps
.size(); ++i
) {
1113 if (m_snapc
.snaps
[i
].val
== snap_id
) {
1114 *parent_md
= m_snap_parents
[i
];
1122 } // namespace image
1123 } // namespace librbd
1125 template class librbd::image::RefreshRequest
<librbd::ImageCtx
>;