]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/test_ImageWatcher.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / test / librbd / test_ImageWatcher.cc
CommitLineData
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 31using namespace std::chrono_literals;
7c673cae
FG
32using namespace ceph;
33using namespace boost::assign;
34using namespace librbd::watch_notify;
35
36void register_test_image_watcher() {
37}
38
39class TestImageWatcher : public TestFixture {
40public:
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
264struct 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
294struct 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
310struct 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
326struct 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
343struct 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
359struct 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
376struct 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
393struct 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
410struct 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
426struct 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
442struct 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
459TEST_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
477TEST_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
511TEST_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
545TEST_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
580TEST_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
610TEST_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
645TEST_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, &notify_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
669TEST_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
700TEST_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", &notify_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
722TEST_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
753TEST_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
784TEST_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
815TEST_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
846TEST_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
866TEST_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
886TEST_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
917TEST_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