]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd_mirror/image_deleter/TrashRemoveRequest.cc
import ceph 14.2.5
[ceph.git] / ceph / src / tools / rbd_mirror / image_deleter / TrashRemoveRequest.cc
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/TrashRemoveRequest.h"
5 #include "include/ceph_assert.h"
6 #include "common/debug.h"
7 #include "common/errno.h"
8 #include "common/WorkQueue.h"
9 #include "cls/rbd/cls_rbd_client.h"
10 #include "librbd/ImageCtx.h"
11 #include "librbd/Journal.h"
12 #include "librbd/TrashWatcher.h"
13 #include "librbd/Utils.h"
14 #include "librbd/trash/RemoveRequest.h"
15 #include "tools/rbd_mirror/image_deleter/SnapshotPurgeRequest.h"
16
17 #define dout_context g_ceph_context
18 #define dout_subsys ceph_subsys_rbd_mirror
19 #undef dout_prefix
20 #define dout_prefix *_dout << "rbd::mirror::image_deleter::TrashRemoveRequest: " \
21 << this << " " << __func__ << ": "
22
23 namespace rbd {
24 namespace mirror {
25 namespace image_deleter {
26
27 using librbd::util::create_context_callback;
28 using librbd::util::create_rados_callback;
29
30 template <typename I>
31 void TrashRemoveRequest<I>::send() {
32 *m_error_result = ERROR_RESULT_RETRY;
33
34 get_trash_image_spec();
35 }
36
37 template <typename I>
38 void TrashRemoveRequest<I>::get_trash_image_spec() {
39 dout(10) << dendl;
40
41 librados::ObjectReadOperation op;
42 librbd::cls_client::trash_get_start(&op, m_image_id);
43
44 auto aio_comp = create_rados_callback<
45 TrashRemoveRequest<I>,
46 &TrashRemoveRequest<I>::handle_get_trash_image_spec>(this);
47 m_out_bl.clear();
48 int r = m_io_ctx.aio_operate(RBD_TRASH, aio_comp, &op, &m_out_bl);
49 ceph_assert(r == 0);
50 aio_comp->release();
51 }
52
53 template <typename I>
54 void TrashRemoveRequest<I>::handle_get_trash_image_spec(int r) {
55 dout(10) << "r=" << r << dendl;
56
57 if (r == 0) {
58 auto bl_it = m_out_bl.cbegin();
59 r = librbd::cls_client::trash_get_finish(&bl_it, &m_trash_image_spec);
60 }
61
62 if (r == -ENOENT || (r >= 0 && m_trash_image_spec.source !=
63 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING)) {
64 dout(10) << "image id " << m_image_id << " not in mirroring trash" << dendl;
65 finish(0);
66 return;
67 } else if (r < 0) {
68 derr << "error getting image id " << m_image_id << " info from trash: "
69 << cpp_strerror(r) << dendl;
70 finish(r);
71 return;
72 }
73
74 if (m_trash_image_spec.state != cls::rbd::TRASH_IMAGE_STATE_NORMAL &&
75 m_trash_image_spec.state != cls::rbd::TRASH_IMAGE_STATE_REMOVING) {
76 dout(10) << "image " << m_image_id << " is not in an expected trash state: "
77 << m_trash_image_spec.state << dendl;
78 *m_error_result = ERROR_RESULT_RETRY_IMMEDIATELY;
79 finish(-EBUSY);
80 return;
81 }
82
83 set_trash_state();
84 }
85
86 template <typename I>
87 void TrashRemoveRequest<I>::set_trash_state() {
88 if (m_trash_image_spec.state == cls::rbd::TRASH_IMAGE_STATE_REMOVING) {
89 get_snap_context();
90 return;
91 }
92
93 dout(10) << dendl;
94
95 librados::ObjectWriteOperation op;
96 librbd::cls_client::trash_state_set(&op, m_image_id,
97 cls::rbd::TRASH_IMAGE_STATE_REMOVING,
98 cls::rbd::TRASH_IMAGE_STATE_NORMAL);
99
100 auto aio_comp = create_rados_callback<
101 TrashRemoveRequest<I>,
102 &TrashRemoveRequest<I>::handle_set_trash_state>(this);
103 int r = m_io_ctx.aio_operate(RBD_TRASH, aio_comp, &op);
104 ceph_assert(r == 0);
105 aio_comp->release();
106 }
107
108 template <typename I>
109 void TrashRemoveRequest<I>::handle_set_trash_state(int r) {
110 dout(10) << "r=" << r << dendl;
111
112 if (r == -ENOENT) {
113 dout(10) << "image id " << m_image_id << " not in mirroring trash" << dendl;
114 finish(0);
115 return;
116 } else if (r < 0 && r != -EOPNOTSUPP) {
117 derr << "error setting trash image state for image id " << m_image_id
118 << ": " << cpp_strerror(r) << dendl;
119 finish(r);
120 return;
121 }
122
123 get_snap_context();
124 }
125
126 template <typename I>
127 void TrashRemoveRequest<I>::get_snap_context() {
128 dout(10) << dendl;
129
130 librados::ObjectReadOperation op;
131 librbd::cls_client::get_snapcontext_start(&op);
132
133 std::string header_oid = librbd::util::header_name(m_image_id);
134
135 auto aio_comp = create_rados_callback<
136 TrashRemoveRequest<I>,
137 &TrashRemoveRequest<I>::handle_get_snap_context>(this);
138 m_out_bl.clear();
139 int r = m_io_ctx.aio_operate(header_oid, aio_comp, &op, &m_out_bl);
140 ceph_assert(r == 0);
141 aio_comp->release();
142 }
143
144 template <typename I>
145 void TrashRemoveRequest<I>::handle_get_snap_context(int r) {
146 dout(10) << "r=" << r << dendl;
147
148 ::SnapContext snapc;
149 if (r == 0) {
150 auto bl_it = m_out_bl.cbegin();
151 r = librbd::cls_client::get_snapcontext_finish(&bl_it, &snapc);
152 }
153 if (r < 0 && r != -ENOENT) {
154 derr << "error retrieving snapshot context for image "
155 << m_image_id << ": " << cpp_strerror(r) << dendl;
156 finish(r);
157 return;
158 }
159
160 m_has_snapshots = (!snapc.empty());
161 purge_snapshots();
162 }
163
164 template <typename I>
165 void TrashRemoveRequest<I>::purge_snapshots() {
166 if (!m_has_snapshots) {
167 remove_image();
168 return;
169 }
170
171 dout(10) << dendl;
172 auto ctx = create_context_callback<
173 TrashRemoveRequest<I>,
174 &TrashRemoveRequest<I>::handle_purge_snapshots>(this);
175 auto req = SnapshotPurgeRequest<I>::create(m_io_ctx, m_image_id, ctx);
176 req->send();
177 }
178
179 template <typename I>
180 void TrashRemoveRequest<I>::handle_purge_snapshots(int r) {
181 dout(10) << "r=" << r << dendl;
182
183 if (r == -EBUSY) {
184 dout(10) << "snapshots still in-use" << dendl;
185 *m_error_result = ERROR_RESULT_RETRY_IMMEDIATELY;
186 finish(r);
187 return;
188 } else if (r < 0) {
189 derr << "failed to purge image snapshots: " << cpp_strerror(r) << dendl;
190 finish(r);
191 return;
192 }
193
194 remove_image();
195 }
196
197 template <typename I>
198 void TrashRemoveRequest<I>::remove_image() {
199 dout(10) << dendl;
200
201 auto ctx = create_context_callback<
202 TrashRemoveRequest<I>,
203 &TrashRemoveRequest<I>::handle_remove_image>(this);
204 auto req = librbd::trash::RemoveRequest<I>::create(
205 m_io_ctx, m_image_id, m_op_work_queue, true, m_progress_ctx,
206 ctx);
207 req->send();
208 }
209
210 template <typename I>
211 void TrashRemoveRequest<I>::handle_remove_image(int r) {
212 dout(10) << "r=" << r << dendl;
213 if (r == -ENOTEMPTY) {
214 // image must have clone v2 snapshot still associated to child
215 dout(10) << "snapshots still in-use" << dendl;
216 *m_error_result = ERROR_RESULT_RETRY_IMMEDIATELY;
217 finish(-EBUSY);
218 return;
219 }
220
221 if (r < 0 && r != -ENOENT) {
222 derr << "error removing image " << m_image_id << " "
223 << "(" << m_image_id << ") from local pool: "
224 << cpp_strerror(r) << dendl;
225 finish(r);
226 return;
227 }
228
229 notify_trash_removed();
230 }
231
232 template <typename I>
233 void TrashRemoveRequest<I>::notify_trash_removed() {
234 dout(10) << dendl;
235
236 Context *ctx = create_context_callback<
237 TrashRemoveRequest<I>,
238 &TrashRemoveRequest<I>::handle_notify_trash_removed>(this);
239 librbd::TrashWatcher<I>::notify_image_removed(m_io_ctx, m_image_id, ctx);
240 }
241
242 template <typename I>
243 void TrashRemoveRequest<I>::handle_notify_trash_removed(int r) {
244 dout(10) << "r=" << r << dendl;
245
246 if (r < 0) {
247 derr << "failed to notify trash watchers: " << cpp_strerror(r) << dendl;
248 }
249
250 finish(0);
251 }
252
253 template <typename I>
254 void TrashRemoveRequest<I>::finish(int r) {
255 dout(10) << "r=" << r << dendl;
256
257 m_on_finish->complete(r);
258 delete this;
259 }
260
261 } // namespace image_deleter
262 } // namespace mirror
263 } // namespace rbd
264
265 template class rbd::mirror::image_deleter::TrashRemoveRequest<librbd::ImageCtx>;