]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/image/RefreshParentRequest.cc
add subtree-ish sources for 12.0.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 if (m_child_image_ctx.parent != nullptr) {
73 // closing parent image
74 m_child_image_ctx.clear_nonexistence_cache();
75 }
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);
79 }
80
81 template <typename I>
82 void RefreshParentRequest<I>::finalize(Context *on_finish) {
83 CephContext *cct = m_child_image_ctx.cct;
84 ldout(cct, 10) << this << " " << __func__ << dendl;
85
86 m_on_finish = on_finish;
87 if (m_parent_image_ctx != nullptr) {
88 send_close_parent();
89 } else {
90 send_complete(0);
91 }
92 }
93
94 template <typename I>
95 void RefreshParentRequest<I>::send_open_parent() {
96 assert(m_parent_md.spec.pool_id >= 0);
97
98 CephContext *cct = m_child_image_ctx.cct;
99 ldout(cct, 10) << this << " " << __func__ << dendl;
100
101 librados::Rados rados(m_child_image_ctx.md_ctx);
102
103 librados::IoCtx parent_io_ctx;
104 int r = rados.ioctx_create2(m_parent_md.spec.pool_id, parent_io_ctx);
105 assert(r == 0);
106
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,
110 true);
111
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);
117 }
118
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);
124 req->send();
125 }
126
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;
131
132 save_result(result);
133 if (*result < 0) {
134 lderr(cct) << "failed to open parent image: " << cpp_strerror(*result)
135 << dendl;
136
137 // image already closed by open state machine
138 delete m_parent_image_ctx;
139 m_parent_image_ctx = nullptr;
140
141 return m_on_finish;
142 }
143
144 send_set_parent_snap();
145 return nullptr;
146 }
147
148 template <typename I>
149 void RefreshParentRequest<I>::send_set_parent_snap() {
150 assert(m_parent_md.spec.snap_id != CEPH_NOSNAP);
151
152 CephContext *cct = m_child_image_ctx.cct;
153 ldout(cct, 10) << this << " " << __func__ << dendl;
154
155 cls::rbd::SnapshotNamespace snap_namespace;
156 std::string snap_name;
157 {
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);
160 if (!info) {
161 lderr(cct) << "failed to locate snapshot: Snapshot with this id not found" << dendl;
162 send_complete(-ENOENT);
163 return;
164 }
165 snap_namespace = info->snap_namespace;
166 snap_name = info->name;
167 }
168
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);
174 req->send();
175 }
176
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;
181
182 save_result(result);
183 if (*result < 0) {
184 lderr(cct) << "failed to set parent snapshot: " << cpp_strerror(*result)
185 << dendl;
186 send_close_parent();
187 return nullptr;
188 }
189
190 return m_on_finish;
191 }
192
193 template <typename I>
194 void RefreshParentRequest<I>::send_close_parent() {
195 assert(m_parent_image_ctx != nullptr);
196
197 CephContext *cct = m_child_image_ctx.cct;
198 ldout(cct, 10) << this << " " << __func__ << dendl;
199
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);
205 req->send();
206 }
207
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;
212
213 delete m_parent_image_ctx;
214 if (*result < 0) {
215 lderr(cct) << "failed to close parent image: " << cpp_strerror(*result)
216 << dendl;
217 }
218
219 if (m_error_result < 0) {
220 // propagate errors from opening the image
221 *result = m_error_result;
222 } else {
223 // ignore errors from closing the image
224 *result = 0;
225 }
226
227 return m_on_finish;
228 }
229
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;
234
235 m_on_finish->complete(r);
236 }
237
238 } // namespace image
239 } // namespace librbd
240
241 template class librbd::image::RefreshParentRequest<librbd::ImageCtx>;