Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / image / RefreshRequest.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/image/RefreshRequest.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "cls/lock/cls_lock_client.h"
8 #include "cls/rbd/cls_rbd_client.h"
9 #include "librbd/ExclusiveLock.h"
10 #include "librbd/ImageCtx.h"
11 #include "librbd/Journal.h"
12 #include "librbd/ObjectMap.h"
13 #include "librbd/Utils.h"
14 #include "librbd/image/RefreshParentRequest.h"
15 #include "librbd/io/ImageRequestWQ.h"
16 #include "librbd/journal/Policy.h"
17
18 #define dout_subsys ceph_subsys_rbd
19 #undef dout_prefix
20 #define dout_prefix *_dout << "librbd::image::RefreshRequest: "
21
22 namespace librbd {
23 namespace image {
24
25 using util::create_rados_callback;
26 using util::create_async_context_callback;
27 using util::create_context_callback;
28
29 template <typename I>
30 RefreshRequest<I>::RefreshRequest(I &image_ctx, bool acquiring_lock,
31                                   bool skip_open_parent, Context *on_finish)
32   : m_image_ctx(image_ctx), m_acquiring_lock(acquiring_lock),
33     m_skip_open_parent_image(skip_open_parent),
34     m_on_finish(create_async_context_callback(m_image_ctx, on_finish)),
35     m_error_result(0), m_flush_aio(false), m_exclusive_lock(nullptr),
36     m_object_map(nullptr), m_journal(nullptr), m_refresh_parent(nullptr) {
37 }
38
39 template <typename I>
40 RefreshRequest<I>::~RefreshRequest() {
41   // these require state machine to close
42   assert(m_exclusive_lock == nullptr);
43   assert(m_object_map == nullptr);
44   assert(m_journal == nullptr);
45   assert(m_refresh_parent == nullptr);
46   assert(!m_blocked_writes);
47 }
48
49 template <typename I>
50 void RefreshRequest<I>::send() {
51   if (m_image_ctx.old_format) {
52     send_v1_read_header();
53   } else {
54     send_v2_get_mutable_metadata();
55   }
56 }
57
58 template <typename I>
59 void RefreshRequest<I>::send_v1_read_header() {
60   CephContext *cct = m_image_ctx.cct;
61   ldout(cct, 10) << this << " " << __func__ << dendl;
62
63   librados::ObjectReadOperation op;
64   op.read(0, 0, nullptr, nullptr);
65
66   using klass = RefreshRequest<I>;
67   librados::AioCompletion *comp = create_rados_callback<
68     klass, &klass::handle_v1_read_header>(this);
69   m_out_bl.clear();
70   int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
71                                          &m_out_bl);
72   assert(r == 0);
73   comp->release();
74 }
75
76 template <typename I>
77 Context *RefreshRequest<I>::handle_v1_read_header(int *result) {
78   CephContext *cct = m_image_ctx.cct;
79   ldout(cct, 10) << this << " " << __func__ << ": " << "r=" << *result << dendl;
80
81   rbd_obj_header_ondisk v1_header;
82   if (*result < 0) {
83     return m_on_finish;
84   } else if (m_out_bl.length() < sizeof(v1_header)) {
85     lderr(cct) << "v1 header too small" << dendl;
86     *result = -EIO;
87     return m_on_finish;
88   } else if (memcmp(RBD_HEADER_TEXT, m_out_bl.c_str(),
89                     sizeof(RBD_HEADER_TEXT)) != 0) {
90     lderr(cct) << "unrecognized v1 header" << dendl;
91     *result = -ENXIO;
92     return m_on_finish;
93   }
94
95   memcpy(&v1_header, m_out_bl.c_str(), sizeof(v1_header));
96   m_order = v1_header.options.order;
97   m_size = v1_header.image_size;
98   m_object_prefix = v1_header.block_name;
99   send_v1_get_snapshots();
100   return nullptr;
101 }
102
103 template <typename I>
104 void RefreshRequest<I>::send_v1_get_snapshots() {
105   CephContext *cct = m_image_ctx.cct;
106   ldout(cct, 10) << this << " " << __func__ << dendl;
107
108   librados::ObjectReadOperation op;
109   cls_client::old_snapshot_list_start(&op);
110
111   using klass = RefreshRequest<I>;
112   librados::AioCompletion *comp = create_rados_callback<
113     klass, &klass::handle_v1_get_snapshots>(this);
114   m_out_bl.clear();
115   int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
116                                          &m_out_bl);
117   assert(r == 0);
118   comp->release();
119 }
120
121 template <typename I>
122 Context *RefreshRequest<I>::handle_v1_get_snapshots(int *result) {
123   CephContext *cct = m_image_ctx.cct;
124   ldout(cct, 10) << this << " " << __func__ << ": " << "r=" << *result << dendl;
125
126   if (*result == 0) {
127     bufferlist::iterator it = m_out_bl.begin();
128     *result = cls_client::old_snapshot_list_finish(
129       &it, &m_snap_names, &m_snap_sizes, &m_snapc);
130   }
131
132   if (*result < 0) {
133     lderr(cct) << "failed to retrieve v1 snapshots: " << cpp_strerror(*result)
134                << dendl;
135     return m_on_finish;
136   }
137
138   if (!m_snapc.is_valid()) {
139     lderr(cct) << "v1 image snap context is invalid" << dendl;
140     *result = -EIO;
141     return m_on_finish;
142   }
143
144   //m_snap_namespaces = {m_snap_names.size(), cls::rbd::UserSnapshotNamespace()};
145   m_snap_namespaces = std::vector<cls::rbd::SnapshotNamespace>(
146                                             m_snap_names.size(),
147                                             cls::rbd::UserSnapshotNamespace());
148
149   m_snap_timestamps = std::vector<utime_t>(m_snap_names.size(), utime_t());
150
151   send_v1_get_locks();
152   return nullptr;
153 }
154
155 template <typename I>
156 void RefreshRequest<I>::send_v1_get_locks() {
157   CephContext *cct = m_image_ctx.cct;
158   ldout(cct, 10) << this << " " << __func__ << dendl;
159
160   librados::ObjectReadOperation op;
161   rados::cls::lock::get_lock_info_start(&op, RBD_LOCK_NAME);
162
163   using klass = RefreshRequest<I>;
164   librados::AioCompletion *comp = create_rados_callback<
165     klass, &klass::handle_v1_get_locks>(this);
166   m_out_bl.clear();
167   int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
168                                          &m_out_bl);
169   assert(r == 0);
170   comp->release();
171 }
172
173 template <typename I>
174 Context *RefreshRequest<I>::handle_v1_get_locks(int *result) {
175   CephContext *cct = m_image_ctx.cct;
176   ldout(cct, 10) << this << " " << __func__ << ": "
177                  << "r=" << *result << dendl;
178
179   // If EOPNOTSUPP, treat image as if there are no locks (we can't
180   // query them).
181   if (*result == -EOPNOTSUPP) {
182     *result = 0;
183   } else if (*result == 0) {
184     bufferlist::iterator it = m_out_bl.begin();
185     ClsLockType lock_type;
186     *result = rados::cls::lock::get_lock_info_finish(&it, &m_lockers,
187                                                      &lock_type, &m_lock_tag);
188     if (*result == 0) {
189       m_exclusive_locked = (lock_type == LOCK_EXCLUSIVE);
190     }
191   }
192   if (*result < 0) {
193     lderr(cct) << "failed to retrieve locks: " << cpp_strerror(*result)
194                << dendl;
195     return m_on_finish;
196   }
197
198   send_v1_apply();
199   return nullptr;
200 }
201
202 template <typename I>
203 void RefreshRequest<I>::send_v1_apply() {
204   CephContext *cct = m_image_ctx.cct;
205   ldout(cct, 10) << this << " " << __func__ << dendl;
206
207   // ensure we are not in a rados callback when applying updates
208   using klass = RefreshRequest<I>;
209   Context *ctx = create_context_callback<
210     klass, &klass::handle_v1_apply>(this);
211   m_image_ctx.op_work_queue->queue(ctx, 0);
212 }
213
214 template <typename I>
215 Context *RefreshRequest<I>::handle_v1_apply(int *result) {
216   CephContext *cct = m_image_ctx.cct;
217   ldout(cct, 10) << this << " " << __func__ << dendl;
218
219   apply();
220   return send_flush_aio();
221 }
222
223 template <typename I>
224 void RefreshRequest<I>::send_v2_get_mutable_metadata() {
225   CephContext *cct = m_image_ctx.cct;
226   ldout(cct, 10) << this << " " << __func__ << dendl;
227
228   uint64_t snap_id;
229   {
230     RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
231     snap_id = m_image_ctx.snap_id;
232   }
233
234   bool read_only = m_image_ctx.read_only || snap_id != CEPH_NOSNAP;
235   librados::ObjectReadOperation op;
236   cls_client::get_mutable_metadata_start(&op, read_only);
237
238   using klass = RefreshRequest<I>;
239   librados::AioCompletion *comp = create_rados_callback<
240     klass, &klass::handle_v2_get_mutable_metadata>(this);
241   m_out_bl.clear();
242   int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
243                                          &m_out_bl);
244   assert(r == 0);
245   comp->release();
246 }
247
248 template <typename I>
249 Context *RefreshRequest<I>::handle_v2_get_mutable_metadata(int *result) {
250   CephContext *cct = m_image_ctx.cct;
251   ldout(cct, 10) << this << " " << __func__ << ": "
252                  << "r=" << *result << dendl;
253
254   if (*result == 0) {
255     bufferlist::iterator it = m_out_bl.begin();
256     *result = cls_client::get_mutable_metadata_finish(&it, &m_size, &m_features,
257                                                       &m_incompatible_features,
258                                                       &m_lockers,
259                                                       &m_exclusive_locked,
260                                                       &m_lock_tag, &m_snapc,
261                                                       &m_parent_md);
262   }
263   if (*result < 0) {
264     lderr(cct) << "failed to retrieve mutable metadata: "
265                << cpp_strerror(*result) << dendl;
266     return m_on_finish;
267   }
268
269   uint64_t unsupported = m_incompatible_features & ~RBD_FEATURES_ALL;
270   if (unsupported != 0ULL) {
271     lderr(cct) << "Image uses unsupported features: " << unsupported << dendl;
272     *result = -ENOSYS;
273     return m_on_finish;
274   }
275
276   if (!m_snapc.is_valid()) {
277     lderr(cct) << "image snap context is invalid!" << dendl;
278     *result = -EIO;
279     return m_on_finish;
280   }
281
282   if (m_acquiring_lock && (m_features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) {
283     ldout(cct, 5) << "ignoring dynamically disabled exclusive lock" << dendl;
284     m_features |= RBD_FEATURE_EXCLUSIVE_LOCK;
285     m_incomplete_update = true;
286   }
287
288   send_v2_get_flags();
289   return nullptr;
290 }
291
292 template <typename I>
293 void RefreshRequest<I>::send_v2_get_flags() {
294   CephContext *cct = m_image_ctx.cct;
295   ldout(cct, 10) << this << " " << __func__ << dendl;
296
297   librados::ObjectReadOperation op;
298   cls_client::get_flags_start(&op, m_snapc.snaps);
299
300   using klass = RefreshRequest<I>;
301   librados::AioCompletion *comp = create_rados_callback<
302     klass, &klass::handle_v2_get_flags>(this);
303   m_out_bl.clear();
304   int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
305                                          &m_out_bl);
306   assert(r == 0);
307   comp->release();
308 }
309
310 template <typename I>
311 Context *RefreshRequest<I>::handle_v2_get_flags(int *result) {
312   CephContext *cct = m_image_ctx.cct;
313   ldout(cct, 10) << this << " " << __func__ << ": "
314                  << "r=" << *result << dendl;
315
316   if (*result == 0) {
317     bufferlist::iterator it = m_out_bl.begin();
318     cls_client::get_flags_finish(&it, &m_flags, m_snapc.snaps, &m_snap_flags);
319   }
320   if (*result == -EOPNOTSUPP) {
321     // Older OSD doesn't support RBD flags, need to assume the worst
322     *result = 0;
323     ldout(cct, 10) << "OSD does not support RBD flags, disabling object map "
324                    << "optimizations" << dendl;
325     m_flags = RBD_FLAG_OBJECT_MAP_INVALID;
326     if ((m_features & RBD_FEATURE_FAST_DIFF) != 0) {
327       m_flags |= RBD_FLAG_FAST_DIFF_INVALID;
328     }
329
330     std::vector<uint64_t> default_flags(m_snapc.snaps.size(), m_flags);
331     m_snap_flags = std::move(default_flags);
332   } else if (*result == -ENOENT) {
333     ldout(cct, 10) << "out-of-sync snapshot state detected" << dendl;
334     send_v2_get_mutable_metadata();
335     return nullptr;
336   } else if (*result < 0) {
337     lderr(cct) << "failed to retrieve flags: " << cpp_strerror(*result)
338                << dendl;
339     return m_on_finish;
340   }
341
342   send_v2_get_group();
343   return nullptr;
344 }
345
346 template <typename I>
347 void RefreshRequest<I>::send_v2_get_group() {
348   CephContext *cct = m_image_ctx.cct;
349   ldout(cct, 10) << this << " " << __func__ << dendl;
350
351   librados::ObjectReadOperation op;
352   cls_client::image_get_group_start(&op);
353
354   using klass = RefreshRequest<I>;
355   librados::AioCompletion *comp = create_rados_callback<
356     klass, &klass::handle_v2_get_group>(this);
357   m_out_bl.clear();
358   int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
359                                          &m_out_bl);
360   assert(r == 0);
361   comp->release();
362 }
363
364 template <typename I>
365 Context *RefreshRequest<I>::handle_v2_get_group(int *result) {
366   CephContext *cct = m_image_ctx.cct;
367   ldout(cct, 10) << this << " " << __func__ << ": "
368                  << "r=" << *result << dendl;
369
370   if (*result == 0) {
371     bufferlist::iterator it = m_out_bl.begin();
372     cls_client::image_get_group_finish(&it, &m_group_spec);
373   }
374   if (*result == -EOPNOTSUPP) {
375     // Older OSD doesn't support RBD groups
376     *result = 0;
377     ldout(cct, 10) << "OSD does not support consistency groups" << dendl;
378   } else if (*result < 0) {
379     lderr(cct) << "failed to retrieve group: " << cpp_strerror(*result)
380                << dendl;
381     return m_on_finish;
382   }
383
384   send_v2_get_snapshots();
385   return nullptr;
386 }
387
388 template <typename I>
389 void RefreshRequest<I>::send_v2_get_snapshots() {
390   if (m_snapc.snaps.empty()) {
391     m_snap_names.clear();
392     m_snap_namespaces.clear();
393     m_snap_sizes.clear();
394     m_snap_parents.clear();
395     m_snap_protection.clear();
396     m_snap_timestamps.clear();
397     send_v2_refresh_parent();
398     return;
399   }
400
401   CephContext *cct = m_image_ctx.cct;
402   ldout(cct, 10) << this << " " << __func__ << dendl;
403
404   librados::ObjectReadOperation op;
405   cls_client::snapshot_list_start(&op, m_snapc.snaps);
406
407   using klass = RefreshRequest<I>;
408   librados::AioCompletion *comp = create_rados_callback<
409     klass, &klass::handle_v2_get_snapshots>(this);
410   m_out_bl.clear();
411   int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
412                                          &m_out_bl);
413   assert(r == 0);
414   comp->release();
415 }
416
417 template <typename I>
418 Context *RefreshRequest<I>::handle_v2_get_snapshots(int *result) {
419   CephContext *cct = m_image_ctx.cct;
420   ldout(cct, 10) << this << " " << __func__ << ": "
421                  << "r=" << *result << dendl;
422
423   if (*result == 0) {
424     bufferlist::iterator it = m_out_bl.begin();
425     *result = cls_client::snapshot_list_finish(&it, m_snapc.snaps,
426                                                &m_snap_names,
427                                                &m_snap_sizes,
428                                                &m_snap_parents,
429                                                &m_snap_protection);
430   }
431   if (*result == -ENOENT) {
432     ldout(cct, 10) << "out-of-sync snapshot state detected" << dendl;
433     send_v2_get_mutable_metadata();
434     return nullptr;
435   } else if (*result < 0) {
436     lderr(cct) << "failed to retrieve snapshots: " << cpp_strerror(*result)
437                << dendl;
438     return m_on_finish;
439   }
440
441   send_v2_get_snap_timestamps();
442   return nullptr;
443 }
444
445 template <typename I>
446 void RefreshRequest<I>::send_v2_get_snap_timestamps() {
447   CephContext *cct = m_image_ctx.cct;
448   ldout(cct, 10) << this << " " << __func__ << dendl;
449
450   librados::ObjectReadOperation op;
451   cls_client::snapshot_timestamp_list_start(&op, m_snapc.snaps);
452
453   using klass = RefreshRequest<I>;
454   librados::AioCompletion *comp = create_rados_callback<
455                   klass, &klass::handle_v2_get_snap_timestamps>(this);
456   m_out_bl.clear();
457   int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
458                                   &m_out_bl);
459   assert(r == 0);
460   comp->release();
461 }
462
463 template <typename I>
464 Context *RefreshRequest<I>::handle_v2_get_snap_timestamps(int *result) {
465   CephContext *cct = m_image_ctx.cct;
466   ldout(cct, 10) << this << " " << __func__ << ": " << "r=" << *result << dendl;
467
468   if (*result == 0) {
469     bufferlist::iterator it = m_out_bl.begin();
470     *result = cls_client::snapshot_timestamp_list_finish(&it, m_snapc.snaps, &m_snap_timestamps);
471   }
472   if (*result == -ENOENT) {
473     ldout(cct, 10) << "out-of-sync snapshot state detected" << dendl;
474     send_v2_get_mutable_metadata();
475     return nullptr;
476   } else if (*result == -EOPNOTSUPP) {
477     m_snap_timestamps = std::vector<utime_t>(m_snap_names.size(), utime_t());
478     // Ignore it means no snap timestamps are available
479   } else if (*result < 0) {
480     lderr(cct) << "failed to retrieve snapshots: " << cpp_strerror(*result)
481                << dendl;
482     return m_on_finish;
483   }
484
485   send_v2_get_snap_namespaces();
486   return nullptr;
487 }
488
489 template <typename I>
490 void RefreshRequest<I>::send_v2_get_snap_namespaces() {
491   CephContext *cct = m_image_ctx.cct;
492   ldout(cct, 10) << this << " " << __func__ << dendl;
493
494   librados::ObjectReadOperation op;
495   cls_client::snapshot_namespace_list_start(&op, m_snapc.snaps);
496
497   using klass = RefreshRequest<I>;
498   librados::AioCompletion *comp = create_rados_callback<
499     klass, &klass::handle_v2_get_snap_namespaces>(this);
500   m_out_bl.clear();
501   int r = m_image_ctx.md_ctx.aio_operate(m_image_ctx.header_oid, comp, &op,
502                                          &m_out_bl);
503   assert(r == 0);
504   comp->release();
505 }
506
507 template <typename I>
508 Context *RefreshRequest<I>::handle_v2_get_snap_namespaces(int *result) {
509   CephContext *cct = m_image_ctx.cct;
510   ldout(cct, 10) << this << " " << __func__ << ": "
511                  << "r=" << *result << dendl;
512
513   if (*result == 0) {
514     bufferlist::iterator it = m_out_bl.begin();
515     *result = cls_client::snapshot_namespace_list_finish(&it, m_snapc.snaps,
516                                                          &m_snap_namespaces);
517   }
518   if (*result == -ENOENT) {
519     ldout(cct, 10) << "out-of-sync snapshot state detected" << dendl;
520     send_v2_get_mutable_metadata();
521     return nullptr;
522   } else if (*result == -EOPNOTSUPP) {
523     m_snap_namespaces = std::vector
524                                 <cls::rbd::SnapshotNamespace>(
525                                              m_snap_names.size(),
526                                              cls::rbd::UserSnapshotNamespace());
527     // Ignore it means no snap namespaces are available
528   } else if (*result < 0) {
529     lderr(cct) << "failed to retrieve snapshots: " << cpp_strerror(*result)
530                << dendl;
531     return m_on_finish;
532   }
533
534   send_v2_refresh_parent();
535   return nullptr;
536 }
537
538 template <typename I>
539 void RefreshRequest<I>::send_v2_refresh_parent() {
540   {
541     RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
542     RWLock::RLocker parent_locker(m_image_ctx.parent_lock);
543
544     ParentInfo parent_md;
545     int r = get_parent_info(m_image_ctx.snap_id, &parent_md);
546     if (!m_skip_open_parent_image && (r < 0 ||
547         RefreshParentRequest<I>::is_refresh_required(m_image_ctx, parent_md))) {
548       CephContext *cct = m_image_ctx.cct;
549       ldout(cct, 10) << this << " " << __func__ << dendl;
550
551       using klass = RefreshRequest<I>;
552       Context *ctx = create_context_callback<
553         klass, &klass::handle_v2_refresh_parent>(this);
554       m_refresh_parent = RefreshParentRequest<I>::create(
555         m_image_ctx, parent_md, ctx);
556     }
557   }
558
559   if (m_refresh_parent != nullptr) {
560     m_refresh_parent->send();
561   } else {
562     send_v2_init_exclusive_lock();
563   }
564 }
565
566 template <typename I>
567 Context *RefreshRequest<I>::handle_v2_refresh_parent(int *result) {
568   CephContext *cct = m_image_ctx.cct;
569   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
570
571   if (*result < 0) {
572     lderr(cct) << "failed to refresh parent image: " << cpp_strerror(*result)
573                << dendl;
574     save_result(result);
575     send_v2_apply();
576     return nullptr;
577   }
578
579   send_v2_init_exclusive_lock();
580   return nullptr;
581 }
582
583 template <typename I>
584 void RefreshRequest<I>::send_v2_init_exclusive_lock() {
585   if ((m_features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0 ||
586       m_image_ctx.read_only || !m_image_ctx.snap_name.empty() ||
587       m_image_ctx.exclusive_lock != nullptr) {
588     send_v2_open_object_map();
589     return;
590   }
591
592   // implies exclusive lock dynamically enabled or image open in-progress
593   CephContext *cct = m_image_ctx.cct;
594   ldout(cct, 10) << this << " " << __func__ << dendl;
595
596   // TODO need safe shut down
597   m_exclusive_lock = m_image_ctx.create_exclusive_lock();
598
599   using klass = RefreshRequest<I>;
600   Context *ctx = create_context_callback<
601     klass, &klass::handle_v2_init_exclusive_lock>(this);
602
603   RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
604   m_exclusive_lock->init(m_features, ctx);
605 }
606
607 template <typename I>
608 Context *RefreshRequest<I>::handle_v2_init_exclusive_lock(int *result) {
609   CephContext *cct = m_image_ctx.cct;
610   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
611
612   if (*result < 0) {
613     lderr(cct) << "failed to initialize exclusive lock: "
614                << cpp_strerror(*result) << dendl;
615     save_result(result);
616   }
617
618   // object map and journal will be opened when exclusive lock is
619   // acquired (if features are enabled)
620   send_v2_apply();
621   return nullptr;
622 }
623
624 template <typename I>
625 void RefreshRequest<I>::send_v2_open_journal() {
626   bool journal_disabled = (
627     (m_features & RBD_FEATURE_JOURNALING) == 0 ||
628      m_image_ctx.read_only ||
629      !m_image_ctx.snap_name.empty() ||
630      m_image_ctx.journal != nullptr ||
631      m_image_ctx.exclusive_lock == nullptr ||
632      !m_image_ctx.exclusive_lock->is_lock_owner());
633   bool journal_disabled_by_policy;
634   {
635     RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
636     journal_disabled_by_policy = (
637       !journal_disabled &&
638       m_image_ctx.get_journal_policy()->journal_disabled());
639   }
640
641   if (journal_disabled || journal_disabled_by_policy) {
642     // journal dynamically enabled -- doesn't own exclusive lock
643     if ((m_features & RBD_FEATURE_JOURNALING) != 0 &&
644         !journal_disabled_by_policy &&
645         m_image_ctx.exclusive_lock != nullptr &&
646         m_image_ctx.journal == nullptr) {
647       m_image_ctx.io_work_queue->set_require_lock(librbd::io::DIRECTION_BOTH,
648                                                   true);
649     }
650     send_v2_block_writes();
651     return;
652   }
653
654   // implies journal dynamically enabled since ExclusiveLock will init
655   // the journal upon acquiring the lock
656   CephContext *cct = m_image_ctx.cct;
657   ldout(cct, 10) << this << " " << __func__ << dendl;
658
659   using klass = RefreshRequest<I>;
660   Context *ctx = create_context_callback<
661     klass, &klass::handle_v2_open_journal>(this);
662
663   // TODO need safe close
664   m_journal = m_image_ctx.create_journal();
665   m_journal->open(ctx);
666 }
667
668 template <typename I>
669 Context *RefreshRequest<I>::handle_v2_open_journal(int *result) {
670   CephContext *cct = m_image_ctx.cct;
671   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
672
673   if (*result < 0) {
674     lderr(cct) << "failed to initialize journal: " << cpp_strerror(*result)
675                << dendl;
676     save_result(result);
677   }
678
679   send_v2_block_writes();
680   return nullptr;
681 }
682
683 template <typename I>
684 void RefreshRequest<I>::send_v2_block_writes() {
685   bool disabled_journaling = false;
686   {
687     RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
688     disabled_journaling = ((m_features & RBD_FEATURE_EXCLUSIVE_LOCK) != 0 &&
689                            (m_features & RBD_FEATURE_JOURNALING) == 0 &&
690                            m_image_ctx.journal != nullptr);
691   }
692
693   if (!disabled_journaling) {
694     send_v2_apply();
695     return;
696   }
697
698   CephContext *cct = m_image_ctx.cct;
699   ldout(cct, 10) << this << " " << __func__ << dendl;
700
701   // we need to block writes temporarily to avoid in-flight journal
702   // writes
703   m_blocked_writes = true;
704   Context *ctx = create_context_callback<
705     RefreshRequest<I>, &RefreshRequest<I>::handle_v2_block_writes>(this);
706
707   RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
708   m_image_ctx.io_work_queue->block_writes(ctx);
709 }
710
711 template <typename I>
712 Context *RefreshRequest<I>::handle_v2_block_writes(int *result) {
713   CephContext *cct = m_image_ctx.cct;
714   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
715
716   if (*result < 0) {
717     lderr(cct) << "failed to block writes: " << cpp_strerror(*result)
718                << dendl;
719     save_result(result);
720   }
721   send_v2_apply();
722   return nullptr;
723 }
724
725 template <typename I>
726 void RefreshRequest<I>::send_v2_open_object_map() {
727   if ((m_features & RBD_FEATURE_OBJECT_MAP) == 0 ||
728       m_image_ctx.object_map != nullptr ||
729       (m_image_ctx.snap_name.empty() &&
730        (m_image_ctx.read_only ||
731         m_image_ctx.exclusive_lock == nullptr ||
732         !m_image_ctx.exclusive_lock->is_lock_owner()))) {
733     send_v2_open_journal();
734     return;
735   }
736
737   // implies object map dynamically enabled or image open in-progress
738   // since SetSnapRequest loads the object map for a snapshot and
739   // ExclusiveLock loads the object map for HEAD
740   CephContext *cct = m_image_ctx.cct;
741   ldout(cct, 10) << this << " " << __func__ << dendl;
742
743   if (m_image_ctx.snap_name.empty()) {
744     m_object_map = m_image_ctx.create_object_map(CEPH_NOSNAP);
745   } else {
746     for (size_t snap_idx = 0; snap_idx < m_snap_names.size(); ++snap_idx) {
747       if (m_snap_names[snap_idx] == m_image_ctx.snap_name) {
748         m_object_map = m_image_ctx.create_object_map(
749           m_snapc.snaps[snap_idx].val);
750         break;
751       }
752     }
753
754     if (m_object_map == nullptr) {
755       lderr(cct) << "failed to locate snapshot: " << m_image_ctx.snap_name
756                  << dendl;
757       send_v2_open_journal();
758       return;
759     }
760   }
761
762   using klass = RefreshRequest<I>;
763   Context *ctx = create_context_callback<
764     klass, &klass::handle_v2_open_object_map>(this);
765   m_object_map->open(ctx);
766 }
767
768 template <typename I>
769 Context *RefreshRequest<I>::handle_v2_open_object_map(int *result) {
770   CephContext *cct = m_image_ctx.cct;
771   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
772
773   if (*result < 0) {
774     lderr(cct) << "failed to open object map: " << cpp_strerror(*result)
775                << dendl;
776     delete m_object_map;
777     m_object_map = nullptr;
778   }
779
780   send_v2_open_journal();
781   return nullptr;
782 }
783
784 template <typename I>
785 void RefreshRequest<I>::send_v2_apply() {
786   CephContext *cct = m_image_ctx.cct;
787   ldout(cct, 10) << this << " " << __func__ << dendl;
788
789   // ensure we are not in a rados callback when applying updates
790   using klass = RefreshRequest<I>;
791   Context *ctx = create_context_callback<
792     klass, &klass::handle_v2_apply>(this);
793   m_image_ctx.op_work_queue->queue(ctx, 0);
794 }
795
796 template <typename I>
797 Context *RefreshRequest<I>::handle_v2_apply(int *result) {
798   CephContext *cct = m_image_ctx.cct;
799   ldout(cct, 10) << this << " " << __func__ << dendl;
800
801   apply();
802
803   return send_v2_finalize_refresh_parent();
804 }
805
806 template <typename I>
807 Context *RefreshRequest<I>::send_v2_finalize_refresh_parent() {
808   if (m_refresh_parent == nullptr) {
809     return send_v2_shut_down_exclusive_lock();
810   }
811
812   CephContext *cct = m_image_ctx.cct;
813   ldout(cct, 10) << this << " " << __func__ << dendl;
814
815   using klass = RefreshRequest<I>;
816   Context *ctx = create_context_callback<
817     klass, &klass::handle_v2_finalize_refresh_parent>(this);
818   m_refresh_parent->finalize(ctx);
819   return nullptr;
820 }
821
822 template <typename I>
823 Context *RefreshRequest<I>::handle_v2_finalize_refresh_parent(int *result) {
824   CephContext *cct = m_image_ctx.cct;
825   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
826
827   assert(m_refresh_parent != nullptr);
828   delete m_refresh_parent;
829   m_refresh_parent = nullptr;
830
831   return send_v2_shut_down_exclusive_lock();
832 }
833
834 template <typename I>
835 Context *RefreshRequest<I>::send_v2_shut_down_exclusive_lock() {
836   if (m_exclusive_lock == nullptr) {
837     return send_v2_close_journal();
838   }
839
840   CephContext *cct = m_image_ctx.cct;
841   ldout(cct, 10) << this << " " << __func__ << dendl;
842
843   // exclusive lock feature was dynamically disabled. in-flight IO will be
844   // flushed and in-flight requests will be canceled before releasing lock
845   using klass = RefreshRequest<I>;
846   Context *ctx = create_context_callback<
847     klass, &klass::handle_v2_shut_down_exclusive_lock>(this);
848   m_exclusive_lock->shut_down(ctx);
849   return nullptr;
850 }
851
852 template <typename I>
853 Context *RefreshRequest<I>::handle_v2_shut_down_exclusive_lock(int *result) {
854   CephContext *cct = m_image_ctx.cct;
855   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
856
857   if (*result < 0) {
858     lderr(cct) << "failed to shut down exclusive lock: "
859                << cpp_strerror(*result) << dendl;
860     save_result(result);
861   }
862
863   {
864     RWLock::WLocker owner_locker(m_image_ctx.owner_lock);
865     assert(m_image_ctx.exclusive_lock == nullptr);
866   }
867
868   assert(m_exclusive_lock != nullptr);
869   delete m_exclusive_lock;
870   m_exclusive_lock = nullptr;
871
872   return send_v2_close_journal();
873 }
874
875 template <typename I>
876 Context *RefreshRequest<I>::send_v2_close_journal() {
877   if (m_journal == nullptr) {
878     return send_v2_close_object_map();
879   }
880
881   CephContext *cct = m_image_ctx.cct;
882   ldout(cct, 10) << this << " " << __func__ << dendl;
883
884   // journal feature was dynamically disabled
885   using klass = RefreshRequest<I>;
886   Context *ctx = create_context_callback<
887     klass, &klass::handle_v2_close_journal>(this);
888   m_journal->close(ctx);
889   return nullptr;
890 }
891
892 template <typename I>
893 Context *RefreshRequest<I>::handle_v2_close_journal(int *result) {
894   CephContext *cct = m_image_ctx.cct;
895   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
896
897   if (*result < 0) {
898     save_result(result);
899     lderr(cct) << "failed to close journal: " << cpp_strerror(*result)
900                << dendl;
901   }
902
903   assert(m_journal != nullptr);
904   delete m_journal;
905   m_journal = nullptr;
906
907   assert(m_blocked_writes);
908   m_blocked_writes = false;
909
910   m_image_ctx.io_work_queue->unblock_writes();
911   return send_v2_close_object_map();
912 }
913
914 template <typename I>
915 Context *RefreshRequest<I>::send_v2_close_object_map() {
916   if (m_object_map == nullptr) {
917     return send_flush_aio();
918   }
919
920   CephContext *cct = m_image_ctx.cct;
921   ldout(cct, 10) << this << " " << __func__ << dendl;
922
923   // object map was dynamically disabled
924   using klass = RefreshRequest<I>;
925   Context *ctx = create_context_callback<
926     klass, &klass::handle_v2_close_object_map>(this);
927   m_object_map->close(ctx);
928   return nullptr;
929 }
930
931 template <typename I>
932 Context *RefreshRequest<I>::handle_v2_close_object_map(int *result) {
933   CephContext *cct = m_image_ctx.cct;
934   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
935
936   assert(*result == 0);
937   assert(m_object_map != nullptr);
938   delete m_object_map;
939   m_object_map = nullptr;
940
941   return send_flush_aio();
942 }
943
944 template <typename I>
945 Context *RefreshRequest<I>::send_flush_aio() {
946   if (m_incomplete_update && m_error_result == 0) {
947     // if this was a partial refresh, notify ImageState
948     m_error_result = -ERESTART;
949   }
950
951   if (m_flush_aio) {
952     CephContext *cct = m_image_ctx.cct;
953     ldout(cct, 10) << this << " " << __func__ << dendl;
954
955     RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
956     using klass = RefreshRequest<I>;
957     Context *ctx = create_context_callback<
958       klass, &klass::handle_flush_aio>(this);
959     m_image_ctx.flush(ctx);
960     return nullptr;
961   } else if (m_error_result < 0) {
962     // propagate saved error back to caller
963     Context *ctx = create_context_callback<
964       RefreshRequest<I>, &RefreshRequest<I>::handle_error>(this);
965     m_image_ctx.op_work_queue->queue(ctx, 0);
966     return nullptr;
967   }
968
969   return m_on_finish;
970 }
971
972 template <typename I>
973 Context *RefreshRequest<I>::handle_flush_aio(int *result) {
974   CephContext *cct = m_image_ctx.cct;
975   ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
976
977   if (*result < 0) {
978     lderr(cct) << "failed to flush pending AIO: " << cpp_strerror(*result)
979                << dendl;
980   }
981
982   return handle_error(result);
983 }
984
985 template <typename I>
986 Context *RefreshRequest<I>::handle_error(int *result) {
987   if (m_error_result < 0) {
988     *result = m_error_result;
989
990     CephContext *cct = m_image_ctx.cct;
991     ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
992   }
993   return m_on_finish;
994 }
995
996 template <typename I>
997 void RefreshRequest<I>::apply() {
998   CephContext *cct = m_image_ctx.cct;
999   ldout(cct, 20) << this << " " << __func__ << dendl;
1000
1001   RWLock::WLocker owner_locker(m_image_ctx.owner_lock);
1002   RWLock::WLocker md_locker(m_image_ctx.md_lock);
1003
1004   {
1005     Mutex::Locker cache_locker(m_image_ctx.cache_lock);
1006     RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
1007     RWLock::WLocker parent_locker(m_image_ctx.parent_lock);
1008
1009     m_image_ctx.size = m_size;
1010     m_image_ctx.lockers = m_lockers;
1011     m_image_ctx.lock_tag = m_lock_tag;
1012     m_image_ctx.exclusive_locked = m_exclusive_locked;
1013
1014     if (m_image_ctx.old_format) {
1015       m_image_ctx.order = m_order;
1016       m_image_ctx.features = 0;
1017       m_image_ctx.flags = 0;
1018       m_image_ctx.object_prefix = std::move(m_object_prefix);
1019       m_image_ctx.init_layout();
1020     } else {
1021       m_image_ctx.features = m_features;
1022       m_image_ctx.flags = m_flags;
1023       m_image_ctx.group_spec = m_group_spec;
1024       m_image_ctx.parent_md = m_parent_md;
1025     }
1026
1027     for (size_t i = 0; i < m_snapc.snaps.size(); ++i) {
1028       std::vector<librados::snap_t>::const_iterator it = std::find(
1029         m_image_ctx.snaps.begin(), m_image_ctx.snaps.end(),
1030         m_snapc.snaps[i].val);
1031       if (it == m_image_ctx.snaps.end()) {
1032         m_flush_aio = true;
1033         ldout(cct, 20) << "new snapshot id=" << m_snapc.snaps[i].val
1034                        << " name=" << m_snap_names[i]
1035                        << " size=" << m_snap_sizes[i]
1036                        << dendl;
1037       }
1038     }
1039
1040     m_image_ctx.snaps.clear();
1041     m_image_ctx.snap_info.clear();
1042     m_image_ctx.snap_ids.clear();
1043     for (size_t i = 0; i < m_snapc.snaps.size(); ++i) {
1044       uint64_t flags = m_image_ctx.old_format ? 0 : m_snap_flags[i];
1045       uint8_t protection_status = m_image_ctx.old_format ?
1046         static_cast<uint8_t>(RBD_PROTECTION_STATUS_UNPROTECTED) :
1047         m_snap_protection[i];
1048       ParentInfo parent;
1049       if (!m_image_ctx.old_format) {
1050         parent = m_snap_parents[i];
1051       }
1052
1053       m_image_ctx.add_snap(m_snap_namespaces[i], m_snap_names[i],
1054                            m_snapc.snaps[i].val, m_snap_sizes[i], parent,
1055                            protection_status, flags, m_snap_timestamps[i]);
1056     }
1057     m_image_ctx.snapc = m_snapc;
1058
1059     if (m_image_ctx.snap_id != CEPH_NOSNAP &&
1060         m_image_ctx.get_snap_id(m_image_ctx.snap_namespace,
1061                                 m_image_ctx.snap_name) != m_image_ctx.snap_id) {
1062       lderr(cct) << "tried to read from a snapshot that no longer exists: "
1063                  << m_image_ctx.snap_name << dendl;
1064       m_image_ctx.snap_exists = false;
1065     }
1066
1067     if (m_refresh_parent != nullptr) {
1068       m_refresh_parent->apply();
1069     }
1070     m_image_ctx.data_ctx.selfmanaged_snap_set_write_ctx(m_image_ctx.snapc.seq,
1071                                                         m_image_ctx.snaps);
1072
1073     // handle dynamically enabled / disabled features
1074     if (m_image_ctx.exclusive_lock != nullptr &&
1075         !m_image_ctx.test_features(RBD_FEATURE_EXCLUSIVE_LOCK,
1076                                    m_image_ctx.snap_lock)) {
1077       // disabling exclusive lock will automatically handle closing
1078       // object map and journaling
1079       assert(m_exclusive_lock == nullptr);
1080       m_exclusive_lock = m_image_ctx.exclusive_lock;
1081     } else {
1082       if (m_exclusive_lock != nullptr) {
1083         assert(m_image_ctx.exclusive_lock == nullptr);
1084         std::swap(m_exclusive_lock, m_image_ctx.exclusive_lock);
1085       }
1086       if (!m_image_ctx.test_features(RBD_FEATURE_JOURNALING,
1087                                      m_image_ctx.snap_lock)) {
1088         if (!m_image_ctx.clone_copy_on_read && m_image_ctx.journal != nullptr) {
1089           m_image_ctx.io_work_queue->set_require_lock(io::DIRECTION_READ,
1090                                                       false);
1091         }
1092         std::swap(m_journal, m_image_ctx.journal);
1093       } else if (m_journal != nullptr) {
1094         std::swap(m_journal, m_image_ctx.journal);
1095       }
1096       if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
1097                                      m_image_ctx.snap_lock) ||
1098           m_object_map != nullptr) {
1099         std::swap(m_object_map, m_image_ctx.object_map);
1100       }
1101     }
1102   }
1103 }
1104
1105 template <typename I>
1106 int RefreshRequest<I>::get_parent_info(uint64_t snap_id,
1107                                        ParentInfo *parent_md) {
1108   if (snap_id == CEPH_NOSNAP) {
1109     *parent_md = m_parent_md;
1110     return 0;
1111   } else {
1112     for (size_t i = 0; i < m_snapc.snaps.size(); ++i) {
1113       if (m_snapc.snaps[i].val == snap_id) {
1114         *parent_md = m_snap_parents[i];
1115         return 0;
1116       }
1117     }
1118   }
1119   return -ENOENT;
1120 }
1121
1122 } // namespace image
1123 } // namespace librbd
1124
1125 template class librbd::image::RefreshRequest<librbd::ImageCtx>;