]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/ImageWatcher.cc
update sources to v12.2.1
[ceph.git] / ceph / src / librbd / ImageWatcher.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
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/Utils.h"
12#include "librbd/exclusive_lock/Policy.h"
13#include "librbd/image_watcher/NotifyLockOwner.h"
14#include "librbd/io/AioCompletion.h"
15#include "librbd/watcher/Utils.h"
16#include "include/encoding.h"
17#include "common/errno.h"
18#include "common/WorkQueue.h"
19#include <boost/bind.hpp>
20
21#define dout_subsys ceph_subsys_rbd
22#undef dout_prefix
23#define dout_prefix *_dout << "librbd::ImageWatcher: "
24
25namespace librbd {
26
27using namespace image_watcher;
28using namespace watch_notify;
29using util::create_async_context_callback;
30using util::create_context_callback;
31using util::create_rados_callback;
32using librbd::watcher::util::HandlePayloadVisitor;
33
34static const double RETRY_DELAY_SECONDS = 1.0;
35
31f18b77
FG
36template <typename I>
37struct ImageWatcher<I>::C_ProcessPayload : public Context {
38 ImageWatcher *image_watcher;
39 uint64_t notify_id;
40 uint64_t handle;
41 watch_notify::Payload payload;
42
43 C_ProcessPayload(ImageWatcher *image_watcher_, uint64_t notify_id_,
44 uint64_t handle_, const watch_notify::Payload &payload)
45 : image_watcher(image_watcher_), notify_id(notify_id_), handle(handle_),
46 payload(payload) {
47 }
48
49 void finish(int r) override {
50 image_watcher->m_async_op_tracker.start_op();
51 if (image_watcher->notifications_blocked()) {
52 // requests are blocked -- just ack the notification
53 bufferlist bl;
54 image_watcher->acknowledge_notify(notify_id, handle, bl);
55 } else {
56 image_watcher->process_payload(notify_id, handle, payload);
57 }
58 image_watcher->m_async_op_tracker.finish_op();
59 }
60};
61
7c673cae
FG
62template <typename I>
63ImageWatcher<I>::ImageWatcher(I &image_ctx)
64 : Watcher(image_ctx.md_ctx, image_ctx.op_work_queue, image_ctx.header_oid),
65 m_image_ctx(image_ctx),
66 m_task_finisher(new TaskFinisher<Task>(*m_image_ctx.cct)),
67 m_async_request_lock(util::unique_lock_name("librbd::ImageWatcher::m_async_request_lock", this)),
68 m_owner_client_id_lock(util::unique_lock_name("librbd::ImageWatcher::m_owner_client_id_lock", this))
69{
70}
71
72template <typename I>
73ImageWatcher<I>::~ImageWatcher()
74{
75 delete m_task_finisher;
76}
77
78template <typename I>
79void ImageWatcher<I>::unregister_watch(Context *on_finish) {
80 CephContext *cct = m_image_ctx.cct;
81 ldout(cct, 10) << this << " unregistering image watcher" << dendl;
82
83 cancel_async_requests();
84
85 FunctionContext *ctx = new FunctionContext([this, on_finish](int r) {
86 m_task_finisher->cancel_all(on_finish);
87 });
88 Watcher::unregister_watch(ctx);
89}
90
31f18b77
FG
91template <typename I>
92void ImageWatcher<I>::block_notifies(Context *on_finish) {
93 CephContext *cct = m_image_ctx.cct;
94 ldout(cct, 10) << this << " " << __func__ << dendl;
95
96 on_finish = new FunctionContext([this, on_finish](int r) {
97 cancel_async_requests();
98 on_finish->complete(r);
99 });
100 Watcher::block_notifies(on_finish);
101}
102
7c673cae
FG
103template <typename I>
104void ImageWatcher<I>::schedule_async_progress(const AsyncRequestId &request,
105 uint64_t offset, uint64_t total) {
106 FunctionContext *ctx = new FunctionContext(
107 boost::bind(&ImageWatcher<I>::notify_async_progress, this, request, offset,
108 total));
109 m_task_finisher->queue(Task(TASK_CODE_ASYNC_PROGRESS, request), ctx);
110}
111
112template <typename I>
113int ImageWatcher<I>::notify_async_progress(const AsyncRequestId &request,
114 uint64_t offset, uint64_t total) {
115 ldout(m_image_ctx.cct, 20) << this << " remote async request progress: "
116 << request << " @ " << offset
117 << "/" << total << dendl;
118
119 send_notify(AsyncProgressPayload(request, offset, total));
120 return 0;
121}
122
123template <typename I>
124void ImageWatcher<I>::schedule_async_complete(const AsyncRequestId &request,
125 int r) {
126 FunctionContext *ctx = new FunctionContext(
127 boost::bind(&ImageWatcher<I>::notify_async_complete, this, request, r));
128 m_task_finisher->queue(ctx);
129}
130
131template <typename I>
132void ImageWatcher<I>::notify_async_complete(const AsyncRequestId &request,
133 int r) {
134 ldout(m_image_ctx.cct, 20) << this << " remote async request finished: "
135 << request << " = " << r << dendl;
136
137 send_notify(AsyncCompletePayload(request, r),
138 new FunctionContext(boost::bind(&ImageWatcher<I>::handle_async_complete,
139 this, request, r, _1)));
140}
141
142template <typename I>
143void ImageWatcher<I>::handle_async_complete(const AsyncRequestId &request,
144 int r, int ret_val) {
145 ldout(m_image_ctx.cct, 20) << this << " " << __func__ << ": "
146 << "request=" << request << ", r=" << ret_val
147 << dendl;
148 if (ret_val < 0) {
149 lderr(m_image_ctx.cct) << this << " failed to notify async complete: "
150 << cpp_strerror(ret_val) << dendl;
151 if (ret_val == -ETIMEDOUT) {
152 schedule_async_complete(request, r);
153 }
154 } else {
155 RWLock::WLocker async_request_locker(m_async_request_lock);
156 m_async_pending.erase(request);
157 }
158}
159
160template <typename I>
161void ImageWatcher<I>::notify_flatten(uint64_t request_id,
162 ProgressContext &prog_ctx,
163 Context *on_finish) {
164 assert(m_image_ctx.owner_lock.is_locked());
165 assert(m_image_ctx.exclusive_lock &&
166 !m_image_ctx.exclusive_lock->is_lock_owner());
167
168 AsyncRequestId async_request_id(get_client_id(), request_id);
169
170 notify_async_request(async_request_id, FlattenPayload(async_request_id),
171 prog_ctx, on_finish);
172}
173
174template <typename I>
175void ImageWatcher<I>::notify_resize(uint64_t request_id, uint64_t size,
176 bool allow_shrink,
177 ProgressContext &prog_ctx,
178 Context *on_finish) {
179 assert(m_image_ctx.owner_lock.is_locked());
180 assert(m_image_ctx.exclusive_lock &&
181 !m_image_ctx.exclusive_lock->is_lock_owner());
182
183 AsyncRequestId async_request_id(get_client_id(), request_id);
184
185 notify_async_request(async_request_id,
186 ResizePayload(size, allow_shrink, async_request_id),
187 prog_ctx, on_finish);
188}
189
190template <typename I>
191void ImageWatcher<I>::notify_snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
192 const std::string &snap_name,
193 Context *on_finish) {
194 assert(m_image_ctx.owner_lock.is_locked());
195 assert(m_image_ctx.exclusive_lock &&
196 !m_image_ctx.exclusive_lock->is_lock_owner());
197
198 notify_lock_owner(SnapCreatePayload(snap_namespace, snap_name), on_finish);
199}
200
201template <typename I>
202void ImageWatcher<I>::notify_snap_rename(const snapid_t &src_snap_id,
203 const std::string &dst_snap_name,
204 Context *on_finish) {
205 assert(m_image_ctx.owner_lock.is_locked());
206 assert(m_image_ctx.exclusive_lock &&
207 !m_image_ctx.exclusive_lock->is_lock_owner());
208
209 notify_lock_owner(SnapRenamePayload(src_snap_id, dst_snap_name), on_finish);
210}
211
212template <typename I>
213void ImageWatcher<I>::notify_snap_remove(const cls::rbd::SnapshotNamespace &snap_namespace,
214 const std::string &snap_name,
215 Context *on_finish) {
216 assert(m_image_ctx.owner_lock.is_locked());
217 assert(m_image_ctx.exclusive_lock &&
218 !m_image_ctx.exclusive_lock->is_lock_owner());
219
220 notify_lock_owner(SnapRemovePayload(snap_namespace, snap_name), on_finish);
221}
222
223template <typename I>
224void ImageWatcher<I>::notify_snap_protect(const cls::rbd::SnapshotNamespace &snap_namespace,
225 const std::string &snap_name,
226 Context *on_finish) {
227 assert(m_image_ctx.owner_lock.is_locked());
228 assert(m_image_ctx.exclusive_lock &&
229 !m_image_ctx.exclusive_lock->is_lock_owner());
230
231 notify_lock_owner(SnapProtectPayload(snap_namespace, snap_name), on_finish);
232}
233
234template <typename I>
235void ImageWatcher<I>::notify_snap_unprotect(const cls::rbd::SnapshotNamespace &snap_namespace,
236 const std::string &snap_name,
237 Context *on_finish) {
238 assert(m_image_ctx.owner_lock.is_locked());
239 assert(m_image_ctx.exclusive_lock &&
240 !m_image_ctx.exclusive_lock->is_lock_owner());
241
242 notify_lock_owner(SnapUnprotectPayload(snap_namespace, snap_name), on_finish);
243}
244
245template <typename I>
246void ImageWatcher<I>::notify_rebuild_object_map(uint64_t request_id,
247 ProgressContext &prog_ctx,
248 Context *on_finish) {
249 assert(m_image_ctx.owner_lock.is_locked());
250 assert(m_image_ctx.exclusive_lock &&
251 !m_image_ctx.exclusive_lock->is_lock_owner());
252
253 AsyncRequestId async_request_id(get_client_id(), request_id);
254
255 notify_async_request(async_request_id,
256 RebuildObjectMapPayload(async_request_id),
257 prog_ctx, on_finish);
258}
259
260template <typename I>
261void ImageWatcher<I>::notify_rename(const std::string &image_name,
262 Context *on_finish) {
263 assert(m_image_ctx.owner_lock.is_locked());
264 assert(m_image_ctx.exclusive_lock &&
265 !m_image_ctx.exclusive_lock->is_lock_owner());
266
267 notify_lock_owner(RenamePayload(image_name), on_finish);
268}
269
270template <typename I>
271void ImageWatcher<I>::notify_update_features(uint64_t features, bool enabled,
272 Context *on_finish) {
273 assert(m_image_ctx.owner_lock.is_locked());
274 assert(m_image_ctx.exclusive_lock &&
275 !m_image_ctx.exclusive_lock->is_lock_owner());
276
277 notify_lock_owner(UpdateFeaturesPayload(features, enabled), on_finish);
278}
279
280template <typename I>
281void ImageWatcher<I>::notify_header_update(Context *on_finish) {
282 ldout(m_image_ctx.cct, 10) << this << ": " << __func__ << dendl;
283
284 // supports legacy (empty buffer) clients
285 send_notify(HeaderUpdatePayload(), on_finish);
286}
287
288template <typename I>
289void ImageWatcher<I>::notify_header_update(librados::IoCtx &io_ctx,
290 const std::string &oid) {
291 // supports legacy (empty buffer) clients
292 bufferlist bl;
293 ::encode(NotifyMessage(HeaderUpdatePayload()), bl);
294 io_ctx.notify2(oid, bl, watcher::Notifier::NOTIFY_TIMEOUT, nullptr);
295}
296
297template <typename I>
298void ImageWatcher<I>::schedule_cancel_async_requests() {
299 FunctionContext *ctx = new FunctionContext(
300 boost::bind(&ImageWatcher<I>::cancel_async_requests, this));
301 m_task_finisher->queue(TASK_CODE_CANCEL_ASYNC_REQUESTS, ctx);
302}
303
304template <typename I>
305void ImageWatcher<I>::cancel_async_requests() {
306 RWLock::WLocker l(m_async_request_lock);
307 for (std::map<AsyncRequestId, AsyncRequest>::iterator iter =
308 m_async_requests.begin();
309 iter != m_async_requests.end(); ++iter) {
310 iter->second.first->complete(-ERESTART);
311 }
312 m_async_requests.clear();
313}
314
315template <typename I>
316void ImageWatcher<I>::set_owner_client_id(const ClientId& client_id) {
317 assert(m_owner_client_id_lock.is_locked());
318 m_owner_client_id = client_id;
319 ldout(m_image_ctx.cct, 10) << this << " current lock owner: "
320 << m_owner_client_id << dendl;
321}
322
323template <typename I>
324ClientId ImageWatcher<I>::get_client_id() {
325 RWLock::RLocker l(this->m_watch_lock);
326 return ClientId(m_image_ctx.md_ctx.get_instance_id(), this->m_watch_handle);
327}
328
329template <typename I>
330void ImageWatcher<I>::notify_acquired_lock() {
331 ldout(m_image_ctx.cct, 10) << this << " notify acquired lock" << dendl;
332
333 ClientId client_id = get_client_id();
334 {
335 Mutex::Locker owner_client_id_locker(m_owner_client_id_lock);
336 set_owner_client_id(client_id);
337 }
338
339 send_notify(AcquiredLockPayload(client_id));
340}
341
342template <typename I>
343void ImageWatcher<I>::notify_released_lock() {
344 ldout(m_image_ctx.cct, 10) << this << " notify released lock" << dendl;
345
346 {
347 Mutex::Locker owner_client_id_locker(m_owner_client_id_lock);
348 set_owner_client_id(ClientId());
349 }
350
351 send_notify(ReleasedLockPayload(get_client_id()));
352}
353
354template <typename I>
355void ImageWatcher<I>::schedule_request_lock(bool use_timer, int timer_delay) {
356 assert(m_image_ctx.owner_lock.is_locked());
357
358 if (m_image_ctx.exclusive_lock == nullptr) {
359 // exclusive lock dynamically disabled via image refresh
360 return;
361 }
362 assert(m_image_ctx.exclusive_lock &&
363 !m_image_ctx.exclusive_lock->is_lock_owner());
364
365 RWLock::RLocker watch_locker(this->m_watch_lock);
366 if (this->m_watch_state == Watcher::WATCH_STATE_REGISTERED) {
367 ldout(m_image_ctx.cct, 15) << this << " requesting exclusive lock" << dendl;
368
369 FunctionContext *ctx = new FunctionContext(
370 boost::bind(&ImageWatcher<I>::notify_request_lock, this));
371 if (use_timer) {
372 if (timer_delay < 0) {
373 timer_delay = RETRY_DELAY_SECONDS;
374 }
375 m_task_finisher->add_event_after(TASK_CODE_REQUEST_LOCK,
376 timer_delay, ctx);
377 } else {
378 m_task_finisher->queue(TASK_CODE_REQUEST_LOCK, ctx);
379 }
380 }
381}
382
383template <typename I>
384void ImageWatcher<I>::notify_request_lock() {
385 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
386 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
387
388 // ExclusiveLock state machine can be dynamically disabled or
389 // race with task cancel
390 if (m_image_ctx.exclusive_lock == nullptr ||
391 m_image_ctx.exclusive_lock->is_lock_owner()) {
392 return;
393 }
394
395 ldout(m_image_ctx.cct, 10) << this << " notify request lock" << dendl;
396
397 notify_lock_owner(RequestLockPayload(get_client_id(), false),
398 create_context_callback<
399 ImageWatcher, &ImageWatcher<I>::handle_request_lock>(this));
400}
401
402template <typename I>
403void ImageWatcher<I>::handle_request_lock(int r) {
404 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
405 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
406
407 // ExclusiveLock state machine cannot transition -- but can be
408 // dynamically disabled
409 if (m_image_ctx.exclusive_lock == nullptr) {
410 return;
411 }
412
413 if (r == -ETIMEDOUT) {
414 ldout(m_image_ctx.cct, 5) << this << " timed out requesting lock: retrying"
415 << dendl;
416
417 // treat this is a dead client -- so retest acquiring the lock
418 m_image_ctx.exclusive_lock->handle_peer_notification(0);
419 } else if (r == -EROFS) {
420 ldout(m_image_ctx.cct, 5) << this << " peer will not release lock" << dendl;
421 m_image_ctx.exclusive_lock->handle_peer_notification(r);
422 } else if (r < 0) {
423 lderr(m_image_ctx.cct) << this << " error requesting lock: "
424 << cpp_strerror(r) << dendl;
425 schedule_request_lock(true);
426 } else {
427 // lock owner acked -- but resend if we don't see them release the lock
181888fb
FG
428 int retry_timeout = m_image_ctx.cct->_conf->template get_val<int64_t>(
429 "client_notify_timeout");
7c673cae
FG
430 ldout(m_image_ctx.cct, 15) << this << " will retry in " << retry_timeout
431 << " seconds" << dendl;
432 schedule_request_lock(true, retry_timeout);
433 }
434}
435
436template <typename I>
437void ImageWatcher<I>::notify_lock_owner(const Payload& payload,
438 Context *on_finish) {
439 assert(on_finish != nullptr);
440 assert(m_image_ctx.owner_lock.is_locked());
441
442 bufferlist bl;
443 ::encode(NotifyMessage(payload), bl);
444
445 NotifyLockOwner *notify_lock_owner = NotifyLockOwner::create(
446 m_image_ctx, this->m_notifier, std::move(bl), on_finish);
447 notify_lock_owner->send();
448}
449
450template <typename I>
451Context *ImageWatcher<I>::remove_async_request(const AsyncRequestId &id) {
452 RWLock::WLocker async_request_locker(m_async_request_lock);
453 auto it = m_async_requests.find(id);
454 if (it != m_async_requests.end()) {
455 Context *on_complete = it->second.first;
456 m_async_requests.erase(it);
457 return on_complete;
458 }
459 return nullptr;
460}
461
462template <typename I>
463void ImageWatcher<I>::schedule_async_request_timed_out(const AsyncRequestId &id) {
464 ldout(m_image_ctx.cct, 20) << "scheduling async request time out: " << id
465 << dendl;
466
467 Context *ctx = new FunctionContext(boost::bind(
468 &ImageWatcher<I>::async_request_timed_out, this, id));
469
470 Task task(TASK_CODE_ASYNC_REQUEST, id);
471 m_task_finisher->cancel(task);
472
473 m_task_finisher->add_event_after(task, m_image_ctx.request_timed_out_seconds,
474 ctx);
475}
476
477template <typename I>
478void ImageWatcher<I>::async_request_timed_out(const AsyncRequestId &id) {
479 Context *on_complete = remove_async_request(id);
480 if (on_complete != nullptr) {
481 ldout(m_image_ctx.cct, 5) << "async request timed out: " << id << dendl;
482 m_image_ctx.op_work_queue->queue(on_complete, -ETIMEDOUT);
483 }
484}
485
486template <typename I>
487void ImageWatcher<I>::notify_async_request(const AsyncRequestId &async_request_id,
488 const Payload& payload,
489 ProgressContext& prog_ctx,
490 Context *on_finish) {
491 assert(on_finish != nullptr);
492 assert(m_image_ctx.owner_lock.is_locked());
493
494 ldout(m_image_ctx.cct, 10) << this << " async request: " << async_request_id
495 << dendl;
496
497 Context *on_notify = new FunctionContext([this, async_request_id](int r) {
498 if (r < 0) {
499 // notification failed -- don't expect updates
500 Context *on_complete = remove_async_request(async_request_id);
501 if (on_complete != nullptr) {
502 on_complete->complete(r);
503 }
504 }
505 });
506
507 Context *on_complete = new FunctionContext(
508 [this, async_request_id, on_finish](int r) {
509 m_task_finisher->cancel(Task(TASK_CODE_ASYNC_REQUEST, async_request_id));
510 on_finish->complete(r);
511 });
512
513 {
514 RWLock::WLocker async_request_locker(m_async_request_lock);
515 m_async_requests[async_request_id] = AsyncRequest(on_complete, &prog_ctx);
516 }
517
518 schedule_async_request_timed_out(async_request_id);
519 notify_lock_owner(payload, on_notify);
520}
521
522template <typename I>
523int ImageWatcher<I>::prepare_async_request(const AsyncRequestId& async_request_id,
524 bool* new_request, Context** ctx,
525 ProgressContext** prog_ctx) {
526 if (async_request_id.client_id == get_client_id()) {
527 return -ERESTART;
528 } else {
529 RWLock::WLocker l(m_async_request_lock);
530 if (m_async_pending.count(async_request_id) == 0) {
531 m_async_pending.insert(async_request_id);
532 *new_request = true;
533 *prog_ctx = new RemoteProgressContext(*this, async_request_id);
534 *ctx = new RemoteContext(*this, async_request_id, *prog_ctx);
535 } else {
536 *new_request = false;
537 }
538 }
539 return 0;
540}
541
542template <typename I>
543bool ImageWatcher<I>::handle_payload(const HeaderUpdatePayload &payload,
544 C_NotifyAck *ack_ctx) {
545 ldout(m_image_ctx.cct, 10) << this << " image header updated" << dendl;
546
547 m_image_ctx.state->handle_update_notification();
548 m_image_ctx.perfcounter->inc(l_librbd_notify);
549 if (ack_ctx != nullptr) {
550 m_image_ctx.state->flush_update_watchers(new C_ResponseMessage(ack_ctx));
551 return false;
552 }
553 return true;
554}
555
556template <typename I>
557bool ImageWatcher<I>::handle_payload(const AcquiredLockPayload &payload,
558 C_NotifyAck *ack_ctx) {
559 ldout(m_image_ctx.cct, 10) << this << " image exclusively locked announcement"
560 << dendl;
561
562 bool cancel_async_requests = true;
563 if (payload.client_id.is_valid()) {
564 Mutex::Locker owner_client_id_locker(m_owner_client_id_lock);
565 if (payload.client_id == m_owner_client_id) {
566 cancel_async_requests = false;
567 }
568 set_owner_client_id(payload.client_id);
569 }
570
571 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
572 if (m_image_ctx.exclusive_lock != nullptr) {
573 // potentially wake up the exclusive lock state machine now that
574 // a lock owner has advertised itself
575 m_image_ctx.exclusive_lock->handle_peer_notification(0);
576 }
577 if (cancel_async_requests &&
578 (m_image_ctx.exclusive_lock == nullptr ||
579 !m_image_ctx.exclusive_lock->is_lock_owner())) {
580 schedule_cancel_async_requests();
581 }
582 return true;
583}
584
585template <typename I>
586bool ImageWatcher<I>::handle_payload(const ReleasedLockPayload &payload,
587 C_NotifyAck *ack_ctx) {
588 ldout(m_image_ctx.cct, 10) << this << " exclusive lock released" << dendl;
589
590 bool cancel_async_requests = true;
591 if (payload.client_id.is_valid()) {
592 Mutex::Locker l(m_owner_client_id_lock);
593 if (payload.client_id != m_owner_client_id) {
594 ldout(m_image_ctx.cct, 10) << this << " unexpected owner: "
595 << payload.client_id << " != "
596 << m_owner_client_id << dendl;
597 cancel_async_requests = false;
598 } else {
599 set_owner_client_id(ClientId());
600 }
601 }
602
603 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
604 if (cancel_async_requests &&
605 (m_image_ctx.exclusive_lock == nullptr ||
606 !m_image_ctx.exclusive_lock->is_lock_owner())) {
607 schedule_cancel_async_requests();
608 }
609
610 // alert the exclusive lock state machine that the lock is available
611 if (m_image_ctx.exclusive_lock != nullptr &&
612 !m_image_ctx.exclusive_lock->is_lock_owner()) {
613 m_task_finisher->cancel(TASK_CODE_REQUEST_LOCK);
614 m_image_ctx.exclusive_lock->handle_peer_notification(0);
615 }
616 return true;
617}
618
619template <typename I>
620bool ImageWatcher<I>::handle_payload(const RequestLockPayload &payload,
621 C_NotifyAck *ack_ctx) {
622 ldout(m_image_ctx.cct, 10) << this << " exclusive lock requested" << dendl;
623 if (payload.client_id == get_client_id()) {
624 return true;
625 }
626
627 RWLock::RLocker l(m_image_ctx.owner_lock);
628 if (m_image_ctx.exclusive_lock != nullptr &&
629 m_image_ctx.exclusive_lock->is_lock_owner()) {
630 int r = 0;
631 bool accept_request = m_image_ctx.exclusive_lock->accept_requests(&r);
632
633 if (accept_request) {
634 assert(r == 0);
635 Mutex::Locker owner_client_id_locker(m_owner_client_id_lock);
636 if (!m_owner_client_id.is_valid()) {
637 return true;
638 }
639
640 ldout(m_image_ctx.cct, 10) << this << " queuing release of exclusive lock"
641 << dendl;
642 r = m_image_ctx.get_exclusive_lock_policy()->lock_requested(
643 payload.force);
644 }
645 ::encode(ResponseMessage(r), ack_ctx->out);
646 }
647 return true;
648}
649
650template <typename I>
651bool ImageWatcher<I>::handle_payload(const AsyncProgressPayload &payload,
652 C_NotifyAck *ack_ctx) {
653 RWLock::RLocker l(m_async_request_lock);
654 std::map<AsyncRequestId, AsyncRequest>::iterator req_it =
655 m_async_requests.find(payload.async_request_id);
656 if (req_it != m_async_requests.end()) {
657 ldout(m_image_ctx.cct, 20) << this << " request progress: "
658 << payload.async_request_id << " @ "
659 << payload.offset << "/" << payload.total
660 << dendl;
661 schedule_async_request_timed_out(payload.async_request_id);
662 req_it->second.second->update_progress(payload.offset, payload.total);
663 }
664 return true;
665}
666
667template <typename I>
668bool ImageWatcher<I>::handle_payload(const AsyncCompletePayload &payload,
669 C_NotifyAck *ack_ctx) {
670 Context *on_complete = remove_async_request(payload.async_request_id);
671 if (on_complete != nullptr) {
672 ldout(m_image_ctx.cct, 10) << this << " request finished: "
673 << payload.async_request_id << "="
674 << payload.result << dendl;
675 on_complete->complete(payload.result);
676 }
677 return true;
678}
679
680template <typename I>
681bool ImageWatcher<I>::handle_payload(const FlattenPayload &payload,
682 C_NotifyAck *ack_ctx) {
683
684 RWLock::RLocker l(m_image_ctx.owner_lock);
685 if (m_image_ctx.exclusive_lock != nullptr) {
686 int r;
687 if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
688 bool new_request;
689 Context *ctx;
690 ProgressContext *prog_ctx;
691 r = prepare_async_request(payload.async_request_id, &new_request,
692 &ctx, &prog_ctx);
693 if (r == 0 && new_request) {
694 ldout(m_image_ctx.cct, 10) << this << " remote flatten request: "
695 << payload.async_request_id << dendl;
696 m_image_ctx.operations->execute_flatten(*prog_ctx, ctx);
697 }
698
699 ::encode(ResponseMessage(r), ack_ctx->out);
700 } else if (r < 0) {
701 ::encode(ResponseMessage(r), ack_ctx->out);
702 }
703 }
704 return true;
705}
706
707template <typename I>
708bool ImageWatcher<I>::handle_payload(const ResizePayload &payload,
709 C_NotifyAck *ack_ctx) {
710 RWLock::RLocker l(m_image_ctx.owner_lock);
711 if (m_image_ctx.exclusive_lock != nullptr) {
712 int r;
713 if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
714 bool new_request;
715 Context *ctx;
716 ProgressContext *prog_ctx;
717 r = prepare_async_request(payload.async_request_id, &new_request,
718 &ctx, &prog_ctx);
719 if (r == 0 && new_request) {
720 ldout(m_image_ctx.cct, 10) << this << " remote resize request: "
721 << payload.async_request_id << " "
722 << payload.size << " "
723 << payload.allow_shrink << dendl;
724 m_image_ctx.operations->execute_resize(payload.size, payload.allow_shrink, *prog_ctx, ctx, 0);
725 }
726
727 ::encode(ResponseMessage(r), ack_ctx->out);
728 } else if (r < 0) {
729 ::encode(ResponseMessage(r), ack_ctx->out);
730 }
731 }
732 return true;
733}
734
735template <typename I>
736bool ImageWatcher<I>::handle_payload(const SnapCreatePayload &payload,
737 C_NotifyAck *ack_ctx) {
738 RWLock::RLocker l(m_image_ctx.owner_lock);
739 if (m_image_ctx.exclusive_lock != nullptr) {
740 int r;
741 if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
742 ldout(m_image_ctx.cct, 10) << this << " remote snap_create request: "
743 << payload.snap_name << dendl;
744
745 m_image_ctx.operations->execute_snap_create(payload.snap_namespace,
746 payload.snap_name,
747 new C_ResponseMessage(ack_ctx),
748 0, false);
749 return false;
750 } else if (r < 0) {
751 ::encode(ResponseMessage(r), ack_ctx->out);
752 }
753 }
754 return true;
755}
756
757template <typename I>
758bool ImageWatcher<I>::handle_payload(const SnapRenamePayload &payload,
759 C_NotifyAck *ack_ctx) {
760 RWLock::RLocker l(m_image_ctx.owner_lock);
761 if (m_image_ctx.exclusive_lock != nullptr) {
762 int r;
763 if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
764 ldout(m_image_ctx.cct, 10) << this << " remote snap_rename request: "
765 << payload.snap_id << " to "
766 << payload.snap_name << dendl;
767
768 m_image_ctx.operations->execute_snap_rename(payload.snap_id,
769 payload.snap_name,
770 new C_ResponseMessage(ack_ctx));
771 return false;
772 } else if (r < 0) {
773 ::encode(ResponseMessage(r), ack_ctx->out);
774 }
775 }
776 return true;
777}
778
779template <typename I>
780bool ImageWatcher<I>::handle_payload(const SnapRemovePayload &payload,
781 C_NotifyAck *ack_ctx) {
782 RWLock::RLocker l(m_image_ctx.owner_lock);
783 if (m_image_ctx.exclusive_lock != nullptr) {
784 int r;
785 if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
786 ldout(m_image_ctx.cct, 10) << this << " remote snap_remove request: "
787 << payload.snap_name << dendl;
788
789 m_image_ctx.operations->execute_snap_remove(payload.snap_namespace,
790 payload.snap_name,
791 new C_ResponseMessage(ack_ctx));
792 return false;
793 } else if (r < 0) {
794 ::encode(ResponseMessage(r), ack_ctx->out);
795 }
796 }
797 return true;
798}
799
800template <typename I>
801bool ImageWatcher<I>::handle_payload(const SnapProtectPayload& payload,
802 C_NotifyAck *ack_ctx) {
803 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
804 if (m_image_ctx.exclusive_lock != nullptr) {
805 int r;
806 if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
807 ldout(m_image_ctx.cct, 10) << this << " remote snap_protect request: "
808 << payload.snap_name << dendl;
809
810 m_image_ctx.operations->execute_snap_protect(payload.snap_namespace,
811 payload.snap_name,
812 new C_ResponseMessage(ack_ctx));
813 return false;
814 } else if (r < 0) {
815 ::encode(ResponseMessage(r), ack_ctx->out);
816 }
817 }
818 return true;
819}
820
821template <typename I>
822bool ImageWatcher<I>::handle_payload(const SnapUnprotectPayload& payload,
823 C_NotifyAck *ack_ctx) {
824 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
825 if (m_image_ctx.exclusive_lock != nullptr) {
826 int r;
827 if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
828 ldout(m_image_ctx.cct, 10) << this << " remote snap_unprotect request: "
829 << payload.snap_name << dendl;
830
831 m_image_ctx.operations->execute_snap_unprotect(payload.snap_namespace,
832 payload.snap_name,
833 new C_ResponseMessage(ack_ctx));
834 return false;
835 } else if (r < 0) {
836 ::encode(ResponseMessage(r), ack_ctx->out);
837 }
838 }
839 return true;
840}
841
842template <typename I>
843bool ImageWatcher<I>::handle_payload(const RebuildObjectMapPayload& payload,
844 C_NotifyAck *ack_ctx) {
845 RWLock::RLocker l(m_image_ctx.owner_lock);
846 if (m_image_ctx.exclusive_lock != nullptr) {
847 int r;
848 if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
849 bool new_request;
850 Context *ctx;
851 ProgressContext *prog_ctx;
852 r = prepare_async_request(payload.async_request_id, &new_request,
853 &ctx, &prog_ctx);
854 if (r == 0 && new_request) {
855 ldout(m_image_ctx.cct, 10) << this
856 << " remote rebuild object map request: "
857 << payload.async_request_id << dendl;
858 m_image_ctx.operations->execute_rebuild_object_map(*prog_ctx, ctx);
859 }
860
861 ::encode(ResponseMessage(r), ack_ctx->out);
862 } else if (r < 0) {
863 ::encode(ResponseMessage(r), ack_ctx->out);
864 }
865 }
866 return true;
867}
868
869template <typename I>
870bool ImageWatcher<I>::handle_payload(const RenamePayload& payload,
871 C_NotifyAck *ack_ctx) {
872 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
873 if (m_image_ctx.exclusive_lock != nullptr) {
874 int r;
875 if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
876 ldout(m_image_ctx.cct, 10) << this << " remote rename request: "
877 << payload.image_name << dendl;
878
879 m_image_ctx.operations->execute_rename(payload.image_name,
880 new C_ResponseMessage(ack_ctx));
881 return false;
882 } else if (r < 0) {
883 ::encode(ResponseMessage(r), ack_ctx->out);
884 }
885 }
886 return true;
887}
888
889template <typename I>
890bool ImageWatcher<I>::handle_payload(const UpdateFeaturesPayload& payload,
891 C_NotifyAck *ack_ctx) {
892 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
893 if (m_image_ctx.exclusive_lock != nullptr) {
894 int r;
895 if (m_image_ctx.exclusive_lock->accept_requests(&r)) {
896 ldout(m_image_ctx.cct, 10) << this << " remote update_features request: "
897 << payload.features << " "
898 << (payload.enabled ? "enabled" : "disabled")
899 << dendl;
900
901 m_image_ctx.operations->execute_update_features(
902 payload.features, payload.enabled, new C_ResponseMessage(ack_ctx), 0);
903 return false;
904 } else if (r < 0) {
905 ::encode(ResponseMessage(r), ack_ctx->out);
906 }
907 }
908 return true;
909}
910
911template <typename I>
912bool ImageWatcher<I>::handle_payload(const UnknownPayload &payload,
913 C_NotifyAck *ack_ctx) {
914 RWLock::RLocker l(m_image_ctx.owner_lock);
915 if (m_image_ctx.exclusive_lock != nullptr) {
916 int r;
917 if (m_image_ctx.exclusive_lock->accept_requests(&r) || r < 0) {
918 ::encode(ResponseMessage(-EOPNOTSUPP), ack_ctx->out);
919 }
920 }
921 return true;
922}
923
924template <typename I>
925void ImageWatcher<I>::process_payload(uint64_t notify_id, uint64_t handle,
31f18b77
FG
926 const Payload &payload) {
927 apply_visitor(HandlePayloadVisitor<ImageWatcher<I>>(this, notify_id, handle),
928 payload);
7c673cae
FG
929}
930
931template <typename I>
932void ImageWatcher<I>::handle_notify(uint64_t notify_id, uint64_t handle,
933 uint64_t notifier_id, bufferlist &bl) {
934 NotifyMessage notify_message;
935 if (bl.length() == 0) {
936 // legacy notification for header updates
937 notify_message = NotifyMessage(HeaderUpdatePayload());
938 } else {
939 try {
940 bufferlist::iterator iter = bl.begin();
941 ::decode(notify_message, iter);
942 } catch (const buffer::error &err) {
943 lderr(m_image_ctx.cct) << this << " error decoding image notification: "
944 << err.what() << dendl;
945 return;
946 }
947 }
948
949 // if an image refresh is required, refresh before processing the request
950 if (notify_message.check_for_refresh() &&
951 m_image_ctx.state->is_refresh_required()) {
952 m_image_ctx.state->refresh(new C_ProcessPayload(this, notify_id, handle,
953 notify_message.payload));
954 } else {
31f18b77 955 process_payload(notify_id, handle, notify_message.payload);
7c673cae
FG
956 }
957}
958
959template <typename I>
960void ImageWatcher<I>::handle_error(uint64_t handle, int err) {
961 lderr(m_image_ctx.cct) << this << " image watch failed: " << handle << ", "
962 << cpp_strerror(err) << dendl;
963
964 {
965 Mutex::Locker l(m_owner_client_id_lock);
966 set_owner_client_id(ClientId());
967 }
968
969 Watcher::handle_error(handle, err);
970}
971
972template <typename I>
973void ImageWatcher<I>::handle_rewatch_complete(int r) {
974 CephContext *cct = m_image_ctx.cct;
975 ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
976
977 {
978 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
979 if (m_image_ctx.exclusive_lock != nullptr) {
980 // update the lock cookie with the new watch handle
981 m_image_ctx.exclusive_lock->reacquire_lock();
982 }
983 }
984
985 // image might have been updated while we didn't have active watch
986 handle_payload(HeaderUpdatePayload(), nullptr);
987}
988
989template <typename I>
990void ImageWatcher<I>::send_notify(const Payload &payload, Context *ctx) {
991 bufferlist bl;
992
993 ::encode(NotifyMessage(payload), bl);
994 Watcher::send_notify(bl, nullptr, ctx);
995}
996
997template <typename I>
998void ImageWatcher<I>::RemoteContext::finish(int r) {
999 m_image_watcher.schedule_async_complete(m_async_request_id, r);
1000}
1001
1002template <typename I>
1003void ImageWatcher<I>::C_ResponseMessage::finish(int r) {
1004 CephContext *cct = notify_ack->cct;
1005 ldout(cct, 10) << this << " C_ResponseMessage: r=" << r << dendl;
1006
1007 ::encode(ResponseMessage(r), notify_ack->out);
1008 notify_ack->complete(0);
1009}
1010
1011} // namespace librbd
1012
1013template class librbd::ImageWatcher<librbd::ImageCtx>;