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 "common/WorkQueue.h"
9 #include "librbd/ImageCtx.h"
10 #include "librbd/Utils.h"
11 #include "librbd/image/CloseRequest.h"
12 #include "librbd/image/OpenRequest.h"
13 #include "librbd/image/SetSnapRequest.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(I
&child_image_ctx
,
27 const ParentInfo
&parent_md
,
29 : m_child_image_ctx(child_image_ctx
), m_parent_md(parent_md
),
30 m_on_finish(on_finish
), m_parent_image_ctx(nullptr),
31 m_parent_snap_id(CEPH_NOSNAP
), m_error_result(0) {
35 bool RefreshParentRequest
<I
>::is_refresh_required(I
&child_image_ctx
,
36 const ParentInfo
&parent_md
) {
37 assert(child_image_ctx
.snap_lock
.is_locked());
38 assert(child_image_ctx
.parent_lock
.is_locked());
39 return (is_open_required(child_image_ctx
, parent_md
) ||
40 is_close_required(child_image_ctx
, parent_md
));
44 bool RefreshParentRequest
<I
>::is_close_required(I
&child_image_ctx
,
45 const ParentInfo
&parent_md
) {
46 return (child_image_ctx
.parent
!= nullptr &&
47 (parent_md
.spec
.pool_id
== -1 || parent_md
.overlap
== 0));
51 bool RefreshParentRequest
<I
>::is_open_required(I
&child_image_ctx
,
52 const ParentInfo
&parent_md
) {
53 return (parent_md
.spec
.pool_id
> -1 && parent_md
.overlap
> 0 &&
54 (child_image_ctx
.parent
== nullptr ||
55 child_image_ctx
.parent
->md_ctx
.get_id() != parent_md
.spec
.pool_id
||
56 child_image_ctx
.parent
->id
!= parent_md
.spec
.image_id
||
57 child_image_ctx
.parent
->snap_id
!= parent_md
.spec
.snap_id
));
61 void RefreshParentRequest
<I
>::send() {
62 if (is_open_required(m_child_image_ctx
, m_parent_md
)) {
65 // parent will be closed (if necessary) during finalize
71 void RefreshParentRequest
<I
>::apply() {
72 if (m_child_image_ctx
.parent
!= nullptr) {
73 // closing parent image
74 m_child_image_ctx
.clear_nonexistence_cache();
76 assert(m_child_image_ctx
.snap_lock
.is_wlocked());
77 assert(m_child_image_ctx
.parent_lock
.is_wlocked());
78 std::swap(m_child_image_ctx
.parent
, m_parent_image_ctx
);
82 void RefreshParentRequest
<I
>::finalize(Context
*on_finish
) {
83 CephContext
*cct
= m_child_image_ctx
.cct
;
84 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
86 m_on_finish
= on_finish
;
87 if (m_parent_image_ctx
!= nullptr) {
95 void RefreshParentRequest
<I
>::send_open_parent() {
96 assert(m_parent_md
.spec
.pool_id
>= 0);
98 CephContext
*cct
= m_child_image_ctx
.cct
;
99 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
101 librados::Rados
rados(m_child_image_ctx
.md_ctx
);
103 librados::IoCtx parent_io_ctx
;
104 int r
= rados
.ioctx_create2(m_parent_md
.spec
.pool_id
, parent_io_ctx
);
107 // since we don't know the image and snapshot name, set their ids and
108 // reset the snap_name and snap_exists fields after we read the header
109 m_parent_image_ctx
= new I("", m_parent_md
.spec
.image_id
, NULL
, parent_io_ctx
,
112 // set rados flags for reading the parent image
113 if (m_child_image_ctx
.balance_parent_reads
) {
114 m_parent_image_ctx
->set_read_flag(librados::OPERATION_BALANCE_READS
);
115 } else if (m_child_image_ctx
.localize_parent_reads
) {
116 m_parent_image_ctx
->set_read_flag(librados::OPERATION_LOCALIZE_READS
);
119 using klass
= RefreshParentRequest
<I
>;
120 Context
*ctx
= create_async_context_callback(
121 m_child_image_ctx
, create_context_callback
<
122 klass
, &klass::handle_open_parent
, false>(this));
123 OpenRequest
<I
> *req
= OpenRequest
<I
>::create(m_parent_image_ctx
, false, ctx
);
127 template <typename I
>
128 Context
*RefreshParentRequest
<I
>::handle_open_parent(int *result
) {
129 CephContext
*cct
= m_child_image_ctx
.cct
;
130 ldout(cct
, 10) << this << " " << __func__
<< " r=" << *result
<< dendl
;
134 lderr(cct
) << "failed to open parent image: " << cpp_strerror(*result
)
137 // image already closed by open state machine
138 delete m_parent_image_ctx
;
139 m_parent_image_ctx
= nullptr;
144 send_set_parent_snap();
148 template <typename I
>
149 void RefreshParentRequest
<I
>::send_set_parent_snap() {
150 assert(m_parent_md
.spec
.snap_id
!= CEPH_NOSNAP
);
152 CephContext
*cct
= m_child_image_ctx
.cct
;
153 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
155 cls::rbd::SnapshotNamespace snap_namespace
;
156 std::string snap_name
;
158 RWLock::RLocker
snap_locker(m_parent_image_ctx
->snap_lock
);
159 const SnapInfo
*info
= m_parent_image_ctx
->get_snap_info(m_parent_md
.spec
.snap_id
);
161 lderr(cct
) << "failed to locate snapshot: Snapshot with this id not found" << dendl
;
162 send_complete(-ENOENT
);
165 snap_namespace
= info
->snap_namespace
;
166 snap_name
= info
->name
;
169 using klass
= RefreshParentRequest
<I
>;
170 Context
*ctx
= create_context_callback
<
171 klass
, &klass::handle_set_parent_snap
, false>(this);
172 SetSnapRequest
<I
> *req
= SetSnapRequest
<I
>::create(
173 *m_parent_image_ctx
, snap_namespace
, snap_name
, ctx
);
177 template <typename I
>
178 Context
*RefreshParentRequest
<I
>::handle_set_parent_snap(int *result
) {
179 CephContext
*cct
= m_child_image_ctx
.cct
;
180 ldout(cct
, 10) << this << " " << __func__
<< " r=" << *result
<< dendl
;
184 lderr(cct
) << "failed to set parent snapshot: " << cpp_strerror(*result
)
193 template <typename I
>
194 void RefreshParentRequest
<I
>::send_close_parent() {
195 assert(m_parent_image_ctx
!= nullptr);
197 CephContext
*cct
= m_child_image_ctx
.cct
;
198 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
200 using klass
= RefreshParentRequest
<I
>;
201 Context
*ctx
= create_async_context_callback(
202 m_child_image_ctx
, create_context_callback
<
203 klass
, &klass::handle_close_parent
, false>(this));
204 CloseRequest
<I
> *req
= CloseRequest
<I
>::create(m_parent_image_ctx
, ctx
);
208 template <typename I
>
209 Context
*RefreshParentRequest
<I
>::handle_close_parent(int *result
) {
210 CephContext
*cct
= m_child_image_ctx
.cct
;
211 ldout(cct
, 10) << this << " " << __func__
<< " r=" << *result
<< dendl
;
213 delete m_parent_image_ctx
;
215 lderr(cct
) << "failed to close parent image: " << cpp_strerror(*result
)
219 if (m_error_result
< 0) {
220 // propagate errors from opening the image
221 *result
= m_error_result
;
223 // ignore errors from closing the image
230 template <typename I
>
231 void RefreshParentRequest
<I
>::send_complete(int r
) {
232 CephContext
*cct
= m_child_image_ctx
.cct
;
233 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
235 m_on_finish
->complete(r
);
239 } // namespace librbd
241 template class librbd::image::RefreshParentRequest
<librbd::ImageCtx
>;