]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/image/SetSnapRequest.cc
update sources to v12.2.3
[ceph.git] / ceph / src / librbd / image / SetSnapRequest.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/image/SetSnapRequest.h"
5#include "common/dout.h"
6#include "common/errno.h"
7#include "librbd/ExclusiveLock.h"
8#include "librbd/ImageCtx.h"
9#include "librbd/ObjectMap.h"
10#include "librbd/Utils.h"
11#include "librbd/image/RefreshParentRequest.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::image::SetSnapRequest: "
17
18namespace librbd {
19namespace image {
20
21using util::create_context_callback;
22
23template <typename I>
24SetSnapRequest<I>::SetSnapRequest(I &image_ctx, const cls::rbd::SnapshotNamespace& snap_namespace,
25 const std::string &snap_name,
26 Context *on_finish)
27 : m_image_ctx(image_ctx), m_snap_namespace(snap_namespace),
28 m_snap_name(snap_name), m_on_finish(on_finish),
29 m_snap_id(CEPH_NOSNAP), m_exclusive_lock(nullptr), m_object_map(nullptr),
30 m_refresh_parent(nullptr), m_writes_blocked(false) {
31}
32
33template <typename I>
34SetSnapRequest<I>::~SetSnapRequest() {
35 assert(!m_writes_blocked);
36 delete m_refresh_parent;
37 delete m_object_map;
38 delete m_exclusive_lock;
39}
40
41template <typename I>
42void SetSnapRequest<I>::send() {
43 if (m_snap_name.empty()) {
44 send_init_exclusive_lock();
45 } else {
46 send_block_writes();
47 }
48}
49
50template <typename I>
51void SetSnapRequest<I>::send_init_exclusive_lock() {
52 {
53 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
54 if (m_image_ctx.exclusive_lock != nullptr) {
55 assert(m_image_ctx.snap_id == CEPH_NOSNAP);
56 send_complete();
57 return;
58 }
59 }
60
61 if (m_image_ctx.read_only ||
62 !m_image_ctx.test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
63 int r = 0;
64 if (send_refresh_parent(&r) != nullptr) {
65 send_complete();
66 }
67 return;
68 }
69
70 CephContext *cct = m_image_ctx.cct;
71 ldout(cct, 10) << __func__ << dendl;
72
73 m_exclusive_lock = ExclusiveLock<I>::create(m_image_ctx);
74
75 using klass = SetSnapRequest<I>;
76 Context *ctx = create_context_callback<
77 klass, &klass::handle_init_exclusive_lock>(this);
78
79 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
80 m_exclusive_lock->init(m_image_ctx.features, ctx);
81}
82
83template <typename I>
84Context *SetSnapRequest<I>::handle_init_exclusive_lock(int *result) {
85 CephContext *cct = m_image_ctx.cct;
86 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
87
88 if (*result < 0) {
89 lderr(cct) << "failed to initialize exclusive lock: "
90 << cpp_strerror(*result) << dendl;
91 finalize();
92 return m_on_finish;
93 }
94 return send_refresh_parent(result);
95}
96
97template <typename I>
98void SetSnapRequest<I>::send_block_writes() {
99 CephContext *cct = m_image_ctx.cct;
100 ldout(cct, 10) << __func__ << dendl;
101
102 m_writes_blocked = true;
103
104 using klass = SetSnapRequest<I>;
105 Context *ctx = create_context_callback<
106 klass, &klass::handle_block_writes>(this);
107
108 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
109 m_image_ctx.io_work_queue->block_writes(ctx);
110}
111
112template <typename I>
113Context *SetSnapRequest<I>::handle_block_writes(int *result) {
114 CephContext *cct = m_image_ctx.cct;
115 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
116
117 if (*result < 0) {
118 lderr(cct) << "failed to block writes: " << cpp_strerror(*result)
119 << dendl;
120 finalize();
121 return m_on_finish;
122 }
123
124 {
125 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
126 m_snap_id = m_image_ctx.get_snap_id(m_snap_namespace, m_snap_name);
127 if (m_snap_id == CEPH_NOSNAP) {
128 ldout(cct, 5) << "failed to locate snapshot '" << m_snap_name << "'"
129 << dendl;
130
131 *result = -ENOENT;
132 finalize();
133 return m_on_finish;
134 }
135 }
136
137 return send_shut_down_exclusive_lock(result);
138}
139
140template <typename I>
141Context *SetSnapRequest<I>::send_shut_down_exclusive_lock(int *result) {
142 {
143 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
144 m_exclusive_lock = m_image_ctx.exclusive_lock;
145 }
146
147 if (m_exclusive_lock == nullptr) {
148 return send_refresh_parent(result);
149 }
150
151 CephContext *cct = m_image_ctx.cct;
152 ldout(cct, 10) << __func__ << dendl;
153
154 using klass = SetSnapRequest<I>;
155 Context *ctx = create_context_callback<
156 klass, &klass::handle_shut_down_exclusive_lock>(this);
157 m_exclusive_lock->shut_down(ctx);
158 return nullptr;
159}
160
161template <typename I>
162Context *SetSnapRequest<I>::handle_shut_down_exclusive_lock(int *result) {
163 CephContext *cct = m_image_ctx.cct;
164 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
165
166 if (*result < 0) {
167 lderr(cct) << "failed to shut down exclusive lock: "
168 << cpp_strerror(*result) << dendl;
169 finalize();
170 return m_on_finish;
171 }
172
173 return send_refresh_parent(result);
174}
175
176template <typename I>
177Context *SetSnapRequest<I>::send_refresh_parent(int *result) {
178 CephContext *cct = m_image_ctx.cct;
179
180 ParentInfo parent_md;
181 bool refresh_parent;
182 {
183 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
184 RWLock::RLocker parent_locker(m_image_ctx.parent_lock);
185
186 const ParentInfo *parent_info = m_image_ctx.get_parent_info(m_snap_id);
187 if (parent_info == nullptr) {
188 *result = -ENOENT;
189 lderr(cct) << "failed to retrieve snapshot parent info" << dendl;
190 finalize();
191 return m_on_finish;
192 }
193
194 parent_md = *parent_info;
195 refresh_parent = RefreshParentRequest<I>::is_refresh_required(m_image_ctx,
196 parent_md);
197 }
198
199 if (!refresh_parent) {
200 if (m_snap_id == CEPH_NOSNAP) {
201 // object map is loaded when exclusive lock is acquired
202 *result = apply();
203 finalize();
204 return m_on_finish;
205 } else {
206 // load snapshot object map
207 return send_open_object_map(result);
208 }
209 }
210
211 ldout(cct, 10) << __func__ << dendl;
212
213 using klass = SetSnapRequest<I>;
214 Context *ctx = create_context_callback<
215 klass, &klass::handle_refresh_parent>(this);
216 m_refresh_parent = RefreshParentRequest<I>::create(m_image_ctx, parent_md,
217 ctx);
218 m_refresh_parent->send();
219 return nullptr;
220}
221
222template <typename I>
223Context *SetSnapRequest<I>::handle_refresh_parent(int *result) {
224 CephContext *cct = m_image_ctx.cct;
225 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
226
227 if (*result < 0) {
228 lderr(cct) << "failed to refresh snapshot parent: " << cpp_strerror(*result)
229 << dendl;
230 finalize();
231 return m_on_finish;
232 }
233
234 if (m_snap_id == CEPH_NOSNAP) {
235 // object map is loaded when exclusive lock is acquired
236 *result = apply();
237 if (*result < 0) {
238 finalize();
239 return m_on_finish;
240 }
241
242 return send_finalize_refresh_parent(result);
243 } else {
244 // load snapshot object map
245 return send_open_object_map(result);
246 }
247}
248
249template <typename I>
250Context *SetSnapRequest<I>::send_open_object_map(int *result) {
251 if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP)) {
252 *result = apply();
253 if (*result < 0) {
254 finalize();
255 return m_on_finish;
256 }
257
258 return send_finalize_refresh_parent(result);
259 }
260
261 CephContext *cct = m_image_ctx.cct;
262 ldout(cct, 10) << __func__ << dendl;
263
264 using klass = SetSnapRequest<I>;
265 Context *ctx = create_context_callback<
266 klass, &klass::handle_open_object_map>(this);
267 m_object_map = ObjectMap<I>::create(m_image_ctx, m_snap_id);
268 m_object_map->open(ctx);
269 return nullptr;
270}
271
272template <typename I>
273Context *SetSnapRequest<I>::handle_open_object_map(int *result) {
274 CephContext *cct = m_image_ctx.cct;
275 ldout(cct, 10) << __func__ << ": r=" << *result << dendl;
276
277 if (*result < 0) {
278 lderr(cct) << "failed to open object map: " << cpp_strerror(*result)
279 << dendl;
280 delete m_object_map;
281 m_object_map = nullptr;
282 }
283
284 *result = apply();
285 if (*result < 0) {
286 finalize();
287 return m_on_finish;
288 }
289
290 return send_finalize_refresh_parent(result);
291}
292
293template <typename I>
294Context *SetSnapRequest<I>::send_finalize_refresh_parent(int *result) {
295 if (m_refresh_parent == nullptr) {
296 finalize();
297 return m_on_finish;
298 }
299
300 CephContext *cct = m_image_ctx.cct;
301 ldout(cct, 10) << this << " " << __func__ << dendl;
302
303 using klass = SetSnapRequest<I>;
304 Context *ctx = create_context_callback<
305 klass, &klass::handle_finalize_refresh_parent>(this);
306 m_refresh_parent->finalize(ctx);
307 return nullptr;
308}
309
310template <typename I>
311Context *SetSnapRequest<I>::handle_finalize_refresh_parent(int *result) {
312 CephContext *cct = m_image_ctx.cct;
313 ldout(cct, 10) << this << " " << __func__ << ": r=" << *result << dendl;
314
315 if (*result < 0) {
316 lderr(cct) << "failed to close parent image: " << cpp_strerror(*result)
317 << dendl;
318 }
319 finalize();
320 return m_on_finish;
321}
322
323template <typename I>
324int SetSnapRequest<I>::apply() {
325 CephContext *cct = m_image_ctx.cct;
326 ldout(cct, 10) << __func__ << dendl;
327
328 RWLock::WLocker owner_locker(m_image_ctx.owner_lock);
b32b8144 329 Mutex::Locker cache_locker(m_image_ctx.cache_lock);
7c673cae
FG
330 RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
331 RWLock::WLocker parent_locker(m_image_ctx.parent_lock);
332 if (m_snap_id != CEPH_NOSNAP) {
333 assert(m_image_ctx.exclusive_lock == nullptr);
334 int r = m_image_ctx.snap_set(m_snap_namespace, m_snap_name);
335 if (r < 0) {
336 return r;
337 }
338 } else {
339 std::swap(m_image_ctx.exclusive_lock, m_exclusive_lock);
340 m_image_ctx.snap_unset();
341 }
342
343 if (m_refresh_parent != nullptr) {
344 m_refresh_parent->apply();
345 }
346
347 std::swap(m_object_map, m_image_ctx.object_map);
348 return 0;
349}
350
351template <typename I>
352void SetSnapRequest<I>::finalize() {
353 if (m_writes_blocked) {
354 m_image_ctx.io_work_queue->unblock_writes();
355 m_writes_blocked = false;
356 }
357}
358
359template <typename I>
360void SetSnapRequest<I>::send_complete() {
361 finalize();
362 m_on_finish->complete(0);
363 delete this;
364}
365
366} // namespace image
367} // namespace librbd
368
369template class librbd::image::SetSnapRequest<librbd::ImageCtx>;