]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "LoadRequest.h" | |
5 | ||
6 | #include "common/dout.h" | |
7 | #include "common/errno.h" | |
8 | #include "librbd/Utils.h" | |
9 | #include "librbd/ImageCtx.h" | |
1e59de90 TL |
10 | #include "librbd/crypto/EncryptionFormat.h" |
11 | #include "librbd/crypto/Types.h" | |
f67539c2 | 12 | #include "librbd/crypto/Utils.h" |
1e59de90 TL |
13 | #include "librbd/io/AioCompletion.h" |
14 | #include "librbd/io/ImageDispatcherInterface.h" | |
15 | #include "librbd/io/ImageDispatchSpec.h" | |
16 | #include "librbd/io/Types.h" | |
f67539c2 TL |
17 | |
18 | #define dout_subsys ceph_subsys_rbd | |
19 | #undef dout_prefix | |
20 | #define dout_prefix *_dout << "librbd::crypto::LoadRequest: " << this \ | |
21 | << " " << __func__ << ": " | |
22 | ||
23 | namespace librbd { | |
24 | namespace crypto { | |
25 | ||
26 | using librbd::util::create_context_callback; | |
27 | ||
28 | template <typename I> | |
29 | LoadRequest<I>::LoadRequest( | |
1e59de90 | 30 | I* image_ctx, std::vector<EncryptionFormat>&& formats, |
f67539c2 | 31 | Context* on_finish) : m_image_ctx(image_ctx), |
1e59de90 TL |
32 | m_on_finish(on_finish), |
33 | m_format_idx(0), | |
34 | m_is_current_format_cloned(false), | |
35 | m_formats(std::move(formats)) { | |
f67539c2 TL |
36 | } |
37 | ||
38 | template <typename I> | |
39 | void LoadRequest<I>::send() { | |
1e59de90 TL |
40 | if (m_formats.empty()) { |
41 | lderr(m_image_ctx->cct) << "no encryption formats were specified" << dendl; | |
42 | finish(-EINVAL); | |
43 | return; | |
44 | } | |
45 | ||
46 | ldout(m_image_ctx->cct, 20) << "got " << m_formats.size() << " formats" | |
47 | << dendl; | |
48 | ||
49 | if (m_image_ctx->encryption_format.get() != nullptr) { | |
f67539c2 TL |
50 | lderr(m_image_ctx->cct) << "encryption already loaded" << dendl; |
51 | finish(-EEXIST); | |
52 | return; | |
53 | } | |
54 | ||
55 | auto ictx = m_image_ctx; | |
56 | while (ictx != nullptr) { | |
57 | if (ictx->test_features(RBD_FEATURE_JOURNALING)) { | |
58 | lderr(m_image_ctx->cct) << "cannot use encryption with journal." | |
59 | << " image name: " << ictx->name << dendl; | |
60 | finish(-ENOTSUP); | |
61 | return; | |
62 | } | |
63 | ictx = ictx->parent; | |
64 | } | |
65 | ||
1e59de90 TL |
66 | m_current_image_ctx = m_image_ctx; |
67 | flush(); | |
68 | } | |
69 | ||
70 | template <typename I> | |
71 | void LoadRequest<I>::flush() { | |
72 | auto ctx = create_context_callback< | |
73 | LoadRequest<I>, &LoadRequest<I>::handle_flush>(this); | |
74 | auto aio_comp = io::AioCompletion::create_and_start( | |
75 | ctx, librbd::util::get_image_ctx(m_image_ctx), io::AIO_TYPE_FLUSH); | |
76 | auto req = io::ImageDispatchSpec::create_flush( | |
77 | *m_image_ctx, io::IMAGE_DISPATCH_LAYER_INTERNAL_START, aio_comp, | |
78 | io::FLUSH_SOURCE_INTERNAL, {}); | |
79 | req->send(); | |
80 | } | |
81 | ||
82 | template <typename I> | |
83 | void LoadRequest<I>::handle_flush(int r) { | |
84 | ldout(m_image_ctx->cct, 20) << "r=" << r << dendl; | |
85 | ||
86 | if (r < 0) { | |
87 | lderr(m_image_ctx->cct) << "failed to flush image" << dendl; | |
88 | finish(r); | |
89 | return; | |
90 | } | |
91 | ||
92 | load(); | |
93 | } | |
94 | ||
95 | template <typename I> | |
96 | void LoadRequest<I>::load() { | |
97 | ldout(m_image_ctx->cct, 20) << "format_idx=" << m_format_idx << dendl; | |
98 | ||
99 | m_detected_format_name = ""; | |
100 | auto ctx = create_context_callback< | |
101 | LoadRequest<I>, &LoadRequest<I>::handle_load>(this); | |
102 | m_formats[m_format_idx]->load(m_current_image_ctx, &m_detected_format_name, | |
103 | ctx); | |
104 | } | |
105 | ||
106 | template <typename I> | |
107 | void LoadRequest<I>::handle_load(int r) { | |
108 | ldout(m_image_ctx->cct, 20) << "r=" << r << dendl; | |
109 | ||
110 | if (r < 0) { | |
111 | if (m_is_current_format_cloned && | |
112 | m_detected_format_name == UNKNOWN_FORMAT) { | |
113 | // encryption format was not detected, assume plaintext | |
114 | ldout(m_image_ctx->cct, 5) << "assuming plaintext for image " | |
115 | << m_current_image_ctx->name << dendl; | |
116 | m_formats.pop_back(); | |
117 | invalidate_cache(); | |
118 | return; | |
119 | } | |
120 | ||
121 | lderr(m_image_ctx->cct) << "failed to load encryption. image name: " | |
122 | << m_current_image_ctx->name << dendl; | |
123 | finish(r); | |
124 | return; | |
125 | } | |
126 | ||
127 | ldout(m_image_ctx->cct, 5) << "loaded format " << m_detected_format_name | |
128 | << (m_is_current_format_cloned ? " (cloned)" : "") | |
129 | << " for image " << m_current_image_ctx->name | |
130 | << dendl; | |
131 | ||
132 | m_format_idx++; | |
133 | m_current_image_ctx = m_current_image_ctx->parent; | |
134 | if (m_current_image_ctx != nullptr) { | |
135 | // move on to loading parent | |
136 | if (m_format_idx >= m_formats.size()) { | |
137 | // try to load next ancestor using the same format | |
138 | ldout(m_image_ctx->cct, 20) << "cloning format" << dendl; | |
139 | m_is_current_format_cloned = true; | |
140 | m_formats.push_back(m_formats[m_formats.size() - 1]->clone()); | |
141 | } | |
142 | ||
143 | load(); | |
144 | } else { | |
145 | if (m_formats.size() != m_format_idx) { | |
146 | lderr(m_image_ctx->cct) << "got " << m_formats.size() | |
147 | << " encryption specs to load, " | |
148 | << "but image has " << m_format_idx - 1 | |
149 | << " ancestors" << dendl; | |
150 | finish(-EINVAL); | |
151 | return; | |
152 | } | |
153 | ||
154 | invalidate_cache(); | |
155 | } | |
156 | } | |
157 | ||
158 | template <typename I> | |
159 | void LoadRequest<I>::invalidate_cache() { | |
f67539c2 | 160 | auto ctx = create_context_callback< |
1e59de90 TL |
161 | LoadRequest<I>, &LoadRequest<I>::handle_invalidate_cache>(this); |
162 | m_image_ctx->io_image_dispatcher->invalidate_cache(ctx); | |
163 | } | |
164 | ||
165 | template <typename I> | |
166 | void LoadRequest<I>::handle_invalidate_cache(int r) { | |
167 | ldout(m_image_ctx->cct, 20) << "r=" << r << dendl; | |
168 | ||
169 | if (r < 0) { | |
170 | lderr(m_image_ctx->cct) << "failed to invalidate image cache" << dendl; | |
171 | } | |
172 | ||
173 | finish(r); | |
f67539c2 TL |
174 | } |
175 | ||
176 | template <typename I> | |
177 | void LoadRequest<I>::finish(int r) { | |
1e59de90 | 178 | ldout(m_image_ctx->cct, 20) << "r=" << r << dendl; |
f67539c2 TL |
179 | |
180 | if (r == 0) { | |
f67539c2 | 181 | auto ictx = m_image_ctx; |
1e59de90 TL |
182 | for (auto& format : m_formats) { |
183 | util::set_crypto(ictx, std::move(format)); | |
f67539c2 TL |
184 | ictx = ictx->parent; |
185 | } | |
186 | } | |
187 | ||
188 | m_on_finish->complete(r); | |
189 | delete this; | |
190 | } | |
191 | ||
192 | } // namespace crypto | |
193 | } // namespace librbd | |
194 | ||
195 | template class librbd::crypto::LoadRequest<librbd::ImageCtx>; |