]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/operation/SnapshotCreateRequest.cc
import ceph 14.2.5
[ceph.git] / ceph / src / librbd / operation / 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 "cls/rbd/cls_rbd_types.h"
5#include "librbd/operation/SnapshotCreateRequest.h"
6#include "common/dout.h"
7#include "common/errno.h"
8#include "librbd/ExclusiveLock.h"
9#include "librbd/ImageCtx.h"
10#include "librbd/ObjectMap.h"
11#include "librbd/Utils.h"
12#include "librbd/io/ImageRequestWQ.h"
13
14#define dout_subsys ceph_subsys_rbd
15#undef dout_prefix
16#define dout_prefix *_dout << "librbd::SnapshotCreateRequest: "
17
18namespace librbd {
19namespace operation {
20
21using util::create_async_context_callback;
22using util::create_context_callback;
23using util::create_rados_callback;
24
25template <typename I>
26SnapshotCreateRequest<I>::SnapshotCreateRequest(I &image_ctx,
27 Context *on_finish,
28 const cls::rbd::SnapshotNamespace &snap_namespace,
29 const std::string &snap_name,
30 uint64_t journal_op_tid,
31 bool skip_object_map)
32 : Request<I>(image_ctx, on_finish, journal_op_tid),
33 m_snap_namespace(snap_namespace), m_snap_name(snap_name),
34 m_skip_object_map(skip_object_map), m_ret_val(0), m_snap_id(CEPH_NOSNAP) {
35}
36
37template <typename I>
38void SnapshotCreateRequest<I>::send_op() {
eafe8130
TL
39 I &image_ctx = this->m_image_ctx;
40 CephContext *cct = image_ctx.cct;
41
42 if (!image_ctx.data_ctx.is_valid()) {
43 lderr(cct) << "missing data pool" << dendl;
44 this->async_complete(-ENODEV);
45 return;
46 }
47
7c673cae
FG
48 send_suspend_requests();
49}
50
51template <typename I>
52void SnapshotCreateRequest<I>::send_suspend_requests() {
53 I &image_ctx = this->m_image_ctx;
54 CephContext *cct = image_ctx.cct;
55 ldout(cct, 5) << this << " " << __func__ << dendl;
56
57 // TODO suspend (shrink) resize to ensure consistent RBD mirror
58 send_suspend_aio();
59}
60
61template <typename I>
62Context *SnapshotCreateRequest<I>::handle_suspend_requests(int *result) {
63 I &image_ctx = this->m_image_ctx;
64 CephContext *cct = image_ctx.cct;
65 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
66
67 // TODO
68 send_suspend_aio();
69 return nullptr;
70}
71
72template <typename I>
73void SnapshotCreateRequest<I>::send_suspend_aio() {
74 I &image_ctx = this->m_image_ctx;
11fdf7f2 75 ceph_assert(image_ctx.owner_lock.is_locked());
7c673cae
FG
76
77 CephContext *cct = image_ctx.cct;
78 ldout(cct, 5) << this << " " << __func__ << dendl;
79
80 image_ctx.io_work_queue->block_writes(create_context_callback<
81 SnapshotCreateRequest<I>,
82 &SnapshotCreateRequest<I>::handle_suspend_aio>(this));
83}
84
85template <typename I>
86Context *SnapshotCreateRequest<I>::handle_suspend_aio(int *result) {
87 I &image_ctx = this->m_image_ctx;
88 CephContext *cct = image_ctx.cct;
89 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
90
91 if (*result < 0) {
92 lderr(cct) << "failed to block writes: " << cpp_strerror(*result) << dendl;
93 image_ctx.io_work_queue->unblock_writes();
94 return this->create_context_finisher(*result);
95 }
96
97 send_append_op_event();
98 return nullptr;
99}
100
101template <typename I>
102void SnapshotCreateRequest<I>::send_append_op_event() {
103 I &image_ctx = this->m_image_ctx;
104 if (!this->template append_op_event<
105 SnapshotCreateRequest<I>,
106 &SnapshotCreateRequest<I>::handle_append_op_event>(this)) {
107 send_allocate_snap_id();
108 return;
109 }
110
111 CephContext *cct = image_ctx.cct;
112 ldout(cct, 5) << this << " " << __func__ << dendl;
113}
114
115template <typename I>
116Context *SnapshotCreateRequest<I>::handle_append_op_event(int *result) {
117 I &image_ctx = this->m_image_ctx;
118 CephContext *cct = image_ctx.cct;
119 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
120
121 if (*result < 0) {
122 image_ctx.io_work_queue->unblock_writes();
123 lderr(cct) << "failed to commit journal entry: " << cpp_strerror(*result)
124 << dendl;
125 return this->create_context_finisher(*result);
126 }
127
128 send_allocate_snap_id();
129 return nullptr;
130}
131
132template <typename I>
133void SnapshotCreateRequest<I>::send_allocate_snap_id() {
134 I &image_ctx = this->m_image_ctx;
135 CephContext *cct = image_ctx.cct;
136 ldout(cct, 5) << this << " " << __func__ << dendl;
137
138 librados::AioCompletion *rados_completion = create_rados_callback<
139 SnapshotCreateRequest<I>,
140 &SnapshotCreateRequest<I>::handle_allocate_snap_id>(this);
3efd9988 141 image_ctx.data_ctx.aio_selfmanaged_snap_create(&m_snap_id, rados_completion);
7c673cae
FG
142 rados_completion->release();
143}
144
145template <typename I>
146Context *SnapshotCreateRequest<I>::handle_allocate_snap_id(int *result) {
147 I &image_ctx = this->m_image_ctx;
148 CephContext *cct = image_ctx.cct;
149 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << ", "
150 << "snap_id=" << m_snap_id << dendl;
151
152 if (*result < 0) {
153 save_result(result);
154 image_ctx.io_work_queue->unblock_writes();
155 lderr(cct) << "failed to allocate snapshot id: " << cpp_strerror(*result)
156 << dendl;
157 return this->create_context_finisher(*result);
158 }
159
160 send_create_snap();
161 return nullptr;
162}
163
164template <typename I>
165void SnapshotCreateRequest<I>::send_create_snap() {
166 I &image_ctx = this->m_image_ctx;
167 CephContext *cct = image_ctx.cct;
168 ldout(cct, 5) << this << " " << __func__ << dendl;
169
170 RWLock::RLocker owner_locker(image_ctx.owner_lock);
171 RWLock::RLocker snap_locker(image_ctx.snap_lock);
172 RWLock::RLocker parent_locker(image_ctx.parent_lock);
173
174 // should have been canceled prior to releasing lock
11fdf7f2
TL
175 ceph_assert(image_ctx.exclusive_lock == nullptr ||
176 image_ctx.exclusive_lock->is_lock_owner());
7c673cae
FG
177
178 // save current size / parent info for creating snapshot record in ImageCtx
179 m_size = image_ctx.size;
180 m_parent_info = image_ctx.parent_md;
181
182 librados::ObjectWriteOperation op;
183 if (image_ctx.old_format) {
184 cls_client::old_snapshot_add(&op, m_snap_id, m_snap_name);
185 } else {
186 cls_client::snapshot_add(&op, m_snap_id, m_snap_name, m_snap_namespace);
187 }
188
189 librados::AioCompletion *rados_completion = create_rados_callback<
190 SnapshotCreateRequest<I>,
191 &SnapshotCreateRequest<I>::handle_create_snap>(this);
192 int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid,
193 rados_completion, &op);
11fdf7f2 194 ceph_assert(r == 0);
7c673cae
FG
195 rados_completion->release();
196}
197
198template <typename I>
199Context *SnapshotCreateRequest<I>::handle_create_snap(int *result) {
200 I &image_ctx = this->m_image_ctx;
201 CephContext *cct = image_ctx.cct;
202 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
203
204 if (*result == -ESTALE) {
205 send_allocate_snap_id();
206 return nullptr;
207 } else if (*result < 0) {
208 save_result(result);
209 send_release_snap_id();
210 return nullptr;
211 }
212
213 return send_create_object_map();
214}
215
216template <typename I>
217Context *SnapshotCreateRequest<I>::send_create_object_map() {
218 I &image_ctx = this->m_image_ctx;
219
7c673cae
FG
220 image_ctx.snap_lock.get_read();
221 if (image_ctx.object_map == nullptr || m_skip_object_map) {
222 image_ctx.snap_lock.put_read();
223
91327a77 224 update_snap_context();
7c673cae
FG
225 image_ctx.io_work_queue->unblock_writes();
226 return this->create_context_finisher(0);
227 }
228
229 CephContext *cct = image_ctx.cct;
230 ldout(cct, 5) << this << " " << __func__ << dendl;
231
232 {
233 RWLock::RLocker object_map_lock(image_ctx.object_map_lock);
234 image_ctx.object_map->snapshot_add(
235 m_snap_id, create_context_callback<
236 SnapshotCreateRequest<I>,
237 &SnapshotCreateRequest<I>::handle_create_object_map>(this));
238 }
239 image_ctx.snap_lock.put_read();
240 return nullptr;
241}
242
243template <typename I>
244Context *SnapshotCreateRequest<I>::handle_create_object_map(int *result) {
245 I &image_ctx = this->m_image_ctx;
246 CephContext *cct = image_ctx.cct;
247 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
248
91327a77 249 update_snap_context();
7c673cae 250 image_ctx.io_work_queue->unblock_writes();
91327a77
AA
251 if (*result < 0) {
252 lderr(cct) << this << " " << __func__ << ": failed to snapshot object map: "
253 << cpp_strerror(*result) << dendl;
254 return this->create_context_finisher(*result);
255 }
256
7c673cae
FG
257 return this->create_context_finisher(0);
258}
259
260template <typename I>
261void SnapshotCreateRequest<I>::send_release_snap_id() {
262 I &image_ctx = this->m_image_ctx;
263 CephContext *cct = image_ctx.cct;
264 ldout(cct, 5) << this << " " << __func__ << dendl;
265
11fdf7f2 266 ceph_assert(m_snap_id != CEPH_NOSNAP);
7c673cae
FG
267
268 librados::AioCompletion *rados_completion = create_rados_callback<
269 SnapshotCreateRequest<I>,
270 &SnapshotCreateRequest<I>::handle_release_snap_id>(this);
3efd9988 271 image_ctx.data_ctx.aio_selfmanaged_snap_remove(m_snap_id, rados_completion);
7c673cae
FG
272 rados_completion->release();
273}
274
275template <typename I>
276Context *SnapshotCreateRequest<I>::handle_release_snap_id(int *result) {
277 I &image_ctx = this->m_image_ctx;
278 CephContext *cct = image_ctx.cct;
279 ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl;
280
11fdf7f2 281 ceph_assert(m_ret_val < 0);
7c673cae
FG
282 *result = m_ret_val;
283
284 image_ctx.io_work_queue->unblock_writes();
285 return this->create_context_finisher(m_ret_val);
286}
287
288template <typename I>
289void SnapshotCreateRequest<I>::update_snap_context() {
290 I &image_ctx = this->m_image_ctx;
291
292 RWLock::RLocker owner_locker(image_ctx.owner_lock);
293 RWLock::WLocker snap_locker(image_ctx.snap_lock);
294 if (image_ctx.old_format) {
295 return;
296 }
297
298 if (image_ctx.get_snap_info(m_snap_id) != NULL) {
299 return;
300 }
301
302 CephContext *cct = image_ctx.cct;
303 ldout(cct, 5) << this << " " << __func__ << dendl;
304
305 // should have been canceled prior to releasing lock
11fdf7f2
TL
306 ceph_assert(image_ctx.exclusive_lock == nullptr ||
307 image_ctx.exclusive_lock->is_lock_owner());
7c673cae
FG
308
309 // immediately add a reference to the new snapshot
310 utime_t snap_time = ceph_clock_now();
311 image_ctx.add_snap(m_snap_namespace, m_snap_name, m_snap_id, m_size,
312 m_parent_info, RBD_PROTECTION_STATUS_UNPROTECTED,
313 0, snap_time);
314
315 // immediately start using the new snap context if we
316 // own the exclusive lock
317 std::vector<snapid_t> snaps;
318 snaps.push_back(m_snap_id);
319 snaps.insert(snaps.end(), image_ctx.snapc.snaps.begin(),
320 image_ctx.snapc.snaps.end());
321
322 image_ctx.snapc.seq = m_snap_id;
323 image_ctx.snapc.snaps.swap(snaps);
324 image_ctx.data_ctx.selfmanaged_snap_set_write_ctx(
325 image_ctx.snapc.seq, image_ctx.snaps);
11fdf7f2
TL
326
327 if (!image_ctx.migration_info.empty()) {
328 auto it = image_ctx.migration_info.snap_map.find(CEPH_NOSNAP);
329 ceph_assert(it != image_ctx.migration_info.snap_map.end());
330 ceph_assert(!it->second.empty());
331 if (it->second[0] == CEPH_NOSNAP) {
332 ldout(cct, 5) << this << " " << __func__
333 << ": updating migration snap_map" << dendl;
334 it->second[0] = m_snap_id;
335 }
336 }
7c673cae
FG
337}
338
339} // namespace operation
340} // namespace librbd
341
342template class librbd::operation::SnapshotCreateRequest<librbd::ImageCtx>;