]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.cc
update sources to v12.1.0
[ceph.git] / ceph / src / tools / rbd_mirror / image_sync / SnapshotCreateRequest.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 "SnapshotCreateRequest.h"
5#include "common/errno.h"
6#include "cls/rbd/cls_rbd_client.h"
7#include "cls/rbd/cls_rbd_types.h"
31f18b77 8#include "librbd/ExclusiveLock.h"
7c673cae
FG
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
20namespace rbd {
21namespace mirror {
22namespace image_sync {
23
24using librbd::util::create_context_callback;
25using librbd::util::create_rados_callback;
26
27template <typename I>
28SnapshotCreateRequest<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
41template <typename I>
42void SnapshotCreateRequest<I>::send() {
43 send_set_size();
44}
45
46template <typename I>
47void 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
31f18b77
FG
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);
7c673cae
FG
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
84template <typename I>
85void 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
104template <typename I>
105void 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
31f18b77
FG
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);
7c673cae
FG
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
138template <typename I>
139void 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
159template <typename I>
160void 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
31f18b77
FG
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);
7c673cae
FG
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
193template <typename I>
194void 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
214template <typename I>
215void SnapshotCreateRequest<I>::send_snap_create() {
216 dout(20) << ": snap_name=" << m_snap_name << dendl;
217
31f18b77
FG
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 });
7c673cae
FG
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
236template <typename I>
237void 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}
249template <typename I>
250void 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();
31f18b77
FG
258 auto snap_it = m_local_image_ctx->snap_ids.find(
259 {cls::rbd::UserSnapshotNamespace(), m_snap_name});
7c673cae
FG
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
31f18b77
FG
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);
7c673cae
FG
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
299template <typename I>
300void 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
31f18b77
FG
313template <typename I>
314Context *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
7c673cae
FG
322template <typename I>
323void 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
334template class rbd::mirror::image_sync::SnapshotCreateRequest<librbd::ImageCtx>;