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 assert(m_child_image_ctx
.cache_lock
.is_locked());
73 assert(m_child_image_ctx
.snap_lock
.is_wlocked());
74 assert(m_child_image_ctx
.parent_lock
.is_wlocked());
75 if (m_child_image_ctx
.parent
!= nullptr) {
76 // closing parent image
77 m_child_image_ctx
.clear_nonexistence_cache();
79 std::swap(m_child_image_ctx
.parent
, m_parent_image_ctx
);
83 void RefreshParentRequest
<I
>::finalize(Context
*on_finish
) {
84 CephContext
*cct
= m_child_image_ctx
.cct
;
85 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
87 m_on_finish
= on_finish
;
88 if (m_parent_image_ctx
!= nullptr) {
96 void RefreshParentRequest
<I
>::send_open_parent() {
97 assert(m_parent_md
.spec
.pool_id
>= 0);
99 CephContext
*cct
= m_child_image_ctx
.cct
;
100 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
102 librados::Rados
rados(m_child_image_ctx
.md_ctx
);
104 librados::IoCtx parent_io_ctx
;
105 int r
= rados
.ioctx_create2(m_parent_md
.spec
.pool_id
, parent_io_ctx
);
108 // since we don't know the image and snapshot name, set their ids and
109 // reset the snap_name and snap_exists fields after we read the header
110 m_parent_image_ctx
= new I("", m_parent_md
.spec
.image_id
, NULL
, parent_io_ctx
,
112 m_parent_image_ctx
->child
= &m_child_image_ctx
;
114 // set rados flags for reading the parent image
115 if (m_child_image_ctx
.balance_parent_reads
) {
116 m_parent_image_ctx
->set_read_flag(librados::OPERATION_BALANCE_READS
);
117 } else if (m_child_image_ctx
.localize_parent_reads
) {
118 m_parent_image_ctx
->set_read_flag(librados::OPERATION_LOCALIZE_READS
);
121 using klass
= RefreshParentRequest
<I
>;
122 Context
*ctx
= create_async_context_callback(
123 m_child_image_ctx
, create_context_callback
<
124 klass
, &klass::handle_open_parent
, false>(this));
125 OpenRequest
<I
> *req
= OpenRequest
<I
>::create(m_parent_image_ctx
, false, ctx
);
129 template <typename I
>
130 Context
*RefreshParentRequest
<I
>::handle_open_parent(int *result
) {
131 CephContext
*cct
= m_child_image_ctx
.cct
;
132 ldout(cct
, 10) << this << " " << __func__
<< " r=" << *result
<< dendl
;
136 lderr(cct
) << "failed to open parent image: " << cpp_strerror(*result
)
139 // image already closed by open state machine
140 delete m_parent_image_ctx
;
141 m_parent_image_ctx
= nullptr;
146 send_set_parent_snap();
150 template <typename I
>
151 void RefreshParentRequest
<I
>::send_set_parent_snap() {
152 assert(m_parent_md
.spec
.snap_id
!= CEPH_NOSNAP
);
154 CephContext
*cct
= m_child_image_ctx
.cct
;
155 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
157 cls::rbd::SnapshotNamespace snap_namespace
;
158 std::string snap_name
;
160 RWLock::RLocker
snap_locker(m_parent_image_ctx
->snap_lock
);
161 const SnapInfo
*info
= m_parent_image_ctx
->get_snap_info(m_parent_md
.spec
.snap_id
);
163 lderr(cct
) << "failed to locate snapshot: Snapshot with this id not found" << dendl
;
164 send_complete(-ENOENT
);
167 snap_namespace
= info
->snap_namespace
;
168 snap_name
= info
->name
;
171 using klass
= RefreshParentRequest
<I
>;
172 Context
*ctx
= create_context_callback
<
173 klass
, &klass::handle_set_parent_snap
, false>(this);
174 SetSnapRequest
<I
> *req
= SetSnapRequest
<I
>::create(
175 *m_parent_image_ctx
, snap_namespace
, snap_name
, ctx
);
179 template <typename I
>
180 Context
*RefreshParentRequest
<I
>::handle_set_parent_snap(int *result
) {
181 CephContext
*cct
= m_child_image_ctx
.cct
;
182 ldout(cct
, 10) << this << " " << __func__
<< " r=" << *result
<< dendl
;
186 lderr(cct
) << "failed to set parent snapshot: " << cpp_strerror(*result
)
195 template <typename I
>
196 void RefreshParentRequest
<I
>::send_close_parent() {
197 assert(m_parent_image_ctx
!= nullptr);
199 CephContext
*cct
= m_child_image_ctx
.cct
;
200 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
202 using klass
= RefreshParentRequest
<I
>;
203 Context
*ctx
= create_async_context_callback(
204 m_child_image_ctx
, create_context_callback
<
205 klass
, &klass::handle_close_parent
, false>(this));
206 CloseRequest
<I
> *req
= CloseRequest
<I
>::create(m_parent_image_ctx
, ctx
);
210 template <typename I
>
211 Context
*RefreshParentRequest
<I
>::handle_close_parent(int *result
) {
212 CephContext
*cct
= m_child_image_ctx
.cct
;
213 ldout(cct
, 10) << this << " " << __func__
<< " r=" << *result
<< dendl
;
215 delete m_parent_image_ctx
;
216 m_parent_image_ctx
= nullptr;
219 lderr(cct
) << "failed to close parent image: " << cpp_strerror(*result
)
223 if (m_error_result
< 0) {
224 // propagate errors from opening the image
225 *result
= m_error_result
;
227 // ignore errors from closing the image
234 template <typename I
>
235 void RefreshParentRequest
<I
>::send_complete(int r
) {
236 CephContext
*cct
= m_child_image_ctx
.cct
;
237 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
239 m_on_finish
->complete(r
);
243 } // namespace librbd
245 template class librbd::image::RefreshParentRequest
<librbd::ImageCtx
>;