]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/api/Pool.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / librbd / api / Pool.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 "librbd/api/Pool.h"
5#include "include/rados/librados.hpp"
6#include "common/dout.h"
7#include "common/errno.h"
9f95a23c 8#include "common/Cond.h"
11fdf7f2
TL
9#include "common/Throttle.h"
10#include "cls/rbd/cls_rbd_client.h"
11#include "osd/osd_types.h"
f67539c2 12#include "librbd/AsioEngine.h"
11fdf7f2
TL
13#include "librbd/ImageCtx.h"
14#include "librbd/Utils.h"
15#include "librbd/api/Config.h"
16#include "librbd/api/Image.h"
17#include "librbd/api/Trash.h"
18#include "librbd/image/ValidatePoolRequest.h"
19
20#define dout_subsys ceph_subsys_rbd
21
22namespace librbd {
23namespace api {
24
25namespace {
26
27#undef dout_prefix
28#define dout_prefix *_dout << "librbd::api::Pool::ImageStatRequest: " \
29 << __func__ << " " << this << ": " \
30 << "(id=" << m_image_id << "): "
31
32template <typename I>
33class ImageStatRequest {
34public:
35 ImageStatRequest(librados::IoCtx& io_ctx, SimpleThrottle& throttle,
36 const std::string& image_id, bool scan_snaps,
37 std::atomic<uint64_t>* bytes,
38 std::atomic<uint64_t>* max_bytes,
39 std::atomic<uint64_t>* snaps)
40 : m_cct(reinterpret_cast<CephContext*>(io_ctx.cct())),
41 m_io_ctx(io_ctx), m_throttle(throttle), m_image_id(image_id),
42 m_scan_snaps(scan_snaps), m_bytes(bytes), m_max_bytes(max_bytes),
43 m_snaps(snaps) {
44 m_throttle.start_op();
45 }
46
47 void send() {
48 get_head();
49 }
50
51protected:
52 void finish(int r) {
53 (*m_max_bytes) += m_max_size;
54 m_throttle.end_op(r);
55
56 delete this;
57 }
58
59private:
60 CephContext* m_cct;
61 librados::IoCtx& m_io_ctx;
62 SimpleThrottle& m_throttle;
63 const std::string& m_image_id;
64 bool m_scan_snaps;
65 std::atomic<uint64_t>* m_bytes;
66 std::atomic<uint64_t>* m_max_bytes;
67 std::atomic<uint64_t>* m_snaps;
68 bufferlist m_out_bl;
69
70 uint64_t m_max_size = 0;
71 ::SnapContext m_snapc;
72
73 void get_head() {
74 ldout(m_cct, 15) << dendl;
75
76 librados::ObjectReadOperation op;
77 cls_client::get_size_start(&op, CEPH_NOSNAP);
78 if (m_scan_snaps) {
79 cls_client::get_snapcontext_start(&op);
80 }
81
82 m_out_bl.clear();
83 auto aio_comp = util::create_rados_callback<
84 ImageStatRequest<I>, &ImageStatRequest<I>::handle_get_head>(this);
85 int r = m_io_ctx.aio_operate(util::header_name(m_image_id), aio_comp, &op,
86 &m_out_bl);
87 ceph_assert(r == 0);
88 aio_comp->release();
89 }
90
91 void handle_get_head(int r) {
92 ldout(m_cct, 15) << "r=" << r << dendl;
93
94 auto it = m_out_bl.cbegin();
95 if (r == 0) {
96 uint8_t order;
97 r = cls_client::get_size_finish(&it, &m_max_size, &order);
98 if (r == 0) {
99 (*m_bytes) += m_max_size;
100 }
101 }
102 if (m_scan_snaps && r == 0) {
103 r = cls_client::get_snapcontext_finish(&it, &m_snapc);
104 if (r == 0) {
105 (*m_snaps) += m_snapc.snaps.size();
106 }
107 }
108
109 if (r == -ENOENT) {
110 finish(r);
111 return;
112 } else if (r < 0) {
113 lderr(m_cct) << "failed to stat image: " << cpp_strerror(r) << dendl;
114 finish(r);
115 return;
116 }
117
118 if (!m_snapc.is_valid()) {
119 lderr(m_cct) << "snap context is invalid" << dendl;
120 finish(-EIO);
121 return;
122 }
123
124 get_snaps();
125 }
126
127 void get_snaps() {
128 if (!m_scan_snaps || m_snapc.snaps.empty()) {
129 finish(0);
130 return;
131 }
132
133 ldout(m_cct, 15) << dendl;
134 librados::ObjectReadOperation op;
135 for (auto snap_seq : m_snapc.snaps) {
136 cls_client::get_size_start(&op, snap_seq);
137 }
138
139 m_out_bl.clear();
140 auto aio_comp = util::create_rados_callback<
141 ImageStatRequest<I>, &ImageStatRequest<I>::handle_get_snaps>(this);
142 int r = m_io_ctx.aio_operate(util::header_name(m_image_id), aio_comp, &op,
143 &m_out_bl);
144 ceph_assert(r == 0);
145 aio_comp->release();
146 }
147
148 void handle_get_snaps(int r) {
149 ldout(m_cct, 15) << "r=" << r << dendl;
150
151 auto it = m_out_bl.cbegin();
152 for ([[maybe_unused]] auto snap_seq : m_snapc.snaps) {
153 uint64_t size;
154 if (r == 0) {
155 uint8_t order;
156 r = cls_client::get_size_finish(&it, &size, &order);
157 }
158 if (r == 0 && m_max_size < size) {
159 m_max_size = size;
160 }
161 }
162
163 if (r == -ENOENT) {
164 ldout(m_cct, 15) << "out-of-sync metadata" << dendl;
165 get_head();
166 } else if (r < 0) {
167 lderr(m_cct) << "failed to retrieve snap size: " << cpp_strerror(r)
168 << dendl;
169 finish(r);
170 } else {
171 finish(0);
172 }
173 }
174
175};
176
177template <typename I>
178void get_pool_stat_option_value(typename Pool<I>::StatOptions* stat_options,
179 rbd_pool_stat_option_t option,
180 uint64_t** value) {
181 auto it = stat_options->find(option);
182 if (it == stat_options->end()) {
183 *value = nullptr;
184 } else {
185 *value = it->second;
186 }
187}
188
189template <typename I>
190int get_pool_stats(librados::IoCtx& io_ctx, const ConfigProxy& config,
191 const std::vector<std::string>& image_ids, uint64_t* image_count,
192 uint64_t* provisioned_bytes, uint64_t* max_provisioned_bytes,
193 uint64_t* snapshot_count) {
194
195 bool scan_snaps = ((max_provisioned_bytes != nullptr) ||
196 (snapshot_count != nullptr));
197
198 SimpleThrottle throttle(
199 config.template get_val<uint64_t>("rbd_concurrent_management_ops"), true);
200 std::atomic<uint64_t> bytes{0};
201 std::atomic<uint64_t> max_bytes{0};
202 std::atomic<uint64_t> snaps{0};
203 for (auto& image_id : image_ids) {
204 if (throttle.pending_error()) {
205 break;
206 }
207
208 auto req = new ImageStatRequest<I>(io_ctx, throttle, image_id,
209 scan_snaps, &bytes, &max_bytes, &snaps);
210 req->send();
211 }
212
213 int r = throttle.wait_for_ret();
214 if (r < 0) {
215 return r;
216 }
217
218 if (image_count != nullptr) {
219 *image_count = image_ids.size();
220 }
221 if (provisioned_bytes != nullptr) {
222 *provisioned_bytes = bytes.load();
223 }
224 if (max_provisioned_bytes != nullptr) {
225 *max_provisioned_bytes = max_bytes.load();
226 }
227 if (snapshot_count != nullptr) {
228 *snapshot_count = snaps.load();
229 }
230
231 return 0;
232}
233
234} // anonymous namespace
235
236#undef dout_prefix
237#define dout_prefix *_dout << "librbd::api::Pool: " << __func__ << ": "
238
239template <typename I>
240int Pool<I>::init(librados::IoCtx& io_ctx, bool force) {
241 auto cct = reinterpret_cast<CephContext*>(io_ctx.cct());
242 ldout(cct, 10) << dendl;
243
244 int r = io_ctx.application_enable(pg_pool_t::APPLICATION_NAME_RBD, force);
245 if (r < 0) {
246 return r;
247 }
248
249 ConfigProxy config{cct->_conf};
250 api::Config<I>::apply_pool_overrides(io_ctx, &config);
251 if (!config.get_val<bool>("rbd_validate_pool")) {
252 return 0;
253 }
254
f67539c2 255 AsioEngine asio_engine(io_ctx);
11fdf7f2
TL
256
257 C_SaferCond ctx;
f67539c2
TL
258 auto req = image::ValidatePoolRequest<I>::create(
259 io_ctx, asio_engine.get_work_queue(), &ctx);
11fdf7f2
TL
260 req->send();
261
262 return ctx.wait();
263}
264
265template <typename I>
266int Pool<I>::add_stat_option(StatOptions* stat_options,
267 rbd_pool_stat_option_t option,
268 uint64_t* value) {
269 switch (option) {
270 case RBD_POOL_STAT_OPTION_IMAGES:
271 case RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES:
272 case RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES:
273 case RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS:
274 case RBD_POOL_STAT_OPTION_TRASH_IMAGES:
275 case RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES:
276 case RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES:
277 case RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS:
278 stat_options->emplace(option, value);
279 return 0;
280 default:
281 break;
282 }
283 return -ENOENT;
284}
285
286template <typename I>
287int Pool<I>::get_stats(librados::IoCtx& io_ctx, StatOptions* stat_options) {
288 auto cct = reinterpret_cast<CephContext*>(io_ctx.cct());
289 ldout(cct, 10) << dendl;
290
291 ConfigProxy config{cct->_conf};
292 api::Config<I>::apply_pool_overrides(io_ctx, &config);
293
294 uint64_t* image_count;
295 uint64_t* provisioned_bytes;
296 uint64_t* max_provisioned_bytes;
297 uint64_t* snapshot_count;
298
299 std::vector<trash_image_info_t> trash_entries;
300 int r = Trash<I>::list(io_ctx, trash_entries, false);
301 if (r < 0 && r != -EOPNOTSUPP) {
302 return r;
303 }
304
305 get_pool_stat_option_value<I>(
306 stat_options, RBD_POOL_STAT_OPTION_IMAGES, &image_count);
307 get_pool_stat_option_value<I>(
308 stat_options, RBD_POOL_STAT_OPTION_IMAGE_PROVISIONED_BYTES,
309 &provisioned_bytes);
310 get_pool_stat_option_value<I>(
311 stat_options, RBD_POOL_STAT_OPTION_IMAGE_MAX_PROVISIONED_BYTES,
312 &max_provisioned_bytes);
313 get_pool_stat_option_value<I>(
314 stat_options, RBD_POOL_STAT_OPTION_IMAGE_SNAPSHOTS, &snapshot_count);
315 if (image_count != nullptr || provisioned_bytes != nullptr ||
316 max_provisioned_bytes != nullptr || snapshot_count != nullptr) {
317 typename Image<I>::ImageNameToIds images;
318 int r = Image<I>::list_images_v2(io_ctx, &images);
319 if (r < 0) {
320 return r;
321 }
322
323 std::vector<std::string> image_ids;
324 image_ids.reserve(images.size() + trash_entries.size());
325 for (auto& it : images) {
326 image_ids.push_back(std::move(it.second));
327 }
328 for (auto& it : trash_entries) {
329 if (it.source == RBD_TRASH_IMAGE_SOURCE_REMOVING) {
330 image_ids.push_back(std::move(it.id));
331 }
332 }
333
334 r = get_pool_stats<I>(io_ctx, config, image_ids, image_count,
335 provisioned_bytes, max_provisioned_bytes,
336 snapshot_count);
337 if (r < 0) {
338 return r;
339 }
340 }
341
342 get_pool_stat_option_value<I>(
343 stat_options, RBD_POOL_STAT_OPTION_TRASH_IMAGES, &image_count);
344 get_pool_stat_option_value<I>(
345 stat_options, RBD_POOL_STAT_OPTION_TRASH_PROVISIONED_BYTES,
346 &provisioned_bytes);
347 get_pool_stat_option_value<I>(
348 stat_options, RBD_POOL_STAT_OPTION_TRASH_MAX_PROVISIONED_BYTES,
349 &max_provisioned_bytes);
350 get_pool_stat_option_value<I>(
351 stat_options, RBD_POOL_STAT_OPTION_TRASH_SNAPSHOTS, &snapshot_count);
352 if (image_count != nullptr || provisioned_bytes != nullptr ||
353 max_provisioned_bytes != nullptr || snapshot_count != nullptr) {
354
355 std::vector<std::string> image_ids;
356 image_ids.reserve(trash_entries.size());
357 for (auto& it : trash_entries) {
358 if (it.source == RBD_TRASH_IMAGE_SOURCE_REMOVING) {
359 continue;
360 }
361 image_ids.push_back(std::move(it.id));
362 }
363
364 r = get_pool_stats<I>(io_ctx, config, image_ids, image_count,
365 provisioned_bytes, max_provisioned_bytes,
366 snapshot_count);
367 if (r < 0) {
368 return r;
369 }
370 }
371
372 return 0;
373}
374
375} // namespace api
376} // namespace librbd
377
378template class librbd::api::Pool<librbd::ImageCtx>;