]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/operation/SnapshotRollbackRequest.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / librbd / operation / SnapshotRollbackRequest.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/operation/SnapshotRollbackRequest.h"
5#include "include/rados/librados.hpp"
6#include "common/dout.h"
7#include "common/errno.h"
8#include "librbd/AsyncObjectThrottle.h"
9#include "librbd/ImageCtx.h"
10#include "librbd/ObjectMap.h"
11#include "librbd/Utils.h"
f67539c2
TL
12#include "librbd/io/ImageDispatcherInterface.h"
13#include "librbd/io/ObjectDispatcherInterface.h"
7c673cae
FG
14#include "librbd/operation/ResizeRequest.h"
15#include "osdc/Striper.h"
16#include <boost/lambda/bind.hpp>
17#include <boost/lambda/construct.hpp>
18
19#define dout_subsys ceph_subsys_rbd
20#undef dout_prefix
21#define dout_prefix *_dout << "librbd::SnapshotRollbackRequest: "
22
23namespace librbd {
24namespace operation {
25
26using util::create_context_callback;
27using util::create_rados_callback;
28
29namespace {
30
31template <typename I>
32class C_RollbackObject : public C_AsyncObjectThrottle<I> {
33public:
34 C_RollbackObject(AsyncObjectThrottle<I> &throttle, I *image_ctx,
11fdf7f2
TL
35 uint64_t snap_id, uint64_t object_num,
36 uint64_t head_num_objects,
37 decltype(I::object_map) snap_object_map)
7c673cae 38 : C_AsyncObjectThrottle<I>(throttle, *image_ctx), m_snap_id(snap_id),
11fdf7f2
TL
39 m_object_num(object_num), m_head_num_objects(head_num_objects),
40 m_snap_object_map(snap_object_map) {
7c673cae
FG
41 }
42
43 int send() override {
44 I &image_ctx = this->m_image_ctx;
45 CephContext *cct = image_ctx.cct;
46 ldout(cct, 20) << "C_RollbackObject: " << __func__ << ": object_num="
47 << m_object_num << dendl;
48
11fdf7f2 49 {
9f95a23c 50 std::shared_lock image_locker{image_ctx.image_lock};
11fdf7f2
TL
51 if (m_object_num < m_head_num_objects &&
52 m_snap_object_map != nullptr &&
53 !image_ctx.object_map->object_may_exist(m_object_num) &&
54 !m_snap_object_map->object_may_exist(m_object_num)) {
55 return 1;
56 }
57 }
58
7c673cae
FG
59 std::string oid = image_ctx.get_object_name(m_object_num);
60
61 librados::ObjectWriteOperation op;
62 op.selfmanaged_snap_rollback(m_snap_id);
63
64 librados::AioCompletion *rados_completion =
65 util::create_rados_callback(this);
66 image_ctx.data_ctx.aio_operate(oid, rados_completion, &op);
67 rados_completion->release();
68 return 0;
69 }
70
71private:
72 uint64_t m_snap_id;
73 uint64_t m_object_num;
11fdf7f2
TL
74 uint64_t m_head_num_objects;
75 decltype(I::object_map) m_snap_object_map;
7c673cae
FG
76};
77
78} // anonymous namespace
79
80template <typename I>
81SnapshotRollbackRequest<I>::SnapshotRollbackRequest(I &image_ctx,
82 Context *on_finish,
83 const cls::rbd::SnapshotNamespace &snap_namespace,
84 const std::string &snap_name,
85 uint64_t snap_id,
86 uint64_t snap_size,
87 ProgressContext &prog_ctx)
88 : Request<I>(image_ctx, on_finish), m_snap_namespace(snap_namespace),
89 m_snap_name(snap_name), m_snap_id(snap_id),
11fdf7f2
TL
90 m_snap_size(snap_size), m_prog_ctx(prog_ctx),
91 m_object_map(nullptr), m_snap_object_map(nullptr) {
7c673cae
FG
92}
93
94template <typename I>
95SnapshotRollbackRequest<I>::~SnapshotRollbackRequest() {
96 I &image_ctx = this->m_image_ctx;
97 if (m_blocking_writes) {
f67539c2 98 image_ctx.io_image_dispatcher->unblock_writes();
7c673cae 99 }
9f95a23c
TL
100 if (m_object_map) {
101 m_object_map->put();
102 m_object_map = nullptr;
103 }
104 if (m_snap_object_map) {
105 m_snap_object_map->put();
106 m_snap_object_map = nullptr;
107 }
7c673cae
FG
108}
109
110template <typename I>
111void SnapshotRollbackRequest<I>::send_op() {
112 send_block_writes();
113}
114
115template <typename I>
116void SnapshotRollbackRequest<I>::send_block_writes() {
117 I &image_ctx = this->m_image_ctx;
118 CephContext *cct = image_ctx.cct;
119 ldout(cct, 5) << this << " " << __func__ << dendl;
120
121 m_blocking_writes = true;
f67539c2 122 image_ctx.io_image_dispatcher->block_writes(create_context_callback<
7c673cae
FG
123 SnapshotRollbackRequest<I>,
124 &SnapshotRollbackRequest<I>::handle_block_writes>(this));
125}
126
127template <typename I>
128Context *SnapshotRollbackRequest<I>::handle_block_writes(int *result) {
129 I &image_ctx = this->m_image_ctx;
130 CephContext *cct = image_ctx.cct;
131 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
132
133 if (*result < 0) {
134 lderr(cct) << "failed to block writes: " << cpp_strerror(*result) << dendl;
135 return this->create_context_finisher(*result);
136 }
137
138 send_resize_image();
139 return nullptr;
140}
141
142template <typename I>
143void SnapshotRollbackRequest<I>::send_resize_image() {
144 I &image_ctx = this->m_image_ctx;
145
146 uint64_t current_size;
147 {
9f95a23c
TL
148 std::shared_lock owner_locker{image_ctx.owner_lock};
149 std::shared_lock image_locker{image_ctx.image_lock};
7c673cae
FG
150 current_size = image_ctx.get_image_size(CEPH_NOSNAP);
151 }
152
11fdf7f2
TL
153 m_head_num_objects = Striper::get_num_objects(image_ctx.layout, current_size);
154
7c673cae 155 if (current_size == m_snap_size) {
11fdf7f2 156 send_get_snap_object_map();
7c673cae
FG
157 return;
158 }
159
160 CephContext *cct = image_ctx.cct;
161 ldout(cct, 5) << this << " " << __func__ << dendl;
162
9f95a23c 163 std::shared_lock owner_locker{image_ctx.owner_lock};
7c673cae
FG
164 Context *ctx = create_context_callback<
165 SnapshotRollbackRequest<I>,
166 &SnapshotRollbackRequest<I>::handle_resize_image>(this);
167 ResizeRequest<I> *req = ResizeRequest<I>::create(image_ctx, ctx, m_snap_size,
168 true, m_no_op_prog_ctx, 0, true);
169 req->send();
170}
171
172template <typename I>
173Context *SnapshotRollbackRequest<I>::handle_resize_image(int *result) {
174 I &image_ctx = this->m_image_ctx;
175 CephContext *cct = image_ctx.cct;
176 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
177
178 if (*result < 0) {
179 lderr(cct) << "failed to resize image for rollback: "
180 << cpp_strerror(*result) << dendl;
181 return this->create_context_finisher(*result);
182 }
183
11fdf7f2
TL
184 send_get_snap_object_map();
185 return nullptr;
186}
187
188template <typename I>
189void SnapshotRollbackRequest<I>::send_get_snap_object_map() {
190 I &image_ctx = this->m_image_ctx;
191
192 uint64_t flags = 0;
193 bool object_map_enabled;
194 CephContext *cct = image_ctx.cct;
195 {
9f95a23c
TL
196 std::shared_lock owner_locker{image_ctx.owner_lock};
197 std::shared_lock image_locker{image_ctx.image_lock};
11fdf7f2
TL
198 object_map_enabled = (image_ctx.object_map != nullptr);
199 int r = image_ctx.get_flags(m_snap_id, &flags);
200 if (r < 0) {
201 object_map_enabled = false;
202 }
203 }
204 if (object_map_enabled &&
205 (flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0) {
206 lderr(cct) << "warning: object-map is invalid for snapshot" << dendl;
207 object_map_enabled = false;
208 }
209 if (!object_map_enabled) {
210 send_rollback_object_map();
211 return;
212 }
213
214 ldout(cct, 5) << this << " " << __func__ << dendl;
215
216 m_snap_object_map = image_ctx.create_object_map(m_snap_id);
217
218 Context *ctx = create_context_callback<
219 SnapshotRollbackRequest<I>,
220 &SnapshotRollbackRequest<I>::handle_get_snap_object_map>(this);
221 m_snap_object_map->open(ctx);
222 return;
223}
224
225template <typename I>
226Context *SnapshotRollbackRequest<I>::handle_get_snap_object_map(int *result) {
227 I &image_ctx = this->m_image_ctx;
228 CephContext *cct = image_ctx.cct;
229 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
230
231 if (*result < 0) {
232 lderr(cct) << this << " " << __func__ << ": failed to open object map: "
233 << cpp_strerror(*result) << dendl;
9f95a23c 234 m_snap_object_map->put();
11fdf7f2
TL
235 m_snap_object_map = nullptr;
236 }
237
7c673cae
FG
238 send_rollback_object_map();
239 return nullptr;
240}
241
242template <typename I>
243void SnapshotRollbackRequest<I>::send_rollback_object_map() {
244 I &image_ctx = this->m_image_ctx;
245
246 {
9f95a23c
TL
247 std::shared_lock owner_locker{image_ctx.owner_lock};
248 std::shared_lock image_locker{image_ctx.image_lock};
7c673cae
FG
249 if (image_ctx.object_map != nullptr) {
250 CephContext *cct = image_ctx.cct;
251 ldout(cct, 5) << this << " " << __func__ << dendl;
252
253 Context *ctx = create_context_callback<
254 SnapshotRollbackRequest<I>,
255 &SnapshotRollbackRequest<I>::handle_rollback_object_map>(this);
256 image_ctx.object_map->rollback(m_snap_id, ctx);
257 return;
258 }
259 }
260
261 send_rollback_objects();
262}
263
264template <typename I>
265Context *SnapshotRollbackRequest<I>::handle_rollback_object_map(int *result) {
266 I &image_ctx = this->m_image_ctx;
267 CephContext *cct = image_ctx.cct;
268 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
269
11fdf7f2
TL
270 if (*result < 0) {
271 lderr(cct) << this << " " << __func__ << ": failed to roll back object "
272 << "map: " << cpp_strerror(*result) << dendl;
273
274 ceph_assert(m_object_map == nullptr);
275 apply();
276 return this->create_context_finisher(*result);
277 }
278
7c673cae
FG
279 send_rollback_objects();
280 return nullptr;
281}
282
283template <typename I>
284void SnapshotRollbackRequest<I>::send_rollback_objects() {
285 I &image_ctx = this->m_image_ctx;
286 CephContext *cct = image_ctx.cct;
287 ldout(cct, 5) << this << " " << __func__ << dendl;
288
9f95a23c 289 std::shared_lock owner_locker{image_ctx.owner_lock};
7c673cae
FG
290 uint64_t num_objects;
291 {
9f95a23c 292 std::shared_lock image_locker{image_ctx.image_lock};
7c673cae
FG
293 num_objects = Striper::get_num_objects(image_ctx.layout,
294 image_ctx.get_current_size());
295 }
296
297 Context *ctx = create_context_callback<
298 SnapshotRollbackRequest<I>,
299 &SnapshotRollbackRequest<I>::handle_rollback_objects>(this);
300 typename AsyncObjectThrottle<I>::ContextFactory context_factory(
301 boost::lambda::bind(boost::lambda::new_ptr<C_RollbackObject<I> >(),
11fdf7f2
TL
302 boost::lambda::_1, &image_ctx, m_snap_id, boost::lambda::_2,
303 m_head_num_objects, m_snap_object_map));
7c673cae
FG
304 AsyncObjectThrottle<I> *throttle = new AsyncObjectThrottle<I>(
305 this, image_ctx, context_factory, ctx, &m_prog_ctx, 0, num_objects);
11fdf7f2
TL
306 throttle->start_ops(
307 image_ctx.config.template get_val<uint64_t>("rbd_concurrent_management_ops"));
7c673cae
FG
308}
309
310template <typename I>
311Context *SnapshotRollbackRequest<I>::handle_rollback_objects(int *result) {
312 I &image_ctx = this->m_image_ctx;
313 CephContext *cct = image_ctx.cct;
314 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
315
316 if (*result == -ERESTART) {
317 ldout(cct, 5) << "snapshot rollback operation interrupted" << dendl;
318 return this->create_context_finisher(*result);
319 } else if (*result < 0) {
320 lderr(cct) << "failed to rollback objects: " << cpp_strerror(*result)
321 << dendl;
322 return this->create_context_finisher(*result);
323 }
324
325 return send_refresh_object_map();
326}
327
328template <typename I>
329Context *SnapshotRollbackRequest<I>::send_refresh_object_map() {
330 I &image_ctx = this->m_image_ctx;
331
332 bool object_map_enabled;
333 {
9f95a23c
TL
334 std::shared_lock owner_locker{image_ctx.owner_lock};
335 std::shared_lock image_locker{image_ctx.image_lock};
7c673cae
FG
336 object_map_enabled = (image_ctx.object_map != nullptr);
337 }
338 if (!object_map_enabled) {
339 return send_invalidate_cache();
340 }
341
342 CephContext *cct = image_ctx.cct;
343 ldout(cct, 5) << this << " " << __func__ << dendl;
344
345 m_object_map = image_ctx.create_object_map(CEPH_NOSNAP);
346
347 Context *ctx = create_context_callback<
348 SnapshotRollbackRequest<I>,
349 &SnapshotRollbackRequest<I>::handle_refresh_object_map>(this);
350 m_object_map->open(ctx);
351 return nullptr;
352}
353
354template <typename I>
355Context *SnapshotRollbackRequest<I>::handle_refresh_object_map(int *result) {
356 I &image_ctx = this->m_image_ctx;
357 CephContext *cct = image_ctx.cct;
358 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
359
11fdf7f2
TL
360 if (*result < 0) {
361 lderr(cct) << this << " " << __func__ << ": failed to open object map: "
362 << cpp_strerror(*result) << dendl;
9f95a23c 363 m_object_map->put();
11fdf7f2
TL
364 m_object_map = nullptr;
365 apply();
366
367 return this->create_context_finisher(*result);
368 }
369
7c673cae
FG
370 return send_invalidate_cache();
371}
372
373template <typename I>
374Context *SnapshotRollbackRequest<I>::send_invalidate_cache() {
375 I &image_ctx = this->m_image_ctx;
376
377 apply();
7c673cae
FG
378
379 CephContext *cct = image_ctx.cct;
380 ldout(cct, 5) << this << " " << __func__ << dendl;
381
9f95a23c
TL
382 if(m_object_map != nullptr) {
383 Context *ctx = create_context_callback<
384 SnapshotRollbackRequest<I>,
385 &SnapshotRollbackRequest<I>::handle_invalidate_cache>(this, m_object_map);
f67539c2 386 image_ctx.io_image_dispatcher->invalidate_cache(ctx);
9f95a23c
TL
387 }
388 else {
389 Context *ctx = create_context_callback<
390 SnapshotRollbackRequest<I>,
391 &SnapshotRollbackRequest<I>::handle_invalidate_cache>(this);
f67539c2 392 image_ctx.io_image_dispatcher->invalidate_cache(ctx);
9f95a23c 393 }
7c673cae
FG
394 return nullptr;
395}
396
397template <typename I>
398Context *SnapshotRollbackRequest<I>::handle_invalidate_cache(int *result) {
399 I &image_ctx = this->m_image_ctx;
400 CephContext *cct = image_ctx.cct;
401 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
402
403 if (*result < 0) {
404 lderr(cct) << "failed to invalidate cache: " << cpp_strerror(*result)
405 << dendl;
406 }
407 return this->create_context_finisher(*result);
408}
409
410template <typename I>
411void SnapshotRollbackRequest<I>::apply() {
412 I &image_ctx = this->m_image_ctx;
413
9f95a23c
TL
414 std::shared_lock owner_locker{image_ctx.owner_lock};
415 std::unique_lock image_locker{image_ctx.image_lock};
7c673cae
FG
416 if (image_ctx.object_map != nullptr) {
417 std::swap(m_object_map, image_ctx.object_map);
418 }
419}
420
421} // namespace operation
422} // namespace librbd
423
424template class librbd::operation::SnapshotRollbackRequest<librbd::ImageCtx>;