]>
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/image/CreateRequest.h" | |
5 | #include "common/dout.h" | |
6 | #include "common/errno.h" | |
7 | #include "cls/rbd/cls_rbd_client.h" | |
8 | #include "include/assert.h" | |
9 | #include "librbd/Utils.h" | |
10 | #include "common/ceph_context.h" | |
11 | #include "librbd/Journal.h" | |
12 | #include "librbd/MirroringWatcher.h" | |
13 | #include "librbd/journal/CreateRequest.h" | |
14 | #include "librbd/journal/RemoveRequest.h" | |
15 | #include "librbd/mirror/EnableRequest.h" | |
16 | #include "librbd/io/AioCompletion.h" | |
17 | #include "journal/Journaler.h" | |
18 | ||
19 | #define dout_subsys ceph_subsys_rbd | |
20 | #undef dout_prefix | |
21 | #define dout_prefix *_dout << "librbd::image::CreateRequest: " << __func__ \ | |
22 | << ": " | |
23 | ||
24 | namespace librbd { | |
25 | namespace image { | |
26 | ||
27 | using util::create_rados_callback; | |
28 | using util::create_context_callback; | |
29 | ||
30 | namespace { | |
31 | ||
32 | int validate_features(CephContext *cct, uint64_t features, | |
33 | bool force_non_primary) { | |
34 | if (features & ~RBD_FEATURES_ALL) { | |
35 | lderr(cct) << "librbd does not support requested features." << dendl; | |
36 | return -ENOSYS; | |
37 | } | |
38 | if ((features & RBD_FEATURE_FAST_DIFF) != 0 && | |
39 | (features & RBD_FEATURE_OBJECT_MAP) == 0) { | |
40 | lderr(cct) << "cannot use fast diff without object map" << dendl; | |
41 | return -EINVAL; | |
42 | } | |
43 | if ((features & RBD_FEATURE_OBJECT_MAP) != 0 && | |
44 | (features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) { | |
45 | lderr(cct) << "cannot use object map without exclusive lock" << dendl; | |
46 | return -EINVAL; | |
47 | } | |
48 | if ((features & RBD_FEATURE_JOURNALING) != 0) { | |
49 | if ((features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) { | |
50 | lderr(cct) << "cannot use journaling without exclusive lock" << dendl; | |
51 | return -EINVAL; | |
52 | } | |
53 | } else if (force_non_primary) { | |
54 | assert(false); | |
55 | } | |
56 | ||
57 | return 0; | |
58 | } | |
59 | ||
60 | int validate_striping(CephContext *cct, uint8_t order, uint64_t stripe_unit, | |
61 | uint64_t stripe_count) { | |
62 | if ((stripe_unit && !stripe_count) || | |
63 | (!stripe_unit && stripe_count)) { | |
64 | lderr(cct) << "must specify both (or neither) of stripe-unit and " | |
65 | << "stripe-count" << dendl; | |
66 | return -EINVAL; | |
67 | } else if (stripe_unit || stripe_count) { | |
68 | if ((1ull << order) % stripe_unit || stripe_unit > (1ull << order)) { | |
69 | lderr(cct) << "stripe unit is not a factor of the object size" << dendl; | |
70 | return -EINVAL; | |
71 | } | |
72 | } | |
73 | return 0; | |
74 | } | |
75 | ||
7c673cae FG |
76 | bool validate_layout(CephContext *cct, uint64_t size, file_layout_t &layout) { |
77 | if (!librbd::ObjectMap<>::is_compatible(layout, size)) { | |
78 | lderr(cct) << "image size not compatible with object map" << dendl; | |
79 | return false; | |
80 | } | |
81 | ||
82 | return true; | |
83 | } | |
84 | ||
85 | int get_image_option(const ImageOptions &image_options, int option, | |
86 | uint8_t *value) { | |
87 | uint64_t large_value; | |
88 | int r = image_options.get(option, &large_value); | |
89 | if (r < 0) { | |
90 | return r; | |
91 | } | |
92 | *value = static_cast<uint8_t>(large_value); | |
93 | return 0; | |
94 | } | |
95 | ||
96 | } // anonymous namespace | |
97 | ||
98 | template<typename I> | |
99 | int CreateRequest<I>::validate_order(CephContext *cct, uint8_t order) { | |
100 | if (order > 25 || order < 12) { | |
101 | lderr(cct) << "order must be in the range [12, 25]" << dendl; | |
102 | return -EDOM; | |
103 | } | |
104 | return 0; | |
105 | } | |
106 | ||
107 | #undef dout_prefix | |
108 | #define dout_prefix *_dout << "librbd::image::CreateRequest: " << this << " " \ | |
109 | << __func__ << ": " | |
110 | ||
111 | template<typename I> | |
112 | CreateRequest<I>::CreateRequest(IoCtx &ioctx, const std::string &image_name, | |
113 | const std::string &image_id, uint64_t size, | |
114 | const ImageOptions &image_options, | |
115 | const std::string &non_primary_global_image_id, | |
116 | const std::string &primary_mirror_uuid, | |
117 | bool skip_mirror_enable, | |
118 | ContextWQ *op_work_queue, Context *on_finish) | |
119 | : m_ioctx(ioctx), m_image_name(image_name), m_image_id(image_id), | |
120 | m_size(size), m_non_primary_global_image_id(non_primary_global_image_id), | |
121 | m_primary_mirror_uuid(primary_mirror_uuid), | |
122 | m_skip_mirror_enable(skip_mirror_enable), | |
123 | m_op_work_queue(op_work_queue), m_on_finish(on_finish) { | |
124 | m_cct = reinterpret_cast<CephContext *>(m_ioctx.cct()); | |
125 | ||
126 | m_id_obj = util::id_obj_name(m_image_name); | |
127 | m_header_obj = util::header_name(m_image_id); | |
128 | m_objmap_name = ObjectMap<>::object_map_name(m_image_id, CEPH_NOSNAP); | |
129 | ||
130 | if (image_options.get(RBD_IMAGE_OPTION_FEATURES, &m_features) != 0) { | |
131 | m_features = util::get_rbd_default_features(m_cct); | |
132 | m_negotiate_features = true; | |
133 | } | |
134 | ||
135 | uint64_t features_clear = 0; | |
136 | uint64_t features_set = 0; | |
137 | image_options.get(RBD_IMAGE_OPTION_FEATURES_CLEAR, &features_clear); | |
138 | image_options.get(RBD_IMAGE_OPTION_FEATURES_SET, &features_set); | |
139 | ||
140 | uint64_t features_conflict = features_clear & features_set; | |
141 | features_clear &= ~features_conflict; | |
142 | features_set &= ~features_conflict; | |
143 | m_features |= features_set; | |
144 | m_features &= ~features_clear; | |
145 | ||
146 | if (image_options.get(RBD_IMAGE_OPTION_STRIPE_UNIT, &m_stripe_unit) != 0 || | |
147 | m_stripe_unit == 0) { | |
181888fb | 148 | m_stripe_unit = m_cct->_conf->get_val<uint64_t>("rbd_default_stripe_unit"); |
7c673cae FG |
149 | } |
150 | if (image_options.get(RBD_IMAGE_OPTION_STRIPE_COUNT, &m_stripe_count) != 0 || | |
151 | m_stripe_count == 0) { | |
181888fb | 152 | m_stripe_count = m_cct->_conf->get_val<uint64_t>("rbd_default_stripe_count"); |
7c673cae FG |
153 | } |
154 | if (get_image_option(image_options, RBD_IMAGE_OPTION_ORDER, &m_order) != 0 || | |
155 | m_order == 0) { | |
181888fb | 156 | m_order = m_cct->_conf->get_val<int64_t>("rbd_default_order"); |
7c673cae FG |
157 | } |
158 | if (get_image_option(image_options, RBD_IMAGE_OPTION_JOURNAL_ORDER, | |
159 | &m_journal_order) != 0) { | |
181888fb | 160 | m_journal_order = m_cct->_conf->get_val<uint64_t>("rbd_journal_order"); |
7c673cae FG |
161 | } |
162 | if (get_image_option(image_options, RBD_IMAGE_OPTION_JOURNAL_SPLAY_WIDTH, | |
163 | &m_journal_splay_width) != 0) { | |
181888fb | 164 | m_journal_splay_width = m_cct->_conf->get_val<uint64_t>("rbd_journal_splay_width"); |
7c673cae FG |
165 | } |
166 | if (image_options.get(RBD_IMAGE_OPTION_JOURNAL_POOL, &m_journal_pool) != 0) { | |
181888fb | 167 | m_journal_pool = m_cct->_conf->get_val<std::string>("rbd_journal_pool"); |
7c673cae FG |
168 | } |
169 | if (image_options.get(RBD_IMAGE_OPTION_DATA_POOL, &m_data_pool) != 0) { | |
181888fb | 170 | m_data_pool = m_cct->_conf->get_val<std::string>("rbd_default_data_pool"); |
7c673cae FG |
171 | } |
172 | ||
173 | m_layout.object_size = 1ull << m_order; | |
174 | if (m_stripe_unit == 0 || m_stripe_count == 0) { | |
175 | m_layout.stripe_unit = m_layout.object_size; | |
176 | m_layout.stripe_count = 1; | |
177 | } else { | |
178 | m_layout.stripe_unit = m_stripe_unit; | |
179 | m_layout.stripe_count = m_stripe_count; | |
180 | } | |
181 | ||
182 | m_force_non_primary = !non_primary_global_image_id.empty(); | |
183 | ||
184 | if (!m_data_pool.empty() && m_data_pool != ioctx.get_pool_name()) { | |
185 | m_features |= RBD_FEATURE_DATA_POOL; | |
186 | } else { | |
187 | m_data_pool.clear(); | |
188 | m_features &= ~RBD_FEATURE_DATA_POOL; | |
189 | } | |
190 | ||
191 | if ((m_stripe_unit != 0 && m_stripe_unit != (1ULL << m_order)) || | |
192 | (m_stripe_count != 0 && m_stripe_count != 1)) { | |
193 | m_features |= RBD_FEATURE_STRIPINGV2; | |
194 | } else { | |
195 | m_features &= ~RBD_FEATURE_STRIPINGV2; | |
196 | } | |
197 | ||
198 | ldout(m_cct, 20) << "name=" << m_image_name << ", " | |
199 | << "id=" << m_image_id << ", " | |
200 | << "size=" << m_size << ", " | |
201 | << "features=" << m_features << ", " | |
202 | << "order=" << (uint64_t)m_order << ", " | |
203 | << "stripe_unit=" << m_stripe_unit << ", " | |
204 | << "stripe_count=" << m_stripe_count << ", " | |
205 | << "journal_order=" << (uint64_t)m_journal_order << ", " | |
206 | << "journal_splay_width=" | |
207 | << (uint64_t)m_journal_splay_width << ", " | |
208 | << "journal_pool=" << m_journal_pool << ", " | |
209 | << "data_pool=" << m_data_pool << dendl; | |
210 | } | |
211 | ||
212 | template<typename I> | |
213 | void CreateRequest<I>::send() { | |
214 | ldout(m_cct, 20) << dendl; | |
215 | ||
216 | int r = validate_features(m_cct, m_features, m_force_non_primary); | |
217 | if (r < 0) { | |
218 | complete(r); | |
219 | return; | |
220 | } | |
221 | ||
222 | r = validate_order(m_cct, m_order); | |
223 | if (r < 0) { | |
224 | complete(r); | |
225 | return; | |
226 | } | |
227 | ||
228 | r = validate_striping(m_cct, m_order, m_stripe_unit, m_stripe_count); | |
229 | if (r < 0) { | |
230 | complete(r); | |
231 | return; | |
232 | } | |
233 | ||
c07f9fc5 FG |
234 | if (((m_features & RBD_FEATURE_OBJECT_MAP) != 0) && |
235 | (!validate_layout(m_cct, m_size, m_layout))) { | |
7c673cae FG |
236 | complete(-EINVAL); |
237 | return; | |
238 | } | |
239 | ||
91327a77 | 240 | validate_data_pool(); |
7c673cae FG |
241 | } |
242 | ||
91327a77 AA |
243 | template <typename I> |
244 | void CreateRequest<I>::validate_data_pool() { | |
245 | m_data_io_ctx = m_ioctx; | |
246 | if ((m_features & RBD_FEATURE_DATA_POOL) != 0) { | |
247 | librados::Rados rados(m_ioctx); | |
248 | int r = rados.ioctx_create(m_data_pool.c_str(), m_data_io_ctx); | |
249 | if (r < 0) { | |
250 | lderr(m_cct) << "data pool " << m_data_pool << " does not exist" << dendl; | |
251 | complete(r); | |
252 | return; | |
253 | } | |
254 | m_data_pool_id = m_data_io_ctx.get_id(); | |
255 | } | |
256 | ||
181888fb | 257 | if (!m_cct->_conf->get_val<bool>("rbd_validate_pool")) { |
7c673cae FG |
258 | create_id_object(); |
259 | return; | |
260 | } | |
261 | ||
262 | ldout(m_cct, 20) << dendl; | |
263 | ||
264 | using klass = CreateRequest<I>; | |
265 | librados::AioCompletion *comp = | |
91327a77 | 266 | create_rados_callback<klass, &klass::handle_validate_data_pool>(this); |
7c673cae FG |
267 | |
268 | librados::ObjectReadOperation op; | |
91327a77 | 269 | op.read(0, 0, nullptr, nullptr); |
7c673cae FG |
270 | |
271 | m_outbl.clear(); | |
91327a77 | 272 | int r = m_data_io_ctx.aio_operate(RBD_INFO, comp, &op, &m_outbl); |
7c673cae FG |
273 | assert(r == 0); |
274 | comp->release(); | |
275 | } | |
276 | ||
91327a77 AA |
277 | template <typename I> |
278 | void CreateRequest<I>::handle_validate_data_pool(int r) { | |
7c673cae FG |
279 | ldout(m_cct, 20) << "r=" << r << dendl; |
280 | ||
91327a77 AA |
281 | bufferlist bl; |
282 | bl.append("overwrite validated"); | |
283 | ||
284 | if (r >= 0 && m_outbl.contents_equal(bl)) { | |
285 | create_id_object(); | |
7c673cae FG |
286 | return; |
287 | } else if ((r < 0) && (r != -ENOENT)) { | |
91327a77 | 288 | lderr(m_cct) << "failed to read RBD info: " << cpp_strerror(r) << dendl; |
7c673cae FG |
289 | complete(r); |
290 | return; | |
291 | } | |
292 | ||
293 | // allocate a self-managed snapshot id if this a new pool to force | |
294 | // self-managed snapshot mode | |
295 | // This call is executed just once per (fresh) pool, hence we do not | |
296 | // try hard to make it asynchronous (and it's pretty safe not to cause | |
297 | // deadlocks). | |
298 | ||
91327a77 AA |
299 | ldout(m_cct, 10) << "validating self-managed RBD snapshot support" << dendl; |
300 | ||
7c673cae | 301 | uint64_t snap_id; |
91327a77 | 302 | r = m_data_io_ctx.selfmanaged_snap_create(&snap_id); |
7c673cae FG |
303 | if (r == -EINVAL) { |
304 | lderr(m_cct) << "pool not configured for self-managed RBD snapshot support" | |
305 | << dendl; | |
306 | complete(r); | |
307 | return; | |
308 | } else if (r < 0) { | |
309 | lderr(m_cct) << "failed to allocate self-managed snapshot: " | |
310 | << cpp_strerror(r) << dendl; | |
311 | complete(r); | |
312 | return; | |
313 | } | |
314 | ||
91327a77 | 315 | r = m_data_io_ctx.selfmanaged_snap_remove(snap_id); |
7c673cae FG |
316 | if (r < 0) { |
317 | // we've already switched to self-managed snapshots -- no need to | |
318 | // error out in case of failure here. | |
319 | ldout(m_cct, 10) << "failed to release self-managed snapshot " << snap_id | |
320 | << ": " << cpp_strerror(r) << dendl; | |
321 | } | |
322 | ||
7c673cae | 323 | ldout(m_cct, 10) << "validating overwrite support" << dendl; |
91327a77 | 324 | |
7c673cae FG |
325 | bufferlist initial_bl; |
326 | initial_bl.append("validate"); | |
327 | r = m_data_io_ctx.write(RBD_INFO, initial_bl, initial_bl.length(), 0); | |
328 | if (r >= 0) { | |
329 | r = m_data_io_ctx.write(RBD_INFO, bl, bl.length(), 0); | |
330 | } | |
331 | if (r == -EOPNOTSUPP) { | |
332 | lderr(m_cct) << "pool missing required overwrite support" << dendl; | |
333 | complete(-EINVAL); | |
334 | return; | |
335 | } else if (r < 0) { | |
336 | lderr(m_cct) << "failed to validate overwrite support: " << cpp_strerror(r) | |
337 | << dendl; | |
338 | complete(r); | |
339 | return; | |
340 | } | |
341 | ||
342 | create_id_object(); | |
343 | } | |
344 | ||
345 | template<typename I> | |
346 | void CreateRequest<I>::create_id_object() { | |
347 | ldout(m_cct, 20) << dendl; | |
348 | ||
349 | librados::ObjectWriteOperation op; | |
350 | op.create(true); | |
351 | cls_client::set_id(&op, m_image_id); | |
352 | ||
353 | using klass = CreateRequest<I>; | |
354 | librados::AioCompletion *comp = | |
355 | create_rados_callback<klass, &klass::handle_create_id_object>(this); | |
356 | int r = m_ioctx.aio_operate(m_id_obj, comp, &op); | |
357 | assert(r == 0); | |
358 | comp->release(); | |
359 | } | |
360 | ||
361 | template<typename I> | |
362 | void CreateRequest<I>::handle_create_id_object(int r) { | |
363 | ldout(m_cct, 20) << "r=" << r << dendl; | |
364 | ||
365 | if (r < 0) { | |
366 | lderr(m_cct) << "error creating RBD id object: " << cpp_strerror(r) | |
367 | << dendl; | |
368 | complete(r); | |
369 | return; | |
370 | } | |
371 | ||
372 | add_image_to_directory(); | |
373 | } | |
374 | ||
375 | template<typename I> | |
376 | void CreateRequest<I>::add_image_to_directory() { | |
377 | ldout(m_cct, 20) << dendl; | |
378 | ||
379 | librados::ObjectWriteOperation op; | |
380 | cls_client::dir_add_image(&op, m_image_name, m_image_id); | |
381 | ||
382 | using klass = CreateRequest<I>; | |
383 | librados::AioCompletion *comp = | |
384 | create_rados_callback<klass, &klass::handle_add_image_to_directory>(this); | |
385 | int r = m_ioctx.aio_operate(RBD_DIRECTORY, comp, &op); | |
386 | assert(r == 0); | |
387 | comp->release(); | |
388 | } | |
389 | ||
390 | template<typename I> | |
391 | void CreateRequest<I>::handle_add_image_to_directory(int r) { | |
392 | ldout(m_cct, 20) << "r=" << r << dendl; | |
393 | ||
394 | if (r < 0) { | |
395 | lderr(m_cct) << "error adding image to directory: " << cpp_strerror(r) | |
396 | << dendl; | |
397 | ||
398 | m_r_saved = r; | |
399 | remove_id_object(); | |
400 | } | |
401 | ||
402 | negotiate_features(); | |
403 | } | |
404 | ||
405 | template<typename I> | |
406 | void CreateRequest<I>::negotiate_features() { | |
407 | if (!m_negotiate_features) { | |
408 | create_image(); | |
409 | return; | |
410 | } | |
411 | ||
412 | ldout(m_cct, 20) << dendl; | |
413 | ||
414 | librados::ObjectReadOperation op; | |
415 | cls_client::get_all_features_start(&op); | |
416 | ||
417 | using klass = CreateRequest<I>; | |
418 | librados::AioCompletion *comp = | |
419 | create_rados_callback<klass, &klass::handle_negotiate_features>(this); | |
420 | ||
421 | m_outbl.clear(); | |
422 | int r = m_ioctx.aio_operate(RBD_DIRECTORY, comp, &op, &m_outbl); | |
423 | assert(r == 0); | |
424 | comp->release(); | |
425 | } | |
426 | ||
427 | template<typename I> | |
428 | void CreateRequest<I>::handle_negotiate_features(int r) { | |
429 | ldout(m_cct, 20) << "r=" << r << dendl; | |
430 | ||
431 | uint64_t all_features; | |
432 | if (r >= 0) { | |
433 | bufferlist::iterator it = m_outbl.begin(); | |
434 | r = cls_client::get_all_features_finish(&it, &all_features); | |
435 | } | |
436 | if (r < 0) { | |
437 | ldout(m_cct, 10) << "error retrieving server supported features set: " | |
438 | << cpp_strerror(r) << dendl; | |
439 | } else if ((m_features & all_features) != m_features) { | |
440 | m_features &= all_features; | |
441 | ldout(m_cct, 10) << "limiting default features set to server supported: " | |
442 | << m_features << dendl; | |
443 | } | |
444 | ||
445 | create_image(); | |
446 | } | |
447 | ||
448 | template<typename I> | |
449 | void CreateRequest<I>::create_image() { | |
450 | ldout(m_cct, 20) << dendl; | |
451 | assert(m_data_pool.empty() || m_data_pool_id != -1); | |
452 | ||
453 | ostringstream oss; | |
454 | oss << RBD_DATA_PREFIX; | |
455 | if (m_data_pool_id != -1) { | |
456 | oss << stringify(m_ioctx.get_id()) << "."; | |
457 | } | |
458 | oss << m_image_id; | |
459 | if (oss.str().length() > RBD_MAX_BLOCK_NAME_PREFIX_LENGTH) { | |
460 | lderr(m_cct) << "object prefix '" << oss.str() << "' too large" << dendl; | |
461 | complete(-EINVAL); | |
462 | return; | |
463 | } | |
464 | ||
465 | librados::ObjectWriteOperation op; | |
466 | op.create(true); | |
467 | cls_client::create_image(&op, m_size, m_order, m_features, oss.str(), | |
468 | m_data_pool_id); | |
469 | ||
470 | using klass = CreateRequest<I>; | |
471 | librados::AioCompletion *comp = | |
472 | create_rados_callback<klass, &klass::handle_create_image>(this); | |
473 | int r = m_ioctx.aio_operate(m_header_obj, comp, &op); | |
474 | assert(r == 0); | |
475 | comp->release(); | |
476 | } | |
477 | ||
478 | template<typename I> | |
479 | void CreateRequest<I>::handle_create_image(int r) { | |
480 | ldout(m_cct, 20) << "r=" << r << dendl; | |
481 | ||
482 | if (r < 0) { | |
483 | lderr(m_cct) << "error writing header: " << cpp_strerror(r) << dendl; | |
484 | m_r_saved = r; | |
485 | remove_from_dir(); | |
486 | return; | |
487 | } | |
488 | ||
489 | set_stripe_unit_count(); | |
490 | } | |
491 | ||
492 | template<typename I> | |
493 | void CreateRequest<I>::set_stripe_unit_count() { | |
494 | if ((!m_stripe_unit && !m_stripe_count) || | |
495 | ((m_stripe_count == 1) && (m_stripe_unit == (1ull << m_order)))) { | |
496 | object_map_resize(); | |
497 | return; | |
498 | } | |
499 | ||
500 | ldout(m_cct, 20) << dendl; | |
501 | ||
502 | librados::ObjectWriteOperation op; | |
503 | cls_client::set_stripe_unit_count(&op, m_stripe_unit, m_stripe_count); | |
504 | ||
505 | using klass = CreateRequest<I>; | |
506 | librados::AioCompletion *comp = | |
507 | create_rados_callback<klass, &klass::handle_set_stripe_unit_count>(this); | |
508 | int r = m_ioctx.aio_operate(m_header_obj, comp, &op); | |
509 | assert(r == 0); | |
510 | comp->release(); | |
511 | } | |
512 | ||
513 | template<typename I> | |
514 | void CreateRequest<I>::handle_set_stripe_unit_count(int r) { | |
515 | ldout(m_cct, 20) << "r=" << r << dendl; | |
516 | ||
517 | if (r < 0) { | |
518 | lderr(m_cct) << "error setting stripe unit/count: " | |
519 | << cpp_strerror(r) << dendl; | |
520 | m_r_saved = r; | |
521 | remove_header_object(); | |
522 | return; | |
523 | } | |
524 | ||
525 | object_map_resize(); | |
526 | } | |
527 | ||
528 | template<typename I> | |
529 | void CreateRequest<I>::object_map_resize() { | |
530 | if ((m_features & RBD_FEATURE_OBJECT_MAP) == 0) { | |
531 | fetch_mirror_mode(); | |
532 | return; | |
533 | } | |
534 | ||
535 | ldout(m_cct, 20) << dendl; | |
536 | ||
537 | librados::ObjectWriteOperation op; | |
538 | cls_client::object_map_resize(&op, Striper::get_num_objects(m_layout, m_size), | |
539 | OBJECT_NONEXISTENT); | |
540 | ||
541 | using klass = CreateRequest<I>; | |
542 | librados::AioCompletion *comp = | |
543 | create_rados_callback<klass, &klass::handle_object_map_resize>(this); | |
544 | int r = m_ioctx.aio_operate(m_objmap_name, comp, &op); | |
545 | assert(r == 0); | |
546 | comp->release(); | |
547 | } | |
548 | ||
549 | template<typename I> | |
550 | void CreateRequest<I>::handle_object_map_resize(int r) { | |
551 | ldout(m_cct, 20) << "r=" << r << dendl; | |
552 | ||
553 | if (r < 0) { | |
554 | lderr(m_cct) << "error creating initial object map: " | |
555 | << cpp_strerror(r) << dendl; | |
556 | ||
557 | m_r_saved = r; | |
558 | remove_header_object(); | |
559 | return; | |
560 | } | |
561 | ||
562 | fetch_mirror_mode(); | |
563 | } | |
564 | ||
565 | template<typename I> | |
566 | void CreateRequest<I>::fetch_mirror_mode() { | |
567 | if ((m_features & RBD_FEATURE_JOURNALING) == 0) { | |
568 | complete(0); | |
569 | return; | |
570 | } | |
571 | ||
572 | ldout(m_cct, 20) << dendl; | |
573 | ||
574 | librados::ObjectReadOperation op; | |
575 | cls_client::mirror_mode_get_start(&op); | |
576 | ||
577 | using klass = CreateRequest<I>; | |
578 | librados::AioCompletion *comp = | |
579 | create_rados_callback<klass, &klass::handle_fetch_mirror_mode>(this); | |
580 | m_outbl.clear(); | |
581 | int r = m_ioctx.aio_operate(RBD_MIRRORING, comp, &op, &m_outbl); | |
582 | assert(r == 0); | |
583 | comp->release(); | |
584 | } | |
585 | ||
586 | template<typename I> | |
587 | void CreateRequest<I>::handle_fetch_mirror_mode(int r) { | |
588 | ldout(m_cct, 20) << "r=" << r << dendl; | |
589 | ||
590 | if ((r < 0) && (r != -ENOENT)) { | |
591 | lderr(m_cct) << "failed to retrieve mirror mode: " << cpp_strerror(r) | |
592 | << dendl; | |
593 | ||
594 | m_r_saved = r; | |
595 | remove_object_map(); | |
596 | return; | |
597 | } | |
598 | ||
599 | cls::rbd::MirrorMode mirror_mode_internal = cls::rbd::MIRROR_MODE_DISABLED; | |
600 | if (r == 0) { | |
601 | bufferlist::iterator it = m_outbl.begin(); | |
602 | r = cls_client::mirror_mode_get_finish(&it, &mirror_mode_internal); | |
603 | if (r < 0) { | |
604 | lderr(m_cct) << "Failed to retrieve mirror mode" << dendl; | |
605 | ||
606 | m_r_saved = r; | |
607 | remove_object_map(); | |
608 | return; | |
609 | } | |
610 | } | |
611 | ||
612 | // TODO: remove redundant code... | |
613 | switch (mirror_mode_internal) { | |
614 | case cls::rbd::MIRROR_MODE_DISABLED: | |
615 | case cls::rbd::MIRROR_MODE_IMAGE: | |
616 | case cls::rbd::MIRROR_MODE_POOL: | |
617 | m_mirror_mode = static_cast<rbd_mirror_mode_t>(mirror_mode_internal); | |
618 | break; | |
619 | default: | |
620 | lderr(m_cct) << "Unknown mirror mode (" | |
621 | << static_cast<uint32_t>(mirror_mode_internal) << ")" << dendl; | |
622 | r = -EINVAL; | |
623 | remove_object_map(); | |
624 | return; | |
625 | } | |
626 | ||
627 | journal_create(); | |
628 | } | |
629 | ||
630 | template<typename I> | |
631 | void CreateRequest<I>::journal_create() { | |
632 | ldout(m_cct, 20) << dendl; | |
633 | ||
634 | using klass = CreateRequest<I>; | |
635 | Context *ctx = create_context_callback<klass, &klass::handle_journal_create>( | |
636 | this); | |
637 | ||
638 | librbd::journal::TagData tag_data; | |
639 | tag_data.mirror_uuid = (m_force_non_primary ? m_primary_mirror_uuid : | |
640 | librbd::Journal<I>::LOCAL_MIRROR_UUID); | |
641 | ||
642 | librbd::journal::CreateRequest<I> *req = | |
643 | librbd::journal::CreateRequest<I>::create( | |
644 | m_ioctx, m_image_id, m_journal_order, m_journal_splay_width, | |
645 | m_journal_pool, cls::journal::Tag::TAG_CLASS_NEW, tag_data, | |
646 | librbd::Journal<I>::IMAGE_CLIENT_ID, m_op_work_queue, ctx); | |
647 | req->send(); | |
648 | } | |
649 | ||
650 | template<typename I> | |
651 | void CreateRequest<I>::handle_journal_create(int r) { | |
652 | ldout(m_cct, 20) << "r=" << r << dendl; | |
653 | ||
654 | if (r < 0) { | |
655 | lderr(m_cct) << "error creating journal: " << cpp_strerror(r) | |
656 | << dendl; | |
657 | ||
658 | m_r_saved = r; | |
659 | remove_object_map(); | |
660 | return; | |
661 | } | |
662 | ||
663 | mirror_image_enable(); | |
664 | } | |
665 | ||
666 | template<typename I> | |
667 | void CreateRequest<I>::mirror_image_enable() { | |
668 | if (((m_mirror_mode != RBD_MIRROR_MODE_POOL) && !m_force_non_primary) || | |
669 | m_skip_mirror_enable) { | |
670 | complete(0); | |
671 | return; | |
672 | } | |
673 | ||
674 | ldout(m_cct, 20) << dendl; | |
675 | auto ctx = create_context_callback< | |
676 | CreateRequest<I>, &CreateRequest<I>::handle_mirror_image_enable>(this); | |
677 | auto req = mirror::EnableRequest<I>::create(m_ioctx, m_image_id, | |
678 | m_non_primary_global_image_id, | |
679 | m_op_work_queue, ctx); | |
680 | req->send(); | |
681 | } | |
682 | ||
683 | template<typename I> | |
684 | void CreateRequest<I>::handle_mirror_image_enable(int r) { | |
685 | ldout(m_cct, 20) << "r=" << r << dendl; | |
686 | ||
687 | if (r < 0) { | |
688 | lderr(m_cct) << "cannot enable mirroring: " << cpp_strerror(r) | |
689 | << dendl; | |
690 | ||
691 | m_r_saved = r; | |
692 | journal_remove(); | |
693 | return; | |
694 | } | |
695 | ||
696 | complete(0); | |
697 | } | |
698 | ||
699 | template<typename I> | |
700 | void CreateRequest<I>::complete(int r) { | |
701 | ldout(m_cct, 20) << dendl; | |
702 | ||
703 | if (r == 0) { | |
704 | ldout(m_cct, 20) << "done." << dendl; | |
705 | } | |
706 | ||
707 | m_data_io_ctx.close(); | |
91327a77 | 708 | auto on_finish = m_on_finish; |
7c673cae | 709 | delete this; |
91327a77 | 710 | on_finish->complete(r); |
7c673cae FG |
711 | } |
712 | ||
713 | // cleanup | |
714 | template<typename I> | |
715 | void CreateRequest<I>::journal_remove() { | |
716 | if ((m_features & RBD_FEATURE_JOURNALING) == 0) { | |
717 | remove_object_map(); | |
718 | return; | |
719 | } | |
720 | ||
721 | ldout(m_cct, 20) << dendl; | |
722 | ||
723 | using klass = CreateRequest<I>; | |
724 | Context *ctx = create_context_callback<klass, &klass::handle_journal_remove>( | |
725 | this); | |
726 | ||
727 | librbd::journal::RemoveRequest<I> *req = | |
728 | librbd::journal::RemoveRequest<I>::create( | |
729 | m_ioctx, m_image_id, librbd::Journal<I>::IMAGE_CLIENT_ID, m_op_work_queue, | |
730 | ctx); | |
731 | req->send(); | |
732 | } | |
733 | ||
734 | template<typename I> | |
735 | void CreateRequest<I>::handle_journal_remove(int r) { | |
736 | ldout(m_cct, 20) << "r=" << r << dendl; | |
737 | ||
738 | if (r < 0) { | |
739 | lderr(m_cct) << "error cleaning up journal after creation failed: " | |
740 | << cpp_strerror(r) << dendl; | |
741 | } | |
742 | ||
743 | remove_object_map(); | |
744 | } | |
745 | ||
746 | template<typename I> | |
747 | void CreateRequest<I>::remove_object_map() { | |
748 | if ((m_features & RBD_FEATURE_OBJECT_MAP) == 0) { | |
749 | remove_header_object(); | |
750 | return; | |
751 | } | |
752 | ||
753 | ldout(m_cct, 20) << dendl; | |
754 | ||
755 | using klass = CreateRequest<I>; | |
756 | librados::AioCompletion *comp = | |
757 | create_rados_callback<klass, &klass::handle_remove_object_map>(this); | |
758 | int r = m_ioctx.aio_remove(m_objmap_name, comp); | |
759 | assert(r == 0); | |
760 | comp->release(); | |
761 | } | |
762 | ||
763 | template<typename I> | |
764 | void CreateRequest<I>::handle_remove_object_map(int r) { | |
765 | ldout(m_cct, 20) << "r=" << r << dendl; | |
766 | ||
767 | if (r < 0) { | |
768 | lderr(m_cct) << "error cleaning up object map after creation failed: " | |
769 | << cpp_strerror(r) << dendl; | |
770 | } | |
771 | ||
772 | remove_header_object(); | |
773 | } | |
774 | ||
775 | template<typename I> | |
776 | void CreateRequest<I>::remove_header_object() { | |
777 | ldout(m_cct, 20) << dendl; | |
778 | ||
779 | using klass = CreateRequest<I>; | |
780 | librados::AioCompletion *comp = | |
781 | create_rados_callback<klass, &klass::handle_remove_header_object>(this); | |
782 | int r = m_ioctx.aio_remove(m_header_obj, comp); | |
783 | assert(r == 0); | |
784 | comp->release(); | |
785 | } | |
786 | ||
787 | template<typename I> | |
788 | void CreateRequest<I>::handle_remove_header_object(int r) { | |
789 | ldout(m_cct, 20) << "r=" << r << dendl; | |
790 | ||
791 | if (r < 0) { | |
792 | lderr(m_cct) << "error cleaning up image header after creation failed: " | |
793 | << cpp_strerror(r) << dendl; | |
794 | } | |
795 | ||
796 | remove_from_dir(); | |
797 | } | |
798 | ||
799 | template<typename I> | |
800 | void CreateRequest<I>::remove_from_dir() { | |
801 | ldout(m_cct, 20) << dendl; | |
802 | ||
803 | librados::ObjectWriteOperation op; | |
804 | cls_client::dir_remove_image(&op, m_image_name, m_image_id); | |
805 | ||
806 | using klass = CreateRequest<I>; | |
807 | librados::AioCompletion *comp = | |
808 | create_rados_callback<klass, &klass::handle_remove_from_dir>(this); | |
809 | int r = m_ioctx.aio_operate(RBD_DIRECTORY, comp, &op); | |
810 | assert(r == 0); | |
811 | comp->release(); | |
812 | } | |
813 | ||
814 | template<typename I> | |
815 | void CreateRequest<I>::handle_remove_from_dir(int r) { | |
816 | ldout(m_cct, 20) << "r=" << r << dendl; | |
817 | ||
818 | if (r < 0) { | |
819 | lderr(m_cct) << "error cleaning up image from rbd_directory object " | |
820 | << "after creation failed: " << cpp_strerror(r) << dendl; | |
821 | } | |
822 | ||
823 | remove_id_object(); | |
824 | } | |
825 | ||
826 | template<typename I> | |
827 | void CreateRequest<I>::remove_id_object() { | |
828 | ldout(m_cct, 20) << dendl; | |
829 | ||
830 | using klass = CreateRequest<I>; | |
831 | librados::AioCompletion *comp = | |
832 | create_rados_callback<klass, &klass::handle_remove_id_object>(this); | |
833 | int r = m_ioctx.aio_remove(m_id_obj, comp); | |
834 | assert(r == 0); | |
835 | comp->release(); | |
836 | } | |
837 | ||
838 | template<typename I> | |
839 | void CreateRequest<I>::handle_remove_id_object(int r) { | |
840 | ldout(m_cct, 20) << "r=" << r << dendl; | |
841 | ||
842 | if (r < 0) { | |
843 | lderr(m_cct) << "error cleaning up id object after creation failed: " | |
844 | << cpp_strerror(r) << dendl; | |
845 | } | |
846 | ||
847 | complete(m_r_saved); | |
848 | } | |
849 | ||
850 | } //namespace image | |
851 | } //namespace librbd | |
852 | ||
853 | template class librbd::image::CreateRequest<librbd::ImageCtx>; |