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