]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/test_ImageWatcher.cc
import 15.2.4
[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"
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
33using namespace ceph;
34using namespace boost::assign;
35using namespace librbd::watch_notify;
36
37void register_test_image_watcher() {
38}
39
40class TestImageWatcher : public TestFixture {
41public:
42
9f95a23c 43 TestImageWatcher() : m_watch_ctx(NULL)
7c673cae
FG
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;
11fdf7f2 67 auto iter = bl.cbegin();
7c673cae 68 DECODE_START(1, iter);
11fdf7f2 69 decode(op, iter);
7c673cae
FG
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
9f95a23c 79 std::lock_guard l{m_parent.m_callback_lock};
7c673cae
FG
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;
9f95a23c 86 m_parent.m_callback_cond.notify_all();
7c673cae
FG
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) {
9f95a23c 135 std::unique_lock l{m_callback_lock};
7c673cae 136 while (m_notifies.size() < m_notify_acks.size()) {
9f95a23c 137 if (m_callback_cond.wait_for(l, 10s) == std::cv_status::timeout) {
7c673cae
FG
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;
11fdf7f2 146 encode(ResponseMessage(r), bl);
7c673cae
FG
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];
11fdf7f2
TL
156 auto iter = payload.cbegin();
157
7c673cae
FG
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;
11fdf7f2 189 encode(NotifyMessage(AsyncProgressPayload(id, offset, total)), bl);
7c673cae
FG
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;
11fdf7f2 196 encode(NotifyMessage(AsyncCompletePayload(id, r)), bl);
7c673cae
FG
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
9f95a23c
TL
211 ceph::mutex m_callback_lock = ceph::make_mutex("m_callback_lock");
212 ceph::condition_variable m_callback_cond;
7c673cae
FG
213
214};
215
216struct ProgressContext : public librbd::ProgressContext {
9f95a23c
TL
217 ceph::mutex mutex = ceph::make_mutex("ProgressContext::mutex");
218 ceph::condition_variable cond;
7c673cae
FG
219 bool received;
220 uint64_t offset;
221 uint64_t total;
222
9f95a23c 223 ProgressContext() : received(false),
7c673cae
FG
224 offset(0), total(0) {}
225
226 int update_progress(uint64_t offset_, uint64_t total_) override {
9f95a23c 227 std::lock_guard l{mutex};
7c673cae
FG
228 offset = offset_;
229 total = total_;
230 received = true;
9f95a23c 231 cond.notify_all();
7c673cae
FG
232 return 0;
233 }
234
235 bool wait(librbd::ImageCtx *ictx, uint64_t offset_, uint64_t total_) {
9f95a23c 236 std::unique_lock l{mutex};
7c673cae 237 while (!received) {
9f95a23c 238 if (cond.wait_for(l, 10s) == std::cv_status::timeout) {
7c673cae
FG
239 break;
240 }
241 }
242 return (received && offset == offset_ && total == total_);
243 }
244};
245
246struct 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()() {
9f95a23c 255 std::shared_lock l{ictx->owner_lock};
7c673cae
FG
256 C_SaferCond ctx;
257 ictx->image_watcher->notify_flatten(0, *progress_context, &ctx);
258 result = ctx.wait();
259 }
260};
261
262struct 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()() {
9f95a23c 271 std::shared_lock l{ictx->owner_lock};
7c673cae
FG
272 C_SaferCond ctx;
273 ictx->image_watcher->notify_resize(0, 0, true, *progress_context, &ctx);
274 result = ctx.wait();
275 }
276};
277
278struct 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()() {
9f95a23c 287 std::shared_lock l{ictx->owner_lock};
7c673cae
FG
288 C_SaferCond ctx;
289 ictx->image_watcher->notify_rebuild_object_map(0, *progress_context, &ctx);
290 result = ctx.wait();
291 }
292};
293
294TEST_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
312TEST_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
346TEST_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
380TEST_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
415TEST_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
9f95a23c 427 std::shared_lock l{ictx->owner_lock};
7c673cae
FG
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
438TEST_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
9f95a23c 450 std::shared_lock l{ictx->owner_lock};
7c673cae
FG
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
461TEST_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
9f95a23c 473 std::shared_lock l{ictx->owner_lock};
7c673cae
FG
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
483TEST_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
9f95a23c 495 std::shared_lock l{ictx->owner_lock};
7c673cae
FG
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
505TEST_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
9f95a23c 517 std::shared_lock l{ictx->owner_lock};
7c673cae
FG
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
529TEST_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
9f95a23c 541 std::shared_lock l{ictx->owner_lock};
7c673cae
FG
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
553TEST_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
9f95a23c 565 std::shared_lock l{ictx->owner_lock};
7c673cae
FG
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
577TEST_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
9f95a23c 589 std::shared_lock l{ictx->owner_lock};
7c673cae
FG
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
599TEST_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
619TEST_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
639TEST_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
670TEST_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
11fdf7f2 676 ictx->config.set_val("rbd_request_timed_out_seconds", "0");
7c673cae
FG
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