]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "cls/rbd/cls_rbd_types.h" | |
5 | #include "librbd/operation/SnapshotCreateRequest.h" | |
6 | #include "common/dout.h" | |
7 | #include "common/errno.h" | |
8 | #include "librbd/ExclusiveLock.h" | |
9 | #include "librbd/ImageCtx.h" | |
10 | #include "librbd/ObjectMap.h" | |
11 | #include "librbd/Utils.h" | |
12 | #include "librbd/io/ImageRequestWQ.h" | |
13 | ||
14 | #define dout_subsys ceph_subsys_rbd | |
15 | #undef dout_prefix | |
16 | #define dout_prefix *_dout << "librbd::SnapshotCreateRequest: " | |
17 | ||
18 | namespace librbd { | |
19 | namespace operation { | |
20 | ||
21 | using util::create_async_context_callback; | |
22 | using util::create_context_callback; | |
23 | using util::create_rados_callback; | |
24 | ||
25 | template <typename I> | |
26 | SnapshotCreateRequest<I>::SnapshotCreateRequest(I &image_ctx, | |
27 | Context *on_finish, | |
28 | const cls::rbd::SnapshotNamespace &snap_namespace, | |
29 | const std::string &snap_name, | |
30 | uint64_t journal_op_tid, | |
31 | bool skip_object_map) | |
32 | : Request<I>(image_ctx, on_finish, journal_op_tid), | |
33 | m_snap_namespace(snap_namespace), m_snap_name(snap_name), | |
34 | m_skip_object_map(skip_object_map), m_ret_val(0), m_snap_id(CEPH_NOSNAP) { | |
35 | } | |
36 | ||
37 | template <typename I> | |
38 | void SnapshotCreateRequest<I>::send_op() { | |
39 | send_suspend_requests(); | |
40 | } | |
41 | ||
42 | template <typename I> | |
43 | void SnapshotCreateRequest<I>::send_suspend_requests() { | |
44 | I &image_ctx = this->m_image_ctx; | |
45 | CephContext *cct = image_ctx.cct; | |
46 | ldout(cct, 5) << this << " " << __func__ << dendl; | |
47 | ||
48 | // TODO suspend (shrink) resize to ensure consistent RBD mirror | |
49 | send_suspend_aio(); | |
50 | } | |
51 | ||
52 | template <typename I> | |
53 | Context *SnapshotCreateRequest<I>::handle_suspend_requests(int *result) { | |
54 | I &image_ctx = this->m_image_ctx; | |
55 | CephContext *cct = image_ctx.cct; | |
56 | ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl; | |
57 | ||
58 | // TODO | |
59 | send_suspend_aio(); | |
60 | return nullptr; | |
61 | } | |
62 | ||
63 | template <typename I> | |
64 | void SnapshotCreateRequest<I>::send_suspend_aio() { | |
65 | I &image_ctx = this->m_image_ctx; | |
66 | assert(image_ctx.owner_lock.is_locked()); | |
67 | ||
68 | CephContext *cct = image_ctx.cct; | |
69 | ldout(cct, 5) << this << " " << __func__ << dendl; | |
70 | ||
71 | image_ctx.io_work_queue->block_writes(create_context_callback< | |
72 | SnapshotCreateRequest<I>, | |
73 | &SnapshotCreateRequest<I>::handle_suspend_aio>(this)); | |
74 | } | |
75 | ||
76 | template <typename I> | |
77 | Context *SnapshotCreateRequest<I>::handle_suspend_aio(int *result) { | |
78 | I &image_ctx = this->m_image_ctx; | |
79 | CephContext *cct = image_ctx.cct; | |
80 | ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl; | |
81 | ||
82 | if (*result < 0) { | |
83 | lderr(cct) << "failed to block writes: " << cpp_strerror(*result) << dendl; | |
84 | image_ctx.io_work_queue->unblock_writes(); | |
85 | return this->create_context_finisher(*result); | |
86 | } | |
87 | ||
88 | send_append_op_event(); | |
89 | return nullptr; | |
90 | } | |
91 | ||
92 | template <typename I> | |
93 | void SnapshotCreateRequest<I>::send_append_op_event() { | |
94 | I &image_ctx = this->m_image_ctx; | |
95 | if (!this->template append_op_event< | |
96 | SnapshotCreateRequest<I>, | |
97 | &SnapshotCreateRequest<I>::handle_append_op_event>(this)) { | |
98 | send_allocate_snap_id(); | |
99 | return; | |
100 | } | |
101 | ||
102 | CephContext *cct = image_ctx.cct; | |
103 | ldout(cct, 5) << this << " " << __func__ << dendl; | |
104 | } | |
105 | ||
106 | template <typename I> | |
107 | Context *SnapshotCreateRequest<I>::handle_append_op_event(int *result) { | |
108 | I &image_ctx = this->m_image_ctx; | |
109 | CephContext *cct = image_ctx.cct; | |
110 | ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl; | |
111 | ||
112 | if (*result < 0) { | |
113 | image_ctx.io_work_queue->unblock_writes(); | |
114 | lderr(cct) << "failed to commit journal entry: " << cpp_strerror(*result) | |
115 | << dendl; | |
116 | return this->create_context_finisher(*result); | |
117 | } | |
118 | ||
119 | send_allocate_snap_id(); | |
120 | return nullptr; | |
121 | } | |
122 | ||
123 | template <typename I> | |
124 | void SnapshotCreateRequest<I>::send_allocate_snap_id() { | |
125 | I &image_ctx = this->m_image_ctx; | |
126 | CephContext *cct = image_ctx.cct; | |
127 | ldout(cct, 5) << this << " " << __func__ << dendl; | |
128 | ||
129 | librados::AioCompletion *rados_completion = create_rados_callback< | |
130 | SnapshotCreateRequest<I>, | |
131 | &SnapshotCreateRequest<I>::handle_allocate_snap_id>(this); | |
3efd9988 | 132 | image_ctx.data_ctx.aio_selfmanaged_snap_create(&m_snap_id, rados_completion); |
7c673cae FG |
133 | rados_completion->release(); |
134 | } | |
135 | ||
136 | template <typename I> | |
137 | Context *SnapshotCreateRequest<I>::handle_allocate_snap_id(int *result) { | |
138 | I &image_ctx = this->m_image_ctx; | |
139 | CephContext *cct = image_ctx.cct; | |
140 | ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << ", " | |
141 | << "snap_id=" << m_snap_id << dendl; | |
142 | ||
143 | if (*result < 0) { | |
144 | save_result(result); | |
145 | image_ctx.io_work_queue->unblock_writes(); | |
146 | lderr(cct) << "failed to allocate snapshot id: " << cpp_strerror(*result) | |
147 | << dendl; | |
148 | return this->create_context_finisher(*result); | |
149 | } | |
150 | ||
151 | send_create_snap(); | |
152 | return nullptr; | |
153 | } | |
154 | ||
155 | template <typename I> | |
156 | void SnapshotCreateRequest<I>::send_create_snap() { | |
157 | I &image_ctx = this->m_image_ctx; | |
158 | CephContext *cct = image_ctx.cct; | |
159 | ldout(cct, 5) << this << " " << __func__ << dendl; | |
160 | ||
161 | RWLock::RLocker owner_locker(image_ctx.owner_lock); | |
162 | RWLock::RLocker snap_locker(image_ctx.snap_lock); | |
163 | RWLock::RLocker parent_locker(image_ctx.parent_lock); | |
164 | ||
165 | // should have been canceled prior to releasing lock | |
166 | assert(image_ctx.exclusive_lock == nullptr || | |
167 | image_ctx.exclusive_lock->is_lock_owner()); | |
168 | ||
169 | // save current size / parent info for creating snapshot record in ImageCtx | |
170 | m_size = image_ctx.size; | |
171 | m_parent_info = image_ctx.parent_md; | |
172 | ||
173 | librados::ObjectWriteOperation op; | |
174 | if (image_ctx.old_format) { | |
175 | cls_client::old_snapshot_add(&op, m_snap_id, m_snap_name); | |
176 | } else { | |
177 | cls_client::snapshot_add(&op, m_snap_id, m_snap_name, m_snap_namespace); | |
178 | } | |
179 | ||
180 | librados::AioCompletion *rados_completion = create_rados_callback< | |
181 | SnapshotCreateRequest<I>, | |
182 | &SnapshotCreateRequest<I>::handle_create_snap>(this); | |
183 | int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, | |
184 | rados_completion, &op); | |
185 | assert(r == 0); | |
186 | rados_completion->release(); | |
187 | } | |
188 | ||
189 | template <typename I> | |
190 | Context *SnapshotCreateRequest<I>::handle_create_snap(int *result) { | |
191 | I &image_ctx = this->m_image_ctx; | |
192 | CephContext *cct = image_ctx.cct; | |
193 | ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl; | |
194 | ||
195 | if (*result == -ESTALE) { | |
196 | send_allocate_snap_id(); | |
197 | return nullptr; | |
198 | } else if (*result < 0) { | |
199 | save_result(result); | |
200 | send_release_snap_id(); | |
201 | return nullptr; | |
202 | } | |
203 | ||
204 | return send_create_object_map(); | |
205 | } | |
206 | ||
207 | template <typename I> | |
208 | Context *SnapshotCreateRequest<I>::send_create_object_map() { | |
209 | I &image_ctx = this->m_image_ctx; | |
210 | ||
211 | update_snap_context(); | |
212 | ||
213 | image_ctx.snap_lock.get_read(); | |
214 | if (image_ctx.object_map == nullptr || m_skip_object_map) { | |
215 | image_ctx.snap_lock.put_read(); | |
216 | ||
217 | image_ctx.io_work_queue->unblock_writes(); | |
218 | return this->create_context_finisher(0); | |
219 | } | |
220 | ||
221 | CephContext *cct = image_ctx.cct; | |
222 | ldout(cct, 5) << this << " " << __func__ << dendl; | |
223 | ||
224 | { | |
225 | RWLock::RLocker object_map_lock(image_ctx.object_map_lock); | |
226 | image_ctx.object_map->snapshot_add( | |
227 | m_snap_id, create_context_callback< | |
228 | SnapshotCreateRequest<I>, | |
229 | &SnapshotCreateRequest<I>::handle_create_object_map>(this)); | |
230 | } | |
231 | image_ctx.snap_lock.put_read(); | |
232 | return nullptr; | |
233 | } | |
234 | ||
235 | template <typename I> | |
236 | Context *SnapshotCreateRequest<I>::handle_create_object_map(int *result) { | |
237 | I &image_ctx = this->m_image_ctx; | |
238 | CephContext *cct = image_ctx.cct; | |
239 | ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl; | |
240 | ||
241 | assert(*result == 0); | |
242 | ||
243 | image_ctx.io_work_queue->unblock_writes(); | |
244 | return this->create_context_finisher(0); | |
245 | } | |
246 | ||
247 | template <typename I> | |
248 | void SnapshotCreateRequest<I>::send_release_snap_id() { | |
249 | I &image_ctx = this->m_image_ctx; | |
250 | CephContext *cct = image_ctx.cct; | |
251 | ldout(cct, 5) << this << " " << __func__ << dendl; | |
252 | ||
253 | assert(m_snap_id != CEPH_NOSNAP); | |
254 | ||
255 | librados::AioCompletion *rados_completion = create_rados_callback< | |
256 | SnapshotCreateRequest<I>, | |
257 | &SnapshotCreateRequest<I>::handle_release_snap_id>(this); | |
3efd9988 | 258 | image_ctx.data_ctx.aio_selfmanaged_snap_remove(m_snap_id, rados_completion); |
7c673cae FG |
259 | rados_completion->release(); |
260 | } | |
261 | ||
262 | template <typename I> | |
263 | Context *SnapshotCreateRequest<I>::handle_release_snap_id(int *result) { | |
264 | I &image_ctx = this->m_image_ctx; | |
265 | CephContext *cct = image_ctx.cct; | |
266 | ldout(cct, 5) << this << " " << __func__ << ": r=" << *result << dendl; | |
267 | ||
268 | assert(m_ret_val < 0); | |
269 | *result = m_ret_val; | |
270 | ||
271 | image_ctx.io_work_queue->unblock_writes(); | |
272 | return this->create_context_finisher(m_ret_val); | |
273 | } | |
274 | ||
275 | template <typename I> | |
276 | void SnapshotCreateRequest<I>::update_snap_context() { | |
277 | I &image_ctx = this->m_image_ctx; | |
278 | ||
279 | RWLock::RLocker owner_locker(image_ctx.owner_lock); | |
280 | RWLock::WLocker snap_locker(image_ctx.snap_lock); | |
281 | if (image_ctx.old_format) { | |
282 | return; | |
283 | } | |
284 | ||
285 | if (image_ctx.get_snap_info(m_snap_id) != NULL) { | |
286 | return; | |
287 | } | |
288 | ||
289 | CephContext *cct = image_ctx.cct; | |
290 | ldout(cct, 5) << this << " " << __func__ << dendl; | |
291 | ||
292 | // should have been canceled prior to releasing lock | |
293 | assert(image_ctx.exclusive_lock == nullptr || | |
294 | image_ctx.exclusive_lock->is_lock_owner()); | |
295 | ||
296 | // immediately add a reference to the new snapshot | |
297 | utime_t snap_time = ceph_clock_now(); | |
298 | image_ctx.add_snap(m_snap_namespace, m_snap_name, m_snap_id, m_size, | |
299 | m_parent_info, RBD_PROTECTION_STATUS_UNPROTECTED, | |
300 | 0, snap_time); | |
301 | ||
302 | // immediately start using the new snap context if we | |
303 | // own the exclusive lock | |
304 | std::vector<snapid_t> snaps; | |
305 | snaps.push_back(m_snap_id); | |
306 | snaps.insert(snaps.end(), image_ctx.snapc.snaps.begin(), | |
307 | image_ctx.snapc.snaps.end()); | |
308 | ||
309 | image_ctx.snapc.seq = m_snap_id; | |
310 | image_ctx.snapc.snaps.swap(snaps); | |
311 | image_ctx.data_ctx.selfmanaged_snap_set_write_ctx( | |
312 | image_ctx.snapc.seq, image_ctx.snaps); | |
313 | } | |
314 | ||
315 | } // namespace operation | |
316 | } // namespace librbd | |
317 | ||
318 | template class librbd::operation::SnapshotCreateRequest<librbd::ImageCtx>; |