]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/io/WriteBlockImageDispatch.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / librbd / io / WriteBlockImageDispatch.cc
CommitLineData
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 "librbd/io/WriteBlockImageDispatch.h"
5#include "common/dout.h"
6#include "common/Cond.h"
7#include "librbd/ImageCtx.h"
8#include "librbd/Utils.h"
9#include "librbd/asio/ContextWQ.h"
10#include "librbd/io/AioCompletion.h"
11#include "librbd/io/ImageDispatchSpec.h"
12
13#define dout_subsys ceph_subsys_rbd
14#undef dout_prefix
15#define dout_prefix *_dout << "librbd::io::WriteBlockImageDispatch: " << this \
16 << " " << __func__ << ": "
17
18namespace librbd {
19namespace io {
20
21template <typename I>
22struct WriteBlockImageDispatch<I>::C_BlockedWrites : public Context {
23 WriteBlockImageDispatch *dispatch;
24 explicit C_BlockedWrites(WriteBlockImageDispatch *dispatch)
25 : dispatch(dispatch) {
26 }
27
28 void finish(int r) override {
29 dispatch->handle_blocked_writes(r);
30 }
31};
32
33template <typename I>
34WriteBlockImageDispatch<I>::WriteBlockImageDispatch(I* image_ctx)
35 : m_image_ctx(image_ctx),
36 m_lock(ceph::make_shared_mutex(
37 util::unique_lock_name("librbd::io::WriteBlockImageDispatch::m_lock",
38 this))) {
39 auto cct = m_image_ctx->cct;
40 ldout(cct, 5) << "ictx=" << image_ctx << dendl;
41}
42
43template <typename I>
44void WriteBlockImageDispatch<I>::shut_down(Context* on_finish) {
45 on_finish->complete(0);
46}
47
48template <typename I>
49int WriteBlockImageDispatch<I>::block_writes() {
50 C_SaferCond cond_ctx;
51 block_writes(&cond_ctx);
52 return cond_ctx.wait();
53}
54
55template <typename I>
56void WriteBlockImageDispatch<I>::block_writes(Context *on_blocked) {
57 ceph_assert(ceph_mutex_is_locked(m_image_ctx->owner_lock));
58 auto cct = m_image_ctx->cct;
59
60 // ensure owner lock is not held after block_writes completes
61 on_blocked = util::create_async_context_callback(
62 *m_image_ctx, on_blocked);
63
64 {
65 std::unique_lock locker{m_lock};
66 ++m_write_blockers;
67 ldout(cct, 5) << m_image_ctx << ", "
68 << "num=" << m_write_blockers << dendl;
69 if (!m_write_blocker_contexts.empty() || m_in_flight_writes > 0) {
70 ldout(cct, 5) << "waiting for in-flight writes to complete: "
71 << "in_flight_writes=" << m_in_flight_writes << dendl;
72 m_write_blocker_contexts.push_back(on_blocked);
73 return;
74 }
75 }
76
77 flush_io(on_blocked);
78};
79
80template <typename I>
81void WriteBlockImageDispatch<I>::unblock_writes() {
82 auto cct = m_image_ctx->cct;
83
84 Contexts waiter_contexts;
85 Contexts dispatch_contexts;
86 {
87 std::unique_lock locker{m_lock};
88 ceph_assert(m_write_blockers > 0);
89 --m_write_blockers;
90
91 ldout(cct, 5) << m_image_ctx << ", "
92 << "num=" << m_write_blockers << dendl;
93 if (m_write_blockers == 0) {
94 std::swap(waiter_contexts, m_unblocked_write_waiter_contexts);
95 std::swap(dispatch_contexts, m_on_dispatches);
96 }
97 }
98
99 for (auto ctx : waiter_contexts) {
100 ctx->complete(0);
101 }
102
103 for (auto ctx : dispatch_contexts) {
104 ctx->complete(0);
105 }
106}
107
108template <typename I>
109void WriteBlockImageDispatch<I>::wait_on_writes_unblocked(
110 Context *on_unblocked) {
111 ceph_assert(ceph_mutex_is_locked(m_image_ctx->owner_lock));
112 auto cct = m_image_ctx->cct;
113
114 {
115 std::unique_lock locker{m_lock};
116 ldout(cct, 20) << m_image_ctx << ", "
117 << "write_blockers=" << m_write_blockers << dendl;
118 if (!m_unblocked_write_waiter_contexts.empty() || m_write_blockers > 0) {
119 m_unblocked_write_waiter_contexts.push_back(on_unblocked);
120 return;
121 }
122 }
123
124 on_unblocked->complete(0);
125}
126
127template <typename I>
128bool WriteBlockImageDispatch<I>::write(
129 AioCompletion* aio_comp, Extents &&image_extents, bufferlist &&bl,
1e59de90 130 int op_flags, const ZTracer::Trace &parent_trace,
f67539c2
TL
131 uint64_t tid, std::atomic<uint32_t>* image_dispatch_flags,
132 DispatchResult* dispatch_result, Context** on_finish,
133 Context* on_dispatched) {
134 auto cct = m_image_ctx->cct;
135 ldout(cct, 20) << "tid=" << tid << dendl;
136
137 return process_io(tid, dispatch_result, on_finish, on_dispatched);
138}
139
140template <typename I>
141bool WriteBlockImageDispatch<I>::discard(
142 AioCompletion* aio_comp, Extents &&image_extents,
1e59de90
TL
143 uint32_t discard_granularity_bytes, const ZTracer::Trace &parent_trace,
144 uint64_t tid, std::atomic<uint32_t>* image_dispatch_flags,
f67539c2
TL
145 DispatchResult* dispatch_result, Context** on_finish,
146 Context* on_dispatched) {
147 auto cct = m_image_ctx->cct;
148 ldout(cct, 20) << "tid=" << tid << dendl;
149
150 return process_io(tid, dispatch_result, on_finish, on_dispatched);
151}
152
153template <typename I>
154bool WriteBlockImageDispatch<I>::write_same(
155 AioCompletion* aio_comp, Extents &&image_extents, bufferlist &&bl,
1e59de90 156 int op_flags, const ZTracer::Trace &parent_trace,
f67539c2
TL
157 uint64_t tid, std::atomic<uint32_t>* image_dispatch_flags,
158 DispatchResult* dispatch_result, Context** on_finish,
159 Context* on_dispatched) {
160 auto cct = m_image_ctx->cct;
161 ldout(cct, 20) << "tid=" << tid << dendl;
162
163 return process_io(tid, dispatch_result, on_finish, on_dispatched);
164}
165
166template <typename I>
167bool WriteBlockImageDispatch<I>::compare_and_write(
1e59de90
TL
168 AioCompletion* aio_comp, Extents &&image_extents,
169 bufferlist &&cmp_bl, bufferlist &&bl, uint64_t *mismatch_offset,
170 int op_flags, const ZTracer::Trace &parent_trace,
171 uint64_t tid, std::atomic<uint32_t>* image_dispatch_flags,
f67539c2
TL
172 DispatchResult* dispatch_result, Context** on_finish,
173 Context* on_dispatched) {
174 auto cct = m_image_ctx->cct;
175 ldout(cct, 20) << "tid=" << tid << dendl;
176
177 return process_io(tid, dispatch_result, on_finish, on_dispatched);
178}
179
180template <typename I>
181bool WriteBlockImageDispatch<I>::flush(
182 AioCompletion* aio_comp, FlushSource flush_source,
183 const ZTracer::Trace &parent_trace, uint64_t tid,
184 std::atomic<uint32_t>* image_dispatch_flags,
185 DispatchResult* dispatch_result, Context** on_finish,
186 Context* on_dispatched) {
187 auto cct = m_image_ctx->cct;
188 ldout(cct, 20) << "tid=" << tid << dendl;
189
190 if (flush_source != FLUSH_SOURCE_USER) {
191 return false;
192 }
193
194 return process_io(tid, dispatch_result, on_finish, on_dispatched);
195}
196
197template <typename I>
198void WriteBlockImageDispatch<I>::handle_finished(int r, uint64_t tid) {
199 auto cct = m_image_ctx->cct;
200 ldout(cct, 20) << "r=" << r << ", tid=" << tid << dendl;
201
202 std::unique_lock locker{m_lock};
203 ceph_assert(m_in_flight_writes > 0);
204 --m_in_flight_writes;
205
206 bool writes_blocked = false;
207 if (m_write_blockers > 0 && m_in_flight_writes == 0) {
208 ldout(cct, 10) << "flushing all in-flight IO for blocked writes" << dendl;
209 writes_blocked = true;
210 }
211 locker.unlock();
212
213 if (writes_blocked) {
214 flush_io(new C_BlockedWrites(this));
215 }
216}
217
218template <typename I>
219bool WriteBlockImageDispatch<I>::process_io(
220 uint64_t tid, DispatchResult* dispatch_result, Context** on_finish,
221 Context* on_dispatched) {
222 std::unique_lock locker{m_lock};
223 if (m_write_blockers > 0 || !m_on_dispatches.empty()) {
224 *dispatch_result = DISPATCH_RESULT_RESTART;
225 m_on_dispatches.push_back(on_dispatched);
226 return true;
227 }
228
229 ++m_in_flight_writes;
230 *on_finish = new LambdaContext([this, tid, on_finish=*on_finish](int r) {
231 handle_finished(r, tid);
232 on_finish->complete(r);
233 });
234 return false;
235}
236
237template <typename I>
238void WriteBlockImageDispatch<I>::flush_io(Context* on_finish) {
239 auto cct = m_image_ctx->cct;
240 ldout(cct, 10) << dendl;
241
242 // ensure that all in-flight IO is flushed
243 auto aio_comp = AioCompletion::create_and_start(
244 on_finish, util::get_image_ctx(m_image_ctx), librbd::io::AIO_TYPE_FLUSH);
245 auto req = ImageDispatchSpec::create_flush(
246 *m_image_ctx, IMAGE_DISPATCH_LAYER_WRITE_BLOCK, aio_comp,
247 FLUSH_SOURCE_WRITE_BLOCK, {});
248 req->send();
249}
250
251template <typename I>
252void WriteBlockImageDispatch<I>::handle_blocked_writes(int r) {
253 auto cct = m_image_ctx->cct;
254 ldout(cct, 10) << dendl;
255
256 Contexts write_blocker_contexts;
257 {
258 std::unique_lock locker{m_lock};
259 std::swap(write_blocker_contexts, m_write_blocker_contexts);
260 }
261
262 for (auto ctx : write_blocker_contexts) {
263 ctx->complete(0);
264 }
265}
266
267} // namespace io
268} // namespace librbd
269
270template class librbd::io::WriteBlockImageDispatch<librbd::ImageCtx>;