1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/api/Group.h"
5 #include "common/errno.h"
6 #include "librbd/ImageState.h"
7 #include "librbd/Utils.h"
8 #include "librbd/io/AioCompletion.h"
10 #define dout_subsys ceph_subsys_rbd
12 #define dout_prefix *_dout << "librbd::api::Group: " << __func__ << ": "
19 // list binds to list() here, so std::list is explicitly used below
21 using ceph::bufferlist
;
22 using librados::snap_t
;
23 using librados::IoCtx
;
24 using librados::Rados
;
29 // Consistency groups functions
32 int Group
<I
>::create(librados::IoCtx
& io_ctx
, const char *group_name
)
34 CephContext
*cct
= (CephContext
*)io_ctx
.cct();
37 uint64_t bid
= rados
.get_instance_id();
39 uint32_t extra
= rand() % 0xFFFFFFFF;
41 bid_ss
<< std::hex
<< bid
<< std::hex
<< extra
;
42 string id
= bid_ss
.str();
44 ldout(cct
, 2) << "adding consistency group to directory..." << dendl
;
46 int r
= cls_client::group_dir_add(&io_ctx
, RBD_GROUP_DIRECTORY
, group_name
,
49 lderr(cct
) << "error adding consistency group to directory: "
54 string header_oid
= util::group_header_name(id
);
56 r
= cls_client::group_create(&io_ctx
, header_oid
);
58 lderr(cct
) << "error writing header: " << cpp_strerror(r
) << dendl
;
59 goto err_remove_from_dir
;
65 int remove_r
= cls_client::group_dir_remove(&io_ctx
, RBD_GROUP_DIRECTORY
,
68 lderr(cct
) << "error cleaning up consistency group from rbd_directory "
69 << "object after creation failed: " << cpp_strerror(remove_r
)
77 int Group
<I
>::remove(librados::IoCtx
& io_ctx
, const char *group_name
)
79 CephContext
*cct((CephContext
*)io_ctx
.cct());
80 ldout(cct
, 20) << "io_ctx=" << &io_ctx
<< " " << group_name
<< dendl
;
82 std::vector
<group_image_status_t
> images
;
83 int r
= image_list(io_ctx
, group_name
, &images
);
84 if (r
< 0 && r
!= -ENOENT
) {
85 lderr(cct
) << "error listing group images" << dendl
;
89 for (auto i
: images
) {
90 librados::Rados
rados(io_ctx
);
92 rados
.ioctx_create2(i
.pool
, image_ioctx
);
93 r
= image_remove(io_ctx
, group_name
, image_ioctx
, i
.name
.c_str());
94 if (r
< 0 && r
!= -ENOENT
) {
95 lderr(cct
) << "error removing image from a group" << dendl
;
100 std::string group_id
;
101 r
= cls_client::dir_get_id(&io_ctx
, RBD_GROUP_DIRECTORY
,
102 std::string(group_name
), &group_id
);
103 if (r
< 0 && r
!= -ENOENT
) {
104 lderr(cct
) << "error getting id of group" << dendl
;
108 string header_oid
= util::group_header_name(group_id
);
110 r
= io_ctx
.remove(header_oid
);
111 if (r
< 0 && r
!= -ENOENT
) {
112 lderr(cct
) << "error removing header: " << cpp_strerror(-r
) << dendl
;
116 r
= cls_client::group_dir_remove(&io_ctx
, RBD_GROUP_DIRECTORY
, group_name
,
118 if (r
< 0 && r
!= -ENOENT
) {
119 lderr(cct
) << "error removing group from directory" << dendl
;
126 template <typename I
>
127 int Group
<I
>::list(IoCtx
& io_ctx
, vector
<string
> *names
)
129 CephContext
*cct
= (CephContext
*)io_ctx
.cct();
130 ldout(cct
, 20) << "io_ctx=" << &io_ctx
<< dendl
;
133 string last_read
= "";
136 map
<string
, string
> groups
;
137 r
= cls_client::group_dir_list(&io_ctx
, RBD_GROUP_DIRECTORY
, last_read
,
141 lderr(cct
) << "error listing group in directory: "
142 << cpp_strerror(r
) << dendl
;
148 for (pair
<string
, string
> group
: groups
) {
149 names
->push_back(group
.first
);
151 if (!groups
.empty()) {
152 last_read
= groups
.rbegin()->first
;
155 } while (r
== max_read
);
160 template <typename I
>
161 int Group
<I
>::image_add(librados::IoCtx
& group_ioctx
, const char *group_name
,
162 librados::IoCtx
& image_ioctx
, const char *image_name
)
164 CephContext
*cct
= (CephContext
*)group_ioctx
.cct();
165 ldout(cct
, 20) << "io_ctx=" << &group_ioctx
166 << " group name " << group_name
<< " image "
167 << &image_ioctx
<< " name " << image_name
<< dendl
;
171 int r
= cls_client::dir_get_id(&group_ioctx
, RBD_GROUP_DIRECTORY
, group_name
,
174 lderr(cct
) << "error reading consistency group id object: "
179 string group_header_oid
= util::group_header_name(group_id
);
182 ldout(cct
, 20) << "adding image to group name " << group_name
183 << " group id " << group_header_oid
<< dendl
;
187 r
= cls_client::dir_get_id(&image_ioctx
, RBD_DIRECTORY
, image_name
,
190 lderr(cct
) << "error reading image id object: "
191 << cpp_strerror(-r
) << dendl
;
195 string image_header_oid
= util::header_name(image_id
);
197 ldout(cct
, 20) << "adding image " << image_name
198 << " image id " << image_header_oid
<< dendl
;
200 cls::rbd::GroupImageStatus
incomplete_st(
201 image_id
, image_ioctx
.get_id(),
202 cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE
);
203 cls::rbd::GroupImageStatus
attached_st(
204 image_id
, image_ioctx
.get_id(), cls::rbd::GROUP_IMAGE_LINK_STATE_ATTACHED
);
206 r
= cls_client::group_image_set(&group_ioctx
, group_header_oid
,
209 cls::rbd::GroupSpec
group_spec(group_id
, group_ioctx
.get_id());
212 lderr(cct
) << "error adding image reference to consistency group: "
213 << cpp_strerror(-r
) << dendl
;
217 r
= cls_client::image_add_group(&image_ioctx
, image_header_oid
, group_spec
);
219 lderr(cct
) << "error adding group reference to image: "
220 << cpp_strerror(-r
) << dendl
;
221 cls::rbd::GroupImageSpec
spec(image_id
, image_ioctx
.get_id());
222 cls_client::group_image_remove(&group_ioctx
, group_header_oid
, spec
);
223 // Ignore errors in the clean up procedure.
227 r
= cls_client::group_image_set(&group_ioctx
, group_header_oid
,
233 template <typename I
>
234 int Group
<I
>::image_remove(librados::IoCtx
& group_ioctx
, const char *group_name
,
235 librados::IoCtx
& image_ioctx
, const char *image_name
)
237 CephContext
*cct
= (CephContext
*)group_ioctx
.cct();
238 ldout(cct
, 20) << "io_ctx=" << &group_ioctx
239 << " group name " << group_name
<< " image "
240 << &image_ioctx
<< " name " << image_name
<< dendl
;
243 int r
= cls_client::dir_get_id(&image_ioctx
, RBD_DIRECTORY
, image_name
,
246 lderr(cct
) << "error reading image id object: "
247 << cpp_strerror(-r
) << dendl
;
251 return Group
<I
>::image_remove_by_id(group_ioctx
, group_name
, image_ioctx
,
255 template <typename I
>
256 int Group
<I
>::image_remove_by_id(librados::IoCtx
& group_ioctx
,
257 const char *group_name
,
258 librados::IoCtx
& image_ioctx
,
259 const char *image_id
)
261 CephContext
*cct
= (CephContext
*)group_ioctx
.cct();
262 ldout(cct
, 20) << "group_remove_image_by_id " << &group_ioctx
263 << " group name " << group_name
<< " image "
264 << &image_ioctx
<< " id " << image_id
<< dendl
;
268 int r
= cls_client::dir_get_id(&group_ioctx
, RBD_GROUP_DIRECTORY
, group_name
,
271 lderr(cct
) << "error reading consistency group id object: "
276 string group_header_oid
= util::group_header_name(group_id
);
278 ldout(cct
, 20) << "adding image to group name " << group_name
279 << " group id " << group_header_oid
<< dendl
;
281 string image_header_oid
= util::header_name(image_id
);
283 ldout(cct
, 20) << "removing " << " image id " << image_header_oid
<< dendl
;
285 cls::rbd::GroupSpec
group_spec(group_id
, group_ioctx
.get_id());
287 cls::rbd::GroupImageStatus
incomplete_st(
288 image_id
, image_ioctx
.get_id(),
289 cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE
);
291 cls::rbd::GroupImageSpec
spec(image_id
, image_ioctx
.get_id());
293 r
= cls_client::group_image_set(&group_ioctx
, group_header_oid
,
297 lderr(cct
) << "couldn't put image into removing state: "
298 << cpp_strerror(-r
) << dendl
;
302 r
= cls_client::image_remove_group(&image_ioctx
, image_header_oid
,
304 if ((r
< 0) && (r
!= -ENOENT
)) {
305 lderr(cct
) << "couldn't remove group reference from image"
306 << cpp_strerror(-r
) << dendl
;
310 r
= cls_client::group_image_remove(&group_ioctx
, group_header_oid
, spec
);
312 lderr(cct
) << "couldn't remove image from group"
313 << cpp_strerror(-r
) << dendl
;
320 template <typename I
>
321 int Group
<I
>::image_list(librados::IoCtx
& group_ioctx
,
322 const char *group_name
,
323 std::vector
<group_image_status_t
> *images
)
325 CephContext
*cct
= (CephContext
*)group_ioctx
.cct();
326 ldout(cct
, 20) << "io_ctx=" << &group_ioctx
327 << " group name " << group_name
<< dendl
;
331 int r
= cls_client::dir_get_id(&group_ioctx
, RBD_GROUP_DIRECTORY
,
332 group_name
, &group_id
);
334 lderr(cct
) << "error reading consistency group id object: "
339 string group_header_oid
= util::group_header_name(group_id
);
341 ldout(cct
, 20) << "listing images in group name "
342 << group_name
<< " group id " << group_header_oid
<< dendl
;
344 std::vector
<cls::rbd::GroupImageStatus
> image_ids
;
346 const int max_read
= 1024;
348 std::vector
<cls::rbd::GroupImageStatus
> image_ids_page
;
349 cls::rbd::GroupImageSpec start_last
;
351 r
= cls_client::group_image_list(&group_ioctx
, group_header_oid
,
352 start_last
, max_read
, &image_ids_page
);
355 lderr(cct
) << "error reading image list from consistency group: "
356 << cpp_strerror(-r
) << dendl
;
359 image_ids
.insert(image_ids
.end(),
360 image_ids_page
.begin(), image_ids_page
.end());
362 if (image_ids_page
.size() > 0)
363 start_last
= image_ids_page
.rbegin()->spec
;
365 r
= image_ids_page
.size();
366 } while (r
== max_read
);
368 for (auto i
: image_ids
) {
369 librados::Rados
rados(group_ioctx
);
371 rados
.ioctx_create2(i
.spec
.pool_id
, ioctx
);
372 std::string image_name
;
373 r
= cls_client::dir_get_name(&ioctx
, RBD_DIRECTORY
,
374 i
.spec
.image_id
, &image_name
);
380 group_image_status_t
{
383 static_cast<group_image_state_t
>(i
.state
)});
389 template <typename I
>
390 int Group
<I
>::image_get_group(I
*ictx
, group_spec_t
*group_spec
)
392 int r
= ictx
->state
->refresh_if_required();
396 if (-1 != ictx
->group_spec
.pool_id
) {
397 librados::Rados
rados(ictx
->md_ctx
);
399 rados
.ioctx_create2(ictx
->group_spec
.pool_id
, ioctx
);
401 std::string group_name
;
402 r
= cls_client::dir_get_name(&ioctx
, RBD_GROUP_DIRECTORY
,
403 ictx
->group_spec
.group_id
, &group_name
);
406 group_spec
->pool
= ictx
->group_spec
.pool_id
;
407 group_spec
->name
= group_name
;
409 group_spec
->pool
= -1;
410 group_spec
->name
= "";
417 } // namespace librbd
419 template class librbd::api::Group
<librbd::ImageCtx
>;