]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/operation/SnapshotRollbackRequest.cc
update sources to ceph Nautilus 14.2.1
[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"
12#include "librbd/io/ImageRequestWQ.h"
11fdf7f2 13#include "librbd/io/ObjectDispatcher.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
TL
49 {
50 RWLock::RLocker snap_locker(image_ctx.snap_lock);
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) {
98 image_ctx.io_work_queue->unblock_writes();
99 }
100 delete m_object_map;
11fdf7f2 101 delete m_snap_object_map;
7c673cae
FG
102}
103
104template <typename I>
105void SnapshotRollbackRequest<I>::send_op() {
106 send_block_writes();
107}
108
109template <typename I>
110void SnapshotRollbackRequest<I>::send_block_writes() {
111 I &image_ctx = this->m_image_ctx;
112 CephContext *cct = image_ctx.cct;
113 ldout(cct, 5) << this << " " << __func__ << dendl;
114
115 m_blocking_writes = true;
116 image_ctx.io_work_queue->block_writes(create_context_callback<
117 SnapshotRollbackRequest<I>,
118 &SnapshotRollbackRequest<I>::handle_block_writes>(this));
119}
120
121template <typename I>
122Context *SnapshotRollbackRequest<I>::handle_block_writes(int *result) {
123 I &image_ctx = this->m_image_ctx;
124 CephContext *cct = image_ctx.cct;
125 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
126
127 if (*result < 0) {
128 lderr(cct) << "failed to block writes: " << cpp_strerror(*result) << dendl;
129 return this->create_context_finisher(*result);
130 }
131
132 send_resize_image();
133 return nullptr;
134}
135
136template <typename I>
137void SnapshotRollbackRequest<I>::send_resize_image() {
138 I &image_ctx = this->m_image_ctx;
139
140 uint64_t current_size;
141 {
142 RWLock::RLocker owner_locker(image_ctx.owner_lock);
143 RWLock::RLocker snap_locker(image_ctx.snap_lock);
144 current_size = image_ctx.get_image_size(CEPH_NOSNAP);
145 }
146
11fdf7f2
TL
147 m_head_num_objects = Striper::get_num_objects(image_ctx.layout, current_size);
148
7c673cae 149 if (current_size == m_snap_size) {
11fdf7f2 150 send_get_snap_object_map();
7c673cae
FG
151 return;
152 }
153
154 CephContext *cct = image_ctx.cct;
155 ldout(cct, 5) << this << " " << __func__ << dendl;
156
b32b8144 157 RWLock::RLocker owner_locker(image_ctx.owner_lock);
7c673cae
FG
158 Context *ctx = create_context_callback<
159 SnapshotRollbackRequest<I>,
160 &SnapshotRollbackRequest<I>::handle_resize_image>(this);
161 ResizeRequest<I> *req = ResizeRequest<I>::create(image_ctx, ctx, m_snap_size,
162 true, m_no_op_prog_ctx, 0, true);
163 req->send();
164}
165
166template <typename I>
167Context *SnapshotRollbackRequest<I>::handle_resize_image(int *result) {
168 I &image_ctx = this->m_image_ctx;
169 CephContext *cct = image_ctx.cct;
170 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
171
172 if (*result < 0) {
173 lderr(cct) << "failed to resize image for rollback: "
174 << cpp_strerror(*result) << dendl;
175 return this->create_context_finisher(*result);
176 }
177
11fdf7f2
TL
178 send_get_snap_object_map();
179 return nullptr;
180}
181
182template <typename I>
183void SnapshotRollbackRequest<I>::send_get_snap_object_map() {
184 I &image_ctx = this->m_image_ctx;
185
186 uint64_t flags = 0;
187 bool object_map_enabled;
188 CephContext *cct = image_ctx.cct;
189 {
190 RWLock::RLocker owner_locker(image_ctx.owner_lock);
191 RWLock::RLocker snap_locker(image_ctx.snap_lock);
192 object_map_enabled = (image_ctx.object_map != nullptr);
193 int r = image_ctx.get_flags(m_snap_id, &flags);
194 if (r < 0) {
195 object_map_enabled = false;
196 }
197 }
198 if (object_map_enabled &&
199 (flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0) {
200 lderr(cct) << "warning: object-map is invalid for snapshot" << dendl;
201 object_map_enabled = false;
202 }
203 if (!object_map_enabled) {
204 send_rollback_object_map();
205 return;
206 }
207
208 ldout(cct, 5) << this << " " << __func__ << dendl;
209
210 m_snap_object_map = image_ctx.create_object_map(m_snap_id);
211
212 Context *ctx = create_context_callback<
213 SnapshotRollbackRequest<I>,
214 &SnapshotRollbackRequest<I>::handle_get_snap_object_map>(this);
215 m_snap_object_map->open(ctx);
216 return;
217}
218
219template <typename I>
220Context *SnapshotRollbackRequest<I>::handle_get_snap_object_map(int *result) {
221 I &image_ctx = this->m_image_ctx;
222 CephContext *cct = image_ctx.cct;
223 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
224
225 if (*result < 0) {
226 lderr(cct) << this << " " << __func__ << ": failed to open object map: "
227 << cpp_strerror(*result) << dendl;
228 delete m_snap_object_map;
229 m_snap_object_map = nullptr;
230 }
231
7c673cae
FG
232 send_rollback_object_map();
233 return nullptr;
234}
235
236template <typename I>
237void SnapshotRollbackRequest<I>::send_rollback_object_map() {
238 I &image_ctx = this->m_image_ctx;
239
240 {
241 RWLock::RLocker owner_locker(image_ctx.owner_lock);
242 RWLock::RLocker snap_locker(image_ctx.snap_lock);
243 RWLock::WLocker object_map_lock(image_ctx.object_map_lock);
244 if (image_ctx.object_map != nullptr) {
245 CephContext *cct = image_ctx.cct;
246 ldout(cct, 5) << this << " " << __func__ << dendl;
247
248 Context *ctx = create_context_callback<
249 SnapshotRollbackRequest<I>,
250 &SnapshotRollbackRequest<I>::handle_rollback_object_map>(this);
251 image_ctx.object_map->rollback(m_snap_id, ctx);
252 return;
253 }
254 }
255
256 send_rollback_objects();
257}
258
259template <typename I>
260Context *SnapshotRollbackRequest<I>::handle_rollback_object_map(int *result) {
261 I &image_ctx = this->m_image_ctx;
262 CephContext *cct = image_ctx.cct;
263 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
264
11fdf7f2
TL
265 if (*result < 0) {
266 lderr(cct) << this << " " << __func__ << ": failed to roll back object "
267 << "map: " << cpp_strerror(*result) << dendl;
268
269 ceph_assert(m_object_map == nullptr);
270 apply();
271 return this->create_context_finisher(*result);
272 }
273
7c673cae
FG
274 send_rollback_objects();
275 return nullptr;
276}
277
278template <typename I>
279void SnapshotRollbackRequest<I>::send_rollback_objects() {
280 I &image_ctx = this->m_image_ctx;
281 CephContext *cct = image_ctx.cct;
282 ldout(cct, 5) << this << " " << __func__ << dendl;
283
284 RWLock::RLocker owner_locker(image_ctx.owner_lock);
285 uint64_t num_objects;
286 {
287 RWLock::RLocker snap_locker(image_ctx.snap_lock);
288 num_objects = Striper::get_num_objects(image_ctx.layout,
289 image_ctx.get_current_size());
290 }
291
292 Context *ctx = create_context_callback<
293 SnapshotRollbackRequest<I>,
294 &SnapshotRollbackRequest<I>::handle_rollback_objects>(this);
295 typename AsyncObjectThrottle<I>::ContextFactory context_factory(
296 boost::lambda::bind(boost::lambda::new_ptr<C_RollbackObject<I> >(),
11fdf7f2
TL
297 boost::lambda::_1, &image_ctx, m_snap_id, boost::lambda::_2,
298 m_head_num_objects, m_snap_object_map));
7c673cae
FG
299 AsyncObjectThrottle<I> *throttle = new AsyncObjectThrottle<I>(
300 this, image_ctx, context_factory, ctx, &m_prog_ctx, 0, num_objects);
11fdf7f2
TL
301 throttle->start_ops(
302 image_ctx.config.template get_val<uint64_t>("rbd_concurrent_management_ops"));
7c673cae
FG
303}
304
305template <typename I>
306Context *SnapshotRollbackRequest<I>::handle_rollback_objects(int *result) {
307 I &image_ctx = this->m_image_ctx;
308 CephContext *cct = image_ctx.cct;
309 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
310
311 if (*result == -ERESTART) {
312 ldout(cct, 5) << "snapshot rollback operation interrupted" << dendl;
313 return this->create_context_finisher(*result);
314 } else if (*result < 0) {
315 lderr(cct) << "failed to rollback objects: " << cpp_strerror(*result)
316 << dendl;
317 return this->create_context_finisher(*result);
318 }
319
320 return send_refresh_object_map();
321}
322
323template <typename I>
324Context *SnapshotRollbackRequest<I>::send_refresh_object_map() {
325 I &image_ctx = this->m_image_ctx;
326
327 bool object_map_enabled;
328 {
329 RWLock::RLocker owner_locker(image_ctx.owner_lock);
330 RWLock::RLocker snap_locker(image_ctx.snap_lock);
331 object_map_enabled = (image_ctx.object_map != nullptr);
332 }
333 if (!object_map_enabled) {
334 return send_invalidate_cache();
335 }
336
337 CephContext *cct = image_ctx.cct;
338 ldout(cct, 5) << this << " " << __func__ << dendl;
339
340 m_object_map = image_ctx.create_object_map(CEPH_NOSNAP);
341
342 Context *ctx = create_context_callback<
343 SnapshotRollbackRequest<I>,
344 &SnapshotRollbackRequest<I>::handle_refresh_object_map>(this);
345 m_object_map->open(ctx);
346 return nullptr;
347}
348
349template <typename I>
350Context *SnapshotRollbackRequest<I>::handle_refresh_object_map(int *result) {
351 I &image_ctx = this->m_image_ctx;
352 CephContext *cct = image_ctx.cct;
353 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
354
11fdf7f2
TL
355 if (*result < 0) {
356 lderr(cct) << this << " " << __func__ << ": failed to open object map: "
357 << cpp_strerror(*result) << dendl;
358 delete m_object_map;
359 m_object_map = nullptr;
360 apply();
361
362 return this->create_context_finisher(*result);
363 }
364
7c673cae
FG
365 return send_invalidate_cache();
366}
367
368template <typename I>
369Context *SnapshotRollbackRequest<I>::send_invalidate_cache() {
370 I &image_ctx = this->m_image_ctx;
371
372 apply();
7c673cae
FG
373
374 CephContext *cct = image_ctx.cct;
375 ldout(cct, 5) << this << " " << __func__ << dendl;
376
377 RWLock::RLocker owner_lock(image_ctx.owner_lock);
378 Context *ctx = create_context_callback<
379 SnapshotRollbackRequest<I>,
380 &SnapshotRollbackRequest<I>::handle_invalidate_cache>(this);
11fdf7f2 381 image_ctx.io_object_dispatcher->invalidate_cache(ctx);
7c673cae
FG
382 return nullptr;
383}
384
385template <typename I>
386Context *SnapshotRollbackRequest<I>::handle_invalidate_cache(int *result) {
387 I &image_ctx = this->m_image_ctx;
388 CephContext *cct = image_ctx.cct;
389 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
390
391 if (*result < 0) {
392 lderr(cct) << "failed to invalidate cache: " << cpp_strerror(*result)
393 << dendl;
394 }
395 return this->create_context_finisher(*result);
396}
397
398template <typename I>
399void SnapshotRollbackRequest<I>::apply() {
400 I &image_ctx = this->m_image_ctx;
401
402 RWLock::RLocker owner_locker(image_ctx.owner_lock);
403 RWLock::WLocker snap_locker(image_ctx.snap_lock);
404 if (image_ctx.object_map != nullptr) {
405 std::swap(m_object_map, image_ctx.object_map);
406 }
407}
408
409} // namespace operation
410} // namespace librbd
411
412template class librbd::operation::SnapshotRollbackRequest<librbd::ImageCtx>;