1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/object_map/SnapshotRemoveRequest.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "librbd/ImageCtx.h"
8 #include "librbd/ObjectMap.h"
9 #include "librbd/object_map/InvalidateRequest.h"
10 #include "cls/lock/cls_lock_client.h"
12 #define dout_subsys ceph_subsys_rbd
14 #define dout_prefix *_dout << "librbd::object_map::SnapshotRemoveRequest: " \
15 << this << " " << __func__ << ": "
18 namespace object_map
{
20 void SnapshotRemoveRequest::send() {
21 ceph_assert(ceph_mutex_is_locked(m_image_ctx
.owner_lock
));
22 ceph_assert(ceph_mutex_is_wlocked(m_image_ctx
.image_lock
));
24 if ((m_image_ctx
.features
& RBD_FEATURE_FAST_DIFF
) != 0) {
25 int r
= m_image_ctx
.get_flags(m_snap_id
, &m_flags
);
28 compute_next_snap_id();
35 void SnapshotRemoveRequest::load_map() {
36 CephContext
*cct
= m_image_ctx
.cct
;
37 std::string
snap_oid(ObjectMap
<>::object_map_name(m_image_ctx
.id
, m_snap_id
));
38 ldout(cct
, 5) << "snap_oid=" << snap_oid
<< dendl
;
40 librados::ObjectReadOperation op
;
41 cls_client::object_map_load_start(&op
);
43 auto rados_completion
= librbd::util::create_rados_callback
<
44 SnapshotRemoveRequest
, &SnapshotRemoveRequest::handle_load_map
>(this);
45 int r
= m_image_ctx
.md_ctx
.aio_operate(snap_oid
, rados_completion
, &op
,
48 rados_completion
->release();
51 void SnapshotRemoveRequest::handle_load_map(int r
) {
52 CephContext
*cct
= m_image_ctx
.cct
;
53 ldout(cct
, 5) << "r=" << r
<< dendl
;
56 auto it
= m_out_bl
.cbegin();
57 r
= cls_client::object_map_load_finish(&it
, &m_snap_object_map
);
60 // implies we have already deleted this snapshot and handled the
61 // necessary fast-diff cleanup
65 std::string
oid(ObjectMap
<>::object_map_name(m_image_ctx
.id
, m_snap_id
));
66 lderr(cct
) << "failed to load object map " << oid
<< ": "
67 << cpp_strerror(r
) << dendl
;
69 std::shared_lock owner_locker
{m_image_ctx
.owner_lock
};
70 std::unique_lock image_locker
{m_image_ctx
.image_lock
};
71 invalidate_next_map();
78 void SnapshotRemoveRequest::remove_snapshot() {
79 if ((m_flags
& RBD_FLAG_OBJECT_MAP_INVALID
) != 0) {
80 // snapshot object map exists on disk but is invalid. cannot clean fast-diff
81 // on next snapshot if current snapshot was invalid.
82 std::shared_lock owner_locker
{m_image_ctx
.owner_lock
};
83 std::unique_lock image_locker
{m_image_ctx
.image_lock
};
84 invalidate_next_map();
88 CephContext
*cct
= m_image_ctx
.cct
;
89 std::string
oid(ObjectMap
<>::object_map_name(m_image_ctx
.id
, m_next_snap_id
));
90 ldout(cct
, 5) << "oid=" << oid
<< dendl
;
92 librados::ObjectWriteOperation op
;
93 if (m_next_snap_id
== CEPH_NOSNAP
) {
94 rados::cls::lock::assert_locked(&op
, RBD_LOCK_NAME
, LOCK_EXCLUSIVE
, "", "");
96 cls_client::object_map_snap_remove(&op
, m_snap_object_map
);
98 auto rados_completion
= librbd::util::create_rados_callback
<
99 SnapshotRemoveRequest
,
100 &SnapshotRemoveRequest::handle_remove_snapshot
>(this);
101 int r
= m_image_ctx
.md_ctx
.aio_operate(oid
, rados_completion
, &op
);
103 rados_completion
->release();
106 void SnapshotRemoveRequest::handle_remove_snapshot(int r
) {
107 CephContext
*cct
= m_image_ctx
.cct
;
108 ldout(cct
, 5) << "r=" << r
<< dendl
;
109 if (r
< 0 && r
!= -ENOENT
) {
110 std::string
oid(ObjectMap
<>::object_map_name(m_image_ctx
.id
,
112 lderr(cct
) << "failed to remove object map snapshot " << oid
<< ": "
113 << cpp_strerror(r
) << dendl
;
115 std::shared_lock owner_locker
{m_image_ctx
.owner_lock
};
116 std::unique_lock image_locker
{m_image_ctx
.image_lock
};
117 invalidate_next_map();
121 std::shared_lock image_locker
{m_image_ctx
.image_lock
};
126 void SnapshotRemoveRequest::invalidate_next_map() {
127 ceph_assert(ceph_mutex_is_locked(m_image_ctx
.owner_lock
));
128 ceph_assert(ceph_mutex_is_wlocked(m_image_ctx
.image_lock
));
130 CephContext
*cct
= m_image_ctx
.cct
;
131 ldout(cct
, 5) << dendl
;
133 auto ctx
= librbd::util::create_context_callback
<
134 SnapshotRemoveRequest
,
135 &SnapshotRemoveRequest::handle_invalidate_next_map
>(this);
136 InvalidateRequest
<> *req
= new InvalidateRequest
<>(m_image_ctx
,
137 m_next_snap_id
, true, ctx
);
141 void SnapshotRemoveRequest::handle_invalidate_next_map(int r
) {
142 CephContext
*cct
= m_image_ctx
.cct
;
143 ldout(cct
, 5) << "r=" << r
<< dendl
;
146 std::string
oid(ObjectMap
<>::object_map_name(m_image_ctx
.id
,
148 lderr(cct
) << "failed to invalidate object map " << oid
<< ": "
149 << cpp_strerror(r
) << dendl
;
157 void SnapshotRemoveRequest::remove_map() {
158 CephContext
*cct
= m_image_ctx
.cct
;
159 std::string
oid(ObjectMap
<>::object_map_name(m_image_ctx
.id
, m_snap_id
));
160 ldout(cct
, 5) << "oid=" << oid
<< dendl
;
162 librados::ObjectWriteOperation op
;
165 auto rados_completion
= librbd::util::create_rados_callback
<
166 SnapshotRemoveRequest
, &SnapshotRemoveRequest::handle_remove_map
>(this);
167 int r
= m_image_ctx
.md_ctx
.aio_operate(oid
, rados_completion
, &op
);
169 rados_completion
->release();
172 void SnapshotRemoveRequest::handle_remove_map(int r
) {
173 CephContext
*cct
= m_image_ctx
.cct
;
174 ldout(cct
, 5) << "r=" << r
<< dendl
;
176 if (r
< 0 && r
!= -ENOENT
) {
177 std::string
oid(ObjectMap
<>::object_map_name(m_image_ctx
.id
, m_snap_id
));
178 lderr(cct
) << "failed to remove object map " << oid
<< ": "
179 << cpp_strerror(r
) << dendl
;
187 void SnapshotRemoveRequest::compute_next_snap_id() {
188 ceph_assert(ceph_mutex_is_locked(m_image_ctx
.image_lock
));
190 m_next_snap_id
= CEPH_NOSNAP
;
191 std::map
<librados::snap_t
, SnapInfo
>::const_iterator it
=
192 m_image_ctx
.snap_info
.find(m_snap_id
);
193 ceph_assert(it
!= m_image_ctx
.snap_info
.end());
196 if (it
!= m_image_ctx
.snap_info
.end()) {
197 m_next_snap_id
= it
->first
;
201 void SnapshotRemoveRequest::update_object_map() {
202 assert(ceph_mutex_is_locked(m_image_ctx
.image_lock
));
203 std::unique_lock object_map_locker
{*m_object_map_lock
};
204 if (m_next_snap_id
== m_image_ctx
.snap_id
&& m_next_snap_id
== CEPH_NOSNAP
) {
205 CephContext
*cct
= m_image_ctx
.cct
;
206 ldout(cct
, 5) << dendl
;
208 auto it
= m_object_map
.begin();
209 auto end_it
= m_object_map
.end();
210 auto snap_it
= m_snap_object_map
.begin();
212 for (; it
!= end_it
; ++it
) {
213 if (*it
== OBJECT_EXISTS_CLEAN
&&
214 (i
>= m_snap_object_map
.size() ||
215 *snap_it
== OBJECT_EXISTS
)) {
218 if (i
< m_snap_object_map
.size()) {
226 } // namespace object_map
227 } // namespace librbd