]>
Commit | Line | Data |
---|---|---|
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/api/Group.h" | |
5 | #include "common/errno.h" | |
6 | #include "librbd/ImageState.h" | |
7 | #include "librbd/Utils.h" | |
8 | #include "librbd/io/AioCompletion.h" | |
9 | ||
10 | #define dout_subsys ceph_subsys_rbd | |
11 | #undef dout_prefix | |
12 | #define dout_prefix *_dout << "librbd::api::Group: " << __func__ << ": " | |
13 | ||
14 | using std::map; | |
15 | using std::pair; | |
16 | using std::set; | |
17 | using std::string; | |
18 | using std::vector; | |
19 | // list binds to list() here, so std::list is explicitly used below | |
20 | ||
21 | using ceph::bufferlist; | |
22 | using librados::snap_t; | |
23 | using librados::IoCtx; | |
24 | using librados::Rados; | |
25 | ||
26 | namespace librbd { | |
27 | namespace api { | |
28 | ||
29 | // Consistency groups functions | |
30 | ||
31 | template <typename I> | |
32 | int Group<I>::create(librados::IoCtx& io_ctx, const char *group_name) | |
33 | { | |
34 | CephContext *cct = (CephContext *)io_ctx.cct(); | |
35 | ||
36 | Rados rados(io_ctx); | |
37 | uint64_t bid = rados.get_instance_id(); | |
38 | ||
39 | uint32_t extra = rand() % 0xFFFFFFFF; | |
40 | ostringstream bid_ss; | |
41 | bid_ss << std::hex << bid << std::hex << extra; | |
42 | string id = bid_ss.str(); | |
43 | ||
44 | ldout(cct, 2) << "adding consistency group to directory..." << dendl; | |
45 | ||
46 | int r = cls_client::group_dir_add(&io_ctx, RBD_GROUP_DIRECTORY, group_name, | |
47 | id); | |
48 | if (r < 0) { | |
49 | lderr(cct) << "error adding consistency group to directory: " | |
50 | << cpp_strerror(r) | |
51 | << dendl; | |
52 | return r; | |
53 | } | |
54 | string header_oid = util::group_header_name(id); | |
55 | ||
56 | r = cls_client::group_create(&io_ctx, header_oid); | |
57 | if (r < 0) { | |
58 | lderr(cct) << "error writing header: " << cpp_strerror(r) << dendl; | |
59 | goto err_remove_from_dir; | |
60 | } | |
61 | ||
62 | return 0; | |
63 | ||
64 | err_remove_from_dir: | |
65 | int remove_r = cls_client::group_dir_remove(&io_ctx, RBD_GROUP_DIRECTORY, | |
66 | group_name, id); | |
67 | if (remove_r < 0) { | |
68 | lderr(cct) << "error cleaning up consistency group from rbd_directory " | |
69 | << "object after creation failed: " << cpp_strerror(remove_r) | |
70 | << dendl; | |
71 | } | |
72 | ||
73 | return r; | |
74 | } | |
75 | ||
76 | template <typename I> | |
77 | int Group<I>::remove(librados::IoCtx& io_ctx, const char *group_name) | |
78 | { | |
79 | CephContext *cct((CephContext *)io_ctx.cct()); | |
80 | ldout(cct, 20) << "io_ctx=" << &io_ctx << " " << group_name << dendl; | |
81 | ||
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; | |
86 | return r; | |
87 | } | |
88 | ||
89 | for (auto i : images) { | |
90 | librados::Rados rados(io_ctx); | |
91 | IoCtx image_ioctx; | |
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; | |
96 | return r; | |
97 | } | |
98 | } | |
99 | ||
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; | |
105 | return r; | |
106 | } | |
107 | ||
108 | string header_oid = util::group_header_name(group_id); | |
109 | ||
110 | r = io_ctx.remove(header_oid); | |
111 | if (r < 0 && r != -ENOENT) { | |
112 | lderr(cct) << "error removing header: " << cpp_strerror(-r) << dendl; | |
113 | return r; | |
114 | } | |
115 | ||
116 | r = cls_client::group_dir_remove(&io_ctx, RBD_GROUP_DIRECTORY, group_name, | |
117 | group_id); | |
118 | if (r < 0 && r != -ENOENT) { | |
119 | lderr(cct) << "error removing group from directory" << dendl; | |
120 | return r; | |
121 | } | |
122 | ||
123 | return 0; | |
124 | } | |
125 | ||
126 | template <typename I> | |
127 | int Group<I>::list(IoCtx& io_ctx, vector<string> *names) | |
128 | { | |
129 | CephContext *cct = (CephContext *)io_ctx.cct(); | |
130 | ldout(cct, 20) << "io_ctx=" << &io_ctx << dendl; | |
131 | ||
132 | int max_read = 1024; | |
133 | string last_read = ""; | |
134 | int r; | |
135 | do { | |
136 | map<string, string> groups; | |
137 | r = cls_client::group_dir_list(&io_ctx, RBD_GROUP_DIRECTORY, last_read, | |
138 | max_read, &groups); | |
139 | if (r < 0) { | |
31f18b77 FG |
140 | if (r != -ENOENT) { |
141 | lderr(cct) << "error listing group in directory: " | |
142 | << cpp_strerror(r) << dendl; | |
143 | } else { | |
144 | r = 0; | |
145 | } | |
7c673cae FG |
146 | return r; |
147 | } | |
148 | for (pair<string, string> group : groups) { | |
149 | names->push_back(group.first); | |
150 | } | |
151 | if (!groups.empty()) { | |
152 | last_read = groups.rbegin()->first; | |
153 | } | |
154 | r = groups.size(); | |
155 | } while (r == max_read); | |
156 | ||
157 | return 0; | |
158 | } | |
159 | ||
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) | |
163 | { | |
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; | |
168 | ||
169 | string group_id; | |
170 | ||
171 | int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY, group_name, | |
172 | &group_id); | |
173 | if (r < 0) { | |
174 | lderr(cct) << "error reading consistency group id object: " | |
175 | << cpp_strerror(r) | |
176 | << dendl; | |
177 | return r; | |
178 | } | |
179 | string group_header_oid = util::group_header_name(group_id); | |
180 | ||
181 | ||
182 | ldout(cct, 20) << "adding image to group name " << group_name | |
183 | << " group id " << group_header_oid << dendl; | |
184 | ||
185 | string image_id; | |
186 | ||
187 | r = cls_client::dir_get_id(&image_ioctx, RBD_DIRECTORY, image_name, | |
188 | &image_id); | |
189 | if (r < 0) { | |
190 | lderr(cct) << "error reading image id object: " | |
191 | << cpp_strerror(-r) << dendl; | |
192 | return r; | |
193 | } | |
194 | ||
195 | string image_header_oid = util::header_name(image_id); | |
196 | ||
197 | ldout(cct, 20) << "adding image " << image_name | |
198 | << " image id " << image_header_oid << dendl; | |
199 | ||
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); | |
205 | ||
206 | r = cls_client::group_image_set(&group_ioctx, group_header_oid, | |
207 | incomplete_st); | |
208 | ||
209 | cls::rbd::GroupSpec group_spec(group_id, group_ioctx.get_id()); | |
210 | ||
211 | if (r < 0) { | |
212 | lderr(cct) << "error adding image reference to consistency group: " | |
213 | << cpp_strerror(-r) << dendl; | |
214 | return r; | |
215 | } | |
216 | ||
217 | r = cls_client::image_add_group(&image_ioctx, image_header_oid, group_spec); | |
218 | if (r < 0) { | |
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. | |
224 | return r; | |
225 | } | |
226 | ||
227 | r = cls_client::group_image_set(&group_ioctx, group_header_oid, | |
228 | attached_st); | |
229 | ||
230 | return r; | |
231 | } | |
232 | ||
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) | |
236 | { | |
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; | |
241 | ||
242 | string image_id; | |
243 | int r = cls_client::dir_get_id(&image_ioctx, RBD_DIRECTORY, image_name, | |
244 | &image_id); | |
245 | if (r < 0) { | |
246 | lderr(cct) << "error reading image id object: " | |
247 | << cpp_strerror(-r) << dendl; | |
248 | return r; | |
249 | } | |
250 | ||
251 | return Group<I>::image_remove_by_id(group_ioctx, group_name, image_ioctx, | |
252 | image_id.c_str()); | |
253 | } | |
254 | ||
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) | |
260 | { | |
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; | |
265 | ||
266 | string group_id; | |
267 | ||
268 | int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY, group_name, | |
269 | &group_id); | |
270 | if (r < 0) { | |
271 | lderr(cct) << "error reading consistency group id object: " | |
272 | << cpp_strerror(r) | |
273 | << dendl; | |
274 | return r; | |
275 | } | |
276 | string group_header_oid = util::group_header_name(group_id); | |
277 | ||
278 | ldout(cct, 20) << "adding image to group name " << group_name | |
279 | << " group id " << group_header_oid << dendl; | |
280 | ||
281 | string image_header_oid = util::header_name(image_id); | |
282 | ||
283 | ldout(cct, 20) << "removing " << " image id " << image_header_oid << dendl; | |
284 | ||
285 | cls::rbd::GroupSpec group_spec(group_id, group_ioctx.get_id()); | |
286 | ||
287 | cls::rbd::GroupImageStatus incomplete_st( | |
288 | image_id, image_ioctx.get_id(), | |
289 | cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE); | |
290 | ||
291 | cls::rbd::GroupImageSpec spec(image_id, image_ioctx.get_id()); | |
292 | ||
293 | r = cls_client::group_image_set(&group_ioctx, group_header_oid, | |
294 | incomplete_st); | |
295 | ||
296 | if (r < 0) { | |
297 | lderr(cct) << "couldn't put image into removing state: " | |
298 | << cpp_strerror(-r) << dendl; | |
299 | return r; | |
300 | } | |
301 | ||
302 | r = cls_client::image_remove_group(&image_ioctx, image_header_oid, | |
303 | group_spec); | |
304 | if ((r < 0) && (r != -ENOENT)) { | |
305 | lderr(cct) << "couldn't remove group reference from image" | |
306 | << cpp_strerror(-r) << dendl; | |
307 | return r; | |
308 | } | |
309 | ||
310 | r = cls_client::group_image_remove(&group_ioctx, group_header_oid, spec); | |
311 | if (r < 0) { | |
312 | lderr(cct) << "couldn't remove image from group" | |
313 | << cpp_strerror(-r) << dendl; | |
314 | return r; | |
315 | } | |
316 | ||
317 | return 0; | |
318 | } | |
319 | ||
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) | |
324 | { | |
325 | CephContext *cct = (CephContext *)group_ioctx.cct(); | |
326 | ldout(cct, 20) << "io_ctx=" << &group_ioctx | |
327 | << " group name " << group_name << dendl; | |
328 | ||
329 | string group_id; | |
330 | ||
331 | int r = cls_client::dir_get_id(&group_ioctx, RBD_GROUP_DIRECTORY, | |
332 | group_name, &group_id); | |
333 | if (r < 0) { | |
334 | lderr(cct) << "error reading consistency group id object: " | |
335 | << cpp_strerror(r) | |
336 | << dendl; | |
337 | return r; | |
338 | } | |
339 | string group_header_oid = util::group_header_name(group_id); | |
340 | ||
341 | ldout(cct, 20) << "listing images in group name " | |
342 | << group_name << " group id " << group_header_oid << dendl; | |
343 | ||
344 | std::vector<cls::rbd::GroupImageStatus> image_ids; | |
345 | ||
346 | const int max_read = 1024; | |
347 | do { | |
348 | std::vector<cls::rbd::GroupImageStatus> image_ids_page; | |
349 | cls::rbd::GroupImageSpec start_last; | |
350 | ||
351 | r = cls_client::group_image_list(&group_ioctx, group_header_oid, | |
352 | start_last, max_read, &image_ids_page); | |
353 | ||
354 | if (r < 0) { | |
355 | lderr(cct) << "error reading image list from consistency group: " | |
356 | << cpp_strerror(-r) << dendl; | |
357 | return r; | |
358 | } | |
359 | image_ids.insert(image_ids.end(), | |
360 | image_ids_page.begin(), image_ids_page.end()); | |
361 | ||
362 | if (image_ids_page.size() > 0) | |
363 | start_last = image_ids_page.rbegin()->spec; | |
364 | ||
365 | r = image_ids_page.size(); | |
366 | } while (r == max_read); | |
367 | ||
368 | for (auto i : image_ids) { | |
369 | librados::Rados rados(group_ioctx); | |
370 | IoCtx 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); | |
375 | if (r < 0) { | |
376 | return r; | |
377 | } | |
378 | ||
379 | images->push_back( | |
380 | group_image_status_t { | |
381 | image_name, | |
382 | i.spec.pool_id, | |
383 | static_cast<group_image_state_t>(i.state)}); | |
384 | } | |
385 | ||
386 | return 0; | |
387 | } | |
388 | ||
389 | template <typename I> | |
390 | int Group<I>::image_get_group(I *ictx, group_spec_t *group_spec) | |
391 | { | |
392 | int r = ictx->state->refresh_if_required(); | |
393 | if (r < 0) | |
394 | return r; | |
395 | ||
396 | if (-1 != ictx->group_spec.pool_id) { | |
397 | librados::Rados rados(ictx->md_ctx); | |
398 | IoCtx ioctx; | |
399 | rados.ioctx_create2(ictx->group_spec.pool_id, ioctx); | |
400 | ||
401 | std::string group_name; | |
402 | r = cls_client::dir_get_name(&ioctx, RBD_GROUP_DIRECTORY, | |
403 | ictx->group_spec.group_id, &group_name); | |
404 | if (r < 0) | |
405 | return r; | |
406 | group_spec->pool = ictx->group_spec.pool_id; | |
407 | group_spec->name = group_name; | |
408 | } else { | |
409 | group_spec->pool = -1; | |
410 | group_spec->name = ""; | |
411 | } | |
412 | ||
413 | return 0; | |
414 | } | |
415 | ||
416 | } // namespace api | |
417 | } // namespace librbd | |
418 | ||
419 | template class librbd::api::Group<librbd::ImageCtx>; |