1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/image/RefreshParentRequest.h"
5 #include "include/rados/librados.hpp"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "librbd/ImageCtx.h"
9 #include "librbd/ImageState.h"
10 #include "librbd/Utils.h"
11 #include "librbd/asio/ContextWQ.h"
12 #include "librbd/io/ObjectDispatcherInterface.h"
13 #include "librbd/migration/OpenSourceImageRequest.h"
15 #define dout_subsys ceph_subsys_rbd
17 #define dout_prefix *_dout << "librbd::image::RefreshParentRequest: "
22 using util::create_async_context_callback
;
23 using util::create_context_callback
;
26 RefreshParentRequest
<I
>::RefreshParentRequest(
27 I
&child_image_ctx
, const ParentImageInfo
&parent_md
,
28 const MigrationInfo
&migration_info
, Context
*on_finish
)
29 : m_child_image_ctx(child_image_ctx
), m_parent_md(parent_md
),
30 m_migration_info(migration_info
), m_on_finish(on_finish
),
31 m_parent_image_ctx(nullptr), m_parent_snap_id(CEPH_NOSNAP
),
36 bool RefreshParentRequest
<I
>::is_refresh_required(
37 I
&child_image_ctx
, const ParentImageInfo
&parent_md
,
38 const MigrationInfo
&migration_info
) {
39 ceph_assert(ceph_mutex_is_locked(child_image_ctx
.image_lock
));
40 return (is_open_required(child_image_ctx
, parent_md
, migration_info
) ||
41 is_close_required(child_image_ctx
, parent_md
, migration_info
));
45 bool RefreshParentRequest
<I
>::is_close_required(
46 I
&child_image_ctx
, const ParentImageInfo
&parent_md
,
47 const MigrationInfo
&migration_info
) {
48 return (child_image_ctx
.parent
!= nullptr &&
49 !does_parent_exist(child_image_ctx
, parent_md
, migration_info
));
53 bool RefreshParentRequest
<I
>::is_open_required(
54 I
&child_image_ctx
, const ParentImageInfo
&parent_md
,
55 const MigrationInfo
&migration_info
) {
56 return (does_parent_exist(child_image_ctx
, parent_md
, migration_info
) &&
57 (child_image_ctx
.parent
== nullptr ||
58 child_image_ctx
.parent
->md_ctx
.get_id() != parent_md
.spec
.pool_id
||
59 child_image_ctx
.parent
->md_ctx
.get_namespace() !=
60 parent_md
.spec
.pool_namespace
||
61 child_image_ctx
.parent
->id
!= parent_md
.spec
.image_id
||
62 child_image_ctx
.parent
->snap_id
!= parent_md
.spec
.snap_id
));
66 bool RefreshParentRequest
<I
>::does_parent_exist(
67 I
&child_image_ctx
, const ParentImageInfo
&parent_md
,
68 const MigrationInfo
&migration_info
) {
69 if (child_image_ctx
.child
!= nullptr &&
70 child_image_ctx
.child
->migration_info
.empty() && parent_md
.overlap
== 0) {
71 // intermediate, non-migrating images should only open their parent if they
76 return (parent_md
.spec
.pool_id
> -1 && parent_md
.overlap
> 0) ||
77 !migration_info
.empty();
81 void RefreshParentRequest
<I
>::send() {
82 if (is_open_required(m_child_image_ctx
, m_parent_md
, m_migration_info
)) {
85 // parent will be closed (if necessary) during finalize
91 void RefreshParentRequest
<I
>::apply() {
92 ceph_assert(ceph_mutex_is_wlocked(m_child_image_ctx
.image_lock
));
93 std::swap(m_child_image_ctx
.parent
, m_parent_image_ctx
);
97 void RefreshParentRequest
<I
>::finalize(Context
*on_finish
) {
98 CephContext
*cct
= m_child_image_ctx
.cct
;
99 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
101 m_on_finish
= on_finish
;
102 if (m_parent_image_ctx
!= nullptr) {
109 template <typename I
>
110 void RefreshParentRequest
<I
>::send_open_parent() {
111 ceph_assert(m_parent_md
.spec
.pool_id
>= 0);
113 CephContext
*cct
= m_child_image_ctx
.cct
;
114 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
116 if (!m_migration_info
.empty()) {
117 auto ctx
= create_async_context_callback(
118 m_child_image_ctx
, create_context_callback
<
119 RefreshParentRequest
<I
>,
120 &RefreshParentRequest
<I
>::handle_open_parent
, false>(this));
121 auto req
= migration::OpenSourceImageRequest
<I
>::create(
122 m_child_image_ctx
.md_ctx
, &m_child_image_ctx
, m_parent_md
.spec
.snap_id
,
123 m_migration_info
, &m_parent_image_ctx
, ctx
);
128 librados::IoCtx parent_io_ctx
;
129 int r
= util::create_ioctx(m_child_image_ctx
.md_ctx
, "parent image",
130 m_parent_md
.spec
.pool_id
,
131 m_parent_md
.spec
.pool_namespace
, &parent_io_ctx
);
137 m_parent_image_ctx
= new I("", m_parent_md
.spec
.image_id
,
138 m_parent_md
.spec
.snap_id
, parent_io_ctx
, true);
139 m_parent_image_ctx
->child
= &m_child_image_ctx
;
141 // set rados flags for reading the parent image
142 if (m_child_image_ctx
.config
.template get_val
<bool>("rbd_balance_parent_reads")) {
143 m_parent_image_ctx
->set_read_flag(librados::OPERATION_BALANCE_READS
);
144 } else if (m_child_image_ctx
.config
.template get_val
<bool>("rbd_localize_parent_reads")) {
145 m_parent_image_ctx
->set_read_flag(librados::OPERATION_LOCALIZE_READS
);
148 auto ctx
= create_async_context_callback(
149 m_child_image_ctx
, create_context_callback
<
150 RefreshParentRequest
<I
>,
151 &RefreshParentRequest
<I
>::handle_open_parent
, false>(this));
152 m_parent_image_ctx
->state
->open(0U, ctx
);
155 template <typename I
>
156 Context
*RefreshParentRequest
<I
>::handle_open_parent(int *result
) {
157 CephContext
*cct
= m_child_image_ctx
.cct
;
158 ldout(cct
, 10) << this << " " << __func__
<< " r=" << *result
<< dendl
;
162 lderr(cct
) << "failed to open parent image: " << cpp_strerror(*result
)
165 // image already closed by open state machine
166 m_parent_image_ctx
= nullptr;
172 template <typename I
>
173 void RefreshParentRequest
<I
>::send_close_parent() {
174 ceph_assert(m_parent_image_ctx
!= nullptr);
176 CephContext
*cct
= m_child_image_ctx
.cct
;
177 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
179 auto ctx
= create_async_context_callback(
180 m_child_image_ctx
, create_context_callback
<
181 RefreshParentRequest
<I
>,
182 &RefreshParentRequest
<I
>::handle_close_parent
, false>(this));
183 m_parent_image_ctx
->state
->close(ctx
);
186 template <typename I
>
187 Context
*RefreshParentRequest
<I
>::handle_close_parent(int *result
) {
188 CephContext
*cct
= m_child_image_ctx
.cct
;
189 ldout(cct
, 10) << this << " " << __func__
<< " r=" << *result
<< dendl
;
191 m_parent_image_ctx
= nullptr;
194 lderr(cct
) << "failed to close parent image: " << cpp_strerror(*result
)
198 send_reset_existence_cache();
202 template <typename I
>
203 void RefreshParentRequest
<I
>::send_reset_existence_cache() {
204 CephContext
*cct
= m_child_image_ctx
.cct
;
205 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
207 Context
*ctx
= create_async_context_callback(
208 m_child_image_ctx
, create_context_callback
<
209 RefreshParentRequest
<I
>,
210 &RefreshParentRequest
<I
>::handle_reset_existence_cache
, false>(this));
211 m_child_image_ctx
.io_object_dispatcher
->reset_existence_cache(ctx
);
214 template <typename I
>
215 Context
*RefreshParentRequest
<I
>::handle_reset_existence_cache(int *result
) {
216 CephContext
*cct
= m_child_image_ctx
.cct
;
217 ldout(cct
, 10) << this << " " << __func__
<< " r=" << *result
<< dendl
;
220 lderr(cct
) << "failed to reset object existence cache: "
221 << cpp_strerror(*result
) << dendl
;
224 if (m_error_result
< 0) {
225 // propagate errors from opening the image
226 *result
= m_error_result
;
233 template <typename I
>
234 void RefreshParentRequest
<I
>::send_complete(int r
) {
235 CephContext
*cct
= m_child_image_ctx
.cct
;
236 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
238 m_on_finish
->complete(r
);
242 } // namespace librbd
244 template class librbd::image::RefreshParentRequest
<librbd::ImageCtx
>;