]>
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 | #include "test/librbd/test_fixture.h" | |
4 | #include "test/librbd/test_support.h" | |
5 | #include "include/int_types.h" | |
6 | #include "include/stringify.h" | |
7 | #include "include/rados/librados.h" | |
8 | #include "include/rbd/librbd.hpp" | |
9 | #include "common/Cond.h" | |
9f95a23c | 10 | #include "common/ceph_mutex.h" |
7c673cae | 11 | #include "common/errno.h" |
7c673cae FG |
12 | #include "cls/lock/cls_lock_client.h" |
13 | #include "cls/lock/cls_lock_types.h" | |
14 | #include "librbd/internal.h" | |
15 | #include "librbd/ImageCtx.h" | |
16 | #include "librbd/ImageWatcher.h" | |
17 | #include "librbd/WatchNotifyTypes.h" | |
18 | #include "librbd/io/AioCompletion.h" | |
7c673cae FG |
19 | #include "test/librados/test.h" |
20 | #include "gtest/gtest.h" | |
21 | #include <boost/assign/std/set.hpp> | |
22 | #include <boost/assign/std/map.hpp> | |
7c673cae FG |
23 | #include <boost/scope_exit.hpp> |
24 | #include <boost/thread/thread.hpp> | |
25 | #include <iostream> | |
26 | #include <map> | |
27 | #include <set> | |
28 | #include <sstream> | |
29 | #include <vector> | |
30 | ||
20effc67 | 31 | using namespace std::chrono_literals; |
7c673cae FG |
32 | using namespace ceph; |
33 | using namespace boost::assign; | |
34 | using namespace librbd::watch_notify; | |
35 | ||
36 | void register_test_image_watcher() { | |
37 | } | |
38 | ||
39 | class TestImageWatcher : public TestFixture { | |
40 | public: | |
41 | ||
9f95a23c | 42 | TestImageWatcher() : m_watch_ctx(NULL) |
7c673cae FG |
43 | { |
44 | } | |
45 | ||
46 | class WatchCtx : public librados::WatchCtx2 { | |
47 | public: | |
48 | explicit WatchCtx(TestImageWatcher &parent) : m_parent(parent), m_handle(0) {} | |
49 | ||
50 | int watch(const librbd::ImageCtx &ictx) { | |
51 | m_header_oid = ictx.header_oid; | |
52 | return m_parent.m_ioctx.watch2(m_header_oid, &m_handle, this); | |
53 | } | |
54 | ||
55 | int unwatch() { | |
56 | return m_parent.m_ioctx.unwatch2(m_handle); | |
57 | } | |
58 | ||
59 | void handle_notify(uint64_t notify_id, | |
60 | uint64_t cookie, | |
61 | uint64_t notifier_id, | |
62 | bufferlist& bl) override { | |
63 | try { | |
64 | int op; | |
65 | bufferlist payload; | |
11fdf7f2 | 66 | auto iter = bl.cbegin(); |
7c673cae | 67 | DECODE_START(1, iter); |
11fdf7f2 | 68 | decode(op, iter); |
7c673cae FG |
69 | iter.copy_all(payload); |
70 | DECODE_FINISH(iter); | |
71 | ||
72 | NotifyOp notify_op = static_cast<NotifyOp>(op); | |
73 | /* | |
74 | std::cout << "NOTIFY: " << notify_op << ", " << notify_id | |
75 | << ", " << cookie << ", " << notifier_id << std::endl; | |
76 | */ | |
77 | ||
9f95a23c | 78 | std::lock_guard l{m_parent.m_callback_lock}; |
7c673cae FG |
79 | m_parent.m_notify_payloads[notify_op] = payload; |
80 | ||
81 | bufferlist reply; | |
82 | if (m_parent.m_notify_acks.count(notify_op) > 0) { | |
83 | reply = m_parent.m_notify_acks[notify_op]; | |
84 | m_parent.m_notifies += notify_op; | |
9f95a23c | 85 | m_parent.m_callback_cond.notify_all(); |
7c673cae FG |
86 | } |
87 | ||
88 | m_parent.m_ioctx.notify_ack(m_header_oid, notify_id, cookie, reply); | |
89 | } catch (...) { | |
90 | FAIL(); | |
91 | } | |
92 | } | |
93 | ||
94 | void handle_error(uint64_t cookie, int err) override { | |
95 | std::cerr << "ERROR: " << cookie << ", " << cpp_strerror(err) | |
96 | << std::endl; | |
97 | } | |
98 | ||
99 | uint64_t get_handle() const { | |
100 | return m_handle; | |
101 | } | |
102 | ||
103 | private: | |
104 | TestImageWatcher &m_parent; | |
105 | std::string m_header_oid; | |
106 | uint64_t m_handle; | |
107 | }; | |
108 | ||
109 | void TearDown() override { | |
110 | deregister_image_watch(); | |
111 | TestFixture::TearDown(); | |
112 | } | |
113 | ||
114 | int deregister_image_watch() { | |
115 | if (m_watch_ctx != NULL) { | |
116 | int r = m_watch_ctx->unwatch(); | |
117 | ||
118 | librados::Rados rados(m_ioctx); | |
119 | rados.watch_flush(); | |
120 | ||
121 | delete m_watch_ctx; | |
122 | m_watch_ctx = NULL; | |
123 | return r; | |
124 | } | |
125 | return 0; | |
126 | } | |
127 | ||
128 | int register_image_watch(librbd::ImageCtx &ictx) { | |
129 | m_watch_ctx = new WatchCtx(*this); | |
130 | return m_watch_ctx->watch(ictx); | |
131 | } | |
132 | ||
133 | bool wait_for_notifies(librbd::ImageCtx &ictx) { | |
9f95a23c | 134 | std::unique_lock l{m_callback_lock}; |
7c673cae | 135 | while (m_notifies.size() < m_notify_acks.size()) { |
9f95a23c | 136 | if (m_callback_cond.wait_for(l, 10s) == std::cv_status::timeout) { |
7c673cae FG |
137 | break; |
138 | } | |
139 | } | |
140 | return (m_notifies.size() == m_notify_acks.size()); | |
141 | } | |
142 | ||
143 | bufferlist create_response_message(int r) { | |
144 | bufferlist bl; | |
11fdf7f2 | 145 | encode(ResponseMessage(r), bl); |
7c673cae FG |
146 | return bl; |
147 | } | |
148 | ||
149 | bool extract_async_request_id(NotifyOp op, AsyncRequestId *id) { | |
150 | if (m_notify_payloads.count(op) == 0) { | |
151 | return false; | |
152 | } | |
153 | ||
154 | bufferlist payload = m_notify_payloads[op]; | |
11fdf7f2 | 155 | auto iter = payload.cbegin(); |
f67539c2 | 156 | |
7c673cae FG |
157 | switch (op) { |
158 | case NOTIFY_OP_FLATTEN: | |
159 | { | |
160 | FlattenPayload payload; | |
161 | payload.decode(2, iter); | |
162 | *id = payload.async_request_id; | |
163 | } | |
164 | return true; | |
165 | case NOTIFY_OP_RESIZE: | |
166 | { | |
167 | ResizePayload payload; | |
168 | payload.decode(2, iter); | |
169 | *id = payload.async_request_id; | |
170 | } | |
171 | return true; | |
f67539c2 TL |
172 | case NOTIFY_OP_SNAP_CREATE: |
173 | { | |
174 | SnapCreatePayload payload; | |
175 | payload.decode(7, iter); | |
176 | *id = payload.async_request_id; | |
177 | } | |
178 | return true; | |
179 | case NOTIFY_OP_SNAP_RENAME: | |
180 | { | |
181 | SnapRenamePayload payload; | |
182 | payload.decode(7, iter); | |
183 | *id = payload.async_request_id; | |
184 | } | |
185 | return true; | |
186 | case NOTIFY_OP_SNAP_REMOVE: | |
187 | { | |
188 | SnapRemovePayload payload; | |
189 | payload.decode(7, iter); | |
190 | *id = payload.async_request_id; | |
191 | } | |
192 | return true; | |
193 | case NOTIFY_OP_SNAP_PROTECT: | |
194 | { | |
195 | SnapProtectPayload payload; | |
196 | payload.decode(7, iter); | |
197 | *id = payload.async_request_id; | |
198 | } | |
199 | return true; | |
200 | case NOTIFY_OP_SNAP_UNPROTECT: | |
201 | { | |
202 | SnapUnprotectPayload payload; | |
203 | payload.decode(7, iter); | |
204 | *id = payload.async_request_id; | |
205 | } | |
206 | return true; | |
207 | case NOTIFY_OP_RENAME: | |
208 | { | |
209 | RenamePayload payload; | |
210 | payload.decode(7, iter); | |
211 | *id = payload.async_request_id; | |
212 | } | |
213 | return true; | |
7c673cae FG |
214 | case NOTIFY_OP_REBUILD_OBJECT_MAP: |
215 | { | |
216 | RebuildObjectMapPayload payload; | |
217 | payload.decode(2, iter); | |
218 | *id = payload.async_request_id; | |
219 | } | |
220 | return true; | |
20effc67 TL |
221 | case NOTIFY_OP_UPDATE_FEATURES: |
222 | { | |
223 | UpdateFeaturesPayload payload; | |
224 | payload.decode(7, iter); | |
225 | *id = payload.async_request_id; | |
226 | } | |
227 | return true; | |
7c673cae FG |
228 | default: |
229 | break; | |
230 | } | |
231 | return false; | |
232 | } | |
233 | ||
234 | int notify_async_progress(librbd::ImageCtx *ictx, const AsyncRequestId &id, | |
235 | uint64_t offset, uint64_t total) { | |
236 | bufferlist bl; | |
f67539c2 | 237 | encode(NotifyMessage(new AsyncProgressPayload(id, offset, total)), bl); |
7c673cae FG |
238 | return m_ioctx.notify2(ictx->header_oid, bl, 5000, NULL); |
239 | } | |
240 | ||
241 | int notify_async_complete(librbd::ImageCtx *ictx, const AsyncRequestId &id, | |
242 | int r) { | |
243 | bufferlist bl; | |
f67539c2 | 244 | encode(NotifyMessage(new AsyncCompletePayload(id, r)), bl); |
7c673cae FG |
245 | return m_ioctx.notify2(ictx->header_oid, bl, 5000, NULL); |
246 | } | |
247 | ||
248 | typedef std::map<NotifyOp, bufferlist> NotifyOpPayloads; | |
249 | typedef std::set<NotifyOp> NotifyOps; | |
250 | ||
251 | WatchCtx *m_watch_ctx; | |
252 | ||
253 | NotifyOps m_notifies; | |
254 | NotifyOpPayloads m_notify_payloads; | |
255 | NotifyOpPayloads m_notify_acks; | |
256 | ||
257 | AsyncRequestId m_async_request_id; | |
258 | ||
9f95a23c TL |
259 | ceph::mutex m_callback_lock = ceph::make_mutex("m_callback_lock"); |
260 | ceph::condition_variable m_callback_cond; | |
7c673cae FG |
261 | |
262 | }; | |
263 | ||
264 | struct ProgressContext : public librbd::ProgressContext { | |
9f95a23c TL |
265 | ceph::mutex mutex = ceph::make_mutex("ProgressContext::mutex"); |
266 | ceph::condition_variable cond; | |
7c673cae FG |
267 | bool received; |
268 | uint64_t offset; | |
269 | uint64_t total; | |
270 | ||
9f95a23c | 271 | ProgressContext() : received(false), |
7c673cae FG |
272 | offset(0), total(0) {} |
273 | ||
274 | int update_progress(uint64_t offset_, uint64_t total_) override { | |
9f95a23c | 275 | std::lock_guard l{mutex}; |
7c673cae FG |
276 | offset = offset_; |
277 | total = total_; | |
278 | received = true; | |
9f95a23c | 279 | cond.notify_all(); |
7c673cae FG |
280 | return 0; |
281 | } | |
282 | ||
283 | bool wait(librbd::ImageCtx *ictx, uint64_t offset_, uint64_t total_) { | |
9f95a23c | 284 | std::unique_lock l{mutex}; |
7c673cae | 285 | while (!received) { |
9f95a23c | 286 | if (cond.wait_for(l, 10s) == std::cv_status::timeout) { |
7c673cae FG |
287 | break; |
288 | } | |
289 | } | |
290 | return (received && offset == offset_ && total == total_); | |
291 | } | |
292 | }; | |
293 | ||
294 | struct FlattenTask { | |
295 | librbd::ImageCtx *ictx; | |
296 | ProgressContext *progress_context; | |
297 | int result; | |
298 | ||
299 | FlattenTask(librbd::ImageCtx *ictx_, ProgressContext *ctx) | |
300 | : ictx(ictx_), progress_context(ctx), result(0) {} | |
301 | ||
302 | void operator()() { | |
9f95a23c | 303 | std::shared_lock l{ictx->owner_lock}; |
7c673cae FG |
304 | C_SaferCond ctx; |
305 | ictx->image_watcher->notify_flatten(0, *progress_context, &ctx); | |
306 | result = ctx.wait(); | |
307 | } | |
308 | }; | |
309 | ||
310 | struct ResizeTask { | |
311 | librbd::ImageCtx *ictx; | |
312 | ProgressContext *progress_context; | |
313 | int result; | |
314 | ||
315 | ResizeTask(librbd::ImageCtx *ictx_, ProgressContext *ctx) | |
316 | : ictx(ictx_), progress_context(ctx), result(0) {} | |
317 | ||
318 | void operator()() { | |
9f95a23c | 319 | std::shared_lock l{ictx->owner_lock}; |
7c673cae FG |
320 | C_SaferCond ctx; |
321 | ictx->image_watcher->notify_resize(0, 0, true, *progress_context, &ctx); | |
322 | result = ctx.wait(); | |
323 | } | |
324 | }; | |
325 | ||
f67539c2 TL |
326 | struct SnapCreateTask { |
327 | librbd::ImageCtx *ictx; | |
328 | ProgressContext *progress_context; | |
329 | int result; | |
330 | ||
331 | SnapCreateTask(librbd::ImageCtx *ictx_, ProgressContext *ctx) | |
332 | : ictx(ictx_), progress_context(ctx), result(0) {} | |
333 | ||
334 | void operator()() { | |
335 | std::shared_lock l{ictx->owner_lock}; | |
336 | C_SaferCond ctx; | |
337 | ictx->image_watcher->notify_snap_create(0, cls::rbd::UserSnapshotNamespace(), | |
338 | "snap", 0, *progress_context, &ctx); | |
339 | result = ctx.wait(); | |
340 | } | |
341 | }; | |
342 | ||
343 | struct SnapRenameTask { | |
344 | librbd::ImageCtx *ictx; | |
345 | int result = 0; | |
346 | ||
347 | SnapRenameTask(librbd::ImageCtx *ictx) | |
348 | : ictx(ictx) { | |
349 | } | |
350 | ||
351 | void operator()() { | |
352 | std::shared_lock l{ictx->owner_lock}; | |
353 | C_SaferCond ctx; | |
354 | ictx->image_watcher->notify_snap_rename(0, 1, "snap-rename", &ctx); | |
355 | result = ctx.wait(); | |
356 | } | |
357 | }; | |
358 | ||
359 | struct SnapRemoveTask { | |
360 | librbd::ImageCtx *ictx; | |
361 | int result = 0; | |
362 | ||
363 | SnapRemoveTask(librbd::ImageCtx *ictx) | |
364 | : ictx(ictx) { | |
365 | } | |
366 | ||
367 | void operator()() { | |
368 | std::shared_lock l{ictx->owner_lock}; | |
369 | C_SaferCond ctx; | |
370 | ictx->image_watcher->notify_snap_remove( | |
371 | 0, cls::rbd::UserSnapshotNamespace(), "snap", &ctx); | |
372 | result = ctx.wait(); | |
373 | } | |
374 | }; | |
375 | ||
376 | struct SnapProtectTask { | |
377 | librbd::ImageCtx *ictx; | |
378 | int result = 0; | |
379 | ||
380 | SnapProtectTask(librbd::ImageCtx *ictx) | |
381 | : ictx(ictx) { | |
382 | } | |
383 | ||
384 | void operator()() { | |
385 | std::shared_lock l{ictx->owner_lock}; | |
386 | C_SaferCond ctx; | |
387 | ictx->image_watcher->notify_snap_protect( | |
388 | 0, cls::rbd::UserSnapshotNamespace(), "snap", &ctx); | |
389 | result = ctx.wait(); | |
390 | } | |
391 | }; | |
392 | ||
393 | struct SnapUnprotectTask { | |
394 | librbd::ImageCtx *ictx; | |
395 | int result = 0; | |
396 | ||
397 | SnapUnprotectTask(librbd::ImageCtx *ictx) | |
398 | : ictx(ictx) { | |
399 | } | |
400 | ||
401 | void operator()() { | |
402 | std::shared_lock l{ictx->owner_lock}; | |
403 | C_SaferCond ctx; | |
404 | ictx->image_watcher->notify_snap_unprotect( | |
405 | 0, cls::rbd::UserSnapshotNamespace(), "snap", &ctx); | |
406 | result = ctx.wait(); | |
407 | } | |
408 | }; | |
409 | ||
410 | struct RenameTask { | |
411 | librbd::ImageCtx *ictx; | |
412 | int result = 0; | |
413 | ||
414 | RenameTask(librbd::ImageCtx *ictx) | |
415 | : ictx(ictx) { | |
416 | } | |
417 | ||
418 | void operator()() { | |
419 | std::shared_lock l{ictx->owner_lock}; | |
420 | C_SaferCond ctx; | |
421 | ictx->image_watcher->notify_rename(0, "new_name", &ctx); | |
422 | result = ctx.wait(); | |
423 | } | |
424 | }; | |
425 | ||
7c673cae FG |
426 | struct RebuildObjectMapTask { |
427 | librbd::ImageCtx *ictx; | |
428 | ProgressContext *progress_context; | |
429 | int result; | |
430 | ||
431 | RebuildObjectMapTask(librbd::ImageCtx *ictx_, ProgressContext *ctx) | |
432 | : ictx(ictx_), progress_context(ctx), result(0) {} | |
433 | ||
434 | void operator()() { | |
9f95a23c | 435 | std::shared_lock l{ictx->owner_lock}; |
7c673cae FG |
436 | C_SaferCond ctx; |
437 | ictx->image_watcher->notify_rebuild_object_map(0, *progress_context, &ctx); | |
438 | result = ctx.wait(); | |
439 | } | |
440 | }; | |
441 | ||
20effc67 TL |
442 | struct UpdateFeaturesTask { |
443 | librbd::ImageCtx *ictx; | |
444 | int result; | |
445 | ||
446 | UpdateFeaturesTask(librbd::ImageCtx *ictx) | |
447 | : ictx(ictx), result(0) {} | |
448 | ||
449 | void operator()() { | |
450 | std::shared_lock l{ictx->owner_lock}; | |
451 | C_SaferCond ctx; | |
452 | uint64_t features = 24; | |
453 | bool enabled = 0; | |
454 | ictx->image_watcher->notify_update_features(0, features, enabled, &ctx); | |
455 | result = ctx.wait(); | |
456 | } | |
457 | }; | |
458 | ||
7c673cae FG |
459 | TEST_F(TestImageWatcher, NotifyHeaderUpdate) { |
460 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
461 | ||
462 | librbd::ImageCtx *ictx; | |
463 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
464 | ||
465 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
466 | ||
467 | m_notify_acks = {{NOTIFY_OP_HEADER_UPDATE, {}}}; | |
468 | ictx->notify_update(); | |
469 | ||
470 | ASSERT_TRUE(wait_for_notifies(*ictx)); | |
471 | ||
472 | NotifyOps expected_notify_ops; | |
473 | expected_notify_ops += NOTIFY_OP_HEADER_UPDATE; | |
474 | ASSERT_EQ(expected_notify_ops, m_notifies); | |
475 | } | |
476 | ||
477 | TEST_F(TestImageWatcher, NotifyFlatten) { | |
478 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
479 | ||
480 | librbd::ImageCtx *ictx; | |
481 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
482 | ||
483 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 484 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
485 | "auto " + stringify(m_watch_ctx->get_handle()))); |
486 | ||
487 | m_notify_acks = {{NOTIFY_OP_FLATTEN, create_response_message(0)}}; | |
488 | ||
489 | ProgressContext progress_context; | |
490 | FlattenTask flatten_task(ictx, &progress_context); | |
491 | boost::thread thread(boost::ref(flatten_task)); | |
492 | ||
493 | ASSERT_TRUE(wait_for_notifies(*ictx)); | |
494 | ||
495 | NotifyOps expected_notify_ops; | |
496 | expected_notify_ops += NOTIFY_OP_FLATTEN; | |
497 | ASSERT_EQ(expected_notify_ops, m_notifies); | |
498 | ||
499 | AsyncRequestId async_request_id; | |
500 | ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_FLATTEN, &async_request_id)); | |
501 | ||
502 | ASSERT_EQ(0, notify_async_progress(ictx, async_request_id, 10, 20)); | |
503 | ASSERT_TRUE(progress_context.wait(ictx, 10, 20)); | |
504 | ||
505 | ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0)); | |
506 | ||
507 | ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10))); | |
508 | ASSERT_EQ(0, flatten_task.result); | |
509 | } | |
510 | ||
511 | TEST_F(TestImageWatcher, NotifyResize) { | |
512 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
513 | ||
514 | librbd::ImageCtx *ictx; | |
515 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
516 | ||
517 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 518 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
519 | "auto " + stringify(m_watch_ctx->get_handle()))); |
520 | ||
521 | m_notify_acks = {{NOTIFY_OP_RESIZE, create_response_message(0)}}; | |
522 | ||
523 | ProgressContext progress_context; | |
524 | ResizeTask resize_task(ictx, &progress_context); | |
525 | boost::thread thread(boost::ref(resize_task)); | |
526 | ||
527 | ASSERT_TRUE(wait_for_notifies(*ictx)); | |
528 | ||
529 | NotifyOps expected_notify_ops; | |
530 | expected_notify_ops += NOTIFY_OP_RESIZE; | |
531 | ASSERT_EQ(expected_notify_ops, m_notifies); | |
532 | ||
533 | AsyncRequestId async_request_id; | |
534 | ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_RESIZE, &async_request_id)); | |
535 | ||
536 | ASSERT_EQ(0, notify_async_progress(ictx, async_request_id, 10, 20)); | |
537 | ASSERT_TRUE(progress_context.wait(ictx, 10, 20)); | |
538 | ||
539 | ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0)); | |
540 | ||
541 | ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10))); | |
542 | ASSERT_EQ(0, resize_task.result); | |
543 | } | |
544 | ||
545 | TEST_F(TestImageWatcher, NotifyRebuildObjectMap) { | |
546 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
547 | ||
548 | librbd::ImageCtx *ictx; | |
549 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
550 | ||
551 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 552 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
553 | "auto " + stringify(m_watch_ctx->get_handle()))); |
554 | ||
555 | m_notify_acks = {{NOTIFY_OP_REBUILD_OBJECT_MAP, create_response_message(0)}}; | |
556 | ||
557 | ProgressContext progress_context; | |
558 | RebuildObjectMapTask rebuild_task(ictx, &progress_context); | |
559 | boost::thread thread(boost::ref(rebuild_task)); | |
560 | ||
561 | ASSERT_TRUE(wait_for_notifies(*ictx)); | |
562 | ||
563 | NotifyOps expected_notify_ops; | |
564 | expected_notify_ops += NOTIFY_OP_REBUILD_OBJECT_MAP; | |
565 | ASSERT_EQ(expected_notify_ops, m_notifies); | |
566 | ||
567 | AsyncRequestId async_request_id; | |
568 | ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_REBUILD_OBJECT_MAP, | |
569 | &async_request_id)); | |
570 | ||
571 | ASSERT_EQ(0, notify_async_progress(ictx, async_request_id, 10, 20)); | |
572 | ASSERT_TRUE(progress_context.wait(ictx, 10, 20)); | |
573 | ||
574 | ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0)); | |
575 | ||
576 | ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10))); | |
577 | ASSERT_EQ(0, rebuild_task.result); | |
578 | } | |
579 | ||
20effc67 TL |
580 | TEST_F(TestImageWatcher, NotifyUpdateFeatures) { |
581 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
582 | ||
583 | librbd::ImageCtx *ictx; | |
584 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
585 | ||
586 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
587 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, | |
588 | "auto " + stringify(m_watch_ctx->get_handle()))); | |
589 | ||
590 | m_notify_acks = {{NOTIFY_OP_UPDATE_FEATURES, create_response_message(0)}}; | |
591 | ||
592 | UpdateFeaturesTask update_features_task(ictx); | |
593 | boost::thread thread(boost::ref(update_features_task)); | |
594 | ||
595 | ASSERT_TRUE(wait_for_notifies(*ictx)); | |
596 | ||
597 | NotifyOps expected_notify_ops; | |
598 | expected_notify_ops += NOTIFY_OP_UPDATE_FEATURES; | |
599 | ASSERT_EQ(expected_notify_ops, m_notifies); | |
600 | ||
601 | AsyncRequestId async_request_id; | |
602 | ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_UPDATE_FEATURES, | |
603 | &async_request_id)); | |
604 | ||
605 | ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0)); | |
606 | ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10))); | |
607 | ASSERT_EQ(0, update_features_task.result); | |
608 | } | |
609 | ||
7c673cae FG |
610 | TEST_F(TestImageWatcher, NotifySnapCreate) { |
611 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
612 | ||
613 | librbd::ImageCtx *ictx; | |
614 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
615 | ||
616 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 617 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
618 | "auto " + stringify(m_watch_ctx->get_handle()))); |
619 | ||
620 | m_notify_acks = {{NOTIFY_OP_SNAP_CREATE, create_response_message(0)}}; | |
621 | ||
f67539c2 TL |
622 | ProgressContext progress_context; |
623 | SnapCreateTask snap_create_task(ictx, &progress_context); | |
624 | boost::thread thread(boost::ref(snap_create_task)); | |
625 | ||
626 | ASSERT_TRUE(wait_for_notifies(*ictx)); | |
7c673cae FG |
627 | |
628 | NotifyOps expected_notify_ops; | |
629 | expected_notify_ops += NOTIFY_OP_SNAP_CREATE; | |
630 | ASSERT_EQ(expected_notify_ops, m_notifies); | |
f67539c2 TL |
631 | |
632 | AsyncRequestId async_request_id; | |
633 | ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_CREATE, | |
634 | &async_request_id)); | |
635 | ||
636 | ASSERT_EQ(0, notify_async_progress(ictx, async_request_id, 1, 10)); | |
637 | ASSERT_TRUE(progress_context.wait(ictx, 1, 10)); | |
638 | ||
639 | ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0)); | |
640 | ||
641 | ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10))); | |
642 | ASSERT_EQ(0, snap_create_task.result); | |
7c673cae FG |
643 | } |
644 | ||
645 | TEST_F(TestImageWatcher, NotifySnapCreateError) { | |
646 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
647 | ||
648 | librbd::ImageCtx *ictx; | |
649 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
650 | ||
651 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 652 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
653 | "auto " + stringify(m_watch_ctx->get_handle()))); |
654 | ||
655 | m_notify_acks = {{NOTIFY_OP_SNAP_CREATE, create_response_message(-EEXIST)}}; | |
656 | ||
9f95a23c | 657 | std::shared_lock l{ictx->owner_lock}; |
7c673cae | 658 | C_SaferCond notify_ctx; |
f67539c2 TL |
659 | librbd::NoOpProgressContext prog_ctx; |
660 | ictx->image_watcher->notify_snap_create(0, cls::rbd::UserSnapshotNamespace(), | |
661 | "snap", 0, prog_ctx, ¬ify_ctx); | |
7c673cae FG |
662 | ASSERT_EQ(-EEXIST, notify_ctx.wait()); |
663 | ||
664 | NotifyOps expected_notify_ops; | |
665 | expected_notify_ops += NOTIFY_OP_SNAP_CREATE; | |
666 | ASSERT_EQ(expected_notify_ops, m_notifies); | |
667 | } | |
668 | ||
669 | TEST_F(TestImageWatcher, NotifySnapRename) { | |
670 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
671 | ||
672 | librbd::ImageCtx *ictx; | |
673 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
674 | ||
675 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 676 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
677 | "auto " + stringify(m_watch_ctx->get_handle()))); |
678 | ||
679 | m_notify_acks = {{NOTIFY_OP_SNAP_RENAME, create_response_message(0)}}; | |
680 | ||
f67539c2 TL |
681 | SnapRenameTask snap_rename_task(ictx); |
682 | boost::thread thread(boost::ref(snap_rename_task)); | |
683 | ||
684 | ASSERT_TRUE(wait_for_notifies(*ictx)); | |
7c673cae FG |
685 | |
686 | NotifyOps expected_notify_ops; | |
687 | expected_notify_ops += NOTIFY_OP_SNAP_RENAME; | |
688 | ASSERT_EQ(expected_notify_ops, m_notifies); | |
f67539c2 TL |
689 | |
690 | AsyncRequestId async_request_id; | |
691 | ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_RENAME, | |
692 | &async_request_id)); | |
693 | ||
694 | ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0)); | |
695 | ||
696 | ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10))); | |
697 | ASSERT_EQ(0, snap_rename_task.result); | |
7c673cae FG |
698 | } |
699 | ||
700 | TEST_F(TestImageWatcher, NotifySnapRenameError) { | |
701 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
702 | ||
703 | librbd::ImageCtx *ictx; | |
704 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
705 | ||
706 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 707 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
708 | "auto " + stringify(m_watch_ctx->get_handle()))); |
709 | ||
710 | m_notify_acks = {{NOTIFY_OP_SNAP_RENAME, create_response_message(-EEXIST)}}; | |
711 | ||
9f95a23c | 712 | std::shared_lock l{ictx->owner_lock}; |
7c673cae | 713 | C_SaferCond notify_ctx; |
f67539c2 | 714 | ictx->image_watcher->notify_snap_rename(0, 1, "snap-rename", ¬ify_ctx); |
7c673cae FG |
715 | ASSERT_EQ(-EEXIST, notify_ctx.wait()); |
716 | ||
717 | NotifyOps expected_notify_ops; | |
718 | expected_notify_ops += NOTIFY_OP_SNAP_RENAME; | |
719 | ASSERT_EQ(expected_notify_ops, m_notifies); | |
720 | } | |
721 | ||
722 | TEST_F(TestImageWatcher, NotifySnapRemove) { | |
723 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
724 | ||
725 | librbd::ImageCtx *ictx; | |
726 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
727 | ||
728 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 729 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
730 | "auto " + stringify(m_watch_ctx->get_handle()))); |
731 | ||
732 | m_notify_acks = {{NOTIFY_OP_SNAP_REMOVE, create_response_message(0)}}; | |
733 | ||
f67539c2 TL |
734 | SnapRemoveTask snap_remove_task(ictx); |
735 | boost::thread thread(boost::ref(snap_remove_task)); | |
736 | ||
737 | ASSERT_TRUE(wait_for_notifies(*ictx)); | |
7c673cae FG |
738 | |
739 | NotifyOps expected_notify_ops; | |
740 | expected_notify_ops += NOTIFY_OP_SNAP_REMOVE; | |
741 | ASSERT_EQ(expected_notify_ops, m_notifies); | |
f67539c2 TL |
742 | |
743 | AsyncRequestId async_request_id; | |
744 | ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_REMOVE, | |
745 | &async_request_id)); | |
746 | ||
747 | ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0)); | |
748 | ||
749 | ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10))); | |
750 | ASSERT_EQ(0, snap_remove_task.result); | |
7c673cae FG |
751 | } |
752 | ||
753 | TEST_F(TestImageWatcher, NotifySnapProtect) { | |
754 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
755 | ||
756 | librbd::ImageCtx *ictx; | |
757 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
758 | ||
759 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 760 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
761 | "auto " + stringify(m_watch_ctx->get_handle()))); |
762 | ||
763 | m_notify_acks = {{NOTIFY_OP_SNAP_PROTECT, create_response_message(0)}}; | |
764 | ||
f67539c2 TL |
765 | SnapProtectTask snap_protect_task(ictx); |
766 | boost::thread thread(boost::ref(snap_protect_task)); | |
767 | ||
768 | ASSERT_TRUE(wait_for_notifies(*ictx)); | |
7c673cae FG |
769 | |
770 | NotifyOps expected_notify_ops; | |
771 | expected_notify_ops += NOTIFY_OP_SNAP_PROTECT; | |
772 | ASSERT_EQ(expected_notify_ops, m_notifies); | |
f67539c2 TL |
773 | |
774 | AsyncRequestId async_request_id; | |
775 | ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_PROTECT, | |
776 | &async_request_id)); | |
777 | ||
778 | ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0)); | |
779 | ||
780 | ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10))); | |
781 | ASSERT_EQ(0, snap_protect_task.result); | |
7c673cae FG |
782 | } |
783 | ||
784 | TEST_F(TestImageWatcher, NotifySnapUnprotect) { | |
785 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
786 | ||
787 | librbd::ImageCtx *ictx; | |
788 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
789 | ||
790 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 791 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
792 | "auto " + stringify(m_watch_ctx->get_handle()))); |
793 | ||
794 | m_notify_acks = {{NOTIFY_OP_SNAP_UNPROTECT, create_response_message(0)}}; | |
795 | ||
f67539c2 TL |
796 | SnapUnprotectTask snap_unprotect_task(ictx); |
797 | boost::thread thread(boost::ref(snap_unprotect_task)); | |
798 | ||
799 | ASSERT_TRUE(wait_for_notifies(*ictx)); | |
7c673cae FG |
800 | |
801 | NotifyOps expected_notify_ops; | |
802 | expected_notify_ops += NOTIFY_OP_SNAP_UNPROTECT; | |
803 | ASSERT_EQ(expected_notify_ops, m_notifies); | |
f67539c2 TL |
804 | |
805 | AsyncRequestId async_request_id; | |
806 | ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_SNAP_UNPROTECT, | |
807 | &async_request_id)); | |
808 | ||
809 | ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0)); | |
810 | ||
811 | ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10))); | |
812 | ASSERT_EQ(0, snap_unprotect_task.result); | |
7c673cae FG |
813 | } |
814 | ||
815 | TEST_F(TestImageWatcher, NotifyRename) { | |
816 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
817 | ||
818 | librbd::ImageCtx *ictx; | |
819 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
820 | ||
821 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 822 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
823 | "auto " + stringify(m_watch_ctx->get_handle()))); |
824 | ||
825 | m_notify_acks = {{NOTIFY_OP_RENAME, create_response_message(0)}}; | |
826 | ||
f67539c2 TL |
827 | RenameTask rename_task(ictx); |
828 | boost::thread thread(boost::ref(rename_task)); | |
829 | ||
830 | ASSERT_TRUE(wait_for_notifies(*ictx)); | |
7c673cae FG |
831 | |
832 | NotifyOps expected_notify_ops; | |
833 | expected_notify_ops += NOTIFY_OP_RENAME; | |
834 | ASSERT_EQ(expected_notify_ops, m_notifies); | |
f67539c2 TL |
835 | |
836 | AsyncRequestId async_request_id; | |
837 | ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_RENAME, | |
838 | &async_request_id)); | |
839 | ||
840 | ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0)); | |
841 | ||
842 | ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10))); | |
843 | ASSERT_EQ(0, rename_task.result); | |
7c673cae FG |
844 | } |
845 | ||
846 | TEST_F(TestImageWatcher, NotifyAsyncTimedOut) { | |
847 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
848 | ||
849 | librbd::ImageCtx *ictx; | |
850 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
851 | ||
852 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 853 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
854 | "auto " + stringify(m_watch_ctx->get_handle()))); |
855 | ||
856 | m_notify_acks = {{NOTIFY_OP_FLATTEN, {}}}; | |
857 | ||
858 | ProgressContext progress_context; | |
859 | FlattenTask flatten_task(ictx, &progress_context); | |
860 | boost::thread thread(boost::ref(flatten_task)); | |
861 | ||
862 | ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10))); | |
863 | ASSERT_EQ(-ETIMEDOUT, flatten_task.result); | |
864 | } | |
865 | ||
866 | TEST_F(TestImageWatcher, NotifyAsyncError) { | |
867 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
868 | ||
869 | librbd::ImageCtx *ictx; | |
870 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
871 | ||
872 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 873 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
874 | "auto " + stringify(m_watch_ctx->get_handle()))); |
875 | ||
876 | m_notify_acks = {{NOTIFY_OP_FLATTEN, create_response_message(-EIO)}}; | |
877 | ||
878 | ProgressContext progress_context; | |
879 | FlattenTask flatten_task(ictx, &progress_context); | |
880 | boost::thread thread(boost::ref(flatten_task)); | |
881 | ||
882 | ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10))); | |
883 | ASSERT_EQ(-EIO, flatten_task.result); | |
884 | } | |
885 | ||
886 | TEST_F(TestImageWatcher, NotifyAsyncCompleteError) { | |
887 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
888 | ||
889 | librbd::ImageCtx *ictx; | |
890 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
891 | ||
892 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 893 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
894 | "auto " + stringify(m_watch_ctx->get_handle()))); |
895 | ||
896 | m_notify_acks = {{NOTIFY_OP_FLATTEN, create_response_message(0)}}; | |
897 | ||
898 | ProgressContext progress_context; | |
899 | FlattenTask flatten_task(ictx, &progress_context); | |
900 | boost::thread thread(boost::ref(flatten_task)); | |
901 | ||
902 | ASSERT_TRUE(wait_for_notifies(*ictx)); | |
903 | ||
904 | NotifyOps expected_notify_ops; | |
905 | expected_notify_ops += NOTIFY_OP_FLATTEN; | |
906 | ASSERT_EQ(expected_notify_ops, m_notifies); | |
907 | ||
908 | AsyncRequestId async_request_id; | |
909 | ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_FLATTEN, &async_request_id)); | |
910 | ||
911 | ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, -ESHUTDOWN)); | |
912 | ||
913 | ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10))); | |
914 | ASSERT_EQ(-ESHUTDOWN, flatten_task.result); | |
915 | } | |
916 | ||
917 | TEST_F(TestImageWatcher, NotifyAsyncRequestTimedOut) { | |
918 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
919 | ||
920 | librbd::ImageCtx *ictx; | |
921 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
922 | ||
11fdf7f2 | 923 | ictx->config.set_val("rbd_request_timed_out_seconds", "0"); |
7c673cae FG |
924 | |
925 | ASSERT_EQ(0, register_image_watch(*ictx)); | |
f67539c2 | 926 | ASSERT_EQ(0, lock_image(*ictx, ClsLockType::EXCLUSIVE, |
7c673cae FG |
927 | "auto " + stringify(m_watch_ctx->get_handle()))); |
928 | ||
929 | m_notify_acks = {{NOTIFY_OP_FLATTEN, create_response_message(0)}}; | |
930 | ||
931 | ProgressContext progress_context; | |
932 | FlattenTask flatten_task(ictx, &progress_context); | |
933 | boost::thread thread(boost::ref(flatten_task)); | |
934 | ||
935 | ASSERT_TRUE(wait_for_notifies(*ictx)); | |
936 | ||
937 | ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10))); | |
938 | ASSERT_EQ(-ETIMEDOUT, flatten_task.result); | |
939 | } | |
940 |