]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/test_ImageWatcher.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / test / librbd / test_ImageWatcher.cc
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"
10 #include "common/errno.h"
11 #include "common/Mutex.h"
12 #include "common/RWLock.h"
13 #include "cls/lock/cls_lock_client.h"
14 #include "cls/lock/cls_lock_types.h"
15 #include "librbd/internal.h"
16 #include "librbd/ImageCtx.h"
17 #include "librbd/ImageWatcher.h"
18 #include "librbd/WatchNotifyTypes.h"
19 #include "librbd/io/AioCompletion.h"
20 #include "librbd/io/ImageRequestWQ.h"
21 #include "test/librados/test.h"
22 #include "gtest/gtest.h"
23 #include <boost/assign/std/set.hpp>
24 #include <boost/assign/std/map.hpp>
25 #include <boost/bind.hpp>
26 #include <boost/scope_exit.hpp>
27 #include <boost/thread/thread.hpp>
28 #include <iostream>
29 #include <map>
30 #include <set>
31 #include <sstream>
32 #include <vector>
33
34 using namespace ceph;
35 using namespace boost::assign;
36 using namespace librbd::watch_notify;
37
38 void register_test_image_watcher() {
39 }
40
41 class TestImageWatcher : public TestFixture {
42 public:
43
44 TestImageWatcher() : m_watch_ctx(NULL), m_callback_lock("m_callback_lock")
45 {
46 }
47
48 class WatchCtx : public librados::WatchCtx2 {
49 public:
50 explicit WatchCtx(TestImageWatcher &parent) : m_parent(parent), m_handle(0) {}
51
52 int watch(const librbd::ImageCtx &ictx) {
53 m_header_oid = ictx.header_oid;
54 return m_parent.m_ioctx.watch2(m_header_oid, &m_handle, this);
55 }
56
57 int unwatch() {
58 return m_parent.m_ioctx.unwatch2(m_handle);
59 }
60
61 void handle_notify(uint64_t notify_id,
62 uint64_t cookie,
63 uint64_t notifier_id,
64 bufferlist& bl) override {
65 try {
66 int op;
67 bufferlist payload;
68 bufferlist::iterator iter = bl.begin();
69 DECODE_START(1, iter);
70 ::decode(op, iter);
71 iter.copy_all(payload);
72 DECODE_FINISH(iter);
73
74 NotifyOp notify_op = static_cast<NotifyOp>(op);
75 /*
76 std::cout << "NOTIFY: " << notify_op << ", " << notify_id
77 << ", " << cookie << ", " << notifier_id << std::endl;
78 */
79
80 Mutex::Locker l(m_parent.m_callback_lock);
81 m_parent.m_notify_payloads[notify_op] = payload;
82
83 bufferlist reply;
84 if (m_parent.m_notify_acks.count(notify_op) > 0) {
85 reply = m_parent.m_notify_acks[notify_op];
86 m_parent.m_notifies += notify_op;
87 m_parent.m_callback_cond.Signal();
88 }
89
90 m_parent.m_ioctx.notify_ack(m_header_oid, notify_id, cookie, reply);
91 } catch (...) {
92 FAIL();
93 }
94 }
95
96 void handle_error(uint64_t cookie, int err) override {
97 std::cerr << "ERROR: " << cookie << ", " << cpp_strerror(err)
98 << std::endl;
99 }
100
101 uint64_t get_handle() const {
102 return m_handle;
103 }
104
105 private:
106 TestImageWatcher &m_parent;
107 std::string m_header_oid;
108 uint64_t m_handle;
109 };
110
111 void TearDown() override {
112 deregister_image_watch();
113 TestFixture::TearDown();
114 }
115
116 int deregister_image_watch() {
117 if (m_watch_ctx != NULL) {
118 int r = m_watch_ctx->unwatch();
119
120 librados::Rados rados(m_ioctx);
121 rados.watch_flush();
122
123 delete m_watch_ctx;
124 m_watch_ctx = NULL;
125 return r;
126 }
127 return 0;
128 }
129
130 int register_image_watch(librbd::ImageCtx &ictx) {
131 m_watch_ctx = new WatchCtx(*this);
132 return m_watch_ctx->watch(ictx);
133 }
134
135 bool wait_for_notifies(librbd::ImageCtx &ictx) {
136 Mutex::Locker l(m_callback_lock);
137 while (m_notifies.size() < m_notify_acks.size()) {
138 int r = m_callback_cond.WaitInterval(m_callback_lock,
139 utime_t(10, 0));
140 if (r != 0) {
141 break;
142 }
143 }
144 return (m_notifies.size() == m_notify_acks.size());
145 }
146
147 bufferlist create_response_message(int r) {
148 bufferlist bl;
149 ::encode(ResponseMessage(r), bl);
150 return bl;
151 }
152
153 bool extract_async_request_id(NotifyOp op, AsyncRequestId *id) {
154 if (m_notify_payloads.count(op) == 0) {
155 return false;
156 }
157
158 bufferlist payload = m_notify_payloads[op];
159 bufferlist::iterator iter = payload.begin();
160
161 switch (op) {
162 case NOTIFY_OP_FLATTEN:
163 {
164 FlattenPayload payload;
165 payload.decode(2, iter);
166 *id = payload.async_request_id;
167 }
168 return true;
169 case NOTIFY_OP_RESIZE:
170 {
171 ResizePayload payload;
172 payload.decode(2, iter);
173 *id = payload.async_request_id;
174 }
175 return true;
176 case NOTIFY_OP_REBUILD_OBJECT_MAP:
177 {
178 RebuildObjectMapPayload payload;
179 payload.decode(2, iter);
180 *id = payload.async_request_id;
181 }
182 return true;
183 default:
184 break;
185 }
186 return false;
187 }
188
189 int notify_async_progress(librbd::ImageCtx *ictx, const AsyncRequestId &id,
190 uint64_t offset, uint64_t total) {
191 bufferlist bl;
192 ::encode(NotifyMessage(AsyncProgressPayload(id, offset, total)), bl);
193 return m_ioctx.notify2(ictx->header_oid, bl, 5000, NULL);
194 }
195
196 int notify_async_complete(librbd::ImageCtx *ictx, const AsyncRequestId &id,
197 int r) {
198 bufferlist bl;
199 ::encode(NotifyMessage(AsyncCompletePayload(id, r)), bl);
200 return m_ioctx.notify2(ictx->header_oid, bl, 5000, NULL);
201 }
202
203 typedef std::map<NotifyOp, bufferlist> NotifyOpPayloads;
204 typedef std::set<NotifyOp> NotifyOps;
205
206 WatchCtx *m_watch_ctx;
207
208 NotifyOps m_notifies;
209 NotifyOpPayloads m_notify_payloads;
210 NotifyOpPayloads m_notify_acks;
211
212 AsyncRequestId m_async_request_id;
213
214 Mutex m_callback_lock;
215 Cond m_callback_cond;
216
217 };
218
219 struct ProgressContext : public librbd::ProgressContext {
220 Mutex mutex;
221 Cond cond;
222 bool received;
223 uint64_t offset;
224 uint64_t total;
225
226 ProgressContext() : mutex("ProgressContext::mutex"), received(false),
227 offset(0), total(0) {}
228
229 int update_progress(uint64_t offset_, uint64_t total_) override {
230 Mutex::Locker l(mutex);
231 offset = offset_;
232 total = total_;
233 received = true;
234 cond.Signal();
235 return 0;
236 }
237
238 bool wait(librbd::ImageCtx *ictx, uint64_t offset_, uint64_t total_) {
239 Mutex::Locker l(mutex);
240 while (!received) {
241 int r = cond.WaitInterval(mutex, utime_t(10, 0));
242 if (r != 0) {
243 break;
244 }
245 }
246 return (received && offset == offset_ && total == total_);
247 }
248 };
249
250 struct FlattenTask {
251 librbd::ImageCtx *ictx;
252 ProgressContext *progress_context;
253 int result;
254
255 FlattenTask(librbd::ImageCtx *ictx_, ProgressContext *ctx)
256 : ictx(ictx_), progress_context(ctx), result(0) {}
257
258 void operator()() {
259 RWLock::RLocker l(ictx->owner_lock);
260 C_SaferCond ctx;
261 ictx->image_watcher->notify_flatten(0, *progress_context, &ctx);
262 result = ctx.wait();
263 }
264 };
265
266 struct ResizeTask {
267 librbd::ImageCtx *ictx;
268 ProgressContext *progress_context;
269 int result;
270
271 ResizeTask(librbd::ImageCtx *ictx_, ProgressContext *ctx)
272 : ictx(ictx_), progress_context(ctx), result(0) {}
273
274 void operator()() {
275 RWLock::RLocker l(ictx->owner_lock);
276 C_SaferCond ctx;
277 ictx->image_watcher->notify_resize(0, 0, true, *progress_context, &ctx);
278 result = ctx.wait();
279 }
280 };
281
282 struct RebuildObjectMapTask {
283 librbd::ImageCtx *ictx;
284 ProgressContext *progress_context;
285 int result;
286
287 RebuildObjectMapTask(librbd::ImageCtx *ictx_, ProgressContext *ctx)
288 : ictx(ictx_), progress_context(ctx), result(0) {}
289
290 void operator()() {
291 RWLock::RLocker l(ictx->owner_lock);
292 C_SaferCond ctx;
293 ictx->image_watcher->notify_rebuild_object_map(0, *progress_context, &ctx);
294 result = ctx.wait();
295 }
296 };
297
298 TEST_F(TestImageWatcher, NotifyHeaderUpdate) {
299 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
300
301 librbd::ImageCtx *ictx;
302 ASSERT_EQ(0, open_image(m_image_name, &ictx));
303
304 ASSERT_EQ(0, register_image_watch(*ictx));
305
306 m_notify_acks = {{NOTIFY_OP_HEADER_UPDATE, {}}};
307 ictx->notify_update();
308
309 ASSERT_TRUE(wait_for_notifies(*ictx));
310
311 NotifyOps expected_notify_ops;
312 expected_notify_ops += NOTIFY_OP_HEADER_UPDATE;
313 ASSERT_EQ(expected_notify_ops, m_notifies);
314 }
315
316 TEST_F(TestImageWatcher, NotifyFlatten) {
317 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
318
319 librbd::ImageCtx *ictx;
320 ASSERT_EQ(0, open_image(m_image_name, &ictx));
321
322 ASSERT_EQ(0, register_image_watch(*ictx));
323 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
324 "auto " + stringify(m_watch_ctx->get_handle())));
325
326 m_notify_acks = {{NOTIFY_OP_FLATTEN, create_response_message(0)}};
327
328 ProgressContext progress_context;
329 FlattenTask flatten_task(ictx, &progress_context);
330 boost::thread thread(boost::ref(flatten_task));
331
332 ASSERT_TRUE(wait_for_notifies(*ictx));
333
334 NotifyOps expected_notify_ops;
335 expected_notify_ops += NOTIFY_OP_FLATTEN;
336 ASSERT_EQ(expected_notify_ops, m_notifies);
337
338 AsyncRequestId async_request_id;
339 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_FLATTEN, &async_request_id));
340
341 ASSERT_EQ(0, notify_async_progress(ictx, async_request_id, 10, 20));
342 ASSERT_TRUE(progress_context.wait(ictx, 10, 20));
343
344 ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0));
345
346 ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
347 ASSERT_EQ(0, flatten_task.result);
348 }
349
350 TEST_F(TestImageWatcher, NotifyResize) {
351 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
352
353 librbd::ImageCtx *ictx;
354 ASSERT_EQ(0, open_image(m_image_name, &ictx));
355
356 ASSERT_EQ(0, register_image_watch(*ictx));
357 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
358 "auto " + stringify(m_watch_ctx->get_handle())));
359
360 m_notify_acks = {{NOTIFY_OP_RESIZE, create_response_message(0)}};
361
362 ProgressContext progress_context;
363 ResizeTask resize_task(ictx, &progress_context);
364 boost::thread thread(boost::ref(resize_task));
365
366 ASSERT_TRUE(wait_for_notifies(*ictx));
367
368 NotifyOps expected_notify_ops;
369 expected_notify_ops += NOTIFY_OP_RESIZE;
370 ASSERT_EQ(expected_notify_ops, m_notifies);
371
372 AsyncRequestId async_request_id;
373 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_RESIZE, &async_request_id));
374
375 ASSERT_EQ(0, notify_async_progress(ictx, async_request_id, 10, 20));
376 ASSERT_TRUE(progress_context.wait(ictx, 10, 20));
377
378 ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0));
379
380 ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
381 ASSERT_EQ(0, resize_task.result);
382 }
383
384 TEST_F(TestImageWatcher, NotifyRebuildObjectMap) {
385 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
386
387 librbd::ImageCtx *ictx;
388 ASSERT_EQ(0, open_image(m_image_name, &ictx));
389
390 ASSERT_EQ(0, register_image_watch(*ictx));
391 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
392 "auto " + stringify(m_watch_ctx->get_handle())));
393
394 m_notify_acks = {{NOTIFY_OP_REBUILD_OBJECT_MAP, create_response_message(0)}};
395
396 ProgressContext progress_context;
397 RebuildObjectMapTask rebuild_task(ictx, &progress_context);
398 boost::thread thread(boost::ref(rebuild_task));
399
400 ASSERT_TRUE(wait_for_notifies(*ictx));
401
402 NotifyOps expected_notify_ops;
403 expected_notify_ops += NOTIFY_OP_REBUILD_OBJECT_MAP;
404 ASSERT_EQ(expected_notify_ops, m_notifies);
405
406 AsyncRequestId async_request_id;
407 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_REBUILD_OBJECT_MAP,
408 &async_request_id));
409
410 ASSERT_EQ(0, notify_async_progress(ictx, async_request_id, 10, 20));
411 ASSERT_TRUE(progress_context.wait(ictx, 10, 20));
412
413 ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0));
414
415 ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
416 ASSERT_EQ(0, rebuild_task.result);
417 }
418
419 TEST_F(TestImageWatcher, NotifySnapCreate) {
420 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
421
422 librbd::ImageCtx *ictx;
423 ASSERT_EQ(0, open_image(m_image_name, &ictx));
424
425 ASSERT_EQ(0, register_image_watch(*ictx));
426 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
427 "auto " + stringify(m_watch_ctx->get_handle())));
428
429 m_notify_acks = {{NOTIFY_OP_SNAP_CREATE, create_response_message(0)}};
430
431 RWLock::RLocker l(ictx->owner_lock);
432 C_SaferCond notify_ctx;
433 ictx->image_watcher->notify_snap_create(cls::rbd::UserSnapshotNamespace(),
434 "snap", &notify_ctx);
435 ASSERT_EQ(0, notify_ctx.wait());
436
437 NotifyOps expected_notify_ops;
438 expected_notify_ops += NOTIFY_OP_SNAP_CREATE;
439 ASSERT_EQ(expected_notify_ops, m_notifies);
440 }
441
442 TEST_F(TestImageWatcher, NotifySnapCreateError) {
443 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
444
445 librbd::ImageCtx *ictx;
446 ASSERT_EQ(0, open_image(m_image_name, &ictx));
447
448 ASSERT_EQ(0, register_image_watch(*ictx));
449 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
450 "auto " + stringify(m_watch_ctx->get_handle())));
451
452 m_notify_acks = {{NOTIFY_OP_SNAP_CREATE, create_response_message(-EEXIST)}};
453
454 RWLock::RLocker l(ictx->owner_lock);
455 C_SaferCond notify_ctx;
456 ictx->image_watcher->notify_snap_create(cls::rbd::UserSnapshotNamespace(),
457 "snap", &notify_ctx);
458 ASSERT_EQ(-EEXIST, notify_ctx.wait());
459
460 NotifyOps expected_notify_ops;
461 expected_notify_ops += NOTIFY_OP_SNAP_CREATE;
462 ASSERT_EQ(expected_notify_ops, m_notifies);
463 }
464
465 TEST_F(TestImageWatcher, NotifySnapRename) {
466 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
467
468 librbd::ImageCtx *ictx;
469 ASSERT_EQ(0, open_image(m_image_name, &ictx));
470
471 ASSERT_EQ(0, register_image_watch(*ictx));
472 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
473 "auto " + stringify(m_watch_ctx->get_handle())));
474
475 m_notify_acks = {{NOTIFY_OP_SNAP_RENAME, create_response_message(0)}};
476
477 RWLock::RLocker l(ictx->owner_lock);
478 C_SaferCond notify_ctx;
479 ictx->image_watcher->notify_snap_rename(1, "snap-rename", &notify_ctx);
480 ASSERT_EQ(0, notify_ctx.wait());
481
482 NotifyOps expected_notify_ops;
483 expected_notify_ops += NOTIFY_OP_SNAP_RENAME;
484 ASSERT_EQ(expected_notify_ops, m_notifies);
485 }
486
487 TEST_F(TestImageWatcher, NotifySnapRenameError) {
488 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
489
490 librbd::ImageCtx *ictx;
491 ASSERT_EQ(0, open_image(m_image_name, &ictx));
492
493 ASSERT_EQ(0, register_image_watch(*ictx));
494 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
495 "auto " + stringify(m_watch_ctx->get_handle())));
496
497 m_notify_acks = {{NOTIFY_OP_SNAP_RENAME, create_response_message(-EEXIST)}};
498
499 RWLock::RLocker l(ictx->owner_lock);
500 C_SaferCond notify_ctx;
501 ictx->image_watcher->notify_snap_rename(1, "snap-rename", &notify_ctx);
502 ASSERT_EQ(-EEXIST, notify_ctx.wait());
503
504 NotifyOps expected_notify_ops;
505 expected_notify_ops += NOTIFY_OP_SNAP_RENAME;
506 ASSERT_EQ(expected_notify_ops, m_notifies);
507 }
508
509 TEST_F(TestImageWatcher, NotifySnapRemove) {
510 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
511
512 librbd::ImageCtx *ictx;
513 ASSERT_EQ(0, open_image(m_image_name, &ictx));
514
515 ASSERT_EQ(0, register_image_watch(*ictx));
516 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
517 "auto " + stringify(m_watch_ctx->get_handle())));
518
519 m_notify_acks = {{NOTIFY_OP_SNAP_REMOVE, create_response_message(0)}};
520
521 RWLock::RLocker l(ictx->owner_lock);
522 C_SaferCond notify_ctx;
523 ictx->image_watcher->notify_snap_remove(cls::rbd::UserSnapshotNamespace(),
524 "snap",
525 &notify_ctx);
526 ASSERT_EQ(0, notify_ctx.wait());
527
528 NotifyOps expected_notify_ops;
529 expected_notify_ops += NOTIFY_OP_SNAP_REMOVE;
530 ASSERT_EQ(expected_notify_ops, m_notifies);
531 }
532
533 TEST_F(TestImageWatcher, NotifySnapProtect) {
534 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
535
536 librbd::ImageCtx *ictx;
537 ASSERT_EQ(0, open_image(m_image_name, &ictx));
538
539 ASSERT_EQ(0, register_image_watch(*ictx));
540 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
541 "auto " + stringify(m_watch_ctx->get_handle())));
542
543 m_notify_acks = {{NOTIFY_OP_SNAP_PROTECT, create_response_message(0)}};
544
545 RWLock::RLocker l(ictx->owner_lock);
546 C_SaferCond notify_ctx;
547 ictx->image_watcher->notify_snap_protect(cls::rbd::UserSnapshotNamespace(),
548 "snap",
549 &notify_ctx);
550 ASSERT_EQ(0, notify_ctx.wait());
551
552 NotifyOps expected_notify_ops;
553 expected_notify_ops += NOTIFY_OP_SNAP_PROTECT;
554 ASSERT_EQ(expected_notify_ops, m_notifies);
555 }
556
557 TEST_F(TestImageWatcher, NotifySnapUnprotect) {
558 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
559
560 librbd::ImageCtx *ictx;
561 ASSERT_EQ(0, open_image(m_image_name, &ictx));
562
563 ASSERT_EQ(0, register_image_watch(*ictx));
564 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
565 "auto " + stringify(m_watch_ctx->get_handle())));
566
567 m_notify_acks = {{NOTIFY_OP_SNAP_UNPROTECT, create_response_message(0)}};
568
569 RWLock::RLocker l(ictx->owner_lock);
570 C_SaferCond notify_ctx;
571 ictx->image_watcher->notify_snap_unprotect(cls::rbd::UserSnapshotNamespace(),
572 "snap",
573 &notify_ctx);
574 ASSERT_EQ(0, notify_ctx.wait());
575
576 NotifyOps expected_notify_ops;
577 expected_notify_ops += NOTIFY_OP_SNAP_UNPROTECT;
578 ASSERT_EQ(expected_notify_ops, m_notifies);
579 }
580
581 TEST_F(TestImageWatcher, NotifyRename) {
582 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
583
584 librbd::ImageCtx *ictx;
585 ASSERT_EQ(0, open_image(m_image_name, &ictx));
586
587 ASSERT_EQ(0, register_image_watch(*ictx));
588 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
589 "auto " + stringify(m_watch_ctx->get_handle())));
590
591 m_notify_acks = {{NOTIFY_OP_RENAME, create_response_message(0)}};
592
593 RWLock::RLocker l(ictx->owner_lock);
594 C_SaferCond notify_ctx;
595 ictx->image_watcher->notify_rename("new_name", &notify_ctx);
596 ASSERT_EQ(0, notify_ctx.wait());
597
598 NotifyOps expected_notify_ops;
599 expected_notify_ops += NOTIFY_OP_RENAME;
600 ASSERT_EQ(expected_notify_ops, m_notifies);
601 }
602
603 TEST_F(TestImageWatcher, NotifyAsyncTimedOut) {
604 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
605
606 librbd::ImageCtx *ictx;
607 ASSERT_EQ(0, open_image(m_image_name, &ictx));
608
609 ASSERT_EQ(0, register_image_watch(*ictx));
610 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
611 "auto " + stringify(m_watch_ctx->get_handle())));
612
613 m_notify_acks = {{NOTIFY_OP_FLATTEN, {}}};
614
615 ProgressContext progress_context;
616 FlattenTask flatten_task(ictx, &progress_context);
617 boost::thread thread(boost::ref(flatten_task));
618
619 ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
620 ASSERT_EQ(-ETIMEDOUT, flatten_task.result);
621 }
622
623 TEST_F(TestImageWatcher, NotifyAsyncError) {
624 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
625
626 librbd::ImageCtx *ictx;
627 ASSERT_EQ(0, open_image(m_image_name, &ictx));
628
629 ASSERT_EQ(0, register_image_watch(*ictx));
630 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
631 "auto " + stringify(m_watch_ctx->get_handle())));
632
633 m_notify_acks = {{NOTIFY_OP_FLATTEN, create_response_message(-EIO)}};
634
635 ProgressContext progress_context;
636 FlattenTask flatten_task(ictx, &progress_context);
637 boost::thread thread(boost::ref(flatten_task));
638
639 ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
640 ASSERT_EQ(-EIO, flatten_task.result);
641 }
642
643 TEST_F(TestImageWatcher, NotifyAsyncCompleteError) {
644 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
645
646 librbd::ImageCtx *ictx;
647 ASSERT_EQ(0, open_image(m_image_name, &ictx));
648
649 ASSERT_EQ(0, register_image_watch(*ictx));
650 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
651 "auto " + stringify(m_watch_ctx->get_handle())));
652
653 m_notify_acks = {{NOTIFY_OP_FLATTEN, create_response_message(0)}};
654
655 ProgressContext progress_context;
656 FlattenTask flatten_task(ictx, &progress_context);
657 boost::thread thread(boost::ref(flatten_task));
658
659 ASSERT_TRUE(wait_for_notifies(*ictx));
660
661 NotifyOps expected_notify_ops;
662 expected_notify_ops += NOTIFY_OP_FLATTEN;
663 ASSERT_EQ(expected_notify_ops, m_notifies);
664
665 AsyncRequestId async_request_id;
666 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_FLATTEN, &async_request_id));
667
668 ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, -ESHUTDOWN));
669
670 ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
671 ASSERT_EQ(-ESHUTDOWN, flatten_task.result);
672 }
673
674 TEST_F(TestImageWatcher, NotifyAsyncRequestTimedOut) {
675 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
676
677 librbd::ImageCtx *ictx;
678 ASSERT_EQ(0, open_image(m_image_name, &ictx));
679
680 ictx->request_timed_out_seconds = 0;
681
682 ASSERT_EQ(0, register_image_watch(*ictx));
683 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
684 "auto " + stringify(m_watch_ctx->get_handle())));
685
686 m_notify_acks = {{NOTIFY_OP_FLATTEN, create_response_message(0)}};
687
688 ProgressContext progress_context;
689 FlattenTask flatten_task(ictx, &progress_context);
690 boost::thread thread(boost::ref(flatten_task));
691
692 ASSERT_TRUE(wait_for_notifies(*ictx));
693
694 ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
695 ASSERT_EQ(-ETIMEDOUT, flatten_task.result);
696 }
697