]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/image/RefreshParentRequest.cc
bump version to 18.2.2-pve1
[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 "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"
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(
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),
32 m_error_result(0) {
33 }
34
35 template <typename I>
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));
42 }
43
44 template <typename I>
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));
50 }
51
52 template <typename I>
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));
63 }
64
65 template <typename I>
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
72 // overlap
73 return false;
74 }
75
76 return (parent_md.spec.pool_id > -1 && parent_md.overlap > 0) ||
77 !migration_info.empty();
78 }
79
80 template <typename I>
81 void RefreshParentRequest<I>::send() {
82 if (is_open_required(m_child_image_ctx, m_parent_md, m_migration_info)) {
83 send_open_parent();
84 } else {
85 // parent will be closed (if necessary) during finalize
86 send_complete(0);
87 }
88 }
89
90 template <typename I>
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);
94 }
95
96 template <typename I>
97 void RefreshParentRequest<I>::finalize(Context *on_finish) {
98 CephContext *cct = m_child_image_ctx.cct;
99 ldout(cct, 10) << this << " " << __func__ << dendl;
100
101 m_on_finish = on_finish;
102 if (m_parent_image_ctx != nullptr) {
103 send_close_parent();
104 } else {
105 send_complete(0);
106 }
107 }
108
109 template <typename I>
110 void RefreshParentRequest<I>::send_open_parent() {
111 ceph_assert(m_parent_md.spec.pool_id >= 0);
112
113 CephContext *cct = m_child_image_ctx.cct;
114 ldout(cct, 10) << this << " " << __func__ << dendl;
115
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);
124 req->send();
125 return;
126 }
127
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);
132 if (r < 0) {
133 send_complete(r);
134 return;
135 }
136
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;
140
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);
146 }
147
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);
153 }
154
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;
159
160 save_result(result);
161 if (*result < 0) {
162 lderr(cct) << "failed to open parent image: " << cpp_strerror(*result)
163 << dendl;
164
165 // image already closed by open state machine
166 m_parent_image_ctx = nullptr;
167 }
168
169 return m_on_finish;
170 }
171
172 template <typename I>
173 void RefreshParentRequest<I>::send_close_parent() {
174 ceph_assert(m_parent_image_ctx != nullptr);
175
176 CephContext *cct = m_child_image_ctx.cct;
177 ldout(cct, 10) << this << " " << __func__ << dendl;
178
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);
184 }
185
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;
190
191 m_parent_image_ctx = nullptr;
192
193 if (*result < 0) {
194 lderr(cct) << "failed to close parent image: " << cpp_strerror(*result)
195 << dendl;
196 }
197
198 send_reset_existence_cache();
199 return nullptr;
200 }
201
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;
206
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);
212 }
213
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;
218
219 if (*result < 0) {
220 lderr(cct) << "failed to reset object existence cache: "
221 << cpp_strerror(*result) << dendl;
222 }
223
224 if (m_error_result < 0) {
225 // propagate errors from opening the image
226 *result = m_error_result;
227 } else {
228 *result = 0;
229 }
230 return m_on_finish;
231 }
232
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;
237
238 m_on_finish->complete(r);
239 }
240
241 } // namespace image
242 } // namespace librbd
243
244 template class librbd::image::RefreshParentRequest<librbd::ImageCtx>;