]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/Operations.cc
642cd03a7fefa44dd0e16276cd879fbd1d7b54c7
[ceph.git] / ceph / src / librbd / Operations.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "cls/rbd/cls_rbd_types.h"
5 #include "librbd/Operations.h"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "common/perf_counters.h"
9 #include "common/WorkQueue.h"
10 #include "osdc/Striper.h"
11
12 #include "librbd/ExclusiveLock.h"
13 #include "librbd/ImageCtx.h"
14 #include "librbd/ImageState.h"
15 #include "librbd/ImageWatcher.h"
16 #include "librbd/ObjectMap.h"
17 #include "librbd/Types.h"
18 #include "librbd/Utils.h"
19 #include "librbd/api/Config.h"
20 #include "librbd/journal/DisabledPolicy.h"
21 #include "librbd/journal/StandardPolicy.h"
22 #include "librbd/operation/DisableFeaturesRequest.h"
23 #include "librbd/operation/EnableFeaturesRequest.h"
24 #include "librbd/operation/FlattenRequest.h"
25 #include "librbd/operation/MetadataRemoveRequest.h"
26 #include "librbd/operation/MetadataSetRequest.h"
27 #include "librbd/operation/MigrateRequest.h"
28 #include "librbd/operation/ObjectMapIterate.h"
29 #include "librbd/operation/RebuildObjectMapRequest.h"
30 #include "librbd/operation/RenameRequest.h"
31 #include "librbd/operation/ResizeRequest.h"
32 #include "librbd/operation/SnapshotCreateRequest.h"
33 #include "librbd/operation/SnapshotProtectRequest.h"
34 #include "librbd/operation/SnapshotRemoveRequest.h"
35 #include "librbd/operation/SnapshotRenameRequest.h"
36 #include "librbd/operation/SnapshotRollbackRequest.h"
37 #include "librbd/operation/SnapshotUnprotectRequest.h"
38 #include "librbd/operation/SnapshotLimitRequest.h"
39 #include "librbd/operation/SparsifyRequest.h"
40 #include <set>
41 #include <boost/bind.hpp>
42 #include <boost/scope_exit.hpp>
43
44 #define dout_subsys ceph_subsys_rbd
45 #undef dout_prefix
46 #define dout_prefix *_dout << "librbd::Operations: "
47
48 namespace librbd {
49
50 namespace {
51
52 template <typename I>
53 struct C_NotifyUpdate : public Context {
54 I &image_ctx;
55 Context *on_finish;
56 bool notified = false;
57
58 C_NotifyUpdate(I &image_ctx, Context *on_finish)
59 : image_ctx(image_ctx), on_finish(on_finish) {
60 }
61
62 void complete(int r) override {
63 CephContext *cct = image_ctx.cct;
64 if (notified) {
65 if (r == -ETIMEDOUT) {
66 // don't fail the op if a peer fails to get the update notification
67 lderr(cct) << "update notification timed-out" << dendl;
68 r = 0;
69 } else if (r == -ENOENT) {
70 // don't fail if header is missing (e.g. v1 image rename)
71 ldout(cct, 5) << "update notification on missing header" << dendl;
72 r = 0;
73 } else if (r < 0) {
74 lderr(cct) << "update notification failed: " << cpp_strerror(r)
75 << dendl;
76 }
77 Context::complete(r);
78 return;
79 }
80
81 if (r < 0) {
82 // op failed -- no need to send update notification
83 Context::complete(r);
84 return;
85 }
86
87 notified = true;
88 image_ctx.notify_update(this);
89 }
90 void finish(int r) override {
91 on_finish->complete(r);
92 }
93 };
94
95 template <typename I>
96 struct C_InvokeAsyncRequest : public Context {
97 /**
98 * @verbatim
99 *
100 * <start>
101 * |
102 * . . . . . . | . . . . . . . . . . . . . . . . . .
103 * . . | . .
104 * . v v v .
105 * . REFRESH_IMAGE (skip if not needed) .
106 * . | .
107 * . v .
108 * . ACQUIRE_LOCK (skip if exclusive lock .
109 * . | disabled or has lock) .
110 * . | .
111 * . /--------/ \--------\ . . . . . . . . . . . . .
112 * . | | .
113 * . v v .
114 * LOCAL_REQUEST REMOTE_REQUEST
115 * | |
116 * | |
117 * \--------\ /--------/
118 * |
119 * v
120 * <finish>
121 *
122 * @endverbatim
123 */
124
125 I &image_ctx;
126 std::string request_type;
127 bool permit_snapshot;
128 boost::function<void(Context*)> local;
129 boost::function<void(Context*)> remote;
130 std::set<int> filter_error_codes;
131 Context *on_finish;
132 bool request_lock = false;
133
134 C_InvokeAsyncRequest(I &image_ctx, const std::string& request_type,
135 bool permit_snapshot,
136 const boost::function<void(Context*)>& local,
137 const boost::function<void(Context*)>& remote,
138 const std::set<int> &filter_error_codes,
139 Context *on_finish)
140 : image_ctx(image_ctx), request_type(request_type),
141 permit_snapshot(permit_snapshot), local(local), remote(remote),
142 filter_error_codes(filter_error_codes), on_finish(on_finish) {
143 }
144
145 void send() {
146 send_refresh_image();
147 }
148
149 void send_refresh_image() {
150 if (!image_ctx.state->is_refresh_required()) {
151 send_acquire_exclusive_lock();
152 return;
153 }
154
155 CephContext *cct = image_ctx.cct;
156 ldout(cct, 20) << __func__ << dendl;
157
158 Context *ctx = util::create_context_callback<
159 C_InvokeAsyncRequest<I>,
160 &C_InvokeAsyncRequest<I>::handle_refresh_image>(this);
161 image_ctx.state->refresh(ctx);
162 }
163
164 void handle_refresh_image(int r) {
165 CephContext *cct = image_ctx.cct;
166 ldout(cct, 20) << __func__ << ": r=" << r << dendl;
167
168 if (r < 0) {
169 lderr(cct) << "failed to refresh image: " << cpp_strerror(r) << dendl;
170 complete(r);
171 return;
172 }
173
174 send_acquire_exclusive_lock();
175 }
176
177 void send_acquire_exclusive_lock() {
178 // context can complete before owner_lock is unlocked
179 RWLock &owner_lock(image_ctx.owner_lock);
180 owner_lock.get_read();
181 image_ctx.snap_lock.get_read();
182 if (image_ctx.read_only ||
183 (!permit_snapshot && image_ctx.snap_id != CEPH_NOSNAP)) {
184 image_ctx.snap_lock.put_read();
185 owner_lock.put_read();
186 complete(-EROFS);
187 return;
188 }
189 image_ctx.snap_lock.put_read();
190
191 if (image_ctx.exclusive_lock == nullptr) {
192 send_local_request();
193 owner_lock.put_read();
194 return;
195 } else if (image_ctx.image_watcher == nullptr) {
196 owner_lock.put_read();
197 complete(-EROFS);
198 return;
199 }
200
201 if (image_ctx.exclusive_lock->is_lock_owner() &&
202 image_ctx.exclusive_lock->accept_requests()) {
203 send_local_request();
204 owner_lock.put_read();
205 return;
206 }
207
208 CephContext *cct = image_ctx.cct;
209 ldout(cct, 20) << __func__ << dendl;
210
211 Context *ctx = util::create_async_context_callback(
212 image_ctx, util::create_context_callback<
213 C_InvokeAsyncRequest<I>,
214 &C_InvokeAsyncRequest<I>::handle_acquire_exclusive_lock>(this));
215
216 if (request_lock) {
217 // current lock owner doesn't support op -- try to perform
218 // the action locally
219 request_lock = false;
220 image_ctx.exclusive_lock->acquire_lock(ctx);
221 } else {
222 image_ctx.exclusive_lock->try_acquire_lock(ctx);
223 }
224 owner_lock.put_read();
225 }
226
227 void handle_acquire_exclusive_lock(int r) {
228 CephContext *cct = image_ctx.cct;
229 ldout(cct, 20) << __func__ << ": r=" << r << dendl;
230
231 if (r < 0) {
232 complete(r == -EBLACKLISTED ? -EBLACKLISTED : -EROFS);
233 return;
234 }
235
236 // context can complete before owner_lock is unlocked
237 RWLock &owner_lock(image_ctx.owner_lock);
238 owner_lock.get_read();
239 if (image_ctx.exclusive_lock == nullptr ||
240 image_ctx.exclusive_lock->is_lock_owner()) {
241 send_local_request();
242 owner_lock.put_read();
243 return;
244 }
245
246 send_remote_request();
247 owner_lock.put_read();
248 }
249
250 void send_remote_request() {
251 ceph_assert(image_ctx.owner_lock.is_locked());
252
253 CephContext *cct = image_ctx.cct;
254 ldout(cct, 20) << __func__ << dendl;
255
256 Context *ctx = util::create_async_context_callback(
257 image_ctx, util::create_context_callback<
258 C_InvokeAsyncRequest<I>,
259 &C_InvokeAsyncRequest<I>::handle_remote_request>(this));
260 remote(ctx);
261 }
262
263 void handle_remote_request(int r) {
264 CephContext *cct = image_ctx.cct;
265 ldout(cct, 20) << __func__ << ": r=" << r << dendl;
266
267 if (r == -EOPNOTSUPP) {
268 ldout(cct, 5) << request_type << " not supported by current lock owner"
269 << dendl;
270 request_lock = true;
271 send_refresh_image();
272 return;
273 } else if (r != -ETIMEDOUT && r != -ERESTART) {
274 image_ctx.state->handle_update_notification();
275
276 complete(r);
277 return;
278 }
279
280 ldout(cct, 5) << request_type << " timed out notifying lock owner"
281 << dendl;
282 send_refresh_image();
283 }
284
285 void send_local_request() {
286 ceph_assert(image_ctx.owner_lock.is_locked());
287
288 CephContext *cct = image_ctx.cct;
289 ldout(cct, 20) << __func__ << dendl;
290
291 Context *ctx = util::create_async_context_callback(
292 image_ctx, util::create_context_callback<
293 C_InvokeAsyncRequest<I>,
294 &C_InvokeAsyncRequest<I>::handle_local_request>(this));
295 local(ctx);
296 }
297
298 void handle_local_request(int r) {
299 CephContext *cct = image_ctx.cct;
300 ldout(cct, 20) << __func__ << ": r=" << r << dendl;
301
302 if (r == -ERESTART) {
303 send_refresh_image();
304 return;
305 }
306 complete(r);
307 }
308
309 void finish(int r) override {
310 if (filter_error_codes.count(r) != 0) {
311 r = 0;
312 }
313 on_finish->complete(r);
314 }
315 };
316
317 template <typename I>
318 bool needs_invalidate(I& image_ctx, uint64_t object_no,
319 uint8_t current_state, uint8_t new_state) {
320 if ( (current_state == OBJECT_EXISTS ||
321 current_state == OBJECT_EXISTS_CLEAN) &&
322 (new_state == OBJECT_NONEXISTENT ||
323 new_state == OBJECT_PENDING)) {
324 return false;
325 }
326 return true;
327 }
328
329 } // anonymous namespace
330
331 template <typename I>
332 Operations<I>::Operations(I &image_ctx)
333 : m_image_ctx(image_ctx), m_async_request_seq(0) {
334 }
335
336 template <typename I>
337 int Operations<I>::flatten(ProgressContext &prog_ctx) {
338 CephContext *cct = m_image_ctx.cct;
339 ldout(cct, 20) << "flatten" << dendl;
340
341 int r = m_image_ctx.state->refresh_if_required();
342 if (r < 0) {
343 return r;
344 }
345
346 if (m_image_ctx.read_only) {
347 return -EROFS;
348 }
349
350 {
351 RWLock::RLocker parent_locker(m_image_ctx.parent_lock);
352 if (m_image_ctx.parent_md.spec.pool_id == -1) {
353 lderr(cct) << "image has no parent" << dendl;
354 return -EINVAL;
355 }
356 }
357
358 uint64_t request_id = ++m_async_request_seq;
359 r = invoke_async_request("flatten", false,
360 boost::bind(&Operations<I>::execute_flatten, this,
361 boost::ref(prog_ctx), _1),
362 boost::bind(&ImageWatcher<I>::notify_flatten,
363 m_image_ctx.image_watcher, request_id,
364 boost::ref(prog_ctx), _1));
365
366 if (r < 0 && r != -EINVAL) {
367 return r;
368 }
369 ldout(cct, 20) << "flatten finished" << dendl;
370 return 0;
371 }
372
373 template <typename I>
374 void Operations<I>::execute_flatten(ProgressContext &prog_ctx,
375 Context *on_finish) {
376 ceph_assert(m_image_ctx.owner_lock.is_locked());
377 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
378 m_image_ctx.exclusive_lock->is_lock_owner());
379
380 CephContext *cct = m_image_ctx.cct;
381 ldout(cct, 20) << "flatten" << dendl;
382
383 if (m_image_ctx.read_only || m_image_ctx.operations_disabled) {
384 on_finish->complete(-EROFS);
385 return;
386 }
387
388 m_image_ctx.snap_lock.get_read();
389 m_image_ctx.parent_lock.get_read();
390
391 // can't flatten a non-clone
392 if (m_image_ctx.parent_md.spec.pool_id == -1) {
393 lderr(cct) << "image has no parent" << dendl;
394 m_image_ctx.parent_lock.put_read();
395 m_image_ctx.snap_lock.put_read();
396 on_finish->complete(-EINVAL);
397 return;
398 }
399 if (m_image_ctx.snap_id != CEPH_NOSNAP) {
400 lderr(cct) << "snapshots cannot be flattened" << dendl;
401 m_image_ctx.parent_lock.put_read();
402 m_image_ctx.snap_lock.put_read();
403 on_finish->complete(-EROFS);
404 return;
405 }
406
407 ::SnapContext snapc = m_image_ctx.snapc;
408
409 uint64_t overlap;
410 int r = m_image_ctx.get_parent_overlap(CEPH_NOSNAP, &overlap);
411 ceph_assert(r == 0);
412 ceph_assert(overlap <= m_image_ctx.size);
413
414 uint64_t overlap_objects = Striper::get_num_objects(m_image_ctx.layout,
415 overlap);
416
417 m_image_ctx.parent_lock.put_read();
418 m_image_ctx.snap_lock.put_read();
419
420 operation::FlattenRequest<I> *req = new operation::FlattenRequest<I>(
421 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), overlap_objects,
422 snapc, prog_ctx);
423 req->send();
424 }
425
426 template <typename I>
427 int Operations<I>::rebuild_object_map(ProgressContext &prog_ctx) {
428 CephContext *cct = m_image_ctx.cct;
429 ldout(cct, 10) << "rebuild_object_map" << dendl;
430
431 int r = m_image_ctx.state->refresh_if_required();
432 if (r < 0) {
433 return r;
434 }
435
436 uint64_t request_id = ++m_async_request_seq;
437 r = invoke_async_request("rebuild object map", true,
438 boost::bind(&Operations<I>::execute_rebuild_object_map,
439 this, boost::ref(prog_ctx), _1),
440 boost::bind(&ImageWatcher<I>::notify_rebuild_object_map,
441 m_image_ctx.image_watcher, request_id,
442 boost::ref(prog_ctx), _1));
443
444 ldout(cct, 10) << "rebuild object map finished" << dendl;
445 if (r < 0) {
446 return r;
447 }
448 return 0;
449 }
450
451 template <typename I>
452 void Operations<I>::execute_rebuild_object_map(ProgressContext &prog_ctx,
453 Context *on_finish) {
454 ceph_assert(m_image_ctx.owner_lock.is_locked());
455 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
456 m_image_ctx.exclusive_lock->is_lock_owner());
457
458 CephContext *cct = m_image_ctx.cct;
459 ldout(cct, 5) << this << " " << __func__ << dendl;
460
461 if (m_image_ctx.read_only || m_image_ctx.operations_disabled) {
462 on_finish->complete(-EROFS);
463 return;
464 }
465
466 if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP)) {
467 lderr(cct) << "image must support object-map feature" << dendl;
468 on_finish->complete(-EINVAL);
469 return;
470 }
471
472 operation::RebuildObjectMapRequest<I> *req =
473 new operation::RebuildObjectMapRequest<I>(
474 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), prog_ctx);
475 req->send();
476 }
477
478 template <typename I>
479 int Operations<I>::check_object_map(ProgressContext &prog_ctx) {
480 CephContext *cct = m_image_ctx.cct;
481 ldout(cct, 5) << this << " " << __func__ << dendl;
482 int r = m_image_ctx.state->refresh_if_required();
483 if (r < 0) {
484 return r;
485 }
486
487 r = invoke_async_request("check object map", true,
488 boost::bind(&Operations<I>::check_object_map, this,
489 boost::ref(prog_ctx), _1),
490 [this](Context *c) {
491 m_image_ctx.op_work_queue->queue(c, -EOPNOTSUPP);
492 });
493
494 return r;
495 }
496
497 template <typename I>
498 void Operations<I>::object_map_iterate(ProgressContext &prog_ctx,
499 operation::ObjectIterateWork<I> handle_mismatch,
500 Context *on_finish) {
501 ceph_assert(m_image_ctx.owner_lock.is_locked());
502 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
503 m_image_ctx.exclusive_lock->is_lock_owner());
504
505 if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP)) {
506 on_finish->complete(-EINVAL);
507 return;
508 }
509
510 operation::ObjectMapIterateRequest<I> *req =
511 new operation::ObjectMapIterateRequest<I>(m_image_ctx, on_finish,
512 prog_ctx, handle_mismatch);
513 req->send();
514 }
515
516 template <typename I>
517 void Operations<I>::check_object_map(ProgressContext &prog_ctx,
518 Context *on_finish) {
519 object_map_iterate(prog_ctx, needs_invalidate, on_finish);
520 }
521
522 template <typename I>
523 int Operations<I>::rename(const char *dstname) {
524 CephContext *cct = m_image_ctx.cct;
525 ldout(cct, 5) << this << " " << __func__ << ": dest_name=" << dstname
526 << dendl;
527
528 int r = librbd::detect_format(m_image_ctx.md_ctx, dstname, NULL, NULL);
529 if (r < 0 && r != -ENOENT) {
530 lderr(cct) << "error checking for existing image called "
531 << dstname << ":" << cpp_strerror(r) << dendl;
532 return r;
533 }
534 if (r == 0) {
535 lderr(cct) << "rbd image " << dstname << " already exists" << dendl;
536 return -EEXIST;
537 }
538
539 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
540 r = invoke_async_request("rename", true,
541 boost::bind(&Operations<I>::execute_rename, this,
542 dstname, _1),
543 boost::bind(&ImageWatcher<I>::notify_rename,
544 m_image_ctx.image_watcher, dstname,
545 _1));
546 if (r < 0 && r != -EEXIST) {
547 return r;
548 }
549 } else {
550 C_SaferCond cond_ctx;
551 {
552 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
553 execute_rename(dstname, &cond_ctx);
554 }
555
556 r = cond_ctx.wait();
557 if (r < 0) {
558 return r;
559 }
560 }
561
562 m_image_ctx.set_image_name(dstname);
563 return 0;
564 }
565
566 template <typename I>
567 void Operations<I>::execute_rename(const std::string &dest_name,
568 Context *on_finish) {
569 ceph_assert(m_image_ctx.owner_lock.is_locked());
570 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
571 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
572 m_image_ctx.exclusive_lock->is_lock_owner());
573 }
574
575 if (m_image_ctx.operations_disabled) {
576 on_finish->complete(-EROFS);
577 return;
578 }
579
580 m_image_ctx.snap_lock.get_read();
581 if (m_image_ctx.name == dest_name) {
582 m_image_ctx.snap_lock.put_read();
583 on_finish->complete(-EEXIST);
584 return;
585 }
586 m_image_ctx.snap_lock.put_read();
587
588 CephContext *cct = m_image_ctx.cct;
589 ldout(cct, 5) << this << " " << __func__ << ": dest_name=" << dest_name
590 << dendl;
591
592 if (m_image_ctx.old_format) {
593 // unregister watch before and register back after rename
594 on_finish = new C_NotifyUpdate<I>(m_image_ctx, on_finish);
595 on_finish = new FunctionContext([this, on_finish](int r) {
596 if (m_image_ctx.old_format) {
597 m_image_ctx.image_watcher->set_oid(m_image_ctx.header_oid);
598 }
599 m_image_ctx.image_watcher->register_watch(on_finish);
600 });
601 on_finish = new FunctionContext([this, dest_name, on_finish](int r) {
602 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
603 operation::RenameRequest<I> *req = new operation::RenameRequest<I>(
604 m_image_ctx, on_finish, dest_name);
605 req->send();
606 });
607 m_image_ctx.image_watcher->unregister_watch(on_finish);
608 return;
609 }
610 operation::RenameRequest<I> *req = new operation::RenameRequest<I>(
611 m_image_ctx, on_finish, dest_name);
612 req->send();
613 }
614
615 template <typename I>
616 int Operations<I>::resize(uint64_t size, bool allow_shrink, ProgressContext& prog_ctx) {
617 CephContext *cct = m_image_ctx.cct;
618
619 m_image_ctx.snap_lock.get_read();
620 ldout(cct, 5) << this << " " << __func__ << ": "
621 << "size=" << m_image_ctx.size << ", "
622 << "new_size=" << size << dendl;
623 m_image_ctx.snap_lock.put_read();
624
625 int r = m_image_ctx.state->refresh_if_required();
626 if (r < 0) {
627 return r;
628 }
629
630 if (m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP) &&
631 !ObjectMap<>::is_compatible(m_image_ctx.layout, size)) {
632 lderr(cct) << "New size not compatible with object map" << dendl;
633 return -EINVAL;
634 }
635
636 uint64_t request_id = ++m_async_request_seq;
637 r = invoke_async_request("resize", false,
638 boost::bind(&Operations<I>::execute_resize, this,
639 size, allow_shrink, boost::ref(prog_ctx), _1, 0),
640 boost::bind(&ImageWatcher<I>::notify_resize,
641 m_image_ctx.image_watcher, request_id,
642 size, allow_shrink, boost::ref(prog_ctx), _1));
643
644 m_image_ctx.perfcounter->inc(l_librbd_resize);
645 ldout(cct, 2) << "resize finished" << dendl;
646 return r;
647 }
648
649 template <typename I>
650 void Operations<I>::execute_resize(uint64_t size, bool allow_shrink, ProgressContext &prog_ctx,
651 Context *on_finish,
652 uint64_t journal_op_tid) {
653 ceph_assert(m_image_ctx.owner_lock.is_locked());
654 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
655 m_image_ctx.exclusive_lock->is_lock_owner());
656
657 CephContext *cct = m_image_ctx.cct;
658 m_image_ctx.snap_lock.get_read();
659 ldout(cct, 5) << this << " " << __func__ << ": "
660 << "size=" << m_image_ctx.size << ", "
661 << "new_size=" << size << dendl;
662
663 if (m_image_ctx.snap_id != CEPH_NOSNAP || m_image_ctx.read_only ||
664 m_image_ctx.operations_disabled) {
665 m_image_ctx.snap_lock.put_read();
666 on_finish->complete(-EROFS);
667 return;
668 } else if (m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
669 m_image_ctx.snap_lock) &&
670 !ObjectMap<>::is_compatible(m_image_ctx.layout, size)) {
671 m_image_ctx.snap_lock.put_read();
672 on_finish->complete(-EINVAL);
673 return;
674 }
675 m_image_ctx.snap_lock.put_read();
676
677 operation::ResizeRequest<I> *req = new operation::ResizeRequest<I>(
678 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), size, allow_shrink,
679 prog_ctx, journal_op_tid, false);
680 req->send();
681 }
682
683 template <typename I>
684 int Operations<I>::snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
685 const std::string& snap_name) {
686 if (m_image_ctx.read_only) {
687 return -EROFS;
688 }
689
690 int r = m_image_ctx.state->refresh_if_required();
691 if (r < 0) {
692 return r;
693 }
694
695 C_SaferCond ctx;
696 snap_create(snap_namespace, snap_name, &ctx);
697 r = ctx.wait();
698
699 if (r < 0) {
700 return r;
701 }
702
703 m_image_ctx.perfcounter->inc(l_librbd_snap_create);
704 return r;
705 }
706
707 template <typename I>
708 void Operations<I>::snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
709 const std::string& snap_name,
710 Context *on_finish) {
711 CephContext *cct = m_image_ctx.cct;
712 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
713 << dendl;
714
715 if (m_image_ctx.read_only) {
716 on_finish->complete(-EROFS);
717 return;
718 }
719
720 m_image_ctx.snap_lock.get_read();
721 if (m_image_ctx.get_snap_id(snap_namespace, snap_name) != CEPH_NOSNAP) {
722 m_image_ctx.snap_lock.put_read();
723 on_finish->complete(-EEXIST);
724 return;
725 }
726 m_image_ctx.snap_lock.put_read();
727
728 C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(
729 m_image_ctx, "snap_create", true,
730 boost::bind(&Operations<I>::execute_snap_create, this, snap_namespace, snap_name,
731 _1, 0, false),
732 boost::bind(&ImageWatcher<I>::notify_snap_create, m_image_ctx.image_watcher,
733 snap_namespace, snap_name, _1),
734 {-EEXIST}, on_finish);
735 req->send();
736 }
737
738 template <typename I>
739 void Operations<I>::execute_snap_create(const cls::rbd::SnapshotNamespace &snap_namespace,
740 const std::string &snap_name,
741 Context *on_finish,
742 uint64_t journal_op_tid,
743 bool skip_object_map) {
744 ceph_assert(m_image_ctx.owner_lock.is_locked());
745 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
746 m_image_ctx.exclusive_lock->is_lock_owner());
747
748 CephContext *cct = m_image_ctx.cct;
749 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
750 << dendl;
751
752 if (m_image_ctx.operations_disabled) {
753 on_finish->complete(-EROFS);
754 return;
755 }
756
757 m_image_ctx.snap_lock.get_read();
758 if (m_image_ctx.get_snap_id(snap_namespace, snap_name) != CEPH_NOSNAP) {
759 m_image_ctx.snap_lock.put_read();
760 on_finish->complete(-EEXIST);
761 return;
762 }
763 m_image_ctx.snap_lock.put_read();
764
765 operation::SnapshotCreateRequest<I> *req =
766 new operation::SnapshotCreateRequest<I>(
767 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish),
768 snap_namespace, snap_name, journal_op_tid, skip_object_map);
769 req->send();
770 }
771
772 template <typename I>
773 int Operations<I>::snap_rollback(const cls::rbd::SnapshotNamespace& snap_namespace,
774 const std::string& snap_name,
775 ProgressContext& prog_ctx) {
776 CephContext *cct = m_image_ctx.cct;
777 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
778 << dendl;
779
780 int r = m_image_ctx.state->refresh_if_required();
781 if (r < 0)
782 return r;
783
784 C_SaferCond cond_ctx;
785 {
786 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
787 {
788 // need to drop snap_lock before invalidating cache
789 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
790 if (!m_image_ctx.snap_exists) {
791 return -ENOENT;
792 }
793
794 if (m_image_ctx.snap_id != CEPH_NOSNAP || m_image_ctx.read_only) {
795 return -EROFS;
796 }
797
798 uint64_t snap_id = m_image_ctx.get_snap_id(snap_namespace, snap_name);
799 if (snap_id == CEPH_NOSNAP) {
800 lderr(cct) << "No such snapshot found." << dendl;
801 return -ENOENT;
802 }
803 }
804
805 r = prepare_image_update(false);
806 if (r < 0) {
807 return r;
808 }
809
810 execute_snap_rollback(snap_namespace, snap_name, prog_ctx, &cond_ctx);
811 }
812
813 r = cond_ctx.wait();
814 if (r < 0) {
815 return r;
816 }
817
818 m_image_ctx.perfcounter->inc(l_librbd_snap_rollback);
819 return r;
820 }
821
822 template <typename I>
823 void Operations<I>::execute_snap_rollback(const cls::rbd::SnapshotNamespace& snap_namespace,
824 const std::string &snap_name,
825 ProgressContext& prog_ctx,
826 Context *on_finish) {
827 ceph_assert(m_image_ctx.owner_lock.is_locked());
828 CephContext *cct = m_image_ctx.cct;
829 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
830 << dendl;
831
832 if (m_image_ctx.operations_disabled) {
833 on_finish->complete(-EROFS);
834 return;
835 }
836
837 m_image_ctx.snap_lock.get_read();
838 uint64_t snap_id = m_image_ctx.get_snap_id(snap_namespace, snap_name);
839 if (snap_id == CEPH_NOSNAP) {
840 lderr(cct) << "No such snapshot found." << dendl;
841 m_image_ctx.snap_lock.put_read();
842 on_finish->complete(-ENOENT);
843 return;
844 }
845
846 uint64_t new_size = m_image_ctx.get_image_size(snap_id);
847 m_image_ctx.snap_lock.put_read();
848
849 // async mode used for journal replay
850 operation::SnapshotRollbackRequest<I> *request =
851 new operation::SnapshotRollbackRequest<I>(
852 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), snap_namespace, snap_name,
853 snap_id, new_size, prog_ctx);
854 request->send();
855 }
856
857 template <typename I>
858 int Operations<I>::snap_remove(const cls::rbd::SnapshotNamespace& snap_namespace,
859 const std::string& snap_name) {
860 if (m_image_ctx.read_only) {
861 return -EROFS;
862 }
863
864 int r = m_image_ctx.state->refresh_if_required();
865 if (r < 0) {
866 return r;
867 }
868
869 C_SaferCond ctx;
870 snap_remove(snap_namespace, snap_name, &ctx);
871 r = ctx.wait();
872
873 if (r < 0) {
874 return r;
875 }
876
877 m_image_ctx.perfcounter->inc(l_librbd_snap_remove);
878 return 0;
879 }
880
881 template <typename I>
882 void Operations<I>::snap_remove(const cls::rbd::SnapshotNamespace& snap_namespace,
883 const std::string& snap_name,
884 Context *on_finish) {
885 CephContext *cct = m_image_ctx.cct;
886 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
887 << dendl;
888
889 if (m_image_ctx.read_only) {
890 on_finish->complete(-EROFS);
891 return;
892 }
893
894 // quickly filter out duplicate ops
895 m_image_ctx.snap_lock.get_read();
896 if (m_image_ctx.get_snap_id(snap_namespace, snap_name) == CEPH_NOSNAP) {
897 m_image_ctx.snap_lock.put_read();
898 on_finish->complete(-ENOENT);
899 return;
900 }
901
902 bool proxy_op = ((m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0 ||
903 (m_image_ctx.features & RBD_FEATURE_JOURNALING) != 0);
904 m_image_ctx.snap_lock.put_read();
905
906 if (proxy_op) {
907 C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(
908 m_image_ctx, "snap_remove", true,
909 boost::bind(&Operations<I>::execute_snap_remove, this, snap_namespace, snap_name, _1),
910 boost::bind(&ImageWatcher<I>::notify_snap_remove, m_image_ctx.image_watcher,
911 snap_namespace, snap_name, _1),
912 {-ENOENT}, on_finish);
913 req->send();
914 } else {
915 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
916 execute_snap_remove(snap_namespace, snap_name, on_finish);
917 }
918 }
919
920 template <typename I>
921 void Operations<I>::execute_snap_remove(const cls::rbd::SnapshotNamespace& snap_namespace,
922 const std::string &snap_name,
923 Context *on_finish) {
924 ceph_assert(m_image_ctx.owner_lock.is_locked());
925 {
926 if ((m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0) {
927 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
928 m_image_ctx.exclusive_lock->is_lock_owner());
929 }
930 }
931
932 CephContext *cct = m_image_ctx.cct;
933 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
934 << dendl;
935
936 if (m_image_ctx.operations_disabled) {
937 on_finish->complete(-EROFS);
938 return;
939 }
940
941 m_image_ctx.snap_lock.get_read();
942 uint64_t snap_id = m_image_ctx.get_snap_id(snap_namespace, snap_name);
943 if (snap_id == CEPH_NOSNAP) {
944 lderr(m_image_ctx.cct) << "No such snapshot found." << dendl;
945 m_image_ctx.snap_lock.put_read();
946 on_finish->complete(-ENOENT);
947 return;
948 }
949
950 bool is_protected;
951 int r = m_image_ctx.is_snap_protected(snap_id, &is_protected);
952 if (r < 0) {
953 m_image_ctx.snap_lock.put_read();
954 on_finish->complete(r);
955 return;
956 } else if (is_protected) {
957 lderr(m_image_ctx.cct) << "snapshot is protected" << dendl;
958 m_image_ctx.snap_lock.put_read();
959 on_finish->complete(-EBUSY);
960 return;
961 }
962 m_image_ctx.snap_lock.put_read();
963
964 operation::SnapshotRemoveRequest<I> *req =
965 new operation::SnapshotRemoveRequest<I>(
966 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish),
967 snap_namespace, snap_name, snap_id);
968 req->send();
969 }
970
971 template <typename I>
972 int Operations<I>::snap_rename(const char *srcname, const char *dstname) {
973 CephContext *cct = m_image_ctx.cct;
974 ldout(cct, 5) << this << " " << __func__ << ": "
975 << "snap_name=" << srcname << ", "
976 << "new_snap_name=" << dstname << dendl;
977
978 snapid_t snap_id;
979 if (m_image_ctx.read_only) {
980 return -EROFS;
981 }
982
983 int r = m_image_ctx.state->refresh_if_required();
984 if (r < 0)
985 return r;
986
987 {
988 RWLock::RLocker l(m_image_ctx.snap_lock);
989 snap_id = m_image_ctx.get_snap_id(cls::rbd::UserSnapshotNamespace(), srcname);
990 if (snap_id == CEPH_NOSNAP) {
991 return -ENOENT;
992 }
993 if (m_image_ctx.get_snap_id(cls::rbd::UserSnapshotNamespace(), dstname) != CEPH_NOSNAP) {
994 return -EEXIST;
995 }
996 }
997
998 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
999 r = invoke_async_request("snap_rename", true,
1000 boost::bind(&Operations<I>::execute_snap_rename,
1001 this, snap_id, dstname, _1),
1002 boost::bind(&ImageWatcher<I>::notify_snap_rename,
1003 m_image_ctx.image_watcher, snap_id,
1004 dstname, _1));
1005 if (r < 0 && r != -EEXIST) {
1006 return r;
1007 }
1008 } else {
1009 C_SaferCond cond_ctx;
1010 {
1011 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
1012 execute_snap_rename(snap_id, dstname, &cond_ctx);
1013 }
1014
1015 r = cond_ctx.wait();
1016 if (r < 0) {
1017 return r;
1018 }
1019 }
1020
1021 m_image_ctx.perfcounter->inc(l_librbd_snap_rename);
1022 return 0;
1023 }
1024
1025 template <typename I>
1026 void Operations<I>::execute_snap_rename(const uint64_t src_snap_id,
1027 const std::string &dest_snap_name,
1028 Context *on_finish) {
1029 ceph_assert(m_image_ctx.owner_lock.is_locked());
1030 if ((m_image_ctx.features & RBD_FEATURE_JOURNALING) != 0) {
1031 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
1032 m_image_ctx.exclusive_lock->is_lock_owner());
1033 }
1034
1035 if (m_image_ctx.operations_disabled) {
1036 on_finish->complete(-EROFS);
1037 return;
1038 }
1039
1040 m_image_ctx.snap_lock.get_read();
1041 if (m_image_ctx.get_snap_id(cls::rbd::UserSnapshotNamespace(),
1042 dest_snap_name) != CEPH_NOSNAP) {
1043 // Renaming is supported for snapshots from user namespace only.
1044 m_image_ctx.snap_lock.put_read();
1045 on_finish->complete(-EEXIST);
1046 return;
1047 }
1048 m_image_ctx.snap_lock.put_read();
1049
1050 CephContext *cct = m_image_ctx.cct;
1051 ldout(cct, 5) << this << " " << __func__ << ": "
1052 << "snap_id=" << src_snap_id << ", "
1053 << "new_snap_name=" << dest_snap_name << dendl;
1054
1055 operation::SnapshotRenameRequest<I> *req =
1056 new operation::SnapshotRenameRequest<I>(
1057 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), src_snap_id,
1058 dest_snap_name);
1059 req->send();
1060 }
1061
1062 template <typename I>
1063 int Operations<I>::snap_protect(const cls::rbd::SnapshotNamespace& snap_namespace,
1064 const std::string& snap_name) {
1065 CephContext *cct = m_image_ctx.cct;
1066 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
1067 << dendl;
1068
1069 if (m_image_ctx.read_only) {
1070 return -EROFS;
1071 }
1072
1073 if (!m_image_ctx.test_features(RBD_FEATURE_LAYERING)) {
1074 lderr(cct) << "image must support layering" << dendl;
1075 return -ENOSYS;
1076 }
1077
1078 int r = m_image_ctx.state->refresh_if_required();
1079 if (r < 0) {
1080 return r;
1081 }
1082
1083 {
1084 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
1085 bool is_protected;
1086 r = m_image_ctx.is_snap_protected(m_image_ctx.get_snap_id(snap_namespace, snap_name),
1087 &is_protected);
1088 if (r < 0) {
1089 return r;
1090 }
1091
1092 if (is_protected) {
1093 return -EBUSY;
1094 }
1095 }
1096
1097 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
1098 r = invoke_async_request("snap_protect", true,
1099 boost::bind(&Operations<I>::execute_snap_protect,
1100 this, snap_namespace, snap_name, _1),
1101 boost::bind(&ImageWatcher<I>::notify_snap_protect,
1102 m_image_ctx.image_watcher,
1103 snap_namespace, snap_name, _1));
1104 if (r < 0 && r != -EBUSY) {
1105 return r;
1106 }
1107 } else {
1108 C_SaferCond cond_ctx;
1109 {
1110 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
1111 execute_snap_protect(snap_namespace, snap_name, &cond_ctx);
1112 }
1113
1114 r = cond_ctx.wait();
1115 if (r < 0) {
1116 return r;
1117 }
1118 }
1119 return 0;
1120 }
1121
1122 template <typename I>
1123 void Operations<I>::execute_snap_protect(const cls::rbd::SnapshotNamespace& snap_namespace,
1124 const std::string &snap_name,
1125 Context *on_finish) {
1126 ceph_assert(m_image_ctx.owner_lock.is_locked());
1127 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
1128 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
1129 m_image_ctx.exclusive_lock->is_lock_owner());
1130 }
1131
1132 if (m_image_ctx.operations_disabled) {
1133 on_finish->complete(-EROFS);
1134 return;
1135 }
1136
1137 m_image_ctx.snap_lock.get_read();
1138 bool is_protected;
1139 int r = m_image_ctx.is_snap_protected(m_image_ctx.get_snap_id(snap_namespace, snap_name),
1140 &is_protected);
1141 if (r < 0) {
1142 m_image_ctx.snap_lock.put_read();
1143 on_finish->complete(r);
1144 return;
1145 } else if (is_protected) {
1146 m_image_ctx.snap_lock.put_read();
1147 on_finish->complete(-EBUSY);
1148 return;
1149 }
1150 m_image_ctx.snap_lock.put_read();
1151
1152 CephContext *cct = m_image_ctx.cct;
1153 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
1154 << dendl;
1155
1156 operation::SnapshotProtectRequest<I> *request =
1157 new operation::SnapshotProtectRequest<I>(
1158 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), snap_namespace, snap_name);
1159 request->send();
1160 }
1161
1162 template <typename I>
1163 int Operations<I>::snap_unprotect(const cls::rbd::SnapshotNamespace& snap_namespace,
1164 const std::string& snap_name) {
1165 CephContext *cct = m_image_ctx.cct;
1166 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
1167 << dendl;
1168
1169 if (m_image_ctx.read_only) {
1170 return -EROFS;
1171 }
1172
1173 int r = m_image_ctx.state->refresh_if_required();
1174 if (r < 0) {
1175 return r;
1176 }
1177
1178 {
1179 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
1180 bool is_unprotected;
1181 r = m_image_ctx.is_snap_unprotected(m_image_ctx.get_snap_id(snap_namespace, snap_name),
1182 &is_unprotected);
1183 if (r < 0) {
1184 return r;
1185 }
1186
1187 if (is_unprotected) {
1188 return -EINVAL;
1189 }
1190 }
1191
1192 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
1193 r = invoke_async_request("snap_unprotect", true,
1194 boost::bind(&Operations<I>::execute_snap_unprotect,
1195 this, snap_namespace, snap_name, _1),
1196 boost::bind(&ImageWatcher<I>::notify_snap_unprotect,
1197 m_image_ctx.image_watcher,
1198 snap_namespace, snap_name, _1));
1199 if (r < 0 && r != -EINVAL) {
1200 return r;
1201 }
1202 } else {
1203 C_SaferCond cond_ctx;
1204 {
1205 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
1206 execute_snap_unprotect(snap_namespace, snap_name, &cond_ctx);
1207 }
1208
1209 r = cond_ctx.wait();
1210 if (r < 0) {
1211 return r;
1212 }
1213 }
1214 return 0;
1215 }
1216
1217 template <typename I>
1218 void Operations<I>::execute_snap_unprotect(const cls::rbd::SnapshotNamespace& snap_namespace,
1219 const std::string &snap_name,
1220 Context *on_finish) {
1221 ceph_assert(m_image_ctx.owner_lock.is_locked());
1222 if (m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
1223 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
1224 m_image_ctx.exclusive_lock->is_lock_owner());
1225 }
1226
1227 if (m_image_ctx.operations_disabled) {
1228 on_finish->complete(-EROFS);
1229 return;
1230 }
1231
1232 m_image_ctx.snap_lock.get_read();
1233 bool is_unprotected;
1234 int r = m_image_ctx.is_snap_unprotected(m_image_ctx.get_snap_id(snap_namespace, snap_name),
1235 &is_unprotected);
1236 if (r < 0) {
1237 m_image_ctx.snap_lock.put_read();
1238 on_finish->complete(r);
1239 return;
1240 } else if (is_unprotected) {
1241 m_image_ctx.snap_lock.put_read();
1242 on_finish->complete(-EINVAL);
1243 return;
1244 }
1245 m_image_ctx.snap_lock.put_read();
1246
1247 CephContext *cct = m_image_ctx.cct;
1248 ldout(cct, 5) << this << " " << __func__ << ": snap_name=" << snap_name
1249 << dendl;
1250
1251 operation::SnapshotUnprotectRequest<I> *request =
1252 new operation::SnapshotUnprotectRequest<I>(
1253 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), snap_namespace, snap_name);
1254 request->send();
1255 }
1256
1257 template <typename I>
1258 int Operations<I>::snap_set_limit(uint64_t limit) {
1259 CephContext *cct = m_image_ctx.cct;
1260 ldout(cct, 5) << this << " " << __func__ << ": limit=" << limit << dendl;
1261
1262 if (m_image_ctx.read_only) {
1263 return -EROFS;
1264 }
1265
1266 int r = m_image_ctx.state->refresh_if_required();
1267 if (r < 0) {
1268 return r;
1269 }
1270
1271 C_SaferCond limit_ctx;
1272 {
1273 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
1274 r = prepare_image_update(true);
1275 if (r < 0) {
1276 return r;
1277 }
1278
1279 execute_snap_set_limit(limit, &limit_ctx);
1280 }
1281
1282 r = limit_ctx.wait();
1283 return r;
1284 }
1285
1286 template <typename I>
1287 void Operations<I>::execute_snap_set_limit(const uint64_t limit,
1288 Context *on_finish) {
1289 ceph_assert(m_image_ctx.owner_lock.is_locked());
1290
1291 CephContext *cct = m_image_ctx.cct;
1292 ldout(cct, 5) << this << " " << __func__ << ": limit=" << limit
1293 << dendl;
1294
1295 operation::SnapshotLimitRequest<I> *request =
1296 new operation::SnapshotLimitRequest<I>(m_image_ctx, on_finish, limit);
1297 request->send();
1298 }
1299
1300 template <typename I>
1301 int Operations<I>::update_features(uint64_t features, bool enabled) {
1302 CephContext *cct = m_image_ctx.cct;
1303 ldout(cct, 5) << this << " " << __func__ << ": features=" << features
1304 << ", enabled=" << enabled << dendl;
1305
1306 int r = m_image_ctx.state->refresh_if_required();
1307 if (r < 0) {
1308 return r;
1309 }
1310
1311 if (m_image_ctx.read_only) {
1312 return -EROFS;
1313 } else if (m_image_ctx.old_format) {
1314 lderr(cct) << "old-format images do not support features" << dendl;
1315 return -EINVAL;
1316 }
1317
1318 uint64_t disable_mask = (RBD_FEATURES_MUTABLE |
1319 RBD_FEATURES_DISABLE_ONLY);
1320 if ((enabled && (features & RBD_FEATURES_MUTABLE) != features) ||
1321 (!enabled && (features & disable_mask) != features)) {
1322 lderr(cct) << "cannot update immutable features" << dendl;
1323 return -EINVAL;
1324 }
1325
1326 bool set_object_map = (features & RBD_FEATURE_OBJECT_MAP) == RBD_FEATURE_OBJECT_MAP;
1327 bool set_fast_diff = (features & RBD_FEATURE_FAST_DIFF) == RBD_FEATURE_FAST_DIFF;
1328 bool exist_fast_diff = (m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0;
1329 bool exist_object_map = (m_image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0;
1330
1331 if ((enabled && ((set_object_map && !exist_fast_diff) || (set_fast_diff && !exist_object_map)))
1332 || (!enabled && (set_object_map && exist_fast_diff))) {
1333 features |= (RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF);
1334 }
1335
1336 if (features == 0) {
1337 lderr(cct) << "update requires at least one feature" << dendl;
1338 return -EINVAL;
1339 }
1340 {
1341 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
1342 if (enabled && (features & m_image_ctx.features) != 0) {
1343 lderr(cct) << "one or more requested features are already enabled"
1344 << dendl;
1345 return -EINVAL;
1346 }
1347 if (!enabled && (features & ~m_image_ctx.features) != 0) {
1348 lderr(cct) << "one or more requested features are already disabled"
1349 << dendl;
1350 return -EINVAL;
1351 }
1352 }
1353
1354 // if disabling journaling, avoid attempting to open the journal
1355 // when acquiring the exclusive lock in case the journal is corrupt
1356 bool disabling_journal = false;
1357 if (!enabled && ((features & RBD_FEATURE_JOURNALING) != 0)) {
1358 RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
1359 m_image_ctx.set_journal_policy(new journal::DisabledPolicy());
1360 disabling_journal = true;
1361 }
1362 BOOST_SCOPE_EXIT_ALL( (this)(disabling_journal) ) {
1363 if (disabling_journal) {
1364 RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
1365 m_image_ctx.set_journal_policy(
1366 new journal::StandardPolicy<I>(&m_image_ctx));
1367 }
1368 };
1369
1370 // The journal options are not passed to the lock owner in the
1371 // update features request. Therefore, if journaling is being
1372 // enabled, the lock should be locally acquired instead of
1373 // attempting to send the request to the peer.
1374 if (enabled && (features & RBD_FEATURE_JOURNALING) != 0) {
1375 C_SaferCond cond_ctx;
1376 {
1377 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
1378 r = prepare_image_update(true);
1379 if (r < 0) {
1380 return r;
1381 }
1382
1383 execute_update_features(features, enabled, &cond_ctx, 0);
1384 }
1385
1386 r = cond_ctx.wait();
1387 } else {
1388 r = invoke_async_request("update_features", false,
1389 boost::bind(&Operations<I>::execute_update_features,
1390 this, features, enabled, _1, 0),
1391 boost::bind(&ImageWatcher<I>::notify_update_features,
1392 m_image_ctx.image_watcher, features,
1393 enabled, _1));
1394 }
1395 ldout(cct, 2) << "update_features finished" << dendl;
1396 return r;
1397 }
1398
1399 template <typename I>
1400 void Operations<I>::execute_update_features(uint64_t features, bool enabled,
1401 Context *on_finish,
1402 uint64_t journal_op_tid) {
1403 ceph_assert(m_image_ctx.owner_lock.is_locked());
1404 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
1405 m_image_ctx.exclusive_lock->is_lock_owner());
1406
1407 CephContext *cct = m_image_ctx.cct;
1408 ldout(cct, 5) << this << " " << __func__ << ": features=" << features
1409 << ", enabled=" << enabled << dendl;
1410
1411 if (m_image_ctx.operations_disabled) {
1412 on_finish->complete(-EROFS);
1413 return;
1414 }
1415
1416 if (enabled) {
1417 operation::EnableFeaturesRequest<I> *req =
1418 new operation::EnableFeaturesRequest<I>(
1419 m_image_ctx, on_finish, journal_op_tid, features);
1420 req->send();
1421 } else {
1422 operation::DisableFeaturesRequest<I> *req =
1423 new operation::DisableFeaturesRequest<I>(
1424 m_image_ctx, on_finish, journal_op_tid, features, false);
1425 req->send();
1426 }
1427 }
1428
1429 template <typename I>
1430 int Operations<I>::metadata_set(const std::string &key,
1431 const std::string &value) {
1432 CephContext *cct = m_image_ctx.cct;
1433 ldout(cct, 5) << this << " " << __func__ << ": key=" << key << ", value="
1434 << value << dendl;
1435
1436 std::string config_key;
1437 bool config_override = util::is_metadata_config_override(key, &config_key);
1438 if (config_override) {
1439 // validate config setting
1440 if (!librbd::api::Config<I>::is_option_name(&m_image_ctx, config_key)) {
1441 lderr(cct) << "validation for " << key
1442 << " failed: not allowed image level override" << dendl;
1443 return -EINVAL;
1444 }
1445 int r = ConfigProxy{false}.set_val(config_key.c_str(), value);
1446 if (r < 0) {
1447 return r;
1448 }
1449 }
1450
1451 int r = m_image_ctx.state->refresh_if_required();
1452 if (r < 0) {
1453 return r;
1454 }
1455
1456 if (m_image_ctx.read_only) {
1457 return -EROFS;
1458 }
1459
1460 C_SaferCond metadata_ctx;
1461 {
1462 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
1463 r = prepare_image_update(true);
1464 if (r < 0) {
1465 return r;
1466 }
1467
1468 execute_metadata_set(key, value, &metadata_ctx);
1469 }
1470
1471 r = metadata_ctx.wait();
1472 if (config_override && r >= 0) {
1473 // apply new config key immediately
1474 r = m_image_ctx.state->refresh_if_required();
1475 }
1476
1477 return r;
1478 }
1479
1480 template <typename I>
1481 void Operations<I>::execute_metadata_set(const std::string &key,
1482 const std::string &value,
1483 Context *on_finish) {
1484 ceph_assert(m_image_ctx.owner_lock.is_locked());
1485
1486 CephContext *cct = m_image_ctx.cct;
1487 ldout(cct, 5) << this << " " << __func__ << ": key=" << key << ", value="
1488 << value << dendl;
1489
1490 if (m_image_ctx.operations_disabled) {
1491 on_finish->complete(-EROFS);
1492 return;
1493 }
1494
1495 operation::MetadataSetRequest<I> *request =
1496 new operation::MetadataSetRequest<I>(m_image_ctx,
1497 new C_NotifyUpdate<I>(m_image_ctx, on_finish),
1498 key, value);
1499 request->send();
1500 }
1501
1502 template <typename I>
1503 int Operations<I>::metadata_remove(const std::string &key) {
1504 CephContext *cct = m_image_ctx.cct;
1505 ldout(cct, 5) << this << " " << __func__ << ": key=" << key << dendl;
1506
1507 int r = m_image_ctx.state->refresh_if_required();
1508 if (r < 0) {
1509 return r;
1510 }
1511
1512 if (m_image_ctx.read_only) {
1513 return -EROFS;
1514 }
1515
1516 std::string value;
1517 r = cls_client::metadata_get(&m_image_ctx.md_ctx, m_image_ctx.header_oid, key, &value);
1518 if(r < 0)
1519 return r;
1520
1521 C_SaferCond metadata_ctx;
1522 {
1523 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
1524 r = prepare_image_update(true);
1525 if (r < 0) {
1526 return r;
1527 }
1528
1529 execute_metadata_remove(key, &metadata_ctx);
1530 }
1531
1532 r = metadata_ctx.wait();
1533
1534 std::string config_key;
1535 if (util::is_metadata_config_override(key, &config_key) && r >= 0) {
1536 // apply new config key immediately
1537 r = m_image_ctx.state->refresh_if_required();
1538 }
1539
1540 return r;
1541 }
1542
1543 template <typename I>
1544 void Operations<I>::execute_metadata_remove(const std::string &key,
1545 Context *on_finish) {
1546 ceph_assert(m_image_ctx.owner_lock.is_locked());
1547
1548 CephContext *cct = m_image_ctx.cct;
1549 ldout(cct, 5) << this << " " << __func__ << ": key=" << key << dendl;
1550
1551 if (m_image_ctx.operations_disabled) {
1552 on_finish->complete(-EROFS);
1553 return;
1554 }
1555
1556 operation::MetadataRemoveRequest<I> *request =
1557 new operation::MetadataRemoveRequest<I>(
1558 m_image_ctx,
1559 new C_NotifyUpdate<I>(m_image_ctx, on_finish), key);
1560 request->send();
1561 }
1562
1563 template <typename I>
1564 int Operations<I>::migrate(ProgressContext &prog_ctx) {
1565 CephContext *cct = m_image_ctx.cct;
1566 ldout(cct, 20) << "migrate" << dendl;
1567
1568 int r = m_image_ctx.state->refresh_if_required();
1569 if (r < 0) {
1570 return r;
1571 }
1572
1573 if (m_image_ctx.read_only) {
1574 return -EROFS;
1575 }
1576
1577 {
1578 RWLock::RLocker parent_locker(m_image_ctx.parent_lock);
1579 if (m_image_ctx.migration_info.empty()) {
1580 lderr(cct) << "image has no migrating parent" << dendl;
1581 return -EINVAL;
1582 }
1583 }
1584
1585 uint64_t request_id = ++m_async_request_seq;
1586 r = invoke_async_request("migrate", false,
1587 boost::bind(&Operations<I>::execute_migrate, this,
1588 boost::ref(prog_ctx), _1),
1589 boost::bind(&ImageWatcher<I>::notify_migrate,
1590 m_image_ctx.image_watcher, request_id,
1591 boost::ref(prog_ctx), _1));
1592
1593 if (r < 0 && r != -EINVAL) {
1594 return r;
1595 }
1596 ldout(cct, 20) << "migrate finished" << dendl;
1597 return 0;
1598 }
1599
1600 template <typename I>
1601 void Operations<I>::execute_migrate(ProgressContext &prog_ctx,
1602 Context *on_finish) {
1603 ceph_assert(m_image_ctx.owner_lock.is_locked());
1604 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
1605 m_image_ctx.exclusive_lock->is_lock_owner());
1606
1607 CephContext *cct = m_image_ctx.cct;
1608 ldout(cct, 20) << "migrate" << dendl;
1609
1610 if (m_image_ctx.read_only || m_image_ctx.operations_disabled) {
1611 on_finish->complete(-EROFS);
1612 return;
1613 }
1614
1615 m_image_ctx.snap_lock.get_read();
1616 m_image_ctx.parent_lock.get_read();
1617
1618 if (m_image_ctx.migration_info.empty()) {
1619 lderr(cct) << "image has no migrating parent" << dendl;
1620 m_image_ctx.parent_lock.put_read();
1621 m_image_ctx.snap_lock.put_read();
1622 on_finish->complete(-EINVAL);
1623 return;
1624 }
1625 if (m_image_ctx.snap_id != CEPH_NOSNAP) {
1626 lderr(cct) << "snapshots cannot be migrated" << dendl;
1627 m_image_ctx.parent_lock.put_read();
1628 m_image_ctx.snap_lock.put_read();
1629 on_finish->complete(-EROFS);
1630 return;
1631 }
1632
1633 m_image_ctx.parent_lock.put_read();
1634 m_image_ctx.snap_lock.put_read();
1635
1636 operation::MigrateRequest<I> *req = new operation::MigrateRequest<I>(
1637 m_image_ctx, new C_NotifyUpdate<I>(m_image_ctx, on_finish), prog_ctx);
1638 req->send();
1639 }
1640
1641 template <typename I>
1642 int Operations<I>::sparsify(size_t sparse_size, ProgressContext &prog_ctx) {
1643 CephContext *cct = m_image_ctx.cct;
1644 ldout(cct, 20) << "sparsify" << dendl;
1645
1646 if (sparse_size < 4096 || sparse_size > m_image_ctx.get_object_size() ||
1647 (sparse_size & (sparse_size - 1)) != 0) {
1648 lderr(cct) << "sparse size should be power of two not less than 4096"
1649 << " and not larger image object size" << dendl;
1650 return -EINVAL;
1651 }
1652
1653 uint64_t request_id = ++m_async_request_seq;
1654 int r = invoke_async_request("sparsify", false,
1655 boost::bind(&Operations<I>::execute_sparsify,
1656 this, sparse_size,
1657 boost::ref(prog_ctx), _1),
1658 boost::bind(&ImageWatcher<I>::notify_sparsify,
1659 m_image_ctx.image_watcher,
1660 request_id, sparse_size,
1661 boost::ref(prog_ctx), _1));
1662 if (r < 0 && r != -EINVAL) {
1663 return r;
1664 }
1665 ldout(cct, 20) << "resparsify finished" << dendl;
1666 return 0;
1667 }
1668
1669 template <typename I>
1670 void Operations<I>::execute_sparsify(size_t sparse_size,
1671 ProgressContext &prog_ctx,
1672 Context *on_finish) {
1673 ceph_assert(m_image_ctx.owner_lock.is_locked());
1674 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
1675 m_image_ctx.exclusive_lock->is_lock_owner());
1676
1677 CephContext *cct = m_image_ctx.cct;
1678 ldout(cct, 20) << "sparsify" << dendl;
1679
1680 if (m_image_ctx.operations_disabled) {
1681 on_finish->complete(-EROFS);
1682 return;
1683 }
1684
1685 auto req = new operation::SparsifyRequest<I>(
1686 m_image_ctx, sparse_size, new C_NotifyUpdate<I>(m_image_ctx, on_finish),
1687 prog_ctx);
1688 req->send();
1689 }
1690
1691 template <typename I>
1692 int Operations<I>::prepare_image_update(bool request_lock) {
1693 ceph_assert(m_image_ctx.owner_lock.is_locked() &&
1694 !m_image_ctx.owner_lock.is_wlocked());
1695 if (m_image_ctx.image_watcher == nullptr) {
1696 return -EROFS;
1697 }
1698
1699 // need to upgrade to a write lock
1700 C_SaferCond ctx;
1701 m_image_ctx.owner_lock.put_read();
1702 bool attempting_lock = false;
1703 {
1704 RWLock::WLocker owner_locker(m_image_ctx.owner_lock);
1705 if (m_image_ctx.exclusive_lock != nullptr &&
1706 (!m_image_ctx.exclusive_lock->is_lock_owner() ||
1707 !m_image_ctx.exclusive_lock->accept_requests())) {
1708
1709 attempting_lock = true;
1710 m_image_ctx.exclusive_lock->block_requests(0);
1711
1712 if (request_lock) {
1713 m_image_ctx.exclusive_lock->acquire_lock(&ctx);
1714 } else {
1715 m_image_ctx.exclusive_lock->try_acquire_lock(&ctx);
1716 }
1717 }
1718 }
1719
1720 int r = 0;
1721 if (attempting_lock) {
1722 r = ctx.wait();
1723 }
1724
1725 m_image_ctx.owner_lock.get_read();
1726 if (attempting_lock && m_image_ctx.exclusive_lock != nullptr) {
1727 m_image_ctx.exclusive_lock->unblock_requests();
1728 }
1729
1730 if (r == -EAGAIN || r == -EBUSY) {
1731 r = 0;
1732 }
1733 if (r < 0) {
1734 return r;
1735 } else if (m_image_ctx.exclusive_lock != nullptr &&
1736 !m_image_ctx.exclusive_lock->is_lock_owner()) {
1737 return m_image_ctx.exclusive_lock->get_unlocked_op_error();
1738 }
1739
1740 return 0;
1741 }
1742
1743 template <typename I>
1744 int Operations<I>::invoke_async_request(const std::string& request_type,
1745 bool permit_snapshot,
1746 const boost::function<void(Context*)>& local_request,
1747 const boost::function<void(Context*)>& remote_request) {
1748 C_SaferCond ctx;
1749 C_InvokeAsyncRequest<I> *req = new C_InvokeAsyncRequest<I>(m_image_ctx,
1750 request_type,
1751 permit_snapshot,
1752 local_request,
1753 remote_request,
1754 {}, &ctx);
1755 req->send();
1756 return ctx.wait();
1757 }
1758
1759 } // namespace librbd
1760
1761 template class librbd::Operations<librbd::ImageCtx>;