]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/operation/FlattenRequest.cc
update sources to ceph Nautilus 14.2.1
[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;
11fdf7f2 39 ceph_assert(image_ctx.owner_lock.is_locked());
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
TL
48 {
49 RWLock::RLocker snap_lock(image_ctx.snap_lock);
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
FG
57 bufferlist bl;
58 string oid = image_ctx.get_object_name(m_object_no);
b32b8144 59 auto req = new io::ObjectWriteRequest<I>(&image_ctx, oid, m_object_no, 0,
11fdf7f2
TL
60 std::move(bl), m_snapc, 0, {},
61 this);
7c673cae
FG
62 if (!req->has_parent()) {
63 // stop early if the parent went away - it just means
64 // another flatten finished first or the image was resized
65 delete req;
66 return 1;
67 }
68
69 req->send();
70 return 0;
71 }
72
73private:
7c673cae
FG
74 ::SnapContext m_snapc;
75 uint64_t m_object_no;
76};
77
78template <typename I>
79bool FlattenRequest<I>::should_complete(int r) {
80 I &image_ctx = this->m_image_ctx;
81 CephContext *cct = image_ctx.cct;
11fdf7f2
TL
82 ldout(cct, 5) << "r=" << r << dendl;
83 if (r < 0) {
84 lderr(cct) << "encountered error: " << cpp_strerror(r) << dendl;
7c673cae 85 }
11fdf7f2 86 return true;
7c673cae
FG
87}
88
89template <typename I>
90void FlattenRequest<I>::send_op() {
11fdf7f2
TL
91 flatten_objects();
92}
93
94template <typename I>
95void FlattenRequest<I>::flatten_objects() {
7c673cae 96 I &image_ctx = this->m_image_ctx;
11fdf7f2
TL
97 ceph_assert(image_ctx.owner_lock.is_locked());
98
7c673cae 99 CephContext *cct = image_ctx.cct;
11fdf7f2 100 ldout(cct, 5) << dendl;
7c673cae 101
11fdf7f2
TL
102 assert(image_ctx.owner_lock.is_locked());
103 auto ctx = create_context_callback<
104 FlattenRequest<I>,
105 &FlattenRequest<I>::handle_flatten_objects>(this);
7c673cae
FG
106 typename AsyncObjectThrottle<I>::ContextFactory context_factory(
107 boost::lambda::bind(boost::lambda::new_ptr<C_FlattenObject<I> >(),
11fdf7f2 108 boost::lambda::_1, &image_ctx, m_snapc, boost::lambda::_2));
7c673cae 109 AsyncObjectThrottle<I> *throttle = new AsyncObjectThrottle<I>(
11fdf7f2
TL
110 this, image_ctx, context_factory, ctx, &m_prog_ctx, 0, m_overlap_objects);
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
11fdf7f2 131 detach_child();
7c673cae
FG
132}
133
134template <typename I>
11fdf7f2 135void FlattenRequest<I>::detach_child() {
7c673cae 136 I &image_ctx = this->m_image_ctx;
7c673cae
FG
137 CephContext *cct = image_ctx.cct;
138
139 // should have been canceled prior to releasing lock
11fdf7f2
TL
140 image_ctx.owner_lock.get_read();
141 ceph_assert(image_ctx.exclusive_lock == nullptr ||
142 image_ctx.exclusive_lock->is_lock_owner());
7c673cae
FG
143
144 // if there are no snaps, remove from the children object as well
145 // (if snapshots remain, they have their own parent info, and the child
146 // will be removed when the last snap goes away)
11fdf7f2 147 image_ctx.snap_lock.get_read();
7c673cae
FG
148 if ((image_ctx.features & RBD_FEATURE_DEEP_FLATTEN) == 0 &&
149 !image_ctx.snaps.empty()) {
11fdf7f2
TL
150 image_ctx.snap_lock.put_read();
151 image_ctx.owner_lock.put_read();
152 detach_parent();
153 return;
154 }
155 image_ctx.snap_lock.put_read();
156
157 ldout(cct, 5) << dendl;
158 auto ctx = create_context_callback<
159 FlattenRequest<I>,
160 &FlattenRequest<I>::handle_detach_child>(this);
161 auto req = image::DetachChildRequest<I>::create(image_ctx, ctx);
162 req->send();
163 image_ctx.owner_lock.put_read();
164}
165
166template <typename I>
167void FlattenRequest<I>::handle_detach_child(int r) {
168 I &image_ctx = this->m_image_ctx;
169 CephContext *cct = image_ctx.cct;
170 ldout(cct, 5) << "r=" << r << dendl;
171
172 if (r < 0 && r != -ENOENT) {
173 lderr(cct) << "detach encountered an error: " << cpp_strerror(r) << dendl;
174 this->complete(r);
175 return;
176 }
177
178 detach_parent();
179}
180
181template <typename I>
182void FlattenRequest<I>::detach_parent() {
183 I &image_ctx = this->m_image_ctx;
184 CephContext *cct = image_ctx.cct;
185 ldout(cct, 5) << dendl;
186
187 // should have been canceled prior to releasing lock
188 image_ctx.owner_lock.get_read();
189 ceph_assert(image_ctx.exclusive_lock == nullptr ||
190 image_ctx.exclusive_lock->is_lock_owner());
191
192 // stop early if the parent went away - it just means
193 // another flatten finished first, so this one is useless.
194 image_ctx.parent_lock.get_read();
195 if (!image_ctx.parent) {
196 ldout(cct, 5) << "image already flattened" << dendl;
197 image_ctx.parent_lock.put_read();
198 image_ctx.owner_lock.put_read();
199 this->complete(0);
200 return;
7c673cae 201 }
11fdf7f2
TL
202 image_ctx.parent_lock.put_read();
203
204 // remove parent from this (base) image
205 auto ctx = create_context_callback<
206 FlattenRequest<I>,
207 &FlattenRequest<I>::handle_detach_parent>(this);
208 auto req = image::DetachParentRequest<I>::create(image_ctx, ctx);
209 req->send();
210 image_ctx.owner_lock.put_read();
211}
7c673cae 212
11fdf7f2
TL
213template <typename I>
214void FlattenRequest<I>::handle_detach_parent(int r) {
215 I &image_ctx = this->m_image_ctx;
216 CephContext *cct = image_ctx.cct;
217 ldout(cct, 5) << "r=" << r << dendl;
7c673cae 218
11fdf7f2
TL
219 if (r < 0) {
220 lderr(cct) << "remove parent encountered an error: " << cpp_strerror(r)
221 << dendl;
222 }
7c673cae 223
11fdf7f2 224 this->complete(r);
7c673cae
FG
225}
226
227} // namespace operation
228} // namespace librbd
229
230template class librbd::operation::FlattenRequest<librbd::ImageCtx>;