1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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/WorkQueue.h"
10 #include "librbd/ExclusiveLock.h"
11 #include "librbd/ImageCtx.h"
12 #include "librbd/ImageState.h"
13 #include "librbd/ImageWatcher.h"
14 #include "librbd/ObjectMap.h"
15 #include "librbd/Utils.h"
16 #include "librbd/journal/DisabledPolicy.h"
17 #include "librbd/journal/StandardPolicy.h"
18 #include "librbd/operation/DisableFeaturesRequest.h"
19 #include "librbd/operation/EnableFeaturesRequest.h"
20 #include "librbd/operation/FlattenRequest.h"
21 #include "librbd/operation/MetadataRemoveRequest.h"
22 #include "librbd/operation/MetadataSetRequest.h"
23 #include "librbd/operation/ObjectMapIterate.h"
24 #include "librbd/operation/RebuildObjectMapRequest.h"
25 #include "librbd/operation/RenameRequest.h"
26 #include "librbd/operation/ResizeRequest.h"
27 #include "librbd/operation/SnapshotCreateRequest.h"
28 #include "librbd/operation/SnapshotProtectRequest.h"
29 #include "librbd/operation/SnapshotRemoveRequest.h"
30 #include "librbd/operation/SnapshotRenameRequest.h"
31 #include "librbd/operation/SnapshotRollbackRequest.h"
32 #include "librbd/operation/SnapshotUnprotectRequest.h"
33 #include "librbd/operation/SnapshotLimitRequest.h"
35 #include <boost/bind.hpp>
36 #include <boost/scope_exit.hpp>
38 #define dout_subsys ceph_subsys_rbd
40 #define dout_prefix *_dout << "librbd::Operations: "
47 struct C_NotifyUpdate
: public Context
{
50 bool notified
= false;
52 C_NotifyUpdate(I
&image_ctx
, Context
*on_finish
)
53 : image_ctx(image_ctx
), on_finish(on_finish
) {
56 void complete(int r
) override
{
57 CephContext
*cct
= image_ctx
.cct
;
59 if (r
== -ETIMEDOUT
) {
60 // don't fail the op if a peer fails to get the update notification
61 lderr(cct
) << "update notification timed-out" << dendl
;
63 } else if (r
== -ENOENT
) {
64 // don't fail if header is missing (e.g. v1 image rename)
65 ldout(cct
, 5) << "update notification on missing header" << dendl
;
68 lderr(cct
) << "update notification failed: " << cpp_strerror(r
)
76 // op failed -- no need to send update notification
82 image_ctx
.notify_update(this);
84 void finish(int r
) override
{
85 on_finish
->complete(r
);
90 struct C_InvokeAsyncRequest
: public Context
{
96 * . . . . . . | . . . . . . . . . . . . . . . . . .
99 * . REFRESH_IMAGE (skip if not needed) .
102 * . ACQUIRE_LOCK (skip if exclusive lock .
103 * . | disabled or has lock) .
105 * . /--------/ \--------\ . . . . . . . . . . . . .
108 * LOCAL_REQUEST REMOTE_REQUEST
111 * \--------\ /--------/
120 std::string request_type
;
121 bool permit_snapshot
;
122 boost::function
<void(Context
*)> local
;
123 boost::function
<void(Context
*)> remote
;
124 std::set
<int> filter_error_codes
;
126 bool request_lock
= false;
128 C_InvokeAsyncRequest(I
&image_ctx
, const std::string
& request_type
,
129 bool permit_snapshot
,
130 const boost::function
<void(Context
*)>& local
,
131 const boost::function
<void(Context
*)>& remote
,
132 const std::set
<int> &filter_error_codes
,
134 : image_ctx(image_ctx
), request_type(request_type
),
135 permit_snapshot(permit_snapshot
), local(local
), remote(remote
),
136 filter_error_codes(filter_error_codes
), on_finish(on_finish
) {
140 send_refresh_image();
143 void send_refresh_image() {
144 if (!image_ctx
.state
->is_refresh_required()) {
145 send_acquire_exclusive_lock();
149 CephContext
*cct
= image_ctx
.cct
;
150 ldout(cct
, 20) << __func__
<< dendl
;
152 Context
*ctx
= util::create_context_callback
<
153 C_InvokeAsyncRequest
<I
>,
154 &C_InvokeAsyncRequest
<I
>::handle_refresh_image
>(this);
155 image_ctx
.state
->refresh(ctx
);
158 void handle_refresh_image(int r
) {
159 CephContext
*cct
= image_ctx
.cct
;
160 ldout(cct
, 20) << __func__
<< ": r=" << r
<< dendl
;
163 lderr(cct
) << "failed to refresh image: " << cpp_strerror(r
) << dendl
;
168 send_acquire_exclusive_lock();
171 void send_acquire_exclusive_lock() {
172 // context can complete before owner_lock is unlocked
173 RWLock
&owner_lock(image_ctx
.owner_lock
);
174 owner_lock
.get_read();
175 image_ctx
.snap_lock
.get_read();
176 if (image_ctx
.read_only
||
177 (!permit_snapshot
&& image_ctx
.snap_id
!= CEPH_NOSNAP
)) {
178 image_ctx
.snap_lock
.put_read();
179 owner_lock
.put_read();
183 image_ctx
.snap_lock
.put_read();
185 if (image_ctx
.exclusive_lock
== nullptr) {
186 send_local_request();
187 owner_lock
.put_read();
189 } else if (image_ctx
.image_watcher
== nullptr) {
190 owner_lock
.put_read();
196 if (image_ctx
.exclusive_lock
->is_lock_owner() &&
197 image_ctx
.exclusive_lock
->accept_requests(&r
)) {
198 send_local_request();
199 owner_lock
.put_read();
203 CephContext
*cct
= image_ctx
.cct
;
204 ldout(cct
, 20) << __func__
<< dendl
;
206 Context
*ctx
= util::create_async_context_callback(
207 image_ctx
, util::create_context_callback
<
208 C_InvokeAsyncRequest
<I
>,
209 &C_InvokeAsyncRequest
<I
>::handle_acquire_exclusive_lock
>(this));
212 // current lock owner doesn't support op -- try to perform
213 // the action locally
214 request_lock
= false;
215 image_ctx
.exclusive_lock
->acquire_lock(ctx
);
217 image_ctx
.exclusive_lock
->try_acquire_lock(ctx
);
219 owner_lock
.put_read();
222 void handle_acquire_exclusive_lock(int r
) {
223 CephContext
*cct
= image_ctx
.cct
;
224 ldout(cct
, 20) << __func__
<< ": r=" << r
<< dendl
;
231 // context can complete before owner_lock is unlocked
232 RWLock
&owner_lock(image_ctx
.owner_lock
);
233 owner_lock
.get_read();
234 if (image_ctx
.exclusive_lock
->is_lock_owner()) {
235 send_local_request();
236 owner_lock
.put_read();
240 send_remote_request();
241 owner_lock
.put_read();
244 void send_remote_request() {
245 assert(image_ctx
.owner_lock
.is_locked());
247 CephContext
*cct
= image_ctx
.cct
;
248 ldout(cct
, 20) << __func__
<< dendl
;
250 Context
*ctx
= util::create_context_callback
<
251 C_InvokeAsyncRequest
<I
>, &C_InvokeAsyncRequest
<I
>::handle_remote_request
>(
256 void handle_remote_request(int r
) {
257 CephContext
*cct
= image_ctx
.cct
;
258 ldout(cct
, 20) << __func__
<< ": r=" << r
<< dendl
;
260 if (r
== -EOPNOTSUPP
) {
261 ldout(cct
, 5) << request_type
<< " not supported by current lock owner"
264 send_refresh_image();
266 } else if (r
!= -ETIMEDOUT
&& r
!= -ERESTART
) {
267 image_ctx
.state
->handle_update_notification();
273 ldout(cct
, 5) << request_type
<< " timed out notifying lock owner"
275 send_refresh_image();
278 void send_local_request() {
279 assert(image_ctx
.owner_lock
.is_locked());
281 CephContext
*cct
= image_ctx
.cct
;
282 ldout(cct
, 20) << __func__
<< dendl
;
284 Context
*ctx
= util::create_async_context_callback(
285 image_ctx
, util::create_context_callback
<
286 C_InvokeAsyncRequest
<I
>,
287 &C_InvokeAsyncRequest
<I
>::handle_local_request
>(this));
291 void handle_local_request(int r
) {
292 CephContext
*cct
= image_ctx
.cct
;
293 ldout(cct
, 20) << __func__
<< ": r=" << r
<< dendl
;
295 if (r
== -ERESTART
) {
296 send_refresh_image();
302 void finish(int r
) override
{
303 if (filter_error_codes
.count(r
) != 0) {
306 on_finish
->complete(r
);
310 template <typename I
>
311 bool needs_invalidate(I
& image_ctx
, uint64_t object_no
,
312 uint8_t current_state
, uint8_t new_state
) {
313 if ( (current_state
== OBJECT_EXISTS
||
314 current_state
== OBJECT_EXISTS_CLEAN
) &&
315 (new_state
== OBJECT_NONEXISTENT
||
316 new_state
== OBJECT_PENDING
)) {
322 } // anonymous namespace
324 template <typename I
>
325 Operations
<I
>::Operations(I
&image_ctx
)
326 : m_image_ctx(image_ctx
), m_async_request_seq(0) {
329 template <typename I
>
330 int Operations
<I
>::flatten(ProgressContext
&prog_ctx
) {
331 CephContext
*cct
= m_image_ctx
.cct
;
332 ldout(cct
, 20) << "flatten" << dendl
;
334 int r
= m_image_ctx
.state
->refresh_if_required();
339 if (m_image_ctx
.read_only
) {
344 RWLock::RLocker
parent_locker(m_image_ctx
.parent_lock
);
345 if (m_image_ctx
.parent_md
.spec
.pool_id
== -1) {
346 lderr(cct
) << "image has no parent" << dendl
;
351 uint64_t request_id
= ++m_async_request_seq
;
352 r
= invoke_async_request("flatten", false,
353 boost::bind(&Operations
<I
>::execute_flatten
, this,
354 boost::ref(prog_ctx
), _1
),
355 boost::bind(&ImageWatcher
<I
>::notify_flatten
,
356 m_image_ctx
.image_watcher
, request_id
,
357 boost::ref(prog_ctx
), _1
));
359 if (r
< 0 && r
!= -EINVAL
) {
362 ldout(cct
, 20) << "flatten finished" << dendl
;
366 template <typename I
>
367 void Operations
<I
>::execute_flatten(ProgressContext
&prog_ctx
,
368 Context
*on_finish
) {
369 assert(m_image_ctx
.owner_lock
.is_locked());
370 assert(m_image_ctx
.exclusive_lock
== nullptr ||
371 m_image_ctx
.exclusive_lock
->is_lock_owner());
373 CephContext
*cct
= m_image_ctx
.cct
;
374 ldout(cct
, 20) << "flatten" << dendl
;
376 if (m_image_ctx
.read_only
) {
377 on_finish
->complete(-EROFS
);
381 m_image_ctx
.snap_lock
.get_read();
382 m_image_ctx
.parent_lock
.get_read();
384 // can't flatten a non-clone
385 if (m_image_ctx
.parent_md
.spec
.pool_id
== -1) {
386 lderr(cct
) << "image has no parent" << dendl
;
387 m_image_ctx
.parent_lock
.put_read();
388 m_image_ctx
.snap_lock
.put_read();
389 on_finish
->complete(-EINVAL
);
392 if (m_image_ctx
.snap_id
!= CEPH_NOSNAP
) {
393 lderr(cct
) << "snapshots cannot be flattened" << dendl
;
394 m_image_ctx
.parent_lock
.put_read();
395 m_image_ctx
.snap_lock
.put_read();
396 on_finish
->complete(-EROFS
);
400 ::SnapContext snapc
= m_image_ctx
.snapc
;
401 assert(m_image_ctx
.parent
!= NULL
);
404 int r
= m_image_ctx
.get_parent_overlap(CEPH_NOSNAP
, &overlap
);
406 assert(overlap
<= m_image_ctx
.size
);
408 uint64_t object_size
= m_image_ctx
.get_object_size();
409 uint64_t overlap_objects
= Striper::get_num_objects(m_image_ctx
.layout
,
412 m_image_ctx
.parent_lock
.put_read();
413 m_image_ctx
.snap_lock
.put_read();
415 operation::FlattenRequest
<I
> *req
= new operation::FlattenRequest
<I
>(
416 m_image_ctx
, new C_NotifyUpdate
<I
>(m_image_ctx
, on_finish
), object_size
,
417 overlap_objects
, snapc
, prog_ctx
);
421 template <typename I
>
422 int Operations
<I
>::rebuild_object_map(ProgressContext
&prog_ctx
) {
423 CephContext
*cct
= m_image_ctx
.cct
;
424 ldout(cct
, 10) << "rebuild_object_map" << dendl
;
426 int r
= m_image_ctx
.state
->refresh_if_required();
431 uint64_t request_id
= ++m_async_request_seq
;
432 r
= invoke_async_request("rebuild object map", true,
433 boost::bind(&Operations
<I
>::execute_rebuild_object_map
,
434 this, boost::ref(prog_ctx
), _1
),
435 boost::bind(&ImageWatcher
<I
>::notify_rebuild_object_map
,
436 m_image_ctx
.image_watcher
, request_id
,
437 boost::ref(prog_ctx
), _1
));
439 ldout(cct
, 10) << "rebuild object map finished" << dendl
;
446 template <typename I
>
447 void Operations
<I
>::execute_rebuild_object_map(ProgressContext
&prog_ctx
,
448 Context
*on_finish
) {
449 assert(m_image_ctx
.owner_lock
.is_locked());
450 assert(m_image_ctx
.exclusive_lock
== nullptr ||
451 m_image_ctx
.exclusive_lock
->is_lock_owner());
453 CephContext
*cct
= m_image_ctx
.cct
;
454 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
456 if (m_image_ctx
.read_only
) {
457 on_finish
->complete(-EROFS
);
460 if (!m_image_ctx
.test_features(RBD_FEATURE_OBJECT_MAP
)) {
461 lderr(cct
) << "image must support object-map feature" << dendl
;
462 on_finish
->complete(-EINVAL
);
466 operation::RebuildObjectMapRequest
<I
> *req
=
467 new operation::RebuildObjectMapRequest
<I
>(
468 m_image_ctx
, new C_NotifyUpdate
<I
>(m_image_ctx
, on_finish
), prog_ctx
);
472 template <typename I
>
473 int Operations
<I
>::check_object_map(ProgressContext
&prog_ctx
) {
474 CephContext
*cct
= m_image_ctx
.cct
;
475 ldout(cct
, 5) << this << " " << __func__
<< dendl
;
476 int r
= m_image_ctx
.state
->refresh_if_required();
481 r
= invoke_async_request("check object map", true,
482 boost::bind(&Operations
<I
>::check_object_map
, this,
483 boost::ref(prog_ctx
), _1
),
484 [] (Context
*c
) { c
->complete(-EOPNOTSUPP
); });
489 template <typename I
>
490 void Operations
<I
>::object_map_iterate(ProgressContext
&prog_ctx
,
491 operation::ObjectIterateWork
<I
> handle_mismatch
,
492 Context
*on_finish
) {
493 assert(m_image_ctx
.owner_lock
.is_locked());
494 assert(m_image_ctx
.exclusive_lock
== nullptr ||
495 m_image_ctx
.exclusive_lock
->is_lock_owner());
497 if (!m_image_ctx
.test_features(RBD_FEATURE_OBJECT_MAP
)) {
498 on_finish
->complete(-EINVAL
);
502 operation::ObjectMapIterateRequest
<I
> *req
=
503 new operation::ObjectMapIterateRequest
<I
>(m_image_ctx
, on_finish
,
504 prog_ctx
, handle_mismatch
);
508 template <typename I
>
509 void Operations
<I
>::check_object_map(ProgressContext
&prog_ctx
,
510 Context
*on_finish
) {
511 object_map_iterate(prog_ctx
, needs_invalidate
, on_finish
);
514 template <typename I
>
515 int Operations
<I
>::rename(const char *dstname
) {
516 CephContext
*cct
= m_image_ctx
.cct
;
517 ldout(cct
, 5) << this << " " << __func__
<< ": dest_name=" << dstname
520 int r
= librbd::detect_format(m_image_ctx
.md_ctx
, dstname
, NULL
, NULL
);
521 if (r
< 0 && r
!= -ENOENT
) {
522 lderr(cct
) << "error checking for existing image called "
523 << dstname
<< ":" << cpp_strerror(r
) << dendl
;
527 lderr(cct
) << "rbd image " << dstname
<< " already exists" << dendl
;
531 if (m_image_ctx
.test_features(RBD_FEATURE_JOURNALING
)) {
532 r
= invoke_async_request("rename", true,
533 boost::bind(&Operations
<I
>::execute_rename
, this,
535 boost::bind(&ImageWatcher
<I
>::notify_rename
,
536 m_image_ctx
.image_watcher
, dstname
,
538 if (r
< 0 && r
!= -EEXIST
) {
542 RWLock::RLocker
owner_lock(m_image_ctx
.owner_lock
);
543 C_SaferCond cond_ctx
;
544 execute_rename(dstname
, &cond_ctx
);
552 m_image_ctx
.set_image_name(dstname
);
556 template <typename I
>
557 void Operations
<I
>::execute_rename(const std::string
&dest_name
,
558 Context
*on_finish
) {
559 assert(m_image_ctx
.owner_lock
.is_locked());
560 if (m_image_ctx
.test_features(RBD_FEATURE_JOURNALING
)) {
561 assert(m_image_ctx
.exclusive_lock
== nullptr ||
562 m_image_ctx
.exclusive_lock
->is_lock_owner());
565 m_image_ctx
.snap_lock
.get_read();
566 if (m_image_ctx
.name
== dest_name
) {
567 m_image_ctx
.snap_lock
.put_read();
568 on_finish
->complete(-EEXIST
);
571 m_image_ctx
.snap_lock
.put_read();
573 CephContext
*cct
= m_image_ctx
.cct
;
574 ldout(cct
, 5) << this << " " << __func__
<< ": dest_name=" << dest_name
577 if (m_image_ctx
.old_format
) {
578 // unregister watch before and register back after rename
579 on_finish
= new C_NotifyUpdate
<I
>(m_image_ctx
, on_finish
);
580 on_finish
= new FunctionContext([this, on_finish
](int r
) {
581 if (m_image_ctx
.old_format
) {
582 m_image_ctx
.image_watcher
->set_oid(m_image_ctx
.header_oid
);
584 m_image_ctx
.image_watcher
->register_watch(on_finish
);
586 on_finish
= new FunctionContext([this, dest_name
, on_finish
](int r
) {
587 operation::RenameRequest
<I
> *req
= new operation::RenameRequest
<I
>(
588 m_image_ctx
, on_finish
, dest_name
);
591 m_image_ctx
.image_watcher
->unregister_watch(on_finish
);
594 operation::RenameRequest
<I
> *req
= new operation::RenameRequest
<I
>(
595 m_image_ctx
, on_finish
, dest_name
);
599 template <typename I
>
600 int Operations
<I
>::resize(uint64_t size
, bool allow_shrink
, ProgressContext
& prog_ctx
) {
601 CephContext
*cct
= m_image_ctx
.cct
;
603 m_image_ctx
.snap_lock
.get_read();
604 ldout(cct
, 5) << this << " " << __func__
<< ": "
605 << "size=" << m_image_ctx
.size
<< ", "
606 << "new_size=" << size
<< dendl
;
607 m_image_ctx
.snap_lock
.put_read();
609 int r
= m_image_ctx
.state
->refresh_if_required();
614 if (m_image_ctx
.test_features(RBD_FEATURE_OBJECT_MAP
) &&
615 !ObjectMap
<>::is_compatible(m_image_ctx
.layout
, size
)) {
616 lderr(cct
) << "New size not compatible with object map" << dendl
;
620 uint64_t request_id
= ++m_async_request_seq
;
621 r
= invoke_async_request("resize", false,
622 boost::bind(&Operations
<I
>::execute_resize
, this,
623 size
, allow_shrink
, boost::ref(prog_ctx
), _1
, 0),
624 boost::bind(&ImageWatcher
<I
>::notify_resize
,
625 m_image_ctx
.image_watcher
, request_id
,
626 size
, allow_shrink
, boost::ref(prog_ctx
), _1
));
628 m_image_ctx
.perfcounter
->inc(l_librbd_resize
);
629 ldout(cct
, 2) << "resize finished" << dendl
;
633 template <typename I
>
634 void Operations
<I
>::execute_resize(uint64_t size
, bool allow_shrink
, ProgressContext
&prog_ctx
,
636 uint64_t journal_op_tid
) {
637 assert(m_image_ctx
.owner_lock
.is_locked());
638 assert(m_image_ctx
.exclusive_lock
== nullptr ||
639 m_image_ctx
.exclusive_lock
->is_lock_owner());
641 CephContext
*cct
= m_image_ctx
.cct
;
642 m_image_ctx
.snap_lock
.get_read();
643 ldout(cct
, 5) << this << " " << __func__
<< ": "
644 << "size=" << m_image_ctx
.size
<< ", "
645 << "new_size=" << size
<< dendl
;
647 if (m_image_ctx
.snap_id
!= CEPH_NOSNAP
|| m_image_ctx
.read_only
) {
648 m_image_ctx
.snap_lock
.put_read();
649 on_finish
->complete(-EROFS
);
651 } else if (m_image_ctx
.test_features(RBD_FEATURE_OBJECT_MAP
,
652 m_image_ctx
.snap_lock
) &&
653 !ObjectMap
<>::is_compatible(m_image_ctx
.layout
, size
)) {
654 m_image_ctx
.snap_lock
.put_read();
655 on_finish
->complete(-EINVAL
);
658 m_image_ctx
.snap_lock
.put_read();
660 operation::ResizeRequest
<I
> *req
= new operation::ResizeRequest
<I
>(
661 m_image_ctx
, new C_NotifyUpdate
<I
>(m_image_ctx
, on_finish
), size
, allow_shrink
,
662 prog_ctx
, journal_op_tid
, false);
666 template <typename I
>
667 int Operations
<I
>::snap_create(const cls::rbd::SnapshotNamespace
&snap_namespace
,
668 const char *snap_name
) {
669 if (m_image_ctx
.read_only
) {
673 int r
= m_image_ctx
.state
->refresh_if_required();
679 snap_create(snap_namespace
, snap_name
, &ctx
);
686 m_image_ctx
.perfcounter
->inc(l_librbd_snap_create
);
690 template <typename I
>
691 void Operations
<I
>::snap_create(const cls::rbd::SnapshotNamespace
&snap_namespace
,
692 const char *snap_name
,
693 Context
*on_finish
) {
694 CephContext
*cct
= m_image_ctx
.cct
;
695 ldout(cct
, 5) << this << " " << __func__
<< ": snap_name=" << snap_name
698 if (m_image_ctx
.read_only
) {
699 on_finish
->complete(-EROFS
);
703 m_image_ctx
.snap_lock
.get_read();
704 if (m_image_ctx
.get_snap_id(snap_namespace
, snap_name
) != CEPH_NOSNAP
) {
705 m_image_ctx
.snap_lock
.put_read();
706 on_finish
->complete(-EEXIST
);
709 m_image_ctx
.snap_lock
.put_read();
711 C_InvokeAsyncRequest
<I
> *req
= new C_InvokeAsyncRequest
<I
>(
712 m_image_ctx
, "snap_create", true,
713 boost::bind(&Operations
<I
>::execute_snap_create
, this, snap_namespace
, snap_name
,
715 boost::bind(&ImageWatcher
<I
>::notify_snap_create
, m_image_ctx
.image_watcher
,
716 snap_namespace
, snap_name
, _1
),
717 {-EEXIST
}, on_finish
);
721 template <typename I
>
722 void Operations
<I
>::execute_snap_create(const cls::rbd::SnapshotNamespace
&snap_namespace
,
723 const std::string
&snap_name
,
725 uint64_t journal_op_tid
,
726 bool skip_object_map
) {
727 assert(m_image_ctx
.owner_lock
.is_locked());
728 assert(m_image_ctx
.exclusive_lock
== nullptr ||
729 m_image_ctx
.exclusive_lock
->is_lock_owner());
731 CephContext
*cct
= m_image_ctx
.cct
;
732 ldout(cct
, 5) << this << " " << __func__
<< ": snap_name=" << snap_name
735 m_image_ctx
.snap_lock
.get_read();
736 if (m_image_ctx
.get_snap_id(snap_namespace
, snap_name
) != CEPH_NOSNAP
) {
737 m_image_ctx
.snap_lock
.put_read();
738 on_finish
->complete(-EEXIST
);
741 m_image_ctx
.snap_lock
.put_read();
743 operation::SnapshotCreateRequest
<I
> *req
=
744 new operation::SnapshotCreateRequest
<I
>(
745 m_image_ctx
, new C_NotifyUpdate
<I
>(m_image_ctx
, on_finish
),
746 snap_namespace
, snap_name
, journal_op_tid
, skip_object_map
);
750 template <typename I
>
751 int Operations
<I
>::snap_rollback(const cls::rbd::SnapshotNamespace
& snap_namespace
,
752 const char *snap_name
,
753 ProgressContext
& prog_ctx
) {
754 CephContext
*cct
= m_image_ctx
.cct
;
755 ldout(cct
, 5) << this << " " << __func__
<< ": snap_name=" << snap_name
758 int r
= m_image_ctx
.state
->refresh_if_required();
762 RWLock::RLocker
owner_locker(m_image_ctx
.owner_lock
);
764 // need to drop snap_lock before invalidating cache
765 RWLock::RLocker
snap_locker(m_image_ctx
.snap_lock
);
766 if (!m_image_ctx
.snap_exists
) {
770 if (m_image_ctx
.snap_id
!= CEPH_NOSNAP
|| m_image_ctx
.read_only
) {
774 uint64_t snap_id
= m_image_ctx
.get_snap_id(snap_namespace
, snap_name
);
775 if (snap_id
== CEPH_NOSNAP
) {
776 lderr(cct
) << "No such snapshot found." << dendl
;
781 r
= prepare_image_update();
785 if (m_image_ctx
.exclusive_lock
!= nullptr &&
786 !m_image_ctx
.exclusive_lock
->is_lock_owner()) {
790 C_SaferCond cond_ctx
;
791 execute_snap_rollback(snap_namespace
, snap_name
, prog_ctx
, &cond_ctx
);
797 m_image_ctx
.perfcounter
->inc(l_librbd_snap_rollback
);
801 template <typename I
>
802 void Operations
<I
>::execute_snap_rollback(const cls::rbd::SnapshotNamespace
& snap_namespace
,
803 const std::string
&snap_name
,
804 ProgressContext
& prog_ctx
,
805 Context
*on_finish
) {
806 assert(m_image_ctx
.owner_lock
.is_locked());
807 CephContext
*cct
= m_image_ctx
.cct
;
808 ldout(cct
, 5) << this << " " << __func__
<< ": snap_name=" << snap_name
811 m_image_ctx
.snap_lock
.get_read();
812 uint64_t snap_id
= m_image_ctx
.get_snap_id(snap_namespace
, snap_name
);
813 if (snap_id
== CEPH_NOSNAP
) {
814 lderr(cct
) << "No such snapshot found." << dendl
;
815 m_image_ctx
.snap_lock
.put_read();
816 on_finish
->complete(-ENOENT
);
820 uint64_t new_size
= m_image_ctx
.get_image_size(snap_id
);
821 m_image_ctx
.snap_lock
.put_read();
823 // async mode used for journal replay
824 operation::SnapshotRollbackRequest
<I
> *request
=
825 new operation::SnapshotRollbackRequest
<I
>(
826 m_image_ctx
, new C_NotifyUpdate
<I
>(m_image_ctx
, on_finish
), snap_namespace
, snap_name
,
827 snap_id
, new_size
, prog_ctx
);
831 template <typename I
>
832 int Operations
<I
>::snap_remove(const cls::rbd::SnapshotNamespace
& snap_namespace
,
833 const char *snap_name
) {
834 if (m_image_ctx
.read_only
) {
838 int r
= m_image_ctx
.state
->refresh_if_required();
844 snap_remove(snap_namespace
, snap_name
, &ctx
);
851 m_image_ctx
.perfcounter
->inc(l_librbd_snap_remove
);
855 template <typename I
>
856 void Operations
<I
>::snap_remove(const cls::rbd::SnapshotNamespace
& snap_namespace
,
857 const char *snap_name
,
858 Context
*on_finish
) {
859 CephContext
*cct
= m_image_ctx
.cct
;
860 ldout(cct
, 5) << this << " " << __func__
<< ": snap_name=" << snap_name
863 if (m_image_ctx
.read_only
) {
864 on_finish
->complete(-EROFS
);
868 // quickly filter out duplicate ops
869 m_image_ctx
.snap_lock
.get_read();
870 if (m_image_ctx
.get_snap_id(snap_namespace
, snap_name
) == CEPH_NOSNAP
) {
871 m_image_ctx
.snap_lock
.put_read();
872 on_finish
->complete(-ENOENT
);
876 bool proxy_op
= ((m_image_ctx
.features
& RBD_FEATURE_FAST_DIFF
) != 0 ||
877 (m_image_ctx
.features
& RBD_FEATURE_JOURNALING
) != 0);
878 m_image_ctx
.snap_lock
.put_read();
881 C_InvokeAsyncRequest
<I
> *req
= new C_InvokeAsyncRequest
<I
>(
882 m_image_ctx
, "snap_remove", true,
883 boost::bind(&Operations
<I
>::execute_snap_remove
, this, snap_namespace
, snap_name
, _1
),
884 boost::bind(&ImageWatcher
<I
>::notify_snap_remove
, m_image_ctx
.image_watcher
,
885 snap_namespace
, snap_name
, _1
),
886 {-ENOENT
}, on_finish
);
889 RWLock::RLocker
owner_lock(m_image_ctx
.owner_lock
);
890 execute_snap_remove(snap_namespace
, snap_name
, on_finish
);
894 template <typename I
>
895 void Operations
<I
>::execute_snap_remove(const cls::rbd::SnapshotNamespace
& snap_namespace
,
896 const std::string
&snap_name
,
897 Context
*on_finish
) {
898 assert(m_image_ctx
.owner_lock
.is_locked());
900 if ((m_image_ctx
.features
& RBD_FEATURE_FAST_DIFF
) != 0) {
901 assert(m_image_ctx
.exclusive_lock
== nullptr ||
902 m_image_ctx
.exclusive_lock
->is_lock_owner());
906 CephContext
*cct
= m_image_ctx
.cct
;
907 ldout(cct
, 5) << this << " " << __func__
<< ": snap_name=" << snap_name
910 m_image_ctx
.snap_lock
.get_read();
911 uint64_t snap_id
= m_image_ctx
.get_snap_id(snap_namespace
, snap_name
);
912 if (snap_id
== CEPH_NOSNAP
) {
913 lderr(m_image_ctx
.cct
) << "No such snapshot found." << dendl
;
914 m_image_ctx
.snap_lock
.put_read();
915 on_finish
->complete(-ENOENT
);
920 int r
= m_image_ctx
.is_snap_protected(snap_id
, &is_protected
);
922 m_image_ctx
.snap_lock
.put_read();
923 on_finish
->complete(r
);
925 } else if (is_protected
) {
926 lderr(m_image_ctx
.cct
) << "snapshot is protected" << dendl
;
927 m_image_ctx
.snap_lock
.put_read();
928 on_finish
->complete(-EBUSY
);
931 m_image_ctx
.snap_lock
.put_read();
933 operation::SnapshotRemoveRequest
<I
> *req
=
934 new operation::SnapshotRemoveRequest
<I
>(
935 m_image_ctx
, new C_NotifyUpdate
<I
>(m_image_ctx
, on_finish
),
936 snap_namespace
, snap_name
, snap_id
);
940 template <typename I
>
941 int Operations
<I
>::snap_rename(const char *srcname
, const char *dstname
) {
942 CephContext
*cct
= m_image_ctx
.cct
;
943 ldout(cct
, 5) << this << " " << __func__
<< ": "
944 << "snap_name=" << srcname
<< ", "
945 << "new_snap_name=" << dstname
<< dendl
;
948 if (m_image_ctx
.read_only
) {
952 int r
= m_image_ctx
.state
->refresh_if_required();
957 RWLock::RLocker
l(m_image_ctx
.snap_lock
);
958 snap_id
= m_image_ctx
.get_snap_id(cls::rbd::UserSnapshotNamespace(), srcname
);
959 if (snap_id
== CEPH_NOSNAP
) {
962 if (m_image_ctx
.get_snap_id(cls::rbd::UserSnapshotNamespace(), dstname
) != CEPH_NOSNAP
) {
967 if (m_image_ctx
.test_features(RBD_FEATURE_JOURNALING
)) {
968 r
= invoke_async_request("snap_rename", true,
969 boost::bind(&Operations
<I
>::execute_snap_rename
,
970 this, snap_id
, dstname
, _1
),
971 boost::bind(&ImageWatcher
<I
>::notify_snap_rename
,
972 m_image_ctx
.image_watcher
, snap_id
,
974 if (r
< 0 && r
!= -EEXIST
) {
978 RWLock::RLocker
owner_lock(m_image_ctx
.owner_lock
);
979 C_SaferCond cond_ctx
;
980 execute_snap_rename(snap_id
, dstname
, &cond_ctx
);
988 m_image_ctx
.perfcounter
->inc(l_librbd_snap_rename
);
992 template <typename I
>
993 void Operations
<I
>::execute_snap_rename(const uint64_t src_snap_id
,
994 const std::string
&dest_snap_name
,
995 Context
*on_finish
) {
996 assert(m_image_ctx
.owner_lock
.is_locked());
997 if ((m_image_ctx
.features
& RBD_FEATURE_JOURNALING
) != 0) {
998 assert(m_image_ctx
.exclusive_lock
== nullptr ||
999 m_image_ctx
.exclusive_lock
->is_lock_owner());
1002 m_image_ctx
.snap_lock
.get_read();
1003 if (m_image_ctx
.get_snap_id(cls::rbd::UserSnapshotNamespace(),
1004 dest_snap_name
) != CEPH_NOSNAP
) {
1005 // Renaming is supported for snapshots from user namespace only.
1006 m_image_ctx
.snap_lock
.put_read();
1007 on_finish
->complete(-EEXIST
);
1010 m_image_ctx
.snap_lock
.put_read();
1012 CephContext
*cct
= m_image_ctx
.cct
;
1013 ldout(cct
, 5) << this << " " << __func__
<< ": "
1014 << "snap_id=" << src_snap_id
<< ", "
1015 << "new_snap_name=" << dest_snap_name
<< dendl
;
1017 operation::SnapshotRenameRequest
<I
> *req
=
1018 new operation::SnapshotRenameRequest
<I
>(
1019 m_image_ctx
, new C_NotifyUpdate
<I
>(m_image_ctx
, on_finish
), src_snap_id
,
1024 template <typename I
>
1025 int Operations
<I
>::snap_protect(const cls::rbd::SnapshotNamespace
& snap_namespace
,
1026 const char *snap_name
) {
1027 CephContext
*cct
= m_image_ctx
.cct
;
1028 ldout(cct
, 5) << this << " " << __func__
<< ": snap_name=" << snap_name
1031 if (m_image_ctx
.read_only
) {
1035 if (!m_image_ctx
.test_features(RBD_FEATURE_LAYERING
)) {
1036 lderr(cct
) << "image must support layering" << dendl
;
1040 int r
= m_image_ctx
.state
->refresh_if_required();
1046 RWLock::RLocker
snap_locker(m_image_ctx
.snap_lock
);
1048 r
= m_image_ctx
.is_snap_protected(m_image_ctx
.get_snap_id(snap_namespace
, snap_name
),
1059 if (m_image_ctx
.test_features(RBD_FEATURE_JOURNALING
)) {
1060 r
= invoke_async_request("snap_protect", true,
1061 boost::bind(&Operations
<I
>::execute_snap_protect
,
1062 this, snap_namespace
, snap_name
, _1
),
1063 boost::bind(&ImageWatcher
<I
>::notify_snap_protect
,
1064 m_image_ctx
.image_watcher
,
1065 snap_namespace
, snap_name
, _1
));
1066 if (r
< 0 && r
!= -EBUSY
) {
1070 RWLock::RLocker
owner_lock(m_image_ctx
.owner_lock
);
1071 C_SaferCond cond_ctx
;
1072 execute_snap_protect(snap_namespace
, snap_name
, &cond_ctx
);
1074 r
= cond_ctx
.wait();
1082 template <typename I
>
1083 void Operations
<I
>::execute_snap_protect(const cls::rbd::SnapshotNamespace
& snap_namespace
,
1084 const std::string
&snap_name
,
1085 Context
*on_finish
) {
1086 assert(m_image_ctx
.owner_lock
.is_locked());
1087 if (m_image_ctx
.test_features(RBD_FEATURE_JOURNALING
)) {
1088 assert(m_image_ctx
.exclusive_lock
== nullptr ||
1089 m_image_ctx
.exclusive_lock
->is_lock_owner());
1092 m_image_ctx
.snap_lock
.get_read();
1094 int r
= m_image_ctx
.is_snap_protected(m_image_ctx
.get_snap_id(snap_namespace
, snap_name
),
1097 m_image_ctx
.snap_lock
.put_read();
1098 on_finish
->complete(r
);
1100 } else if (is_protected
) {
1101 m_image_ctx
.snap_lock
.put_read();
1102 on_finish
->complete(-EBUSY
);
1105 m_image_ctx
.snap_lock
.put_read();
1107 CephContext
*cct
= m_image_ctx
.cct
;
1108 ldout(cct
, 5) << this << " " << __func__
<< ": snap_name=" << snap_name
1111 operation::SnapshotProtectRequest
<I
> *request
=
1112 new operation::SnapshotProtectRequest
<I
>(
1113 m_image_ctx
, new C_NotifyUpdate
<I
>(m_image_ctx
, on_finish
), snap_namespace
, snap_name
);
1117 template <typename I
>
1118 int Operations
<I
>::snap_unprotect(const cls::rbd::SnapshotNamespace
& snap_namespace
,
1119 const char *snap_name
) {
1120 CephContext
*cct
= m_image_ctx
.cct
;
1121 ldout(cct
, 5) << this << " " << __func__
<< ": snap_name=" << snap_name
1124 if (m_image_ctx
.read_only
) {
1128 int r
= m_image_ctx
.state
->refresh_if_required();
1134 RWLock::RLocker
snap_locker(m_image_ctx
.snap_lock
);
1135 bool is_unprotected
;
1136 r
= m_image_ctx
.is_snap_unprotected(m_image_ctx
.get_snap_id(snap_namespace
, snap_name
),
1142 if (is_unprotected
) {
1147 if (m_image_ctx
.test_features(RBD_FEATURE_JOURNALING
)) {
1148 r
= invoke_async_request("snap_unprotect", true,
1149 boost::bind(&Operations
<I
>::execute_snap_unprotect
,
1150 this, snap_namespace
, snap_name
, _1
),
1151 boost::bind(&ImageWatcher
<I
>::notify_snap_unprotect
,
1152 m_image_ctx
.image_watcher
,
1153 snap_namespace
, snap_name
, _1
));
1154 if (r
< 0 && r
!= -EINVAL
) {
1158 RWLock::RLocker
owner_lock(m_image_ctx
.owner_lock
);
1159 C_SaferCond cond_ctx
;
1160 execute_snap_unprotect(snap_namespace
, snap_name
, &cond_ctx
);
1162 r
= cond_ctx
.wait();
1170 template <typename I
>
1171 void Operations
<I
>::execute_snap_unprotect(const cls::rbd::SnapshotNamespace
& snap_namespace
,
1172 const std::string
&snap_name
,
1173 Context
*on_finish
) {
1174 assert(m_image_ctx
.owner_lock
.is_locked());
1175 if (m_image_ctx
.test_features(RBD_FEATURE_JOURNALING
)) {
1176 assert(m_image_ctx
.exclusive_lock
== nullptr ||
1177 m_image_ctx
.exclusive_lock
->is_lock_owner());
1180 m_image_ctx
.snap_lock
.get_read();
1181 bool is_unprotected
;
1182 int r
= m_image_ctx
.is_snap_unprotected(m_image_ctx
.get_snap_id(snap_namespace
, snap_name
),
1185 m_image_ctx
.snap_lock
.put_read();
1186 on_finish
->complete(r
);
1188 } else if (is_unprotected
) {
1189 m_image_ctx
.snap_lock
.put_read();
1190 on_finish
->complete(-EINVAL
);
1193 m_image_ctx
.snap_lock
.put_read();
1195 CephContext
*cct
= m_image_ctx
.cct
;
1196 ldout(cct
, 5) << this << " " << __func__
<< ": snap_name=" << snap_name
1199 operation::SnapshotUnprotectRequest
<I
> *request
=
1200 new operation::SnapshotUnprotectRequest
<I
>(
1201 m_image_ctx
, new C_NotifyUpdate
<I
>(m_image_ctx
, on_finish
), snap_namespace
, snap_name
);
1205 template <typename I
>
1206 int Operations
<I
>::snap_set_limit(uint64_t limit
) {
1207 CephContext
*cct
= m_image_ctx
.cct
;
1208 ldout(cct
, 5) << this << " " << __func__
<< ": limit=" << limit
<< dendl
;
1210 if (m_image_ctx
.read_only
) {
1214 int r
= m_image_ctx
.state
->refresh_if_required();
1220 RWLock::RLocker
owner_lock(m_image_ctx
.owner_lock
);
1221 C_SaferCond limit_ctx
;
1223 if (m_image_ctx
.exclusive_lock
!= nullptr &&
1224 !m_image_ctx
.exclusive_lock
->is_lock_owner()) {
1225 C_SaferCond lock_ctx
;
1227 m_image_ctx
.exclusive_lock
->acquire_lock(&lock_ctx
);
1228 r
= lock_ctx
.wait();
1234 execute_snap_set_limit(limit
, &limit_ctx
);
1235 r
= limit_ctx
.wait();
1241 template <typename I
>
1242 void Operations
<I
>::execute_snap_set_limit(const uint64_t limit
,
1243 Context
*on_finish
) {
1244 assert(m_image_ctx
.owner_lock
.is_locked());
1246 CephContext
*cct
= m_image_ctx
.cct
;
1247 ldout(cct
, 5) << this << " " << __func__
<< ": limit=" << limit
1250 operation::SnapshotLimitRequest
<I
> *request
=
1251 new operation::SnapshotLimitRequest
<I
>(m_image_ctx
, on_finish
, limit
);
1255 template <typename I
>
1256 int Operations
<I
>::update_features(uint64_t features
, bool enabled
) {
1257 CephContext
*cct
= m_image_ctx
.cct
;
1258 ldout(cct
, 5) << this << " " << __func__
<< ": features=" << features
1259 << ", enabled=" << enabled
<< dendl
;
1261 int r
= m_image_ctx
.state
->refresh_if_required();
1266 if (m_image_ctx
.read_only
) {
1268 } else if (m_image_ctx
.old_format
) {
1269 lderr(cct
) << "old-format images do not support features" << dendl
;
1273 uint64_t disable_mask
= (RBD_FEATURES_MUTABLE
|
1274 RBD_FEATURES_DISABLE_ONLY
);
1275 if ((enabled
&& (features
& RBD_FEATURES_MUTABLE
) != features
) ||
1276 (!enabled
&& (features
& disable_mask
) != features
)) {
1277 lderr(cct
) << "cannot update immutable features" << dendl
;
1280 if (features
== 0) {
1281 lderr(cct
) << "update requires at least one feature" << dendl
;
1285 RWLock::RLocker
snap_locker(m_image_ctx
.snap_lock
);
1286 if (enabled
&& (features
& m_image_ctx
.features
) != 0) {
1287 lderr(cct
) << "one or more requested features are already enabled"
1291 if (!enabled
&& (features
& ~m_image_ctx
.features
) != 0) {
1292 lderr(cct
) << "one or more requested features are already disabled"
1298 // if disabling journaling, avoid attempting to open the journal
1299 // when acquiring the exclusive lock in case the journal is corrupt
1300 bool disabling_journal
= false;
1301 if (!enabled
&& ((features
& RBD_FEATURE_JOURNALING
) != 0)) {
1302 RWLock::WLocker
snap_locker(m_image_ctx
.snap_lock
);
1303 m_image_ctx
.set_journal_policy(new journal::DisabledPolicy());
1304 disabling_journal
= true;
1306 BOOST_SCOPE_EXIT_ALL( (this)(disabling_journal
) ) {
1307 if (disabling_journal
) {
1308 RWLock::WLocker
snap_locker(m_image_ctx
.snap_lock
);
1309 m_image_ctx
.set_journal_policy(
1310 new journal::StandardPolicy
<I
>(&m_image_ctx
));
1314 r
= invoke_async_request("update_features", false,
1315 boost::bind(&Operations
<I
>::execute_update_features
,
1316 this, features
, enabled
, _1
, 0),
1317 boost::bind(&ImageWatcher
<I
>::notify_update_features
,
1318 m_image_ctx
.image_watcher
, features
,
1320 ldout(cct
, 2) << "update_features finished" << dendl
;
1324 template <typename I
>
1325 void Operations
<I
>::execute_update_features(uint64_t features
, bool enabled
,
1327 uint64_t journal_op_tid
) {
1328 assert(m_image_ctx
.owner_lock
.is_locked());
1329 assert(m_image_ctx
.exclusive_lock
== nullptr ||
1330 m_image_ctx
.exclusive_lock
->is_lock_owner());
1332 CephContext
*cct
= m_image_ctx
.cct
;
1333 ldout(cct
, 5) << this << " " << __func__
<< ": features=" << features
1334 << ", enabled=" << enabled
<< dendl
;
1337 operation::EnableFeaturesRequest
<I
> *req
=
1338 new operation::EnableFeaturesRequest
<I
>(
1339 m_image_ctx
, on_finish
, journal_op_tid
, features
);
1342 operation::DisableFeaturesRequest
<I
> *req
=
1343 new operation::DisableFeaturesRequest
<I
>(
1344 m_image_ctx
, on_finish
, journal_op_tid
, features
, false);
1349 template <typename I
>
1350 int Operations
<I
>::metadata_set(const std::string
&key
,
1351 const std::string
&value
) {
1352 CephContext
*cct
= m_image_ctx
.cct
;
1353 ldout(cct
, 5) << this << " " << __func__
<< ": key=" << key
<< ", value="
1356 string start
= m_image_ctx
.METADATA_CONF_PREFIX
;
1357 size_t conf_prefix_len
= start
.size();
1359 if (key
.size() > conf_prefix_len
&& !key
.compare(0, conf_prefix_len
, start
)) {
1360 // validate config setting
1361 string subkey
= key
.substr(conf_prefix_len
, key
.size() - conf_prefix_len
);
1362 int r
= md_config_t().set_val(subkey
.c_str(), value
);
1368 int r
= m_image_ctx
.state
->refresh_if_required();
1373 if (m_image_ctx
.read_only
) {
1378 RWLock::RLocker
owner_lock(m_image_ctx
.owner_lock
);
1379 C_SaferCond metadata_ctx
;
1381 if (m_image_ctx
.exclusive_lock
!= nullptr &&
1382 !m_image_ctx
.exclusive_lock
->is_lock_owner()) {
1383 C_SaferCond lock_ctx
;
1385 m_image_ctx
.exclusive_lock
->acquire_lock(&lock_ctx
);
1386 r
= lock_ctx
.wait();
1392 execute_metadata_set(key
, value
, &metadata_ctx
);
1393 r
= metadata_ctx
.wait();
1399 template <typename I
>
1400 void Operations
<I
>::execute_metadata_set(const std::string
&key
,
1401 const std::string
&value
,
1402 Context
*on_finish
) {
1403 assert(m_image_ctx
.owner_lock
.is_locked());
1405 CephContext
*cct
= m_image_ctx
.cct
;
1406 ldout(cct
, 5) << this << " " << __func__
<< ": key=" << key
<< ", value="
1409 operation::MetadataSetRequest
<I
> *request
=
1410 new operation::MetadataSetRequest
<I
>(m_image_ctx
, on_finish
, key
, value
);
1414 template <typename I
>
1415 int Operations
<I
>::metadata_remove(const std::string
&key
) {
1416 CephContext
*cct
= m_image_ctx
.cct
;
1417 ldout(cct
, 5) << this << " " << __func__
<< ": key=" << key
<< dendl
;
1419 if (m_image_ctx
.read_only
) {
1423 int r
= m_image_ctx
.state
->refresh_if_required();
1428 if (m_image_ctx
.read_only
) {
1433 RWLock::RLocker
owner_lock(m_image_ctx
.owner_lock
);
1434 C_SaferCond metadata_ctx
;
1436 if (m_image_ctx
.exclusive_lock
!= nullptr &&
1437 !m_image_ctx
.exclusive_lock
->is_lock_owner()) {
1438 C_SaferCond lock_ctx
;
1440 m_image_ctx
.exclusive_lock
->acquire_lock(&lock_ctx
);
1441 r
= lock_ctx
.wait();
1447 execute_metadata_remove(key
, &metadata_ctx
);
1448 r
= metadata_ctx
.wait();
1454 template <typename I
>
1455 void Operations
<I
>::execute_metadata_remove(const std::string
&key
,
1456 Context
*on_finish
) {
1457 assert(m_image_ctx
.owner_lock
.is_locked());
1459 CephContext
*cct
= m_image_ctx
.cct
;
1460 ldout(cct
, 5) << this << " " << __func__
<< ": key=" << key
<< dendl
;
1462 operation::MetadataRemoveRequest
<I
> *request
=
1463 new operation::MetadataRemoveRequest
<I
>(m_image_ctx
, on_finish
, key
);
1467 template <typename I
>
1468 int Operations
<I
>::prepare_image_update() {
1469 assert(m_image_ctx
.owner_lock
.is_locked() &&
1470 !m_image_ctx
.owner_lock
.is_wlocked());
1471 if (m_image_ctx
.image_watcher
== NULL
) {
1475 // need to upgrade to a write lock
1477 bool trying_lock
= false;
1479 m_image_ctx
.owner_lock
.put_read();
1481 RWLock::WLocker
owner_locker(m_image_ctx
.owner_lock
);
1482 if (m_image_ctx
.exclusive_lock
!= nullptr &&
1483 (!m_image_ctx
.exclusive_lock
->is_lock_owner() ||
1484 !m_image_ctx
.exclusive_lock
->accept_requests(&r
))) {
1485 m_image_ctx
.exclusive_lock
->try_acquire_lock(&ctx
);
1493 m_image_ctx
.owner_lock
.get_read();
1498 template <typename I
>
1499 int Operations
<I
>::invoke_async_request(const std::string
& request_type
,
1500 bool permit_snapshot
,
1501 const boost::function
<void(Context
*)>& local_request
,
1502 const boost::function
<void(Context
*)>& remote_request
) {
1504 C_InvokeAsyncRequest
<I
> *req
= new C_InvokeAsyncRequest
<I
>(m_image_ctx
,
1514 } // namespace librbd
1516 template class librbd::Operations
<librbd::ImageCtx
>;