1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
14 #define dout_context g_ceph_context
15 #define dout_subsys ceph_subsys_rbd_mirror
17 #define dout_prefix *_dout << "rbd::mirror::image_sync::SnapshotCreateRequest: " \
18 << this << " " << __func__
22 namespace image_sync {
24 using librbd::util::create_context_callback;
25 using librbd::util::create_rados_callback;
28 SnapshotCreateRequest<I>::SnapshotCreateRequest(I *local_image_ctx,
29 const std::string &snap_name,
30 const cls::rbd::SnapshotNamespace &snap_namespace,
32 const librbd::ParentSpec &spec,
33 uint64_t parent_overlap,
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) {
42 void SnapshotCreateRequest<I>::send() {
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();
54 m_local_image_ctx->snap_lock.put_read();
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);
66 auto finish_op_ctx = start_local_op();
67 if (finish_op_ctx == nullptr) {
68 derr << ": lost exclusive lock" << dendl;
73 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
75 finish_op_ctx->complete(0);
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,
85 void SnapshotCreateRequest<I>::handle_set_size(int r) {
86 dout(20) << ": r=" << r << dendl;
89 derr << ": failed to update image size '" << m_snap_name << "': "
90 << cpp_strerror(r) << dendl;
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;
101 send_remove_parent();
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();
113 m_local_image_ctx->parent_lock.put_read();
117 librados::ObjectWriteOperation op;
118 librbd::cls_client::remove_parent(&op);
120 auto finish_op_ctx = start_local_op();
121 if (finish_op_ctx == nullptr) {
122 derr << ": lost exclusive lock" << dendl;
127 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
128 handle_remove_parent(r);
129 finish_op_ctx->complete(0);
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,
138 template <typename I>
139 void SnapshotCreateRequest<I>::handle_remove_parent(int r) {
140 dout(20) << ": r=" << r << dendl;
143 derr << ": failed to remove parent '" << m_snap_name << "': "
144 << cpp_strerror(r) << dendl;
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;
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();
168 m_local_image_ctx->parent_lock.put_read();
172 librados::ObjectWriteOperation op;
173 librbd::cls_client::set_parent(&op, m_parent_spec, m_parent_overlap);
175 auto finish_op_ctx = start_local_op();
176 if (finish_op_ctx == nullptr) {
177 derr << ": lost exclusive lock" << dendl;
182 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
183 handle_set_parent(r);
184 finish_op_ctx->complete(0);
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,
193 template <typename I>
194 void SnapshotCreateRequest<I>::handle_set_parent(int r) {
195 dout(20) << ": r=" << r << dendl;
198 derr << ": failed to set parent '" << m_snap_name << "': "
199 << cpp_strerror(r) << dendl;
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;
214 template <typename I>
215 void SnapshotCreateRequest<I>::send_snap_create() {
216 dout(20) << ": snap_name=" << m_snap_name << dendl;
218 auto finish_op_ctx = start_local_op();
219 if (finish_op_ctx == nullptr) {
220 derr << ": lost exclusive lock" << dendl;
225 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
226 handle_snap_create(r);
227 finish_op_ctx->complete(0);
229 RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
230 m_local_image_ctx->operations->execute_snap_create(m_snap_namespace,
236 template <typename I>
237 void SnapshotCreateRequest<I>::handle_snap_create(int r) {
238 dout(20) << ": r=" << r << dendl;
241 derr << ": failed to create snapshot '" << m_snap_name << "': "
242 << cpp_strerror(r) << dendl;
247 send_create_object_map();
249 template <typename I>
250 void SnapshotCreateRequest<I>::send_create_object_map() {
252 if (!m_local_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP)) {
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();
266 librados::snap_t local_snap_id = snap_it->second;
267 m_local_image_ctx->snap_lock.put_read();
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,
274 << "object_map_oid=" << object_map_oid << ", "
275 << "object_count=" << object_count << dendl;
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);
282 auto finish_op_ctx = start_local_op();
283 if (finish_op_ctx == nullptr) {
284 derr << ": lost exclusive lock" << dendl;
289 auto ctx = new FunctionContext([this, finish_op_ctx](int r) {
290 handle_create_object_map(r);
291 finish_op_ctx->complete(0);
293 librados::AioCompletion *comp = create_rados_callback(ctx);
294 int r = m_local_image_ctx->md_ctx.aio_operate(object_map_oid, comp, &op);
299 template <typename I>
300 void SnapshotCreateRequest<I>::handle_create_object_map(int r) {
301 dout(20) << ": r=" << r << dendl;
304 derr << ": failed to create object map: " << cpp_strerror(r)
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) {
319 return m_local_image_ctx->exclusive_lock->start_op();
322 template <typename I>
323 void SnapshotCreateRequest<I>::finish(int r) {
324 dout(20) << ": r=" << r << dendl;
326 m_on_finish->complete(r);
330 } // namespace image_sync
331 } // namespace mirror
334 template class rbd::mirror::image_sync::SnapshotCreateRequest<librbd::ImageCtx>;