1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/ImageWatcher.h"
5 #include "librbd/ExclusiveLock.h"
6 #include "librbd/ImageCtx.h"
7 #include "librbd/ImageState.h"
8 #include "librbd/internal.h"
9 #include "librbd/Operations.h"
10 #include "librbd/TaskFinisher.h"
11 #include "librbd/Types.h"
12 #include "librbd/Utils.h"
13 #include "librbd/exclusive_lock/Policy.h"
14 #include "librbd/image_watcher/NotifyLockOwner.h"
15 #include "librbd/io/AioCompletion.h"
16 #include "librbd/watcher/Utils.h"
17 #include "include/encoding.h"
18 #include "common/errno.h"
19 #include "common/WorkQueue.h"
20 #include <boost/bind.hpp>
22 #define dout_subsys ceph_subsys_rbd
24 #define dout_prefix *_dout << "librbd::ImageWatcher: "
28 using namespace image_watcher
;
29 using namespace watch_notify
;
30 using util::create_async_context_callback
;
31 using util::create_context_callback
;
32 using util::create_rados_callback
;
33 using librbd::watcher::util::HandlePayloadVisitor
;
35 static const double RETRY_DELAY_SECONDS
= 1.0;
38 struct ImageWatcher
<I
>::C_ProcessPayload
: public Context
{
39 ImageWatcher
*image_watcher
;
42 watch_notify::Payload payload
;
44 C_ProcessPayload(ImageWatcher
*image_watcher_
, uint64_t notify_id_
,
45 uint64_t handle_
, const watch_notify::Payload
&payload
)
46 : image_watcher(image_watcher_
), notify_id(notify_id_
), handle(handle_
),
50 void finish(int r
) override
{
51 image_watcher
->m_async_op_tracker
.start_op();
52 if (image_watcher
->notifications_blocked()) {
53 // requests are blocked -- just ack the notification
55 image_watcher
->acknowledge_notify(notify_id
, handle
, bl
);
57 image_watcher
->process_payload(notify_id
, handle
, payload
);
59 image_watcher
->m_async_op_tracker
.finish_op();
64 ImageWatcher
<I
>::ImageWatcher(I
&image_ctx
)
65 : Watcher(image_ctx
.md_ctx
, image_ctx
.op_work_queue
, image_ctx
.header_oid
),
66 m_image_ctx(image_ctx
),
67 m_task_finisher(new TaskFinisher
<Task
>(*m_image_ctx
.cct
)),
68 m_async_request_lock(util::unique_lock_name("librbd::ImageWatcher::m_async_request_lock", this)),
69 m_owner_client_id_lock(util::unique_lock_name("librbd::ImageWatcher::m_owner_client_id_lock", this))
74 ImageWatcher
<I
>::~ImageWatcher()
76 delete m_task_finisher
;
80 void ImageWatcher
<I
>::unregister_watch(Context
*on_finish
) {
81 CephContext
*cct
= m_image_ctx
.cct
;
82 ldout(cct
, 10) << this << " unregistering image watcher" << dendl
;
84 cancel_async_requests();
86 FunctionContext
*ctx
= new FunctionContext([this, on_finish
](int r
) {
87 m_task_finisher
->cancel_all(on_finish
);
89 Watcher::unregister_watch(ctx
);
93 void ImageWatcher
<I
>::block_notifies(Context
*on_finish
) {
94 CephContext
*cct
= m_image_ctx
.cct
;
95 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
97 on_finish
= new FunctionContext([this, on_finish
](int r
) {
98 cancel_async_requests();
99 on_finish
->complete(r
);
101 Watcher::block_notifies(on_finish
);
104 template <typename I
>
105 void ImageWatcher
<I
>::schedule_async_progress(const AsyncRequestId
&request
,
106 uint64_t offset
, uint64_t total
) {
107 FunctionContext
*ctx
= new FunctionContext(
108 boost::bind(&ImageWatcher
<I
>::notify_async_progress
, this, request
, offset
,
110 m_task_finisher
->queue(Task(TASK_CODE_ASYNC_PROGRESS
, request
), ctx
);
113 template <typename I
>
114 int ImageWatcher
<I
>::notify_async_progress(const AsyncRequestId
&request
,
115 uint64_t offset
, uint64_t total
) {
116 ldout(m_image_ctx
.cct
, 20) << this << " remote async request progress: "
117 << request
<< " @ " << offset
118 << "/" << total
<< dendl
;
120 send_notify(AsyncProgressPayload(request
, offset
, total
));
124 template <typename I
>
125 void ImageWatcher
<I
>::schedule_async_complete(const AsyncRequestId
&request
,
127 FunctionContext
*ctx
= new FunctionContext(
128 boost::bind(&ImageWatcher
<I
>::notify_async_complete
, this, request
, r
));
129 m_task_finisher
->queue(ctx
);
132 template <typename I
>
133 void ImageWatcher
<I
>::notify_async_complete(const AsyncRequestId
&request
,
135 ldout(m_image_ctx
.cct
, 20) << this << " remote async request finished: "
136 << request
<< " = " << r
<< dendl
;
138 send_notify(AsyncCompletePayload(request
, r
),
139 new FunctionContext(boost::bind(&ImageWatcher
<I
>::handle_async_complete
,
140 this, request
, r
, _1
)));
143 template <typename I
>
144 void ImageWatcher
<I
>::handle_async_complete(const AsyncRequestId
&request
,
145 int r
, int ret_val
) {
146 ldout(m_image_ctx
.cct
, 20) << this << " " << __func__
<< ": "
147 << "request=" << request
<< ", r=" << ret_val
150 lderr(m_image_ctx
.cct
) << this << " failed to notify async complete: "
151 << cpp_strerror(ret_val
) << dendl
;
152 if (ret_val
== -ETIMEDOUT
) {
153 schedule_async_complete(request
, r
);
156 RWLock::WLocker
async_request_locker(m_async_request_lock
);
157 m_async_pending
.erase(request
);
161 template <typename I
>
162 void ImageWatcher
<I
>::notify_flatten(uint64_t request_id
,
163 ProgressContext
&prog_ctx
,
164 Context
*on_finish
) {
165 assert(m_image_ctx
.owner_lock
.is_locked());
166 assert(m_image_ctx
.exclusive_lock
&&
167 !m_image_ctx
.exclusive_lock
->is_lock_owner());
169 AsyncRequestId
async_request_id(get_client_id(), request_id
);
171 notify_async_request(async_request_id
, FlattenPayload(async_request_id
),
172 prog_ctx
, on_finish
);
175 template <typename I
>
176 void ImageWatcher
<I
>::notify_resize(uint64_t request_id
, uint64_t size
,
178 ProgressContext
&prog_ctx
,
179 Context
*on_finish
) {
180 assert(m_image_ctx
.owner_lock
.is_locked());
181 assert(m_image_ctx
.exclusive_lock
&&
182 !m_image_ctx
.exclusive_lock
->is_lock_owner());
184 AsyncRequestId
async_request_id(get_client_id(), request_id
);
186 notify_async_request(async_request_id
,
187 ResizePayload(size
, allow_shrink
, async_request_id
),
188 prog_ctx
, on_finish
);
191 template <typename I
>
192 void ImageWatcher
<I
>::notify_snap_create(const cls::rbd::SnapshotNamespace
&snap_namespace
,
193 const std::string
&snap_name
,
194 Context
*on_finish
) {
195 assert(m_image_ctx
.owner_lock
.is_locked());
196 assert(m_image_ctx
.exclusive_lock
&&
197 !m_image_ctx
.exclusive_lock
->is_lock_owner());
199 notify_lock_owner(SnapCreatePayload(snap_namespace
, snap_name
), on_finish
);
202 template <typename I
>
203 void ImageWatcher
<I
>::notify_snap_rename(const snapid_t
&src_snap_id
,
204 const std::string
&dst_snap_name
,
205 Context
*on_finish
) {
206 assert(m_image_ctx
.owner_lock
.is_locked());
207 assert(m_image_ctx
.exclusive_lock
&&
208 !m_image_ctx
.exclusive_lock
->is_lock_owner());
210 notify_lock_owner(SnapRenamePayload(src_snap_id
, dst_snap_name
), on_finish
);
213 template <typename I
>
214 void ImageWatcher
<I
>::notify_snap_remove(const cls::rbd::SnapshotNamespace
&snap_namespace
,
215 const std::string
&snap_name
,
216 Context
*on_finish
) {
217 assert(m_image_ctx
.owner_lock
.is_locked());
218 assert(m_image_ctx
.exclusive_lock
&&
219 !m_image_ctx
.exclusive_lock
->is_lock_owner());
221 notify_lock_owner(SnapRemovePayload(snap_namespace
, snap_name
), on_finish
);
224 template <typename I
>
225 void ImageWatcher
<I
>::notify_snap_protect(const cls::rbd::SnapshotNamespace
&snap_namespace
,
226 const std::string
&snap_name
,
227 Context
*on_finish
) {
228 assert(m_image_ctx
.owner_lock
.is_locked());
229 assert(m_image_ctx
.exclusive_lock
&&
230 !m_image_ctx
.exclusive_lock
->is_lock_owner());
232 notify_lock_owner(SnapProtectPayload(snap_namespace
, snap_name
), on_finish
);
235 template <typename I
>
236 void ImageWatcher
<I
>::notify_snap_unprotect(const cls::rbd::SnapshotNamespace
&snap_namespace
,
237 const std::string
&snap_name
,
238 Context
*on_finish
) {
239 assert(m_image_ctx
.owner_lock
.is_locked());
240 assert(m_image_ctx
.exclusive_lock
&&
241 !m_image_ctx
.exclusive_lock
->is_lock_owner());
243 notify_lock_owner(SnapUnprotectPayload(snap_namespace
, snap_name
), on_finish
);
246 template <typename I
>
247 void ImageWatcher
<I
>::notify_rebuild_object_map(uint64_t request_id
,
248 ProgressContext
&prog_ctx
,
249 Context
*on_finish
) {
250 assert(m_image_ctx
.owner_lock
.is_locked());
251 assert(m_image_ctx
.exclusive_lock
&&
252 !m_image_ctx
.exclusive_lock
->is_lock_owner());
254 AsyncRequestId
async_request_id(get_client_id(), request_id
);
256 notify_async_request(async_request_id
,
257 RebuildObjectMapPayload(async_request_id
),
258 prog_ctx
, on_finish
);
261 template <typename I
>
262 void ImageWatcher
<I
>::notify_rename(const std::string
&image_name
,
263 Context
*on_finish
) {
264 assert(m_image_ctx
.owner_lock
.is_locked());
265 assert(m_image_ctx
.exclusive_lock
&&
266 !m_image_ctx
.exclusive_lock
->is_lock_owner());
268 notify_lock_owner(RenamePayload(image_name
), on_finish
);
271 template <typename I
>
272 void ImageWatcher
<I
>::notify_update_features(uint64_t features
, bool enabled
,
273 Context
*on_finish
) {
274 assert(m_image_ctx
.owner_lock
.is_locked());
275 assert(m_image_ctx
.exclusive_lock
&&
276 !m_image_ctx
.exclusive_lock
->is_lock_owner());
278 notify_lock_owner(UpdateFeaturesPayload(features
, enabled
), on_finish
);
281 template <typename I
>
282 void ImageWatcher
<I
>::notify_header_update(Context
*on_finish
) {
283 ldout(m_image_ctx
.cct
, 10) << this << ": " << __func__
<< dendl
;
285 // supports legacy (empty buffer) clients
286 send_notify(HeaderUpdatePayload(), on_finish
);
289 template <typename I
>
290 void ImageWatcher
<I
>::notify_header_update(librados::IoCtx
&io_ctx
,
291 const std::string
&oid
) {
292 // supports legacy (empty buffer) clients
294 ::encode(NotifyMessage(HeaderUpdatePayload()), bl
);
295 io_ctx
.notify2(oid
, bl
, watcher::Notifier::NOTIFY_TIMEOUT
, nullptr);
298 template <typename I
>
299 void ImageWatcher
<I
>::schedule_cancel_async_requests() {
300 FunctionContext
*ctx
= new FunctionContext(
301 boost::bind(&ImageWatcher
<I
>::cancel_async_requests
, this));
302 m_task_finisher
->queue(TASK_CODE_CANCEL_ASYNC_REQUESTS
, ctx
);
305 template <typename I
>
306 void ImageWatcher
<I
>::cancel_async_requests() {
307 RWLock::WLocker
l(m_async_request_lock
);
308 for (std::map
<AsyncRequestId
, AsyncRequest
>::iterator iter
=
309 m_async_requests
.begin();
310 iter
!= m_async_requests
.end(); ++iter
) {
311 iter
->second
.first
->complete(-ERESTART
);
313 m_async_requests
.clear();
316 template <typename I
>
317 void ImageWatcher
<I
>::set_owner_client_id(const ClientId
& client_id
) {
318 assert(m_owner_client_id_lock
.is_locked());
319 m_owner_client_id
= client_id
;
320 ldout(m_image_ctx
.cct
, 10) << this << " current lock owner: "
321 << m_owner_client_id
<< dendl
;
324 template <typename I
>
325 ClientId ImageWatcher
<I
>::get_client_id() {
326 RWLock::RLocker
l(this->m_watch_lock
);
327 return ClientId(m_image_ctx
.md_ctx
.get_instance_id(), this->m_watch_handle
);
330 template <typename I
>
331 void ImageWatcher
<I
>::notify_acquired_lock() {
332 ldout(m_image_ctx
.cct
, 10) << this << " notify acquired lock" << dendl
;
334 ClientId client_id
= get_client_id();
336 Mutex::Locker
owner_client_id_locker(m_owner_client_id_lock
);
337 set_owner_client_id(client_id
);
340 send_notify(AcquiredLockPayload(client_id
));
343 template <typename I
>
344 void ImageWatcher
<I
>::notify_released_lock() {
345 ldout(m_image_ctx
.cct
, 10) << this << " notify released lock" << dendl
;
348 Mutex::Locker
owner_client_id_locker(m_owner_client_id_lock
);
349 set_owner_client_id(ClientId());
352 send_notify(ReleasedLockPayload(get_client_id()));
355 template <typename I
>
356 void ImageWatcher
<I
>::schedule_request_lock(bool use_timer
, int timer_delay
) {
357 assert(m_image_ctx
.owner_lock
.is_locked());
359 if (m_image_ctx
.exclusive_lock
== nullptr) {
360 // exclusive lock dynamically disabled via image refresh
363 assert(m_image_ctx
.exclusive_lock
&&
364 !m_image_ctx
.exclusive_lock
->is_lock_owner());
366 RWLock::RLocker
watch_locker(this->m_watch_lock
);
367 if (this->is_registered(this->m_watch_lock
)) {
368 ldout(m_image_ctx
.cct
, 15) << this << " requesting exclusive lock" << dendl
;
370 FunctionContext
*ctx
= new FunctionContext(
371 boost::bind(&ImageWatcher
<I
>::notify_request_lock
, this));
373 if (timer_delay
< 0) {
374 timer_delay
= RETRY_DELAY_SECONDS
;
376 m_task_finisher
->add_event_after(TASK_CODE_REQUEST_LOCK
,
379 m_task_finisher
->queue(TASK_CODE_REQUEST_LOCK
, ctx
);
384 template <typename I
>
385 void ImageWatcher
<I
>::notify_request_lock() {
386 RWLock::RLocker
owner_locker(m_image_ctx
.owner_lock
);
387 RWLock::RLocker
snap_locker(m_image_ctx
.snap_lock
);
389 // ExclusiveLock state machine can be dynamically disabled or
390 // race with task cancel
391 if (m_image_ctx
.exclusive_lock
== nullptr ||
392 m_image_ctx
.exclusive_lock
->is_lock_owner()) {
396 ldout(m_image_ctx
.cct
, 10) << this << " notify request lock" << dendl
;
398 notify_lock_owner(RequestLockPayload(get_client_id(), false),
399 create_context_callback
<
400 ImageWatcher
, &ImageWatcher
<I
>::handle_request_lock
>(this));
403 template <typename I
>
404 void ImageWatcher
<I
>::handle_request_lock(int r
) {
405 RWLock::RLocker
owner_locker(m_image_ctx
.owner_lock
);
406 RWLock::RLocker
snap_locker(m_image_ctx
.snap_lock
);
408 // ExclusiveLock state machine cannot transition -- but can be
409 // dynamically disabled
410 if (m_image_ctx
.exclusive_lock
== nullptr) {
414 if (r
== -ETIMEDOUT
) {
415 ldout(m_image_ctx
.cct
, 5) << this << " timed out requesting lock: retrying"
418 // treat this is a dead client -- so retest acquiring the lock
419 m_image_ctx
.exclusive_lock
->handle_peer_notification(0);
420 } else if (r
== -EROFS
) {
421 ldout(m_image_ctx
.cct
, 5) << this << " peer will not release lock" << dendl
;
422 m_image_ctx
.exclusive_lock
->handle_peer_notification(r
);
424 lderr(m_image_ctx
.cct
) << this << " error requesting lock: "
425 << cpp_strerror(r
) << dendl
;
426 schedule_request_lock(true);
428 // lock owner acked -- but resend if we don't see them release the lock
429 int retry_timeout
= m_image_ctx
.cct
->_conf
->template get_val
<int64_t>(
430 "client_notify_timeout");
431 ldout(m_image_ctx
.cct
, 15) << this << " will retry in " << retry_timeout
432 << " seconds" << dendl
;
433 schedule_request_lock(true, retry_timeout
);
437 template <typename I
>
438 void ImageWatcher
<I
>::notify_lock_owner(const Payload
& payload
,
439 Context
*on_finish
) {
440 assert(on_finish
!= nullptr);
441 assert(m_image_ctx
.owner_lock
.is_locked());
444 ::encode(NotifyMessage(payload
), bl
);
446 NotifyLockOwner
*notify_lock_owner
= NotifyLockOwner::create(
447 m_image_ctx
, this->m_notifier
, std::move(bl
), on_finish
);
448 notify_lock_owner
->send();
451 template <typename I
>
452 Context
*ImageWatcher
<I
>::remove_async_request(const AsyncRequestId
&id
) {
453 RWLock::WLocker
async_request_locker(m_async_request_lock
);
454 auto it
= m_async_requests
.find(id
);
455 if (it
!= m_async_requests
.end()) {
456 Context
*on_complete
= it
->second
.first
;
457 m_async_requests
.erase(it
);
463 template <typename I
>
464 void ImageWatcher
<I
>::schedule_async_request_timed_out(const AsyncRequestId
&id
) {
465 ldout(m_image_ctx
.cct
, 20) << "scheduling async request time out: " << id
468 Context
*ctx
= new FunctionContext(boost::bind(
469 &ImageWatcher
<I
>::async_request_timed_out
, this, id
));
471 Task
task(TASK_CODE_ASYNC_REQUEST
, id
);
472 m_task_finisher
->cancel(task
);
474 m_task_finisher
->add_event_after(task
, m_image_ctx
.request_timed_out_seconds
,
478 template <typename I
>
479 void ImageWatcher
<I
>::async_request_timed_out(const AsyncRequestId
&id
) {
480 Context
*on_complete
= remove_async_request(id
);
481 if (on_complete
!= nullptr) {
482 ldout(m_image_ctx
.cct
, 5) << "async request timed out: " << id
<< dendl
;
483 m_image_ctx
.op_work_queue
->queue(on_complete
, -ETIMEDOUT
);
487 template <typename I
>
488 void ImageWatcher
<I
>::notify_async_request(const AsyncRequestId
&async_request_id
,
489 const Payload
& payload
,
490 ProgressContext
& prog_ctx
,
491 Context
*on_finish
) {
492 assert(on_finish
!= nullptr);
493 assert(m_image_ctx
.owner_lock
.is_locked());
495 ldout(m_image_ctx
.cct
, 10) << this << " async request: " << async_request_id
498 Context
*on_notify
= new FunctionContext([this, async_request_id
](int r
) {
500 // notification failed -- don't expect updates
501 Context
*on_complete
= remove_async_request(async_request_id
);
502 if (on_complete
!= nullptr) {
503 on_complete
->complete(r
);
508 Context
*on_complete
= new FunctionContext(
509 [this, async_request_id
, on_finish
](int r
) {
510 m_task_finisher
->cancel(Task(TASK_CODE_ASYNC_REQUEST
, async_request_id
));
511 on_finish
->complete(r
);
515 RWLock::WLocker
async_request_locker(m_async_request_lock
);
516 m_async_requests
[async_request_id
] = AsyncRequest(on_complete
, &prog_ctx
);
519 schedule_async_request_timed_out(async_request_id
);
520 notify_lock_owner(payload
, on_notify
);
523 template <typename I
>
524 int ImageWatcher
<I
>::prepare_async_request(const AsyncRequestId
& async_request_id
,
525 bool* new_request
, Context
** ctx
,
526 ProgressContext
** prog_ctx
) {
527 if (async_request_id
.client_id
== get_client_id()) {
530 RWLock::WLocker
l(m_async_request_lock
);
531 if (m_async_pending
.count(async_request_id
) == 0) {
532 m_async_pending
.insert(async_request_id
);
534 *prog_ctx
= new RemoteProgressContext(*this, async_request_id
);
535 *ctx
= new RemoteContext(*this, async_request_id
, *prog_ctx
);
537 *new_request
= false;
543 template <typename I
>
544 bool ImageWatcher
<I
>::handle_payload(const HeaderUpdatePayload
&payload
,
545 C_NotifyAck
*ack_ctx
) {
546 ldout(m_image_ctx
.cct
, 10) << this << " image header updated" << dendl
;
548 m_image_ctx
.state
->handle_update_notification();
549 m_image_ctx
.perfcounter
->inc(l_librbd_notify
);
550 if (ack_ctx
!= nullptr) {
551 m_image_ctx
.state
->flush_update_watchers(new C_ResponseMessage(ack_ctx
));
557 template <typename I
>
558 bool ImageWatcher
<I
>::handle_payload(const AcquiredLockPayload
&payload
,
559 C_NotifyAck
*ack_ctx
) {
560 ldout(m_image_ctx
.cct
, 10) << this << " image exclusively locked announcement"
563 bool cancel_async_requests
= true;
564 if (payload
.client_id
.is_valid()) {
565 Mutex::Locker
owner_client_id_locker(m_owner_client_id_lock
);
566 if (payload
.client_id
== m_owner_client_id
) {
567 cancel_async_requests
= false;
569 set_owner_client_id(payload
.client_id
);
572 RWLock::RLocker
owner_locker(m_image_ctx
.owner_lock
);
573 if (m_image_ctx
.exclusive_lock
!= nullptr) {
574 // potentially wake up the exclusive lock state machine now that
575 // a lock owner has advertised itself
576 m_image_ctx
.exclusive_lock
->handle_peer_notification(0);
578 if (cancel_async_requests
&&
579 (m_image_ctx
.exclusive_lock
== nullptr ||
580 !m_image_ctx
.exclusive_lock
->is_lock_owner())) {
581 schedule_cancel_async_requests();
586 template <typename I
>
587 bool ImageWatcher
<I
>::handle_payload(const ReleasedLockPayload
&payload
,
588 C_NotifyAck
*ack_ctx
) {
589 ldout(m_image_ctx
.cct
, 10) << this << " exclusive lock released" << dendl
;
591 bool cancel_async_requests
= true;
592 if (payload
.client_id
.is_valid()) {
593 Mutex::Locker
l(m_owner_client_id_lock
);
594 if (payload
.client_id
!= m_owner_client_id
) {
595 ldout(m_image_ctx
.cct
, 10) << this << " unexpected owner: "
596 << payload
.client_id
<< " != "
597 << m_owner_client_id
<< dendl
;
598 cancel_async_requests
= false;
600 set_owner_client_id(ClientId());
604 RWLock::RLocker
owner_locker(m_image_ctx
.owner_lock
);
605 if (cancel_async_requests
&&
606 (m_image_ctx
.exclusive_lock
== nullptr ||
607 !m_image_ctx
.exclusive_lock
->is_lock_owner())) {
608 schedule_cancel_async_requests();
611 // alert the exclusive lock state machine that the lock is available
612 if (m_image_ctx
.exclusive_lock
!= nullptr &&
613 !m_image_ctx
.exclusive_lock
->is_lock_owner()) {
614 m_task_finisher
->cancel(TASK_CODE_REQUEST_LOCK
);
615 m_image_ctx
.exclusive_lock
->handle_peer_notification(0);
620 template <typename I
>
621 bool ImageWatcher
<I
>::handle_payload(const RequestLockPayload
&payload
,
622 C_NotifyAck
*ack_ctx
) {
623 ldout(m_image_ctx
.cct
, 10) << this << " exclusive lock requested" << dendl
;
624 if (payload
.client_id
== get_client_id()) {
628 RWLock::RLocker
l(m_image_ctx
.owner_lock
);
629 if (m_image_ctx
.exclusive_lock
!= nullptr &&
630 m_image_ctx
.exclusive_lock
->is_lock_owner()) {
632 bool accept_request
= m_image_ctx
.exclusive_lock
->accept_requests(&r
);
634 if (accept_request
) {
636 Mutex::Locker
owner_client_id_locker(m_owner_client_id_lock
);
637 if (!m_owner_client_id
.is_valid()) {
641 ldout(m_image_ctx
.cct
, 10) << this << " queuing release of exclusive lock"
643 r
= m_image_ctx
.get_exclusive_lock_policy()->lock_requested(
646 ::encode(ResponseMessage(r
), ack_ctx
->out
);
651 template <typename I
>
652 bool ImageWatcher
<I
>::handle_payload(const AsyncProgressPayload
&payload
,
653 C_NotifyAck
*ack_ctx
) {
654 RWLock::RLocker
l(m_async_request_lock
);
655 std::map
<AsyncRequestId
, AsyncRequest
>::iterator req_it
=
656 m_async_requests
.find(payload
.async_request_id
);
657 if (req_it
!= m_async_requests
.end()) {
658 ldout(m_image_ctx
.cct
, 20) << this << " request progress: "
659 << payload
.async_request_id
<< " @ "
660 << payload
.offset
<< "/" << payload
.total
662 schedule_async_request_timed_out(payload
.async_request_id
);
663 req_it
->second
.second
->update_progress(payload
.offset
, payload
.total
);
668 template <typename I
>
669 bool ImageWatcher
<I
>::handle_payload(const AsyncCompletePayload
&payload
,
670 C_NotifyAck
*ack_ctx
) {
671 Context
*on_complete
= remove_async_request(payload
.async_request_id
);
672 if (on_complete
!= nullptr) {
673 ldout(m_image_ctx
.cct
, 10) << this << " request finished: "
674 << payload
.async_request_id
<< "="
675 << payload
.result
<< dendl
;
676 on_complete
->complete(payload
.result
);
681 template <typename I
>
682 bool ImageWatcher
<I
>::handle_payload(const FlattenPayload
&payload
,
683 C_NotifyAck
*ack_ctx
) {
685 RWLock::RLocker
l(m_image_ctx
.owner_lock
);
686 if (m_image_ctx
.exclusive_lock
!= nullptr) {
688 if (m_image_ctx
.exclusive_lock
->accept_requests(&r
)) {
691 ProgressContext
*prog_ctx
;
692 r
= prepare_async_request(payload
.async_request_id
, &new_request
,
694 if (r
== 0 && new_request
) {
695 ldout(m_image_ctx
.cct
, 10) << this << " remote flatten request: "
696 << payload
.async_request_id
<< dendl
;
697 m_image_ctx
.operations
->execute_flatten(*prog_ctx
, ctx
);
700 ::encode(ResponseMessage(r
), ack_ctx
->out
);
702 ::encode(ResponseMessage(r
), ack_ctx
->out
);
708 template <typename I
>
709 bool ImageWatcher
<I
>::handle_payload(const ResizePayload
&payload
,
710 C_NotifyAck
*ack_ctx
) {
711 RWLock::RLocker
l(m_image_ctx
.owner_lock
);
712 if (m_image_ctx
.exclusive_lock
!= nullptr) {
714 if (m_image_ctx
.exclusive_lock
->accept_requests(&r
)) {
717 ProgressContext
*prog_ctx
;
718 r
= prepare_async_request(payload
.async_request_id
, &new_request
,
720 if (r
== 0 && new_request
) {
721 ldout(m_image_ctx
.cct
, 10) << this << " remote resize request: "
722 << payload
.async_request_id
<< " "
723 << payload
.size
<< " "
724 << payload
.allow_shrink
<< dendl
;
725 m_image_ctx
.operations
->execute_resize(payload
.size
, payload
.allow_shrink
, *prog_ctx
, ctx
, 0);
728 ::encode(ResponseMessage(r
), ack_ctx
->out
);
730 ::encode(ResponseMessage(r
), ack_ctx
->out
);
736 template <typename I
>
737 bool ImageWatcher
<I
>::handle_payload(const SnapCreatePayload
&payload
,
738 C_NotifyAck
*ack_ctx
) {
739 RWLock::RLocker
l(m_image_ctx
.owner_lock
);
740 if (m_image_ctx
.exclusive_lock
!= nullptr) {
742 if (m_image_ctx
.exclusive_lock
->accept_requests(&r
)) {
743 ldout(m_image_ctx
.cct
, 10) << this << " remote snap_create request: "
744 << payload
.snap_name
<< dendl
;
746 m_image_ctx
.operations
->execute_snap_create(payload
.snap_namespace
,
748 new C_ResponseMessage(ack_ctx
),
752 ::encode(ResponseMessage(r
), ack_ctx
->out
);
758 template <typename I
>
759 bool ImageWatcher
<I
>::handle_payload(const SnapRenamePayload
&payload
,
760 C_NotifyAck
*ack_ctx
) {
761 RWLock::RLocker
l(m_image_ctx
.owner_lock
);
762 if (m_image_ctx
.exclusive_lock
!= nullptr) {
764 if (m_image_ctx
.exclusive_lock
->accept_requests(&r
)) {
765 ldout(m_image_ctx
.cct
, 10) << this << " remote snap_rename request: "
766 << payload
.snap_id
<< " to "
767 << payload
.snap_name
<< dendl
;
769 m_image_ctx
.operations
->execute_snap_rename(payload
.snap_id
,
771 new C_ResponseMessage(ack_ctx
));
774 ::encode(ResponseMessage(r
), ack_ctx
->out
);
780 template <typename I
>
781 bool ImageWatcher
<I
>::handle_payload(const SnapRemovePayload
&payload
,
782 C_NotifyAck
*ack_ctx
) {
783 RWLock::RLocker
l(m_image_ctx
.owner_lock
);
784 if (m_image_ctx
.exclusive_lock
!= nullptr) {
786 if (m_image_ctx
.exclusive_lock
->accept_requests(&r
)) {
787 ldout(m_image_ctx
.cct
, 10) << this << " remote snap_remove request: "
788 << payload
.snap_name
<< dendl
;
790 m_image_ctx
.operations
->execute_snap_remove(payload
.snap_namespace
,
792 new C_ResponseMessage(ack_ctx
));
795 ::encode(ResponseMessage(r
), ack_ctx
->out
);
801 template <typename I
>
802 bool ImageWatcher
<I
>::handle_payload(const SnapProtectPayload
& payload
,
803 C_NotifyAck
*ack_ctx
) {
804 RWLock::RLocker
owner_locker(m_image_ctx
.owner_lock
);
805 if (m_image_ctx
.exclusive_lock
!= nullptr) {
807 if (m_image_ctx
.exclusive_lock
->accept_requests(&r
)) {
808 ldout(m_image_ctx
.cct
, 10) << this << " remote snap_protect request: "
809 << payload
.snap_name
<< dendl
;
811 m_image_ctx
.operations
->execute_snap_protect(payload
.snap_namespace
,
813 new C_ResponseMessage(ack_ctx
));
816 ::encode(ResponseMessage(r
), ack_ctx
->out
);
822 template <typename I
>
823 bool ImageWatcher
<I
>::handle_payload(const SnapUnprotectPayload
& payload
,
824 C_NotifyAck
*ack_ctx
) {
825 RWLock::RLocker
owner_locker(m_image_ctx
.owner_lock
);
826 if (m_image_ctx
.exclusive_lock
!= nullptr) {
828 if (m_image_ctx
.exclusive_lock
->accept_requests(&r
)) {
829 ldout(m_image_ctx
.cct
, 10) << this << " remote snap_unprotect request: "
830 << payload
.snap_name
<< dendl
;
832 m_image_ctx
.operations
->execute_snap_unprotect(payload
.snap_namespace
,
834 new C_ResponseMessage(ack_ctx
));
837 ::encode(ResponseMessage(r
), ack_ctx
->out
);
843 template <typename I
>
844 bool ImageWatcher
<I
>::handle_payload(const RebuildObjectMapPayload
& payload
,
845 C_NotifyAck
*ack_ctx
) {
846 RWLock::RLocker
l(m_image_ctx
.owner_lock
);
847 if (m_image_ctx
.exclusive_lock
!= nullptr) {
849 if (m_image_ctx
.exclusive_lock
->accept_requests(&r
)) {
852 ProgressContext
*prog_ctx
;
853 r
= prepare_async_request(payload
.async_request_id
, &new_request
,
855 if (r
== 0 && new_request
) {
856 ldout(m_image_ctx
.cct
, 10) << this
857 << " remote rebuild object map request: "
858 << payload
.async_request_id
<< dendl
;
859 m_image_ctx
.operations
->execute_rebuild_object_map(*prog_ctx
, ctx
);
862 ::encode(ResponseMessage(r
), ack_ctx
->out
);
864 ::encode(ResponseMessage(r
), ack_ctx
->out
);
870 template <typename I
>
871 bool ImageWatcher
<I
>::handle_payload(const RenamePayload
& payload
,
872 C_NotifyAck
*ack_ctx
) {
873 RWLock::RLocker
owner_locker(m_image_ctx
.owner_lock
);
874 if (m_image_ctx
.exclusive_lock
!= nullptr) {
876 if (m_image_ctx
.exclusive_lock
->accept_requests(&r
)) {
877 ldout(m_image_ctx
.cct
, 10) << this << " remote rename request: "
878 << payload
.image_name
<< dendl
;
880 m_image_ctx
.operations
->execute_rename(payload
.image_name
,
881 new C_ResponseMessage(ack_ctx
));
884 ::encode(ResponseMessage(r
), ack_ctx
->out
);
890 template <typename I
>
891 bool ImageWatcher
<I
>::handle_payload(const UpdateFeaturesPayload
& payload
,
892 C_NotifyAck
*ack_ctx
) {
893 RWLock::RLocker
owner_locker(m_image_ctx
.owner_lock
);
894 if (m_image_ctx
.exclusive_lock
!= nullptr) {
896 if (m_image_ctx
.exclusive_lock
->accept_requests(&r
)) {
897 ldout(m_image_ctx
.cct
, 10) << this << " remote update_features request: "
898 << payload
.features
<< " "
899 << (payload
.enabled
? "enabled" : "disabled")
902 m_image_ctx
.operations
->execute_update_features(
903 payload
.features
, payload
.enabled
, new C_ResponseMessage(ack_ctx
), 0);
906 ::encode(ResponseMessage(r
), ack_ctx
->out
);
912 template <typename I
>
913 bool ImageWatcher
<I
>::handle_payload(const UnknownPayload
&payload
,
914 C_NotifyAck
*ack_ctx
) {
915 RWLock::RLocker
l(m_image_ctx
.owner_lock
);
916 if (m_image_ctx
.exclusive_lock
!= nullptr) {
918 if (m_image_ctx
.exclusive_lock
->accept_requests(&r
) || r
< 0) {
919 ::encode(ResponseMessage(-EOPNOTSUPP
), ack_ctx
->out
);
925 template <typename I
>
926 void ImageWatcher
<I
>::process_payload(uint64_t notify_id
, uint64_t handle
,
927 const Payload
&payload
) {
928 apply_visitor(HandlePayloadVisitor
<ImageWatcher
<I
>>(this, notify_id
, handle
),
932 template <typename I
>
933 void ImageWatcher
<I
>::handle_notify(uint64_t notify_id
, uint64_t handle
,
934 uint64_t notifier_id
, bufferlist
&bl
) {
935 NotifyMessage notify_message
;
936 if (bl
.length() == 0) {
937 // legacy notification for header updates
938 notify_message
= NotifyMessage(HeaderUpdatePayload());
941 bufferlist::iterator iter
= bl
.begin();
942 ::decode(notify_message
, iter
);
943 } catch (const buffer::error
&err
) {
944 lderr(m_image_ctx
.cct
) << this << " error decoding image notification: "
945 << err
.what() << dendl
;
950 // if an image refresh is required, refresh before processing the request
951 if (notify_message
.check_for_refresh() &&
952 m_image_ctx
.state
->is_refresh_required()) {
953 m_image_ctx
.state
->refresh(new C_ProcessPayload(this, notify_id
, handle
,
954 notify_message
.payload
));
956 process_payload(notify_id
, handle
, notify_message
.payload
);
960 template <typename I
>
961 void ImageWatcher
<I
>::handle_error(uint64_t handle
, int err
) {
962 lderr(m_image_ctx
.cct
) << this << " image watch failed: " << handle
<< ", "
963 << cpp_strerror(err
) << dendl
;
966 Mutex::Locker
l(m_owner_client_id_lock
);
967 set_owner_client_id(ClientId());
970 Watcher::handle_error(handle
, err
);
973 template <typename I
>
974 void ImageWatcher
<I
>::handle_rewatch_complete(int r
) {
975 CephContext
*cct
= m_image_ctx
.cct
;
976 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << r
<< dendl
;
979 RWLock::RLocker
owner_locker(m_image_ctx
.owner_lock
);
980 if (m_image_ctx
.exclusive_lock
!= nullptr) {
981 // update the lock cookie with the new watch handle
982 m_image_ctx
.exclusive_lock
->reacquire_lock();
986 // image might have been updated while we didn't have active watch
987 handle_payload(HeaderUpdatePayload(), nullptr);
990 template <typename I
>
991 void ImageWatcher
<I
>::send_notify(const Payload
&payload
, Context
*ctx
) {
994 ::encode(NotifyMessage(payload
), bl
);
995 Watcher::send_notify(bl
, nullptr, ctx
);
998 template <typename I
>
999 void ImageWatcher
<I
>::RemoteContext::finish(int r
) {
1000 m_image_watcher
.schedule_async_complete(m_async_request_id
, r
);
1003 template <typename I
>
1004 void ImageWatcher
<I
>::C_ResponseMessage::finish(int r
) {
1005 CephContext
*cct
= notify_ack
->cct
;
1006 ldout(cct
, 10) << this << " C_ResponseMessage: r=" << r
<< dendl
;
1008 ::encode(ResponseMessage(r
), notify_ack
->out
);
1009 notify_ack
->complete(0);
1012 } // namespace librbd
1014 template class librbd::ImageWatcher
<librbd::ImageCtx
>;