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