]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/operation/FlattenRequest.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / librbd / operation / FlattenRequest.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/operation/FlattenRequest.h"
5#include "librbd/AsyncObjectThrottle.h"
6#include "librbd/ExclusiveLock.h"
7#include "librbd/ImageCtx.h"
1e59de90
TL
8#include "librbd/crypto/CryptoInterface.h"
9#include "librbd/crypto/EncryptionFormat.h"
11fdf7f2
TL
10#include "librbd/image/DetachChildRequest.h"
11#include "librbd/image/DetachParentRequest.h"
12#include "librbd/Types.h"
7c673cae 13#include "librbd/io/ObjectRequest.h"
f67539c2 14#include "librbd/io/Utils.h"
7c673cae
FG
15#include "common/dout.h"
16#include "common/errno.h"
1e59de90 17#include "osdc/Striper.h"
7c673cae
FG
18#include <boost/lambda/bind.hpp>
19#include <boost/lambda/construct.hpp>
20
21#define dout_subsys ceph_subsys_rbd
22#undef dout_prefix
11fdf7f2
TL
23#define dout_prefix *_dout << "librbd::operation::FlattenRequest: " << this \
24 << " " << __func__ << ": "
7c673cae
FG
25
26namespace librbd {
27namespace operation {
28
11fdf7f2
TL
29using util::create_context_callback;
30using util::create_rados_callback;
31
7c673cae
FG
32template <typename I>
33class C_FlattenObject : public C_AsyncObjectThrottle<I> {
34public:
35 C_FlattenObject(AsyncObjectThrottle<I> &throttle, I *image_ctx,
f67539c2
TL
36 IOContext io_context, uint64_t object_no)
37 : C_AsyncObjectThrottle<I>(throttle, *image_ctx), m_io_context(io_context),
11fdf7f2 38 m_object_no(object_no) {
7c673cae
FG
39 }
40
41 int send() override {
42 I &image_ctx = this->m_image_ctx;
9f95a23c 43 ceph_assert(ceph_mutex_is_locked(image_ctx.owner_lock));
7c673cae
FG
44 CephContext *cct = image_ctx.cct;
45
46 if (image_ctx.exclusive_lock != nullptr &&
47 !image_ctx.exclusive_lock->is_lock_owner()) {
48 ldout(cct, 1) << "lost exclusive lock during flatten" << dendl;
49 return -ERESTART;
50 }
51
11fdf7f2 52 {
9f95a23c 53 std::shared_lock image_lock{image_ctx.image_lock};
11fdf7f2
TL
54 if (image_ctx.object_map != nullptr &&
55 !image_ctx.object_map->object_may_not_exist(m_object_no)) {
56 // can skip because the object already exists
57 return 1;
58 }
59 }
60
f67539c2
TL
61 if (!io::util::trigger_copyup(
62 &image_ctx, m_object_no, m_io_context, this)) {
7c673cae
FG
63 // stop early if the parent went away - it just means
64 // another flatten finished first or the image was resized
7c673cae
FG
65 return 1;
66 }
67
7c673cae
FG
68 return 0;
69 }
70
71private:
f67539c2 72 IOContext m_io_context;
7c673cae
FG
73 uint64_t m_object_no;
74};
75
76template <typename I>
77bool FlattenRequest<I>::should_complete(int r) {
78 I &image_ctx = this->m_image_ctx;
79 CephContext *cct = image_ctx.cct;
11fdf7f2
TL
80 ldout(cct, 5) << "r=" << r << dendl;
81 if (r < 0) {
82 lderr(cct) << "encountered error: " << cpp_strerror(r) << dendl;
7c673cae 83 }
11fdf7f2 84 return true;
7c673cae
FG
85}
86
87template <typename I>
88void FlattenRequest<I>::send_op() {
11fdf7f2
TL
89 flatten_objects();
90}
91
92template <typename I>
93void FlattenRequest<I>::flatten_objects() {
7c673cae 94 I &image_ctx = this->m_image_ctx;
9f95a23c 95 ceph_assert(ceph_mutex_is_locked(image_ctx.owner_lock));
11fdf7f2 96
7c673cae 97 CephContext *cct = image_ctx.cct;
11fdf7f2 98 ldout(cct, 5) << dendl;
7c673cae 99
9f95a23c 100 assert(ceph_mutex_is_locked(image_ctx.owner_lock));
11fdf7f2
TL
101 auto ctx = create_context_callback<
102 FlattenRequest<I>,
103 &FlattenRequest<I>::handle_flatten_objects>(this);
7c673cae
FG
104 typename AsyncObjectThrottle<I>::ContextFactory context_factory(
105 boost::lambda::bind(boost::lambda::new_ptr<C_FlattenObject<I> >(),
f67539c2
TL
106 boost::lambda::_1, &image_ctx, image_ctx.get_data_io_context(),
107 boost::lambda::_2));
7c673cae 108 AsyncObjectThrottle<I> *throttle = new AsyncObjectThrottle<I>(
1e59de90
TL
109 this, image_ctx, context_factory, ctx, &m_prog_ctx, m_start_object_no,
110 m_start_object_no + m_overlap_objects);
11fdf7f2
TL
111 throttle->start_ops(
112 image_ctx.config.template get_val<uint64_t>("rbd_concurrent_management_ops"));
7c673cae
FG
113}
114
115template <typename I>
11fdf7f2 116void FlattenRequest<I>::handle_flatten_objects(int r) {
7c673cae 117 I &image_ctx = this->m_image_ctx;
7c673cae 118 CephContext *cct = image_ctx.cct;
11fdf7f2 119 ldout(cct, 5) << "r=" << r << dendl;
7c673cae 120
11fdf7f2
TL
121 if (r == -ERESTART) {
122 ldout(cct, 5) << "flatten operation interrupted" << dendl;
123 this->complete(r);
124 return;
125 } else if (r < 0) {
126 lderr(cct) << "flatten encountered an error: " << cpp_strerror(r) << dendl;
127 this->complete(r);
128 return;
7c673cae 129 }
7c673cae 130
1e59de90
TL
131 crypto_flatten();
132}
133
134
135template <typename I>
136void FlattenRequest<I>::crypto_flatten() {
137 I &image_ctx = this->m_image_ctx;
138 CephContext *cct = image_ctx.cct;
139
140 auto encryption_format = image_ctx.encryption_format.get();
141 if (encryption_format == nullptr) {
142 detach_child();
143 return;
144 }
145
146 ldout(cct, 5) << dendl;
147
148 auto ctx = create_context_callback<
149 FlattenRequest<I>,
150 &FlattenRequest<I>::handle_crypto_flatten>(this);
151 encryption_format->flatten(&image_ctx, ctx);
152}
153
154template <typename I>
155void FlattenRequest<I>::handle_crypto_flatten(int r) {
156 I &image_ctx = this->m_image_ctx;
157 CephContext *cct = image_ctx.cct;
158 ldout(cct, 5) << "r=" << r << dendl;
159
160 if (r < 0) {
161 lderr(cct) << "error flattening crypto: " << cpp_strerror(r) << dendl;
162 this->complete(r);
163 return;
164 }
165
11fdf7f2 166 detach_child();
7c673cae
FG
167}
168
169template <typename I>
11fdf7f2 170void FlattenRequest<I>::detach_child() {
7c673cae 171 I &image_ctx = this->m_image_ctx;
7c673cae
FG
172 CephContext *cct = image_ctx.cct;
173
174 // should have been canceled prior to releasing lock
9f95a23c 175 image_ctx.owner_lock.lock_shared();
11fdf7f2
TL
176 ceph_assert(image_ctx.exclusive_lock == nullptr ||
177 image_ctx.exclusive_lock->is_lock_owner());
7c673cae
FG
178
179 // if there are no snaps, remove from the children object as well
180 // (if snapshots remain, they have their own parent info, and the child
181 // will be removed when the last snap goes away)
9f95a23c 182 image_ctx.image_lock.lock_shared();
7c673cae
FG
183 if ((image_ctx.features & RBD_FEATURE_DEEP_FLATTEN) == 0 &&
184 !image_ctx.snaps.empty()) {
9f95a23c
TL
185 image_ctx.image_lock.unlock_shared();
186 image_ctx.owner_lock.unlock_shared();
11fdf7f2
TL
187 detach_parent();
188 return;
189 }
9f95a23c 190 image_ctx.image_lock.unlock_shared();
11fdf7f2
TL
191
192 ldout(cct, 5) << dendl;
193 auto ctx = create_context_callback<
194 FlattenRequest<I>,
195 &FlattenRequest<I>::handle_detach_child>(this);
196 auto req = image::DetachChildRequest<I>::create(image_ctx, ctx);
197 req->send();
9f95a23c 198 image_ctx.owner_lock.unlock_shared();
11fdf7f2
TL
199}
200
201template <typename I>
202void FlattenRequest<I>::handle_detach_child(int r) {
203 I &image_ctx = this->m_image_ctx;
204 CephContext *cct = image_ctx.cct;
205 ldout(cct, 5) << "r=" << r << dendl;
206
207 if (r < 0 && r != -ENOENT) {
208 lderr(cct) << "detach encountered an error: " << cpp_strerror(r) << dendl;
209 this->complete(r);
210 return;
211 }
212
213 detach_parent();
214}
215
216template <typename I>
217void FlattenRequest<I>::detach_parent() {
218 I &image_ctx = this->m_image_ctx;
219 CephContext *cct = image_ctx.cct;
220 ldout(cct, 5) << dendl;
221
222 // should have been canceled prior to releasing lock
9f95a23c 223 image_ctx.owner_lock.lock_shared();
11fdf7f2
TL
224 ceph_assert(image_ctx.exclusive_lock == nullptr ||
225 image_ctx.exclusive_lock->is_lock_owner());
226
227 // stop early if the parent went away - it just means
228 // another flatten finished first, so this one is useless.
9f95a23c 229 image_ctx.image_lock.lock_shared();
11fdf7f2
TL
230 if (!image_ctx.parent) {
231 ldout(cct, 5) << "image already flattened" << dendl;
9f95a23c
TL
232 image_ctx.image_lock.unlock_shared();
233 image_ctx.owner_lock.unlock_shared();
11fdf7f2
TL
234 this->complete(0);
235 return;
7c673cae 236 }
9f95a23c 237 image_ctx.image_lock.unlock_shared();
11fdf7f2
TL
238
239 // remove parent from this (base) image
240 auto ctx = create_context_callback<
241 FlattenRequest<I>,
242 &FlattenRequest<I>::handle_detach_parent>(this);
243 auto req = image::DetachParentRequest<I>::create(image_ctx, ctx);
244 req->send();
9f95a23c 245 image_ctx.owner_lock.unlock_shared();
11fdf7f2 246}
7c673cae 247
11fdf7f2
TL
248template <typename I>
249void FlattenRequest<I>::handle_detach_parent(int r) {
250 I &image_ctx = this->m_image_ctx;
251 CephContext *cct = image_ctx.cct;
252 ldout(cct, 5) << "r=" << r << dendl;
7c673cae 253
11fdf7f2
TL
254 if (r < 0) {
255 lderr(cct) << "remove parent encountered an error: " << cpp_strerror(r)
256 << dendl;
257 }
7c673cae 258
11fdf7f2 259 this->complete(r);
7c673cae
FG
260}
261
262} // namespace operation
263} // namespace librbd
264
265template class librbd::operation::FlattenRequest<librbd::ImageCtx>;