Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / tools / rbd_mirror / image_sync / SnapshotCreateRequest.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 "SnapshotCreateRequest.h"
5 #include "common/errno.h"
6 #include "cls/rbd/cls_rbd_client.h"
7 #include "cls/rbd/cls_rbd_types.h"
8 #include "librbd/ExclusiveLock.h"
9 #include "librbd/ObjectMap.h"
10 #include "librbd/Operations.h"
11 #include "librbd/Utils.h"
12 #include "osdc/Striper.h"
13
14 #define dout_context g_ceph_context
15 #define dout_subsys ceph_subsys_rbd_mirror
16 #undef dout_prefix
17 #define dout_prefix *_dout << "rbd::mirror::image_sync::SnapshotCreateRequest: " \
18                            << this << " " << __func__
19
20 namespace rbd {
21 namespace mirror {
22 namespace image_sync {
23
24 using librbd::util::create_context_callback;
25 using librbd::util::create_rados_callback;
26
27 template <typename I>
28 SnapshotCreateRequest<I>::SnapshotCreateRequest(I *local_image_ctx,
29                                                 const std::string &snap_name,
30                                                 const cls::rbd::SnapshotNamespace &snap_namespace,
31                                                 uint64_t size,
32                                                 const librbd::ParentSpec &spec,
33                                                 uint64_t parent_overlap,
34                                                 Context *on_finish)
35   : m_local_image_ctx(local_image_ctx), m_snap_name(snap_name),
36     m_snap_namespace(snap_namespace), m_size(size),
37     m_parent_spec(spec), m_parent_overlap(parent_overlap),
38     m_on_finish(on_finish) {
39 }
40
41 template <typename I>
42 void SnapshotCreateRequest<I>::send() {
43   send_set_size();
44 }
45
46 template <typename I>
47 void SnapshotCreateRequest<I>::send_set_size() {
48   m_local_image_ctx->snap_lock.get_read();
49   if (m_local_image_ctx->size == m_size) {
50     m_local_image_ctx->snap_lock.put_read();
51     send_remove_parent();
52     return;
53   }
54   m_local_image_ctx->snap_lock.put_read();
55
56   dout(20) << dendl;
57
58   // Change the image size on disk so that the snapshot picks up
59   // the expected size.  We can do this because the last snapshot
60   // we process is the sync snapshot which was created to match the
61   // image size. We also don't need to worry about trimming because
62   // we track the highest possible object number within the sync record
63   librados::ObjectWriteOperation op;
64   librbd::cls_client::set_size(&op, m_size);
65
66   auto finish_op_ctx = start_local_op();
67   if (finish_op_ctx == nullptr) {
68     derr << ": lost exclusive lock" << dendl;
69     finish(-EROFS);
70     return;
71   }
72
73   auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
74       handle_set_size(r);
75       finish_op_ctx->complete(0);
76     });
77   librados::AioCompletion *comp = create_rados_callback(ctx);
78   int r = m_local_image_ctx->md_ctx.aio_operate(m_local_image_ctx->header_oid,
79                                                 comp, &op);
80   assert(r == 0);
81   comp->release();
82 }
83
84 template <typename I>
85 void SnapshotCreateRequest<I>::handle_set_size(int r) {
86   dout(20) << ": r=" << r << dendl;
87
88   if (r < 0) {
89     derr << ": failed to update image size '" << m_snap_name << "': "
90          << cpp_strerror(r) << dendl;
91     finish(r);
92     return;
93   }
94
95   {
96     // adjust in-memory image size now that it's updated on disk
97     RWLock::WLocker snap_locker(m_local_image_ctx->snap_lock);
98     m_local_image_ctx->size = m_size;
99   }
100
101   send_remove_parent();
102 }
103
104 template <typename I>
105 void SnapshotCreateRequest<I>::send_remove_parent() {
106   m_local_image_ctx->parent_lock.get_read();
107   if (m_local_image_ctx->parent_md.spec.pool_id == -1 ||
108       m_local_image_ctx->parent_md.spec == m_parent_spec) {
109     m_local_image_ctx->parent_lock.put_read();
110     send_set_parent();
111     return;
112   }
113   m_local_image_ctx->parent_lock.put_read();
114
115   dout(20) << dendl;
116
117   librados::ObjectWriteOperation op;
118   librbd::cls_client::remove_parent(&op);
119
120   auto finish_op_ctx = start_local_op();
121   if (finish_op_ctx == nullptr) {
122     derr << ": lost exclusive lock" << dendl;
123     finish(-EROFS);
124     return;
125   }
126
127   auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
128       handle_remove_parent(r);
129       finish_op_ctx->complete(0);
130     });
131   librados::AioCompletion *comp = create_rados_callback(ctx);
132   int r = m_local_image_ctx->md_ctx.aio_operate(m_local_image_ctx->header_oid,
133                                                 comp, &op);
134   assert(r == 0);
135   comp->release();
136 }
137
138 template <typename I>
139 void SnapshotCreateRequest<I>::handle_remove_parent(int r) {
140   dout(20) << ": r=" << r << dendl;
141
142   if (r < 0) {
143     derr << ": failed to remove parent '" << m_snap_name << "': "
144          << cpp_strerror(r) << dendl;
145     finish(r);
146     return;
147   }
148
149   {
150     // adjust in-memory parent now that it's updated on disk
151     RWLock::WLocker parent_locker(m_local_image_ctx->parent_lock);
152     m_local_image_ctx->parent_md.spec = {};
153     m_local_image_ctx->parent_md.overlap = 0;
154   }
155
156   send_set_parent();
157 }
158
159 template <typename I>
160 void SnapshotCreateRequest<I>::send_set_parent() {
161   m_local_image_ctx->parent_lock.get_read();
162   if (m_local_image_ctx->parent_md.spec == m_parent_spec &&
163       m_local_image_ctx->parent_md.overlap == m_parent_overlap) {
164     m_local_image_ctx->parent_lock.put_read();
165     send_snap_create();
166     return;
167   }
168   m_local_image_ctx->parent_lock.put_read();
169
170   dout(20) << dendl;
171
172   librados::ObjectWriteOperation op;
173   librbd::cls_client::set_parent(&op, m_parent_spec, m_parent_overlap);
174
175   auto finish_op_ctx = start_local_op();
176   if (finish_op_ctx == nullptr) {
177     derr << ": lost exclusive lock" << dendl;
178     finish(-EROFS);
179     return;
180   }
181
182   auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
183       handle_set_parent(r);
184       finish_op_ctx->complete(0);
185     });
186   librados::AioCompletion *comp = create_rados_callback(ctx);
187   int r = m_local_image_ctx->md_ctx.aio_operate(m_local_image_ctx->header_oid,
188                                                 comp, &op);
189   assert(r == 0);
190   comp->release();
191 }
192
193 template <typename I>
194 void SnapshotCreateRequest<I>::handle_set_parent(int r) {
195   dout(20) << ": r=" << r << dendl;
196
197   if (r < 0) {
198     derr << ": failed to set parent '" << m_snap_name << "': "
199          << cpp_strerror(r) << dendl;
200     finish(r);
201     return;
202   }
203
204   {
205     // adjust in-memory parent now that it's updated on disk
206     RWLock::WLocker parent_locker(m_local_image_ctx->parent_lock);
207     m_local_image_ctx->parent_md.spec = m_parent_spec;
208     m_local_image_ctx->parent_md.overlap = m_parent_overlap;
209   }
210
211   send_snap_create();
212 }
213
214 template <typename I>
215 void SnapshotCreateRequest<I>::send_snap_create() {
216   dout(20) << ": snap_name=" << m_snap_name << dendl;
217
218   auto finish_op_ctx = start_local_op();
219   if (finish_op_ctx == nullptr) {
220     derr << ": lost exclusive lock" << dendl;
221     finish(-EROFS);
222     return;
223   }
224
225   auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
226       handle_snap_create(r);
227       finish_op_ctx->complete(0);
228     });
229   RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
230   m_local_image_ctx->operations->execute_snap_create(m_snap_namespace,
231                                                      m_snap_name.c_str(),
232                                                      ctx,
233                                                      0U, true);
234 }
235
236 template <typename I>
237 void SnapshotCreateRequest<I>::handle_snap_create(int r) {
238   dout(20) << ": r=" << r << dendl;
239
240   if (r < 0) {
241     derr << ": failed to create snapshot '" << m_snap_name << "': "
242          << cpp_strerror(r) << dendl;
243     finish(r);
244     return;
245   }
246
247   send_create_object_map();
248 }
249 template <typename I>
250 void SnapshotCreateRequest<I>::send_create_object_map() {
251
252   if (!m_local_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP)) {
253     finish(0);
254     return;
255   }
256
257   m_local_image_ctx->snap_lock.get_read();
258   auto snap_it = m_local_image_ctx->snap_ids.find(
259     {cls::rbd::UserSnapshotNamespace(), m_snap_name});
260   if (snap_it == m_local_image_ctx->snap_ids.end()) {
261     derr << ": failed to locate snap: " << m_snap_name << dendl;
262     m_local_image_ctx->snap_lock.put_read();
263     finish(-ENOENT);
264     return;
265   }
266   librados::snap_t local_snap_id = snap_it->second;
267   m_local_image_ctx->snap_lock.put_read();
268
269   std::string object_map_oid(librbd::ObjectMap<>::object_map_name(
270     m_local_image_ctx->id, local_snap_id));
271   uint64_t object_count = Striper::get_num_objects(m_local_image_ctx->layout,
272                                                    m_size);
273   dout(20) << ": "
274            << "object_map_oid=" << object_map_oid << ", "
275            << "object_count=" << object_count << dendl;
276
277   // initialize an empty object map of the correct size (object sync
278   // will populate the object map)
279   librados::ObjectWriteOperation op;
280   librbd::cls_client::object_map_resize(&op, object_count, OBJECT_NONEXISTENT);
281
282   auto finish_op_ctx = start_local_op();
283   if (finish_op_ctx == nullptr) {
284     derr << ": lost exclusive lock" << dendl;
285     finish(-EROFS);
286     return;
287   }
288
289   auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
290       handle_create_object_map(r);
291       finish_op_ctx->complete(0);
292     });
293   librados::AioCompletion *comp = create_rados_callback(ctx);
294   int r = m_local_image_ctx->md_ctx.aio_operate(object_map_oid, comp, &op);
295   assert(r == 0);
296   comp->release();
297 }
298
299 template <typename I>
300 void SnapshotCreateRequest<I>::handle_create_object_map(int r) {
301   dout(20) << ": r=" << r << dendl;
302
303   if (r < 0) {
304     derr << ": failed to create object map: " << cpp_strerror(r)
305          << dendl;
306     finish(r);
307     return;
308   }
309
310   finish(0);
311 }
312
313 template <typename I>
314 Context *SnapshotCreateRequest<I>::start_local_op() {
315   RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
316   if (m_local_image_ctx->exclusive_lock == nullptr) {
317     return nullptr;
318   }
319   return m_local_image_ctx->exclusive_lock->start_op();
320 }
321
322 template <typename I>
323 void SnapshotCreateRequest<I>::finish(int r) {
324   dout(20) << ": r=" << r << dendl;
325
326   m_on_finish->complete(r);
327   delete this;
328 }
329
330 } // namespace image_sync
331 } // namespace mirror
332 } // namespace rbd
333
334 template class rbd::mirror::image_sync::SnapshotCreateRequest<librbd::ImageCtx>;