]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/operation/Request.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / librbd / operation / Request.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/operation/Request.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "common/WorkQueue.h"
8 #include "librbd/ImageCtx.h"
9
10 #define dout_subsys ceph_subsys_rbd
11 #undef dout_prefix
12 #define dout_prefix *_dout << "librbd::Request: "
13
14 namespace librbd {
15 namespace operation {
16
17 template <typename I>
18 Request<I>::Request(I &image_ctx, Context *on_finish, uint64_t journal_op_tid)
19 : AsyncRequest<I>(image_ctx, on_finish), m_op_tid(journal_op_tid) {
20 }
21
22 template <typename I>
23 void Request<I>::send() {
24 I &image_ctx = this->m_image_ctx;
25 assert(image_ctx.owner_lock.is_locked());
26
27 // automatically create the event if we don't need to worry
28 // about affecting concurrent IO ops
29 if (can_affect_io() || !append_op_event()) {
30 send_op();
31 }
32 }
33
34 template <typename I>
35 Context *Request<I>::create_context_finisher(int r) {
36 // automatically commit the event if required (delete after commit)
37 if (m_appended_op_event && !m_committed_op_event &&
38 commit_op_event(r)) {
39 return nullptr;
40 }
41
42 I &image_ctx = this->m_image_ctx;
43 CephContext *cct = image_ctx.cct;
44 ldout(cct, 10) << this << " " << __func__ << dendl;
45 return util::create_context_callback<Request<I>, &Request<I>::finish>(this);
46 }
47
48 template <typename I>
49 void Request<I>::finish_and_destroy(int r) {
50 I &image_ctx = this->m_image_ctx;
51 CephContext *cct = image_ctx.cct;
52 ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
53
54 // automatically commit the event if required (delete after commit)
55 if (m_appended_op_event && !m_committed_op_event &&
56 commit_op_event(r)) {
57 return;
58 }
59
60 AsyncRequest<I>::finish_and_destroy(r);
61 }
62
63 template <typename I>
64 void Request<I>::finish(int r) {
65 I &image_ctx = this->m_image_ctx;
66 CephContext *cct = image_ctx.cct;
67 ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
68
69 assert(!m_appended_op_event || m_committed_op_event);
70 AsyncRequest<I>::finish(r);
71 }
72
73 template <typename I>
74 bool Request<I>::append_op_event() {
75 I &image_ctx = this->m_image_ctx;
76
77 assert(image_ctx.owner_lock.is_locked());
78 RWLock::RLocker snap_locker(image_ctx.snap_lock);
79 if (image_ctx.journal != nullptr &&
80 image_ctx.journal->is_journal_appending()) {
81 append_op_event(util::create_context_callback<
82 Request<I>, &Request<I>::handle_op_event_safe>(this));
83 return true;
84 }
85 return false;
86 }
87
88 template <typename I>
89 bool Request<I>::commit_op_event(int r) {
90 I &image_ctx = this->m_image_ctx;
91 RWLock::RLocker snap_locker(image_ctx.snap_lock);
92
93 if (!m_appended_op_event) {
94 return false;
95 }
96
97 assert(m_op_tid != 0);
98 assert(!m_committed_op_event);
99 m_committed_op_event = true;
100
101 if (image_ctx.journal != nullptr &&
102 image_ctx.journal->is_journal_appending()) {
103 CephContext *cct = image_ctx.cct;
104 ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
105
106 // ops will be canceled / completed before closing journal
107 assert(image_ctx.journal->is_journal_ready());
108 image_ctx.journal->commit_op_event(m_op_tid, r,
109 new C_CommitOpEvent(this, r));
110 return true;
111 }
112 return false;
113 }
114
115 template <typename I>
116 void Request<I>::handle_commit_op_event(int r, int original_ret_val) {
117 I &image_ctx = this->m_image_ctx;
118 CephContext *cct = image_ctx.cct;
119 ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
120
121 if (r < 0) {
122 lderr(cct) << "failed to commit op event to journal: " << cpp_strerror(r)
123 << dendl;
124 }
125 if (original_ret_val < 0) {
126 r = original_ret_val;
127 }
128 finish(r);
129 }
130
131 template <typename I>
132 void Request<I>::replay_op_ready(Context *on_safe) {
133 I &image_ctx = this->m_image_ctx;
134 assert(image_ctx.owner_lock.is_locked());
135 assert(image_ctx.snap_lock.is_locked());
136 assert(m_op_tid != 0);
137
138 m_appended_op_event = true;
139 image_ctx.journal->replay_op_ready(
140 m_op_tid, util::create_async_context_callback(image_ctx, on_safe));
141 }
142
143 template <typename I>
144 void Request<I>::append_op_event(Context *on_safe) {
145 I &image_ctx = this->m_image_ctx;
146 assert(image_ctx.owner_lock.is_locked());
147 assert(image_ctx.snap_lock.is_locked());
148
149 CephContext *cct = image_ctx.cct;
150 ldout(cct, 10) << this << " " << __func__ << dendl;
151
152 m_op_tid = image_ctx.journal->allocate_op_tid();
153 image_ctx.journal->append_op_event(
154 m_op_tid, journal::EventEntry{create_event(m_op_tid)},
155 new C_AppendOpEvent(this, on_safe));
156 }
157
158 template <typename I>
159 void Request<I>::handle_op_event_safe(int r) {
160 I &image_ctx = this->m_image_ctx;
161 CephContext *cct = image_ctx.cct;
162 ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
163
164 if (r < 0) {
165 lderr(cct) << "failed to commit op event to journal: " << cpp_strerror(r)
166 << dendl;
167 this->finish(r);
168 delete this;
169 } else {
170 assert(!can_affect_io());
171
172 // haven't started the request state machine yet
173 RWLock::RLocker owner_locker(image_ctx.owner_lock);
174 send_op();
175 }
176 }
177
178 } // namespace operation
179 } // namespace librbd
180
181 #ifndef TEST_F
182 template class librbd::operation::Request<librbd::ImageCtx>;
183 #endif