Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / ImageWatcher.cc
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
25 namespace librbd {
26
27 using namespace image_watcher;
28 using namespace watch_notify;
29 using util::create_async_context_callback;
30 using util::create_context_callback;
31 using util::create_rados_callback;
32 using librbd::watcher::util::HandlePayloadVisitor;
33
34 static const double     RETRY_DELAY_SECONDS = 1.0;
35
36 template <typename I>
37 struct 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
62 template <typename I>
63 ImageWatcher<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
72 template <typename I>
73 ImageWatcher<I>::~ImageWatcher()
74 {
75   delete m_task_finisher;
76 }
77
78 template <typename I>
79 void 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
91 template <typename I>
92 void 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
103 template <typename I>
104 void 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
112 template <typename I>
113 int 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
123 template <typename I>
124 void 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
131 template <typename I>
132 void 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
142 template <typename I>
143 void 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
160 template <typename I>
161 void 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
174 template <typename I>
175 void 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
190 template <typename I>
191 void 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
201 template <typename I>
202 void 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
212 template <typename I>
213 void 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
223 template <typename I>
224 void 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
234 template <typename I>
235 void 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
245 template <typename I>
246 void 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
260 template <typename I>
261 void 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
270 template <typename I>
271 void 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
280 template <typename I>
281 void 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
288 template <typename I>
289 void 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
297 template <typename I>
298 void 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
304 template <typename I>
305 void 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
315 template <typename I>
316 void 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
323 template <typename I>
324 ClientId 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
329 template <typename I>
330 void 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
342 template <typename I>
343 void 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
354 template <typename I>
355 void 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
383 template <typename I>
384 void 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
402 template <typename I>
403 void 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
428     int retry_timeout = m_image_ctx.cct->_conf->template get_val<int64_t>(
429       "client_notify_timeout");
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
436 template <typename I>
437 void 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
450 template <typename I>
451 Context *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
462 template <typename I>
463 void 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
477 template <typename I>
478 void 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
486 template <typename I>
487 void 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
522 template <typename I>
523 int 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
542 template <typename I>
543 bool 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
556 template <typename I>
557 bool 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
585 template <typename I>
586 bool 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
619 template <typename I>
620 bool 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
650 template <typename I>
651 bool 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
667 template <typename I>
668 bool 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
680 template <typename I>
681 bool 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
707 template <typename I>
708 bool 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
735 template <typename I>
736 bool 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
757 template <typename I>
758 bool 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
779 template <typename I>
780 bool 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
800 template <typename I>
801 bool 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
821 template <typename I>
822 bool 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
842 template <typename I>
843 bool 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
869 template <typename I>
870 bool 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
889 template <typename I>
890 bool 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
911 template <typename I>
912 bool 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
924 template <typename I>
925 void ImageWatcher<I>::process_payload(uint64_t notify_id, uint64_t handle,
926                                       const Payload &payload) {
927   apply_visitor(HandlePayloadVisitor<ImageWatcher<I>>(this, notify_id, handle),
928                 payload);
929 }
930
931 template <typename I>
932 void 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 {
955     process_payload(notify_id, handle, notify_message.payload);
956   }
957 }
958
959 template <typename I>
960 void 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
972 template <typename I>
973 void 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
989 template <typename I>
990 void 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
997 template <typename I>
998 void ImageWatcher<I>::RemoteContext::finish(int r) {
999   m_image_watcher.schedule_async_complete(m_async_request_id, r);
1000 }
1001
1002 template <typename I>
1003 void 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
1013 template class librbd::ImageWatcher<librbd::ImageCtx>;