]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/image/RefreshParentRequest.cc
update sources to v12.2.3
[ceph.git] / ceph / src / librbd / image / RefreshParentRequest.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
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"
14
15 #define dout_subsys ceph_subsys_rbd
16 #undef dout_prefix
17 #define dout_prefix *_dout << "librbd::image::RefreshParentRequest: "
18
19 namespace librbd {
20 namespace image {
21
22 using util::create_async_context_callback;
23 using util::create_context_callback;
24
25 template <typename I>
26 RefreshParentRequest<I>::RefreshParentRequest(I &child_image_ctx,
27 const ParentInfo &parent_md,
28 Context *on_finish)
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) {
32 }
33
34 template <typename I>
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));
41 }
42
43 template <typename I>
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));
48 }
49
50 template <typename I>
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));
58 }
59
60 template <typename I>
61 void RefreshParentRequest<I>::send() {
62 if (is_open_required(m_child_image_ctx, m_parent_md)) {
63 send_open_parent();
64 } else {
65 // parent will be closed (if necessary) during finalize
66 send_complete(0);
67 }
68 }
69
70 template <typename I>
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();
78 }
79 std::swap(m_child_image_ctx.parent, m_parent_image_ctx);
80 }
81
82 template <typename I>
83 void RefreshParentRequest<I>::finalize(Context *on_finish) {
84 CephContext *cct = m_child_image_ctx.cct;
85 ldout(cct, 10) << this << " " << __func__ << dendl;
86
87 m_on_finish = on_finish;
88 if (m_parent_image_ctx != nullptr) {
89 send_close_parent();
90 } else {
91 send_complete(0);
92 }
93 }
94
95 template <typename I>
96 void RefreshParentRequest<I>::send_open_parent() {
97 assert(m_parent_md.spec.pool_id >= 0);
98
99 CephContext *cct = m_child_image_ctx.cct;
100 ldout(cct, 10) << this << " " << __func__ << dendl;
101
102 librados::Rados rados(m_child_image_ctx.md_ctx);
103
104 librados::IoCtx parent_io_ctx;
105 int r = rados.ioctx_create2(m_parent_md.spec.pool_id, parent_io_ctx);
106 assert(r == 0);
107
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,
111 true);
112 m_parent_image_ctx->child = &m_child_image_ctx;
113
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);
119 }
120
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);
126 req->send();
127 }
128
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;
133
134 save_result(result);
135 if (*result < 0) {
136 lderr(cct) << "failed to open parent image: " << cpp_strerror(*result)
137 << dendl;
138
139 // image already closed by open state machine
140 delete m_parent_image_ctx;
141 m_parent_image_ctx = nullptr;
142
143 return m_on_finish;
144 }
145
146 send_set_parent_snap();
147 return nullptr;
148 }
149
150 template <typename I>
151 void RefreshParentRequest<I>::send_set_parent_snap() {
152 assert(m_parent_md.spec.snap_id != CEPH_NOSNAP);
153
154 CephContext *cct = m_child_image_ctx.cct;
155 ldout(cct, 10) << this << " " << __func__ << dendl;
156
157 cls::rbd::SnapshotNamespace snap_namespace;
158 std::string snap_name;
159 {
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);
162 if (!info) {
163 lderr(cct) << "failed to locate snapshot: Snapshot with this id not found" << dendl;
164 send_complete(-ENOENT);
165 return;
166 }
167 snap_namespace = info->snap_namespace;
168 snap_name = info->name;
169 }
170
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);
176 req->send();
177 }
178
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;
183
184 save_result(result);
185 if (*result < 0) {
186 lderr(cct) << "failed to set parent snapshot: " << cpp_strerror(*result)
187 << dendl;
188 send_close_parent();
189 return nullptr;
190 }
191
192 return m_on_finish;
193 }
194
195 template <typename I>
196 void RefreshParentRequest<I>::send_close_parent() {
197 assert(m_parent_image_ctx != nullptr);
198
199 CephContext *cct = m_child_image_ctx.cct;
200 ldout(cct, 10) << this << " " << __func__ << dendl;
201
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);
207 req->send();
208 }
209
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;
214
215 delete m_parent_image_ctx;
216 m_parent_image_ctx = nullptr;
217
218 if (*result < 0) {
219 lderr(cct) << "failed to close parent image: " << cpp_strerror(*result)
220 << dendl;
221 }
222
223 if (m_error_result < 0) {
224 // propagate errors from opening the image
225 *result = m_error_result;
226 } else {
227 // ignore errors from closing the image
228 *result = 0;
229 }
230
231 return m_on_finish;
232 }
233
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;
238
239 m_on_finish->complete(r);
240 }
241
242 } // namespace image
243 } // namespace librbd
244
245 template class librbd::image::RefreshParentRequest<librbd::ImageCtx>;