]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/api/Snapshot.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / librbd / api / Snapshot.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/Snapshot.h"
5#include "cls/rbd/cls_rbd_types.h"
6#include "common/errno.h"
9f95a23c 7#include "librbd/internal.h"
11fdf7f2
TL
8#include "librbd/ImageCtx.h"
9#include "librbd/ImageState.h"
10#include "librbd/Operations.h"
11#include "librbd/Utils.h"
9f95a23c 12#include "librbd/api/Image.h"
11fdf7f2
TL
13#include "include/Context.h"
14#include "common/Cond.h"
15
f67539c2
TL
16#include <boost/variant.hpp>
17
11fdf7f2
TL
18#define dout_subsys ceph_subsys_rbd
19#undef dout_prefix
20#define dout_prefix *_dout << "librbd::api::Snapshot: " << __func__ << ": "
21
9f95a23c
TL
22using librados::snap_t;
23
11fdf7f2
TL
24namespace librbd {
25namespace api {
26
27namespace {
28
1e59de90 29class GetGroupVisitor {
11fdf7f2
TL
30public:
31 CephContext* cct;
32 librados::IoCtx *image_ioctx;
33 snap_group_namespace_t *group_snap;
34
35 explicit GetGroupVisitor(CephContext* cct, librados::IoCtx *_image_ioctx,
36 snap_group_namespace_t *group_snap)
37 : cct(cct), image_ioctx(_image_ioctx), group_snap(group_snap) {};
38
39 template <typename T>
40 inline int operator()(const T&) const {
41 // ignore other than GroupSnapshotNamespace types.
42 return -EINVAL;
43 }
44
45 inline int operator()(
46 const cls::rbd::GroupSnapshotNamespace& snap_namespace) {
47 IoCtx group_ioctx;
48 int r = util::create_ioctx(*image_ioctx, "group", snap_namespace.group_pool,
49 {}, &group_ioctx);
50 if (r < 0) {
51 return r;
52 }
53
54 cls::rbd::GroupSnapshot group_snapshot;
55
56 std::string group_name;
57 r = cls_client::dir_get_name(&group_ioctx, RBD_GROUP_DIRECTORY,
58 snap_namespace.group_id, &group_name);
59 if (r < 0) {
60 lderr(cct) << "failed to retrieve group name: " << cpp_strerror(r)
61 << dendl;
62 return r;
63 }
64
20effc67 65 std::string group_header_oid = util::group_header_name(snap_namespace.group_id);
11fdf7f2
TL
66 r = cls_client::group_snap_get_by_id(&group_ioctx,
67 group_header_oid,
68 snap_namespace.group_snapshot_id,
69 &group_snapshot);
70 if (r < 0) {
71 lderr(cct) << "failed to retrieve group snapshot: " << cpp_strerror(r)
72 << dendl;
73 return r;
74 }
75
76 group_snap->group_pool = group_ioctx.get_id();
77 group_snap->group_name = group_name;
78 group_snap->group_snap_name = group_snapshot.name;
79 return 0;
80 }
81};
82
1e59de90 83class GetTrashVisitor {
11fdf7f2
TL
84public:
85 std::string* original_name;
86
87 explicit GetTrashVisitor(std::string* original_name)
88 : original_name(original_name) {
89 }
90
91 template <typename T>
92 inline int operator()(const T&) const {
93 return -EINVAL;
94 }
95
96 inline int operator()(
97 const cls::rbd::TrashSnapshotNamespace& snap_namespace) {
98 *original_name = snap_namespace.original_name;
99 return 0;
100 }
101};
102
1e59de90 103class GetMirrorVisitor {
9f95a23c
TL
104public:
105 snap_mirror_namespace_t *mirror_snap;
106
107 explicit GetMirrorVisitor(snap_mirror_namespace_t *mirror_snap)
108 : mirror_snap(mirror_snap) {
109 }
110
111 template <typename T>
112 inline int operator()(const T&) const {
113 return -EINVAL;
114 }
115
116 inline int operator()(
117 const cls::rbd::MirrorSnapshotNamespace& snap_namespace) {
118 mirror_snap->state = static_cast<snap_mirror_state_t>(snap_namespace.state);
119 mirror_snap->complete = snap_namespace.complete;
120 mirror_snap->mirror_peer_uuids = snap_namespace.mirror_peer_uuids;
121 mirror_snap->primary_mirror_uuid = snap_namespace.primary_mirror_uuid;
122 mirror_snap->primary_snap_id = snap_namespace.primary_snap_id;
123 mirror_snap->last_copied_object_number =
124 snap_namespace.last_copied_object_number;
125 return 0;
126 }
127};
128
11fdf7f2
TL
129} // anonymous namespace
130
131template <typename I>
132int Snapshot<I>::get_group_namespace(I *ictx, uint64_t snap_id,
133 snap_group_namespace_t *group_snap) {
134 int r = ictx->state->refresh_if_required();
135 if (r < 0) {
136 return r;
137 }
138
9f95a23c 139 std::shared_lock image_locker{ictx->image_lock};
11fdf7f2
TL
140 auto snap_info = ictx->get_snap_info(snap_id);
141 if (snap_info == nullptr) {
142 return -ENOENT;
143 }
144
eafe8130 145 GetGroupVisitor ggv = GetGroupVisitor(ictx->cct, &ictx->md_ctx, group_snap);
1e59de90 146 r = snap_info->snap_namespace.visit(ggv);
11fdf7f2
TL
147 if (r < 0) {
148 return r;
149 }
150
151 return 0;
152}
153
154template <typename I>
155int Snapshot<I>::get_trash_namespace(I *ictx, uint64_t snap_id,
156 std::string* original_name) {
157 int r = ictx->state->refresh_if_required();
158 if (r < 0) {
159 return r;
160 }
161
9f95a23c 162 std::shared_lock image_locker{ictx->image_lock};
11fdf7f2
TL
163 auto snap_info = ictx->get_snap_info(snap_id);
164 if (snap_info == nullptr) {
165 return -ENOENT;
166 }
167
168 auto visitor = GetTrashVisitor(original_name);
1e59de90 169 r = snap_info->snap_namespace.visit(visitor);
11fdf7f2
TL
170 if (r < 0) {
171 return r;
172 }
173
174 return 0;
175}
176
9f95a23c
TL
177template <typename I>
178int Snapshot<I>::get_mirror_namespace(
179 I *ictx, uint64_t snap_id, snap_mirror_namespace_t *mirror_snap) {
180 int r = ictx->state->refresh_if_required();
181 if (r < 0) {
182 return r;
183 }
184
185 std::shared_lock image_locker{ictx->image_lock};
186 auto snap_info = ictx->get_snap_info(snap_id);
187 if (snap_info == nullptr) {
188 return -ENOENT;
189 }
190
191 auto gmv = GetMirrorVisitor(mirror_snap);
1e59de90 192 r = snap_info->snap_namespace.visit(gmv);
9f95a23c
TL
193 if (r < 0) {
194 return r;
195 }
196
197 return 0;
198}
199
11fdf7f2
TL
200template <typename I>
201int Snapshot<I>::get_namespace_type(I *ictx, uint64_t snap_id,
202 snap_namespace_type_t *namespace_type) {
203 int r = ictx->state->refresh_if_required();
204 if (r < 0) {
205 return r;
206 }
207
9f95a23c 208 std::shared_lock l{ictx->image_lock};
11fdf7f2
TL
209 auto snap_info = ictx->get_snap_info(snap_id);
210 if (snap_info == nullptr) {
211 return -ENOENT;
212 }
213
214 *namespace_type = static_cast<snap_namespace_type_t>(
215 cls::rbd::get_snap_namespace_type(snap_info->snap_namespace));
216 return 0;
217}
218
219template <typename I>
220int Snapshot<I>::remove(I *ictx, uint64_t snap_id) {
221 ldout(ictx->cct, 20) << "snap_remove " << ictx << " " << snap_id << dendl;
222
223 int r = ictx->state->refresh_if_required();
224 if (r < 0) {
225 return r;
226 }
227
228 cls::rbd::SnapshotNamespace snapshot_namespace;
229 std::string snapshot_name;
230 {
9f95a23c 231 std::shared_lock image_locker{ictx->image_lock};
11fdf7f2
TL
232 auto it = ictx->snap_info.find(snap_id);
233 if (it == ictx->snap_info.end()) {
234 return -ENOENT;
235 }
236
237 snapshot_namespace = it->second.snap_namespace;
238 snapshot_name = it->second.name;
239 }
240
241 C_SaferCond ctx;
242 ictx->operations->snap_remove(snapshot_namespace, snapshot_name, &ctx);
243 r = ctx.wait();
244 return r;
245}
246
9f95a23c
TL
247template <typename I>
248int Snapshot<I>::get_name(I *ictx, uint64_t snap_id, std::string *snap_name)
249 {
250 ldout(ictx->cct, 20) << "snap_get_name " << ictx << " " << snap_id << dendl;
251
252 int r = ictx->state->refresh_if_required();
253 if (r < 0)
254 return r;
255
256 std::shared_lock image_locker{ictx->image_lock};
257 r = ictx->get_snap_name(snap_id, snap_name);
258
259 return r;
260 }
261
262template <typename I>
263int Snapshot<I>::get_id(I *ictx, const std::string& snap_name, uint64_t *snap_id)
264 {
265 ldout(ictx->cct, 20) << "snap_get_id " << ictx << " " << snap_name << dendl;
266
267 int r = ictx->state->refresh_if_required();
268 if (r < 0)
269 return r;
270
271 std::shared_lock image_locker{ictx->image_lock};
272 *snap_id = ictx->get_snap_id(cls::rbd::UserSnapshotNamespace(), snap_name);
273 if (*snap_id == CEPH_NOSNAP)
274 return -ENOENT;
275
276 return 0;
277 }
278
279template <typename I>
20effc67 280int Snapshot<I>::list(I *ictx, std::vector<snap_info_t>& snaps) {
9f95a23c
TL
281 ldout(ictx->cct, 20) << "snap_list " << ictx << dendl;
282
283 int r = ictx->state->refresh_if_required();
284 if (r < 0)
285 return r;
286
287 std::shared_lock l{ictx->image_lock};
288 for (auto &it : ictx->snap_info) {
289 snap_info_t info;
290 info.name = it.second.name;
291 info.id = it.first;
292 info.size = it.second.size;
293 snaps.push_back(info);
294 }
295
296 return 0;
297}
298
299template <typename I>
300int Snapshot<I>::exists(I *ictx, const cls::rbd::SnapshotNamespace& snap_namespace,
301 const char *snap_name, bool *exists) {
302 ldout(ictx->cct, 20) << "snap_exists " << ictx << " " << snap_name << dendl;
303
304 int r = ictx->state->refresh_if_required();
305 if (r < 0)
306 return r;
307
308 std::shared_lock l{ictx->image_lock};
309 *exists = ictx->get_snap_id(snap_namespace, snap_name) != CEPH_NOSNAP;
310 return 0;
311}
312
f67539c2
TL
313template <typename I>
314int Snapshot<I>::create(I *ictx, const char *snap_name, uint32_t flags,
315 ProgressContext& pctx) {
316 ldout(ictx->cct, 20) << "snap_create " << ictx << " " << snap_name
317 << " flags: " << flags << dendl;
318
319 uint64_t internal_flags = 0;
320 int r = util::snap_create_flags_api_to_internal(ictx->cct, flags,
321 &internal_flags);
322 if (r < 0) {
323 return r;
324 }
325
326 return ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
327 snap_name, internal_flags, pctx);
328}
329
9f95a23c
TL
330template <typename I>
331int Snapshot<I>::remove(I *ictx, const char *snap_name, uint32_t flags,
332 ProgressContext& pctx) {
333 ldout(ictx->cct, 20) << "snap_remove " << ictx << " " << snap_name << " flags: " << flags << dendl;
334
335 int r = 0;
336
337 r = ictx->state->refresh_if_required();
338 if (r < 0)
339 return r;
340
341 if (flags & RBD_SNAP_REMOVE_FLATTEN) {
342 r = Image<I>::flatten_children(ictx, snap_name, pctx);
343 if (r < 0) {
344 return r;
345 }
346 }
347
348 bool protect;
349 r = is_protected(ictx, snap_name, &protect);
350 if (r < 0) {
351 return r;
352 }
353
354 if (protect && flags & RBD_SNAP_REMOVE_UNPROTECT) {
355 r = ictx->operations->snap_unprotect(cls::rbd::UserSnapshotNamespace(), snap_name);
356 if (r < 0) {
357 lderr(ictx->cct) << "failed to unprotect snapshot: " << snap_name << dendl;
358 return r;
359 }
360
361 r = is_protected(ictx, snap_name, &protect);
362 if (r < 0) {
363 return r;
364 }
365 if (protect) {
366 lderr(ictx->cct) << "snapshot is still protected after unprotection" << dendl;
367 ceph_abort();
368 }
369 }
370
371 C_SaferCond ctx;
372 ictx->operations->snap_remove(cls::rbd::UserSnapshotNamespace(), snap_name, &ctx);
373
374 r = ctx.wait();
375 return r;
376}
377
378template <typename I>
379int Snapshot<I>::get_timestamp(I *ictx, uint64_t snap_id, struct timespec *timestamp) {
380 auto snap_it = ictx->snap_info.find(snap_id);
381 ceph_assert(snap_it != ictx->snap_info.end());
382 utime_t time = snap_it->second.timestamp;
383 time.to_timespec(timestamp);
384 return 0;
385}
386
387template <typename I>
388int Snapshot<I>::get_limit(I *ictx, uint64_t *limit) {
389 int r = cls_client::snapshot_get_limit(&ictx->md_ctx, ictx->header_oid,
390 limit);
391 if (r == -EOPNOTSUPP) {
392 *limit = UINT64_MAX;
393 r = 0;
394 }
395 return r;
396}
397
398template <typename I>
399int Snapshot<I>::set_limit(I *ictx, uint64_t limit) {
400 return ictx->operations->snap_set_limit(limit);
401}
402
403template <typename I>
404int Snapshot<I>::is_protected(I *ictx, const char *snap_name, bool *protect) {
405 ldout(ictx->cct, 20) << "snap_is_protected " << ictx << " " << snap_name
406 << dendl;
407
408 int r = ictx->state->refresh_if_required();
409 if (r < 0)
410 return r;
411
412 std::shared_lock l{ictx->image_lock};
413 snap_t snap_id = ictx->get_snap_id(cls::rbd::UserSnapshotNamespace(), snap_name);
414 if (snap_id == CEPH_NOSNAP)
415 return -ENOENT;
416 bool is_unprotected;
417 r = ictx->is_snap_unprotected(snap_id, &is_unprotected);
418 // consider both PROTECTED or UNPROTECTING to be 'protected',
419 // since in either state they can't be deleted
420 *protect = !is_unprotected;
421 return r;
422}
423
424template <typename I>
425int Snapshot<I>::get_namespace(I *ictx, const char *snap_name,
426 cls::rbd::SnapshotNamespace *snap_namespace) {
427 ldout(ictx->cct, 20) << "get_snap_namespace " << ictx << " " << snap_name
428 << dendl;
429
430 int r = ictx->state->refresh_if_required();
431 if (r < 0)
432 return r;
433 std::shared_lock l{ictx->image_lock};
434 snap_t snap_id = ictx->get_snap_id(*snap_namespace, snap_name);
435 if (snap_id == CEPH_NOSNAP)
436 return -ENOENT;
437 r = ictx->get_snap_namespace(snap_id, snap_namespace);
438 return r;
439}
440
11fdf7f2
TL
441} // namespace api
442} // namespace librbd
443
444template class librbd::api::Snapshot<librbd::ImageCtx>;