1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/operation/ObjectMapIterate.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "osdc/Striper.h"
8 #include "librbd/AsyncObjectThrottle.h"
9 #include "librbd/ExclusiveLock.h"
10 #include "librbd/ImageCtx.h"
11 #include "librbd/ImageWatcher.h"
12 #include "librbd/internal.h"
13 #include "librbd/ObjectMap.h"
14 #include "librbd/operation/ResizeRequest.h"
15 #include "librbd/object_map/InvalidateRequest.h"
16 #include "librbd/Utils.h"
17 #include <boost/lambda/bind.hpp>
18 #include <boost/lambda/construct.hpp>
20 #define dout_subsys ceph_subsys_rbd
22 #define dout_prefix *_dout << "librbd::ObjectMapIterateRequest: "
30 class C_VerifyObjectCallback
: public C_AsyncObjectThrottle
<I
> {
32 C_VerifyObjectCallback(AsyncObjectThrottle
<I
> &throttle
, I
*image_ctx
,
33 uint64_t snap_id
, uint64_t object_no
,
34 ObjectIterateWork
<I
> handle_mismatch
,
35 std::atomic_flag
*invalidate
)
36 : C_AsyncObjectThrottle
<I
>(throttle
, *image_ctx
),
37 m_snap_id(snap_id
), m_object_no(object_no
),
38 m_oid(image_ctx
->get_object_name(m_object_no
)),
39 m_handle_mismatch(handle_mismatch
),
40 m_invalidate(invalidate
)
42 m_io_ctx
.dup(image_ctx
->data_ctx
);
43 m_io_ctx
.snap_set_read(CEPH_SNAPDIR
);
46 void complete(int r
) override
{
47 I
&image_ctx
= this->m_image_ctx
;
48 if (should_complete(r
)) {
49 ldout(image_ctx
.cct
, 20) << m_oid
<< " C_VerifyObjectCallback completed "
64 librados::IoCtx m_io_ctx
;
68 ObjectIterateWork
<I
> m_handle_mismatch
;
69 std::atomic_flag
*m_invalidate
;
71 librados::snap_set_t m_snap_set
;
72 int m_snap_list_ret
= 0;
74 bool should_complete(int r
) {
75 I
&image_ctx
= this->m_image_ctx
;
76 CephContext
*cct
= image_ctx
.cct
;
80 if (r
< 0 && r
!= -ENOENT
) {
81 lderr(cct
) << m_oid
<< " C_VerifyObjectCallback::should_complete: "
82 << "encountered an error: " << cpp_strerror(r
) << dendl
;
86 ldout(cct
, 20) << m_oid
<< " C_VerifyObjectCallback::should_complete: "
89 return object_map_action(get_object_state());
92 void send_list_snaps() {
93 I
&image_ctx
= this->m_image_ctx
;
94 ceph_assert(ceph_mutex_is_locked(image_ctx
.owner_lock
));
95 ldout(image_ctx
.cct
, 5) << m_oid
96 << " C_VerifyObjectCallback::send_list_snaps"
99 librados::ObjectReadOperation op
;
100 op
.list_snaps(&m_snap_set
, &m_snap_list_ret
);
102 librados::AioCompletion
*comp
= util::create_rados_callback(this);
103 int r
= m_io_ctx
.aio_operate(m_oid
, comp
, &op
, NULL
);
108 uint8_t get_object_state() {
109 I
&image_ctx
= this->m_image_ctx
;
110 std::shared_lock image_locker
{image_ctx
.image_lock
};
111 for (std::vector
<librados::clone_info_t
>::const_iterator r
=
112 m_snap_set
.clones
.begin(); r
!= m_snap_set
.clones
.end(); ++r
) {
113 librados::snap_t from_snap_id
;
114 librados::snap_t to_snap_id
;
115 if (r
->cloneid
== librados::SNAP_HEAD
) {
116 from_snap_id
= next_valid_snap_id(m_snap_set
.seq
+ 1);
117 to_snap_id
= librados::SNAP_HEAD
;
119 from_snap_id
= next_valid_snap_id(r
->snaps
[0]);
120 to_snap_id
= r
->snaps
[r
->snaps
.size()-1];
123 if (to_snap_id
< m_snap_id
) {
125 } else if (m_snap_id
< from_snap_id
) {
129 if ((image_ctx
.features
& RBD_FEATURE_FAST_DIFF
) != 0 &&
130 from_snap_id
!= m_snap_id
) {
131 return OBJECT_EXISTS_CLEAN
;
133 return OBJECT_EXISTS
;
135 return OBJECT_NONEXISTENT
;
138 uint64_t next_valid_snap_id(uint64_t snap_id
) {
139 I
&image_ctx
= this->m_image_ctx
;
140 ceph_assert(ceph_mutex_is_locked(image_ctx
.image_lock
));
142 std::map
<librados::snap_t
, SnapInfo
>::iterator it
=
143 image_ctx
.snap_info
.lower_bound(snap_id
);
144 if (it
== image_ctx
.snap_info
.end()) {
150 bool object_map_action(uint8_t new_state
) {
151 I
&image_ctx
= this->m_image_ctx
;
152 CephContext
*cct
= image_ctx
.cct
;
153 std::shared_lock owner_locker
{image_ctx
.owner_lock
};
155 // should have been canceled prior to releasing lock
156 ceph_assert(image_ctx
.exclusive_lock
== nullptr ||
157 image_ctx
.exclusive_lock
->is_lock_owner());
159 std::shared_lock image_locker
{image_ctx
.image_lock
};
160 ceph_assert(image_ctx
.object_map
!= nullptr);
162 uint8_t state
= (*image_ctx
.object_map
)[m_object_no
];
163 ldout(cct
, 10) << "C_VerifyObjectCallback::object_map_action"
164 << " object " << image_ctx
.get_object_name(m_object_no
)
165 << " state " << (int)state
166 << " new_state " << (int)new_state
<< dendl
;
168 if (state
!= new_state
) {
171 ceph_assert(m_handle_mismatch
);
172 r
= m_handle_mismatch(image_ctx
, m_object_no
, state
, new_state
);
174 lderr(cct
) << "object map error: object "
175 << image_ctx
.get_object_name(m_object_no
)
176 << " marked as " << (int)state
<< ", but should be "
177 << (int)new_state
<< dendl
;
178 m_invalidate
->test_and_set();
180 ldout(cct
, 1) << "object map inconsistent: object "
181 << image_ctx
.get_object_name(m_object_no
)
182 << " marked as " << (int)state
<< ", but should be "
183 << (int)new_state
<< dendl
;
191 } // anonymous namespace
193 template <typename I
>
194 void ObjectMapIterateRequest
<I
>::send() {
195 if (!m_image_ctx
.data_ctx
.is_valid()) {
196 this->async_complete(-ENODEV
);
200 send_verify_objects();
203 template <typename I
>
204 bool ObjectMapIterateRequest
<I
>::should_complete(int r
) {
205 CephContext
*cct
= m_image_ctx
.cct
;
206 ldout(cct
, 5) << this << " should_complete: " << " r=" << r
<< dendl
;
209 lderr(cct
) << "missing data pool" << dendl
;
214 lderr(cct
) << "object map operation encountered an error: "
215 << cpp_strerror(r
) << dendl
;
218 std::shared_lock owner_lock
{m_image_ctx
.owner_lock
};
220 case STATE_VERIFY_OBJECTS
:
221 if (m_invalidate
.test_and_set()) {
222 send_invalidate_object_map();
229 case STATE_INVALIDATE_OBJECT_MAP
:
247 template <typename I
>
248 void ObjectMapIterateRequest
<I
>::send_verify_objects() {
249 ceph_assert(ceph_mutex_is_locked(m_image_ctx
.owner_lock
));
250 CephContext
*cct
= m_image_ctx
.cct
;
253 uint64_t num_objects
;
255 std::shared_lock l
{m_image_ctx
.image_lock
};
256 snap_id
= m_image_ctx
.snap_id
;
257 num_objects
= Striper::get_num_objects(m_image_ctx
.layout
,
258 m_image_ctx
.get_image_size(snap_id
));
260 ldout(cct
, 5) << this << " send_verify_objects" << dendl
;
262 m_state
= STATE_VERIFY_OBJECTS
;
264 typename AsyncObjectThrottle
<I
>::ContextFactory
context_factory(
265 boost::lambda::bind(boost::lambda::new_ptr
<C_VerifyObjectCallback
<I
> >(),
266 boost::lambda::_1
, &m_image_ctx
, snap_id
,
267 boost::lambda::_2
, m_handle_mismatch
, &m_invalidate
));
268 AsyncObjectThrottle
<I
> *throttle
= new AsyncObjectThrottle
<I
>(
269 this, m_image_ctx
, context_factory
, this->create_callback_context(),
270 &m_prog_ctx
, 0, num_objects
);
272 m_image_ctx
.config
.template get_val
<uint64_t>("rbd_concurrent_management_ops"));
275 template <typename I
>
276 uint64_t ObjectMapIterateRequest
<I
>::get_image_size() const {
277 ceph_assert(ceph_mutex_is_locked(m_image_ctx
.image_lock
));
278 if (m_image_ctx
.snap_id
== CEPH_NOSNAP
) {
279 if (!m_image_ctx
.resize_reqs
.empty()) {
280 return m_image_ctx
.resize_reqs
.front()->get_image_size();
282 return m_image_ctx
.size
;
285 return m_image_ctx
.get_image_size(m_image_ctx
.snap_id
);
288 template <typename I
>
289 void ObjectMapIterateRequest
<I
>::send_invalidate_object_map() {
290 CephContext
*cct
= m_image_ctx
.cct
;
292 ldout(cct
, 5) << this << " send_invalidate_object_map" << dendl
;
293 m_state
= STATE_INVALIDATE_OBJECT_MAP
;
295 object_map::InvalidateRequest
<I
>*req
=
296 object_map::InvalidateRequest
<I
>::create(m_image_ctx
, m_image_ctx
.snap_id
,
298 this->create_callback_context());
300 ceph_assert(ceph_mutex_is_locked(m_image_ctx
.owner_lock
));
301 std::unique_lock image_locker
{m_image_ctx
.image_lock
};
305 } // namespace operation
306 } // namespace librbd
308 template class librbd::operation::ObjectMapIterateRequest
<librbd::ImageCtx
>;