]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd_mirror/image_deleter/SnapshotPurgeRequest.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / tools / rbd_mirror / image_deleter / SnapshotPurgeRequest.cc
CommitLineData
11fdf7f2
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "tools/rbd_mirror/image_deleter/SnapshotPurgeRequest.h"
5#include "common/debug.h"
6#include "common/errno.h"
7#include "librbd/ExclusiveLock.h"
8#include "librbd/ImageCtx.h"
9#include "librbd/ImageState.h"
10#include "librbd/Operations.h"
11#include "librbd/Utils.h"
12#include "librbd/journal/Policy.h"
13#include "tools/rbd_mirror/image_deleter/Types.h"
14
15#define dout_context g_ceph_context
16#define dout_subsys ceph_subsys_rbd_mirror
17#undef dout_prefix
18#define dout_prefix *_dout << "rbd::mirror::image_deleter::SnapshotPurgeRequest: " \
19 << this << " " << __func__ << ": "
20
21namespace rbd {
22namespace mirror {
23namespace image_deleter {
24
25using librbd::util::create_context_callback;
26
27template <typename I>
28void SnapshotPurgeRequest<I>::send() {
29 open_image();
30}
31
32template <typename I>
33void SnapshotPurgeRequest<I>::open_image() {
34 dout(10) << dendl;
35 m_image_ctx = I::create("", m_image_id, nullptr, m_io_ctx, false);
36
9f95a23c
TL
37 // ensure non-primary images can be modified
38 m_image_ctx->read_only_mask &= ~librbd::IMAGE_READ_ONLY_FLAG_NON_PRIMARY;
39
11fdf7f2 40 {
9f95a23c 41 std::unique_lock image_locker{m_image_ctx->image_lock};
11fdf7f2
TL
42 m_image_ctx->set_journal_policy(new JournalPolicy());
43 }
44
45 Context *ctx = create_context_callback<
46 SnapshotPurgeRequest<I>, &SnapshotPurgeRequest<I>::handle_open_image>(
47 this);
48 m_image_ctx->state->open(librbd::OPEN_FLAG_SKIP_OPEN_PARENT, ctx);
49}
50
51template <typename I>
52void SnapshotPurgeRequest<I>::handle_open_image(int r) {
53 dout(10) << "r=" << r << dendl;
54
55 if (r < 0) {
56 derr << "failed to open image '" << m_image_id << "': " << cpp_strerror(r)
57 << dendl;
58 m_image_ctx->destroy();
59 m_image_ctx = nullptr;
60
61 finish(r);
62 return;
63 }
64
65 acquire_lock();
66}
67
68template <typename I>
69void SnapshotPurgeRequest<I>::acquire_lock() {
70 dout(10) << dendl;
71
9f95a23c 72 m_image_ctx->owner_lock.lock_shared();
11fdf7f2 73 if (m_image_ctx->exclusive_lock == nullptr) {
9f95a23c 74 m_image_ctx->owner_lock.unlock_shared();
11fdf7f2 75
9f95a23c 76 start_snap_unprotect();
11fdf7f2
TL
77 return;
78 }
79
80 m_image_ctx->exclusive_lock->acquire_lock(create_context_callback<
81 SnapshotPurgeRequest<I>, &SnapshotPurgeRequest<I>::handle_acquire_lock>(
82 this));
9f95a23c 83 m_image_ctx->owner_lock.unlock_shared();
11fdf7f2
TL
84}
85
86template <typename I>
87void SnapshotPurgeRequest<I>::handle_acquire_lock(int r) {
88 dout(10) << "r=" << r << dendl;
89
90 if (r < 0) {
91 derr << "failed to acquire exclusive lock: " << cpp_strerror(r) << dendl;
92 m_ret_val = r;
93 close_image();
94 return;
95 }
96
9f95a23c
TL
97 start_snap_unprotect();
98}
99
100template <typename I>
101void SnapshotPurgeRequest<I>::start_snap_unprotect() {
102 dout(10) << dendl;
103
11fdf7f2 104 {
9f95a23c 105 std::shared_lock image_locker{m_image_ctx->image_lock};
11fdf7f2
TL
106 m_snaps = m_image_ctx->snaps;
107 }
108 snap_unprotect();
109}
110
111template <typename I>
112void SnapshotPurgeRequest<I>::snap_unprotect() {
113 if (m_snaps.empty()) {
114 close_image();
115 return;
116 }
117
118 librados::snap_t snap_id = m_snaps.back();
9f95a23c 119 m_image_ctx->image_lock.lock_shared();
11fdf7f2
TL
120 int r = m_image_ctx->get_snap_namespace(snap_id, &m_snap_namespace);
121 if (r < 0) {
9f95a23c 122 m_image_ctx->image_lock.unlock_shared();
11fdf7f2
TL
123
124 derr << "failed to get snap namespace: " << cpp_strerror(r) << dendl;
125 m_ret_val = r;
126 close_image();
127 return;
128 }
129
130 r = m_image_ctx->get_snap_name(snap_id, &m_snap_name);
131 if (r < 0) {
9f95a23c 132 m_image_ctx->image_lock.unlock_shared();
11fdf7f2
TL
133
134 derr << "failed to get snap name: " << cpp_strerror(r) << dendl;
135 m_ret_val = r;
136 close_image();
137 return;
138 }
139
140 bool is_protected;
141 r = m_image_ctx->is_snap_protected(snap_id, &is_protected);
142 if (r < 0) {
9f95a23c 143 m_image_ctx->image_lock.unlock_shared();
11fdf7f2
TL
144
145 derr << "failed to get snap protection status: " << cpp_strerror(r)
146 << dendl;
147 m_ret_val = r;
148 close_image();
149 return;
150 }
9f95a23c 151 m_image_ctx->image_lock.unlock_shared();
11fdf7f2
TL
152
153 if (!is_protected) {
154 snap_remove();
155 return;
156 }
157
158 dout(10) << "snap_id=" << snap_id << ", "
159 << "snap_namespace=" << m_snap_namespace << ", "
160 << "snap_name=" << m_snap_name << dendl;
161
162 auto finish_op_ctx = start_lock_op(&r);
163 if (finish_op_ctx == nullptr) {
164 derr << "lost exclusive lock" << dendl;
165 m_ret_val = r;
166 close_image();
167 return;
168 }
169
9f95a23c 170 auto ctx = new LambdaContext([this, finish_op_ctx](int r) {
11fdf7f2
TL
171 handle_snap_unprotect(r);
172 finish_op_ctx->complete(0);
173 });
9f95a23c 174 std::shared_lock owner_locker{m_image_ctx->owner_lock};
11fdf7f2
TL
175 m_image_ctx->operations->execute_snap_unprotect(
176 m_snap_namespace, m_snap_name.c_str(), ctx);
177}
178
179template <typename I>
180void SnapshotPurgeRequest<I>::handle_snap_unprotect(int r) {
181 dout(10) << "r=" << r << dendl;
182
183 if (r == -EBUSY) {
184 dout(10) << "snapshot in-use" << dendl;
185 m_ret_val = r;
186 close_image();
187 return;
188 } else if (r < 0) {
189 derr << "failed to unprotect snapshot: " << cpp_strerror(r) << dendl;
190 m_ret_val = r;
191 close_image();
192 return;
193 }
194
195 {
196 // avoid the need to refresh to delete the newly unprotected snapshot
9f95a23c 197 std::shared_lock image_locker{m_image_ctx->image_lock};
11fdf7f2
TL
198 librados::snap_t snap_id = m_snaps.back();
199 auto snap_info_it = m_image_ctx->snap_info.find(snap_id);
200 if (snap_info_it != m_image_ctx->snap_info.end()) {
201 snap_info_it->second.protection_status =
202 RBD_PROTECTION_STATUS_UNPROTECTED;
203 }
204 }
205
206 snap_remove();
207}
208
209template <typename I>
210void SnapshotPurgeRequest<I>::snap_remove() {
211 librados::snap_t snap_id = m_snaps.back();
212 dout(10) << "snap_id=" << snap_id << ", "
213 << "snap_namespace=" << m_snap_namespace << ", "
214 << "snap_name=" << m_snap_name << dendl;
215
216 int r;
217 auto finish_op_ctx = start_lock_op(&r);
218 if (finish_op_ctx == nullptr) {
219 derr << "lost exclusive lock" << dendl;
220 m_ret_val = r;
221 close_image();
222 return;
223 }
224
9f95a23c 225 auto ctx = new LambdaContext([this, finish_op_ctx](int r) {
11fdf7f2
TL
226 handle_snap_remove(r);
227 finish_op_ctx->complete(0);
228 });
9f95a23c 229 std::shared_lock owner_locker{m_image_ctx->owner_lock};
11fdf7f2
TL
230 m_image_ctx->operations->execute_snap_remove(
231 m_snap_namespace, m_snap_name.c_str(), ctx);
232}
233
234template <typename I>
235void SnapshotPurgeRequest<I>::handle_snap_remove(int r) {
236 dout(10) << "r=" << r << dendl;
237
238 if (r == -EBUSY) {
239 dout(10) << "snapshot in-use" << dendl;
240 m_ret_val = r;
241 close_image();
242 return;
243 } else if (r < 0) {
244 derr << "failed to remove snapshot: " << cpp_strerror(r) << dendl;
245 m_ret_val = r;
246 close_image();
247 return;
248 }
249
250 m_snaps.pop_back();
251 snap_unprotect();
252}
253
254template <typename I>
255void SnapshotPurgeRequest<I>::close_image() {
256 dout(10) << dendl;
257
258 m_image_ctx->state->close(create_context_callback<
259 SnapshotPurgeRequest<I>,
260 &SnapshotPurgeRequest<I>::handle_close_image>(this));
261}
262
263template <typename I>
264void SnapshotPurgeRequest<I>::handle_close_image(int r) {
265 dout(10) << "r=" << r << dendl;
266
267 m_image_ctx->destroy();
268 m_image_ctx = nullptr;
269
270 if (r < 0) {
271 derr << "failed to close: " << cpp_strerror(r) << dendl;
272 finish(r);
273 return;
274 }
275 finish(0);
276}
277
278template <typename I>
279void SnapshotPurgeRequest<I>::finish(int r) {
280 if (m_ret_val < 0) {
281 r = m_ret_val;
282 }
283
284 m_on_finish->complete(r);
285 delete this;
286}
287
288template <typename I>
289Context *SnapshotPurgeRequest<I>::start_lock_op(int* r) {
9f95a23c
TL
290 std::shared_lock owner_locker{m_image_ctx->owner_lock};
291 if (m_image_ctx->exclusive_lock == nullptr) {
292 return new LambdaContext([](int r) {});
293 }
11fdf7f2
TL
294 return m_image_ctx->exclusive_lock->start_op(r);
295}
296
297} // namespace image_deleter
298} // namespace mirror
299} // namespace rbd
300
301template class rbd::mirror::image_deleter::SnapshotPurgeRequest<librbd::ImageCtx>;