1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/mirror/snapshot/PromoteRequest.h"
5 #include "common/Timer.h"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "cls/rbd/cls_rbd_client.h"
9 #include "librbd/ExclusiveLock.h"
10 #include "librbd/ImageCtx.h"
11 #include "librbd/ImageState.h"
12 #include "librbd/Operations.h"
13 #include "librbd/Utils.h"
14 #include "librbd/image/ListWatchersRequest.h"
15 #include "librbd/mirror/snapshot/CreateNonPrimaryRequest.h"
16 #include "librbd/mirror/snapshot/CreatePrimaryRequest.h"
17 #include "librbd/mirror/snapshot/Utils.h"
19 #define dout_subsys ceph_subsys_rbd
21 #define dout_prefix *_dout << "librbd::mirror::snapshot::PromoteRequest: " \
22 << this << " " << __func__ << ": "
28 using librbd::util::create_async_context_callback
;
29 using librbd::util::create_context_callback
;
30 using librbd::util::create_rados_callback
;
33 void PromoteRequest
<I
>::send() {
34 CephContext
*cct
= m_image_ctx
->cct
;
35 bool requires_orphan
= false;
36 if (!util::can_create_primary_snapshot(m_image_ctx
, false, true,
38 &m_rollback_snap_id
)) {
39 lderr(cct
) << "cannot promote" << dendl
;
42 } else if (m_rollback_snap_id
== CEPH_NOSNAP
&& !requires_orphan
) {
43 create_promote_snapshot();
47 ldout(cct
, 20) << "requires_orphan=" << requires_orphan
<< ", "
48 << "rollback_snap_id=" << m_rollback_snap_id
<< dendl
;
49 create_orphan_snapshot();
53 void PromoteRequest
<I
>::create_orphan_snapshot() {
54 CephContext
*cct
= m_image_ctx
->cct
;
55 ldout(cct
, 20) << dendl
;
57 auto ctx
= create_context_callback
<
59 &PromoteRequest
<I
>::handle_create_orphan_snapshot
>(this);
61 auto req
= CreateNonPrimaryRequest
<I
>::create(
62 m_image_ctx
, false, "", CEPH_NOSNAP
, {}, {}, nullptr, ctx
);
67 void PromoteRequest
<I
>::handle_create_orphan_snapshot(int r
) {
68 CephContext
*cct
= m_image_ctx
->cct
;
69 ldout(cct
, 20) << "r=" << r
<< dendl
;
72 lderr(cct
) << "failed to create orphan snapshot: " << cpp_strerror(r
)
82 void PromoteRequest
<I
>::list_watchers() {
83 CephContext
*cct
= m_image_ctx
->cct
;
84 ldout(cct
, 20) << dendl
;
86 auto ctx
= create_context_callback
<
88 &PromoteRequest
<I
>::handle_list_watchers
>(this);
91 auto flags
= librbd::image::LIST_WATCHERS_FILTER_OUT_MY_INSTANCE
|
92 librbd::image::LIST_WATCHERS_MIRROR_INSTANCES_ONLY
;
93 auto req
= librbd::image::ListWatchersRequest
<I
>::create(
94 *m_image_ctx
, flags
, &m_watchers
, ctx
);
99 void PromoteRequest
<I
>::handle_list_watchers(int r
) {
100 CephContext
*cct
= m_image_ctx
->cct
;
101 ldout(cct
, 20) << "r=" << r
<< dendl
;
104 lderr(cct
) << "failed to list watchers: " << cpp_strerror(r
)
110 if (m_watchers
.empty()) {
111 acquire_exclusive_lock();
115 wait_update_notify();
118 template <typename I
>
119 void PromoteRequest
<I
>::wait_update_notify() {
120 CephContext
*cct
= m_image_ctx
->cct
;
121 ldout(cct
, 20) << dendl
;
123 ImageCtx::get_timer_instance(cct
, &m_timer
, &m_timer_lock
);
125 std::lock_guard timer_lock
{*m_timer_lock
};
127 m_scheduler_ticks
= 5;
129 int r
= m_image_ctx
->state
->register_update_watcher(&m_update_watch_ctx
,
130 &m_update_watcher_handle
);
132 lderr(cct
) << "failed to register update watcher: " << cpp_strerror(r
)
138 scheduler_unregister_update_watcher();
141 template <typename I
>
142 void PromoteRequest
<I
>::handle_update_notify() {
143 CephContext
*cct
= m_image_ctx
->cct
;
144 ldout(cct
, 20) << dendl
;
146 std::lock_guard timer_lock
{*m_timer_lock
};
147 m_scheduler_ticks
= 0;
150 template <typename I
>
151 void PromoteRequest
<I
>::scheduler_unregister_update_watcher() {
152 ceph_assert(ceph_mutex_is_locked(*m_timer_lock
));
154 CephContext
*cct
= m_image_ctx
->cct
;
155 ldout(cct
, 20) << "scheduler_ticks=" << m_scheduler_ticks
<< dendl
;
157 if (m_scheduler_ticks
> 0) {
159 m_timer
->add_event_after(1, new LambdaContext([this](int) {
160 scheduler_unregister_update_watcher();
165 m_image_ctx
->op_work_queue
->queue(new LambdaContext([this](int) {
166 unregister_update_watcher();
170 template <typename I
>
171 void PromoteRequest
<I
>::unregister_update_watcher() {
172 CephContext
*cct
= m_image_ctx
->cct
;
173 ldout(cct
, 20) << dendl
;
175 auto ctx
= create_context_callback
<
177 &PromoteRequest
<I
>::handle_unregister_update_watcher
>(this);
179 m_image_ctx
->state
->unregister_update_watcher(m_update_watcher_handle
, ctx
);
182 template <typename I
>
183 void PromoteRequest
<I
>::handle_unregister_update_watcher(int r
) {
184 CephContext
*cct
= m_image_ctx
->cct
;
185 ldout(cct
, 20) << "r=" << r
<< dendl
;
188 lderr(cct
) << "failed to unregister update watcher: " << cpp_strerror(r
)
197 template <typename I
>
198 void PromoteRequest
<I
>::acquire_exclusive_lock() {
200 std::unique_lock locker
{m_image_ctx
->owner_lock
};
201 if (m_image_ctx
->exclusive_lock
!= nullptr &&
202 !m_image_ctx
->exclusive_lock
->is_lock_owner()) {
203 CephContext
*cct
= m_image_ctx
->cct
;
204 ldout(cct
, 20) << dendl
;
206 m_lock_acquired
= true;
207 m_image_ctx
->exclusive_lock
->block_requests(0);
209 auto ctx
= create_context_callback
<
211 &PromoteRequest
<I
>::handle_acquire_exclusive_lock
>(this);
213 m_image_ctx
->exclusive_lock
->acquire_lock(ctx
);
221 template <typename I
>
222 void PromoteRequest
<I
>::handle_acquire_exclusive_lock(int r
) {
223 CephContext
*cct
= m_image_ctx
->cct
;
224 ldout(cct
, 20) << "r=" << r
<< dendl
;
227 lderr(cct
) << "failed to acquire exclusive lock: " << cpp_strerror(r
)
232 std::unique_lock locker
{m_image_ctx
->owner_lock
};
233 if (m_image_ctx
->exclusive_lock
!= nullptr &&
234 !m_image_ctx
->exclusive_lock
->is_lock_owner()) {
235 lderr(cct
) << "failed to acquire exclusive lock" << dendl
;
236 r
= m_image_ctx
->exclusive_lock
->get_unlocked_op_error();
246 template <typename I
>
247 void PromoteRequest
<I
>::rollback() {
248 if (m_rollback_snap_id
== CEPH_NOSNAP
) {
249 create_promote_snapshot();
253 CephContext
*cct
= m_image_ctx
->cct
;
254 ldout(cct
, 20) << dendl
;
256 std::shared_lock owner_locker
{m_image_ctx
->owner_lock
};
257 std::shared_lock image_locker
{m_image_ctx
->image_lock
};
259 auto info
= m_image_ctx
->get_snap_info(m_rollback_snap_id
);
260 ceph_assert(info
!= nullptr);
261 auto snap_namespace
= info
->snap_namespace
;
262 auto snap_name
= info
->name
;
264 image_locker
.unlock();
266 auto ctx
= create_async_context_callback(
267 *m_image_ctx
, create_context_callback
<
268 PromoteRequest
<I
>, &PromoteRequest
<I
>::handle_rollback
>(this));
270 m_image_ctx
->operations
->execute_snap_rollback(snap_namespace
, snap_name
,
271 m_progress_ctx
, ctx
);
274 template <typename I
>
275 void PromoteRequest
<I
>::handle_rollback(int r
) {
276 CephContext
*cct
= m_image_ctx
->cct
;
277 ldout(cct
, 20) << "r=" << r
<< dendl
;
280 lderr(cct
) << "failed to rollback: " << cpp_strerror(r
) << dendl
;
285 create_promote_snapshot();
288 template <typename I
>
289 void PromoteRequest
<I
>::create_promote_snapshot() {
290 CephContext
*cct
= m_image_ctx
->cct
;
291 ldout(cct
, 20) << dendl
;
293 auto ctx
= create_context_callback
<
295 &PromoteRequest
<I
>::handle_create_promote_snapshot
>(this);
297 auto req
= CreatePrimaryRequest
<I
>::create(
298 m_image_ctx
, m_global_image_id
, CEPH_NOSNAP
,
299 (snapshot::CREATE_PRIMARY_FLAG_IGNORE_EMPTY_PEERS
|
300 snapshot::CREATE_PRIMARY_FLAG_FORCE
), nullptr, ctx
);
304 template <typename I
>
305 void PromoteRequest
<I
>::handle_create_promote_snapshot(int r
) {
306 CephContext
*cct
= m_image_ctx
->cct
;
307 ldout(cct
, 20) << "r=" << r
<< dendl
;
310 lderr(cct
) << "failed to create promote snapshot: " << cpp_strerror(r
)
316 disable_non_primary_feature();
319 template <typename I
>
320 void PromoteRequest
<I
>::disable_non_primary_feature() {
321 CephContext
*cct
= m_image_ctx
->cct
;
322 ldout(cct
, 10) << dendl
;
324 // remove the non-primary feature flag so that the image can be
325 // R/W by standard RBD clients
326 librados::ObjectWriteOperation op
;
327 cls_client::set_features(&op
, 0U, RBD_FEATURE_NON_PRIMARY
);
329 auto aio_comp
= create_rados_callback
<
331 &PromoteRequest
<I
>::handle_disable_non_primary_feature
>(this);
332 int r
= m_image_ctx
->md_ctx
.aio_operate(m_image_ctx
->header_oid
, aio_comp
,
338 template <typename I
>
339 void PromoteRequest
<I
>::handle_disable_non_primary_feature(int r
) {
340 CephContext
*cct
= m_image_ctx
->cct
;
341 ldout(cct
, 10) << "r=" << r
<< dendl
;
344 lderr(cct
) << "failed to disable non-primary feature: "
345 << cpp_strerror(r
) << dendl
;
350 release_exclusive_lock();
353 template <typename I
>
354 void PromoteRequest
<I
>::release_exclusive_lock() {
355 if (m_lock_acquired
) {
356 std::unique_lock locker
{m_image_ctx
->owner_lock
};
357 if (m_image_ctx
->exclusive_lock
!= nullptr) {
358 CephContext
*cct
= m_image_ctx
->cct
;
359 ldout(cct
, 20) << dendl
;
361 m_image_ctx
->exclusive_lock
->unblock_requests();
363 auto ctx
= create_context_callback
<
365 &PromoteRequest
<I
>::handle_release_exclusive_lock
>(this);
367 m_image_ctx
->exclusive_lock
->release_lock(ctx
);
375 template <typename I
>
376 void PromoteRequest
<I
>::handle_release_exclusive_lock(int r
) {
377 CephContext
*cct
= m_image_ctx
->cct
;
378 ldout(cct
, 20) << "r=" << r
<< dendl
;
381 lderr(cct
) << "failed to release exclusive lock: " << cpp_strerror(r
)
390 template <typename I
>
391 void PromoteRequest
<I
>::finish(int r
) {
392 CephContext
*cct
= m_image_ctx
->cct
;
393 ldout(cct
, 20) << "r=" << r
<< dendl
;
395 m_on_finish
->complete(r
);
399 } // namespace snapshot
400 } // namespace mirror
401 } // namespace librbd
403 template class librbd::mirror::snapshot::PromoteRequest
<librbd::ImageCtx
>;