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/MigrateRequest.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "librbd/AsyncObjectThrottle.h"
8 #include "librbd/ExclusiveLock.h"
9 #include "librbd/ImageCtx.h"
10 #include "librbd/Utils.h"
11 #include "librbd/deep_copy/ObjectCopyRequest.h"
12 #include "librbd/io/AsyncOperation.h"
13 #include "librbd/io/ImageRequestWQ.h"
14 #include "librbd/io/ObjectRequest.h"
15 #include "osdc/Striper.h"
16 #include <boost/lambda/bind.hpp>
17 #include <boost/lambda/construct.hpp>
19 #define dout_subsys ceph_subsys_rbd
21 #define dout_prefix *_dout << "librbd::MigrateRequest: " << this << " " \
27 using util::create_context_callback
;
28 using util::create_async_context_callback
;
33 class C_MigrateObject
: public C_AsyncObjectThrottle
<I
> {
35 C_MigrateObject(AsyncObjectThrottle
<I
> &throttle
, I
*image_ctx
,
36 ::SnapContext snapc
, uint64_t object_no
)
37 : C_AsyncObjectThrottle
<I
>(throttle
, *image_ctx
), m_snapc(snapc
),
38 m_object_no(object_no
) {
42 I
&image_ctx
= this->m_image_ctx
;
43 ceph_assert(ceph_mutex_is_locked(image_ctx
.owner_lock
));
44 CephContext
*cct
= image_ctx
.cct
;
46 if (image_ctx
.exclusive_lock
!= nullptr &&
47 !image_ctx
.exclusive_lock
->is_lock_owner()) {
48 ldout(cct
, 1) << "lost exclusive lock during migrate" << dendl
;
57 ::SnapContext m_snapc
;
60 io::AsyncOperation
*m_async_op
= nullptr;
62 void start_async_op() {
63 I
&image_ctx
= this->m_image_ctx
;
64 ceph_assert(ceph_mutex_is_locked(image_ctx
.owner_lock
));
65 CephContext
*cct
= image_ctx
.cct
;
66 ldout(cct
, 10) << dendl
;
68 ceph_assert(m_async_op
== nullptr);
69 m_async_op
= new io::AsyncOperation();
70 m_async_op
->start_op(image_ctx
);
72 if (!image_ctx
.io_work_queue
->writes_blocked()) {
77 auto ctx
= create_async_context_callback(
78 image_ctx
, create_context_callback
<
79 C_MigrateObject
<I
>, &C_MigrateObject
<I
>::handle_start_async_op
>(this));
80 m_async_op
->finish_op();
83 image_ctx
.io_work_queue
->wait_on_writes_unblocked(ctx
);
86 void handle_start_async_op(int r
) {
87 I
&image_ctx
= this->m_image_ctx
;
88 CephContext
*cct
= image_ctx
.cct
;
89 ldout(cct
, 10) << "r=" << r
<< dendl
;
92 lderr(cct
) << "failed to start async op: " << cpp_strerror(r
) << dendl
;
97 std::shared_lock owner_locker
{image_ctx
.owner_lock
};
101 bool is_within_overlap_bounds() {
102 I
&image_ctx
= this->m_image_ctx
;
103 std::shared_lock image_locker
{image_ctx
.image_lock
};
105 auto overlap
= std::min(image_ctx
.size
, image_ctx
.migration_info
.overlap
);
106 return overlap
> 0 &&
107 Striper::get_num_objects(image_ctx
.layout
, overlap
) > m_object_no
;
110 void migrate_object() {
111 I
&image_ctx
= this->m_image_ctx
;
112 ceph_assert(ceph_mutex_is_locked(image_ctx
.owner_lock
));
113 CephContext
*cct
= image_ctx
.cct
;
115 auto ctx
= create_context_callback
<
116 C_MigrateObject
<I
>, &C_MigrateObject
<I
>::handle_migrate_object
>(this);
118 if (is_within_overlap_bounds()) {
120 auto req
= new io::ObjectWriteRequest
<I
>(&image_ctx
, m_object_no
, 0,
121 std::move(bl
), m_snapc
, 0, {},
124 ldout(cct
, 20) << "copyup object req " << req
<< ", object_no "
125 << m_object_no
<< dendl
;
129 ceph_assert(image_ctx
.parent
!= nullptr);
131 auto req
= deep_copy::ObjectCopyRequest
<I
>::create(
132 image_ctx
.parent
, &image_ctx
, 0, 0, image_ctx
.migration_info
.snap_map
,
133 m_object_no
, image_ctx
.migration_info
.flatten
, nullptr, ctx
);
135 ldout(cct
, 20) << "deep copy object req " << req
<< ", object_no "
136 << m_object_no
<< dendl
;
141 void handle_migrate_object(int r
) {
142 CephContext
*cct
= this->m_image_ctx
.cct
;
143 ldout(cct
, 10) << "r=" << r
<< dendl
;
149 m_async_op
->finish_op();
155 } // anonymous namespace
157 template <typename I
>
158 void MigrateRequest
<I
>::send_op() {
159 I
&image_ctx
= this->m_image_ctx
;
160 ceph_assert(ceph_mutex_is_locked(image_ctx
.owner_lock
));
161 CephContext
*cct
= image_ctx
.cct
;
162 ldout(cct
, 10) << dendl
;
167 template <typename I
>
168 bool MigrateRequest
<I
>::should_complete(int r
) {
169 I
&image_ctx
= this->m_image_ctx
;
170 CephContext
*cct
= image_ctx
.cct
;
171 ldout(cct
, 10) << "r=" << r
<< dendl
;
174 lderr(cct
) << "encountered error: " << cpp_strerror(r
) << dendl
;
180 template <typename I
>
181 void MigrateRequest
<I
>::migrate_objects() {
182 I
&image_ctx
= this->m_image_ctx
;
183 CephContext
*cct
= image_ctx
.cct
;
184 ceph_assert(ceph_mutex_is_locked(image_ctx
.owner_lock
));
186 uint64_t overlap_objects
= get_num_overlap_objects();
188 ldout(cct
, 10) << "from 0 to " << overlap_objects
<< dendl
;
190 auto ctx
= create_context_callback
<
191 MigrateRequest
<I
>, &MigrateRequest
<I
>::handle_migrate_objects
>(this);
193 typename AsyncObjectThrottle
<I
>::ContextFactory
context_factory(
194 boost::lambda::bind(boost::lambda::new_ptr
<C_MigrateObject
<I
> >(),
195 boost::lambda::_1
, &image_ctx
, image_ctx
.snapc
, boost::lambda::_2
));
196 AsyncObjectThrottle
<I
> *throttle
= new AsyncObjectThrottle
<I
>(
197 this, image_ctx
, context_factory
, ctx
, &m_prog_ctx
, 0, overlap_objects
);
199 image_ctx
.config
.template get_val
<uint64_t>("rbd_concurrent_management_ops"));
202 template <typename I
>
203 void MigrateRequest
<I
>::handle_migrate_objects(int r
) {
204 I
&image_ctx
= this->m_image_ctx
;
205 CephContext
*cct
= image_ctx
.cct
;
206 ldout(cct
, 5) << "r=" << r
<< dendl
;
209 lderr(cct
) << "failed to migrate objects: " << cpp_strerror(r
) << dendl
;
215 template <typename I
>
216 uint64_t MigrateRequest
<I
>::get_num_overlap_objects() {
217 I
&image_ctx
= this->m_image_ctx
;
218 CephContext
*cct
= image_ctx
.cct
;
219 ldout(cct
, 10) << dendl
;
221 std::shared_lock image_locker
{image_ctx
.image_lock
};
223 auto overlap
= image_ctx
.migration_info
.overlap
;
226 Striper::get_num_objects(image_ctx
.layout
, overlap
) : 0;
229 } // namespace operation
230 } // namespace librbd
232 template class librbd::operation::MigrateRequest
<librbd::ImageCtx
>;