]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
tests: adjust test cases to refactored librbd
authorJason Dillaman <dillaman@redhat.com>
Wed, 9 Dec 2015 04:14:49 +0000 (23:14 -0500)
committerJason Dillaman <dillaman@redhat.com>
Tue, 15 Dec 2015 01:31:31 +0000 (20:31 -0500)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
26 files changed:
src/test/Makefile-client.am
src/test/librbd/exclusive_lock/test_mock_AcquireRequest.cc
src/test/librbd/exclusive_lock/test_mock_ReleaseRequest.cc
src/test/librbd/mock/MockAioImageRequestWQ.h
src/test/librbd/mock/MockExclusiveLock.h [new file with mode: 0644]
src/test/librbd/mock/MockImageCtx.h
src/test/librbd/mock/MockImageWatcher.h
src/test/librbd/mock/MockObjectMap.h
src/test/librbd/mock/MockReadahead.h [new file with mode: 0644]
src/test/librbd/object_map/test_mock_RefreshRequest.cc
src/test/librbd/object_map/test_mock_ResizeRequest.cc
src/test/librbd/object_map/test_mock_SnapshotCreateRequest.cc
src/test/librbd/object_map/test_mock_SnapshotRemoveRequest.cc
src/test/librbd/object_map/test_mock_SnapshotRollbackRequest.cc
src/test/librbd/object_map/test_mock_UpdateRequest.cc
src/test/librbd/operation/test_mock_SnapshotCreateRequest.cc
src/test/librbd/operation/test_mock_SnapshotProtectRequest.cc
src/test/librbd/operation/test_mock_SnapshotRemoveRequest.cc
src/test/librbd/operation/test_mock_SnapshotUnprotectRequest.cc
src/test/librbd/test_ImageWatcher.cc
src/test/librbd/test_JournalReplay.cc
src/test/librbd/test_ObjectMap.cc
src/test/librbd/test_fixture.cc
src/test/librbd/test_internal.cc
src/test/librbd/test_librbd.cc
src/test/librbd/test_mock_ExclusiveLock.cc

index 9a3f888a4ad56784cfc7723df3778b4d5a3723af..d44a977a5a3acb7d74d03c3f0e7742aea559ba66 100644 (file)
@@ -406,10 +406,12 @@ noinst_HEADERS += \
        test/librbd/test_support.h \
        test/librbd/mock/MockAioImageRequestWQ.h \
        test/librbd/mock/MockContextWQ.h \
+       test/librbd/mock/MockExclusiveLock.h \
        test/librbd/mock/MockImageCtx.h \
        test/librbd/mock/MockImageWatcher.h \
        test/librbd/mock/MockJournal.h \
        test/librbd/mock/MockObjectMap.h \
+       test/librbd/mock/MockReadahead.h \
        test/librbd/object_map/mock/MockInvalidateRequest.h
 
 if LINUX
index 6d276f811a741c0ad68aeb49679fc09fff8e07e5..31e17a0385c95dd76abd74781bb064827b443f0c 100644 (file)
@@ -149,9 +149,10 @@ TEST_F(TestMockExclusiveLockAcquireRequest, Success) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_lock(mock_image_ctx, 0);
 
   MockJournal mock_journal;
@@ -179,9 +180,10 @@ TEST_F(TestMockExclusiveLockAcquireRequest, SuccessJournalDisabled) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_lock(mock_image_ctx, 0);
 
   expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, false);
@@ -206,9 +208,10 @@ TEST_F(TestMockExclusiveLockAcquireRequest, SuccessObjectMapDisabled) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_lock(mock_image_ctx, 0);
 
   MockJournal mock_journal;
@@ -232,15 +235,15 @@ TEST_F(TestMockExclusiveLockAcquireRequest, LockBusy) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_lock(mock_image_ctx, -EBUSY);
   expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
                        "auto 123", MockExclusiveLock::WATCHER_LOCK_TAG,
                        LOCK_EXCLUSIVE);
   expect_list_watchers(mock_image_ctx, 0, "dead client", 123);
-  expect_op_work_queue(mock_image_ctx);
   expect_blacklist_add(mock_image_ctx, 0);
   expect_break_lock(mock_image_ctx, 0);
   expect_lock(mock_image_ctx, -ENOENT);
@@ -259,9 +262,10 @@ TEST_F(TestMockExclusiveLockAcquireRequest, GetLockInfoError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_lock(mock_image_ctx, -EBUSY);
   expect_get_lock_info(mock_image_ctx, -EINVAL, entity_name_t::CLIENT(1), "",
                        "", "", LOCK_EXCLUSIVE);
@@ -280,9 +284,10 @@ TEST_F(TestMockExclusiveLockAcquireRequest, GetLockInfoEmpty) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_lock(mock_image_ctx, -EBUSY);
   expect_get_lock_info(mock_image_ctx, -ENOENT, entity_name_t::CLIENT(1), "",
                        "", "", LOCK_EXCLUSIVE);
@@ -302,9 +307,10 @@ TEST_F(TestMockExclusiveLockAcquireRequest, GetLockInfoExternalTag) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_lock(mock_image_ctx, -EBUSY);
   expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
                        "auto 123", "external tag", LOCK_EXCLUSIVE);
@@ -323,9 +329,10 @@ TEST_F(TestMockExclusiveLockAcquireRequest, GetLockInfoShared) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_lock(mock_image_ctx, -EBUSY);
   expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
                        "auto 123", MockExclusiveLock::WATCHER_LOCK_TAG,
@@ -345,9 +352,10 @@ TEST_F(TestMockExclusiveLockAcquireRequest, GetLockInfoExternalCookie) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_lock(mock_image_ctx, -EBUSY);
   expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
                        "external cookie", MockExclusiveLock::WATCHER_LOCK_TAG,
@@ -367,9 +375,10 @@ TEST_F(TestMockExclusiveLockAcquireRequest, GetWatchersError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_lock(mock_image_ctx, -EBUSY);
   expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
                        "auto 123", MockExclusiveLock::WATCHER_LOCK_TAG,
@@ -390,9 +399,10 @@ TEST_F(TestMockExclusiveLockAcquireRequest, GetWatchersAlive) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_lock(mock_image_ctx, -EBUSY);
   expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
                        "auto 123", MockExclusiveLock::WATCHER_LOCK_TAG,
@@ -413,16 +423,16 @@ TEST_F(TestMockExclusiveLockAcquireRequest, BlacklistDisabled) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
   mock_image_ctx.blacklist_on_break_lock = false;
 
+  InSequence seq;
   expect_lock(mock_image_ctx, -EBUSY);
   expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
                        "auto 123", MockExclusiveLock::WATCHER_LOCK_TAG,
                        LOCK_EXCLUSIVE);
   expect_list_watchers(mock_image_ctx, 0, "dead client", 123);
-  expect_op_work_queue(mock_image_ctx);
   expect_break_lock(mock_image_ctx, 0);
   expect_lock(mock_image_ctx, -ENOENT);
 
@@ -440,15 +450,15 @@ TEST_F(TestMockExclusiveLockAcquireRequest, BlacklistError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_lock(mock_image_ctx, -EBUSY);
   expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
                        "auto 123", MockExclusiveLock::WATCHER_LOCK_TAG,
                        LOCK_EXCLUSIVE);
   expect_list_watchers(mock_image_ctx, 0, "dead client", 123);
-  expect_op_work_queue(mock_image_ctx);
   expect_blacklist_add(mock_image_ctx, -EINVAL);
 
   C_SaferCond ctx;
@@ -465,15 +475,15 @@ TEST_F(TestMockExclusiveLockAcquireRequest, BreakLockMissing) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_lock(mock_image_ctx, -EBUSY);
   expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
                        "auto 123", MockExclusiveLock::WATCHER_LOCK_TAG,
                        LOCK_EXCLUSIVE);
   expect_list_watchers(mock_image_ctx, 0, "dead client", 123);
-  expect_op_work_queue(mock_image_ctx);
   expect_blacklist_add(mock_image_ctx, 0);
   expect_break_lock(mock_image_ctx, -ENOENT);
   expect_lock(mock_image_ctx, -EINVAL);
@@ -492,15 +502,15 @@ TEST_F(TestMockExclusiveLockAcquireRequest, BreakLockError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_lock(mock_image_ctx, -EBUSY);
   expect_get_lock_info(mock_image_ctx, 0, entity_name_t::CLIENT(1), "1.2.3.4",
                        "auto 123", MockExclusiveLock::WATCHER_LOCK_TAG,
                        LOCK_EXCLUSIVE);
   expect_list_watchers(mock_image_ctx, 0, "dead client", 123);
-  expect_op_work_queue(mock_image_ctx);
   expect_blacklist_add(mock_image_ctx, 0);
   expect_break_lock(mock_image_ctx, -EINVAL);
 
index 3be3a084bd1e796a26b9ae243c5974522286b77e..09595afdca516947f01522f12844790471bbdccb 100644 (file)
@@ -59,9 +59,10 @@ TEST_F(TestMockExclusiveLockReleaseRequest, Success) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_cancel_op_requests(mock_image_ctx, 0);
 
   MockJournal *mock_journal = new MockJournal();
@@ -69,7 +70,7 @@ TEST_F(TestMockExclusiveLockReleaseRequest, Success) {
   expect_close_journal(mock_image_ctx, *mock_journal, -EINVAL);
 
   MockObjectMap *mock_object_map = new MockObjectMap();
-  mock_image_ctx.object_map_ptr = mock_object_map;
+  mock_image_ctx.object_map = mock_object_map;
   expect_unlock_object_map(mock_image_ctx, *mock_object_map);
 
   expect_unlock(mock_image_ctx, 0);
@@ -88,13 +89,14 @@ TEST_F(TestMockExclusiveLockReleaseRequest, SuccessJournalDisabled) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_cancel_op_requests(mock_image_ctx, 0);
 
   MockObjectMap *mock_object_map = new MockObjectMap();
-  mock_image_ctx.object_map_ptr = mock_object_map;
+  mock_image_ctx.object_map = mock_object_map;
   expect_unlock_object_map(mock_image_ctx, *mock_object_map);
 
   expect_unlock(mock_image_ctx, 0);
@@ -113,9 +115,10 @@ TEST_F(TestMockExclusiveLockReleaseRequest, SuccessObjectMapDisabled) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_cancel_op_requests(mock_image_ctx, 0);
 
   expect_unlock(mock_image_ctx, 0);
@@ -134,9 +137,10 @@ TEST_F(TestMockExclusiveLockReleaseRequest, UnlockError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  InSequence seq;
   MockImageCtx mock_image_ctx(*ictx);
+  expect_op_work_queue(mock_image_ctx);
 
+  InSequence seq;
   expect_cancel_op_requests(mock_image_ctx, 0);
 
   expect_unlock(mock_image_ctx, -EINVAL);
index cd34807e9d78cf89e8818740f41fd7211863a7e0..c4dbd3bece18e3a275a22bdccf995662e662fed2 100644 (file)
@@ -11,6 +11,8 @@ namespace librbd {
 struct MockAioImageRequestWQ {
   MOCK_METHOD1(block_writes, void(Context *));
   MOCK_METHOD0(unblock_writes, void());
+
+  MOCK_CONST_METHOD0(writes_empty, bool());
 };
 
 } // namespace librbd
diff --git a/src/test/librbd/mock/MockExclusiveLock.h b/src/test/librbd/mock/MockExclusiveLock.h
new file mode 100644 (file)
index 0000000..8227d3e
--- /dev/null
@@ -0,0 +1,25 @@
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_TEST_LIBRBD_MOCK_EXCLUSIVE_LOCK_H
+#define CEPH_TEST_LIBRBD_MOCK_EXCLUSIVE_LOCK_H
+
+#include "include/int_types.h"
+#include "include/rados/librados.hpp"
+#include "gmock/gmock.h"
+
+class Context;
+
+namespace librbd {
+
+struct MockExclusiveLock {
+  MOCK_CONST_METHOD0(is_lock_owner, bool());
+
+  MOCK_METHOD1(assert_header_locked, void(librados::ObjectWriteOperation *));
+
+  MOCK_METHOD1(shut_down, void(Context*));
+};
+
+} // namespace librbd
+
+#endif // CEPH_TEST_LIBRBD_MOCK_EXCLUSIVE_LOCK_H
index 893aa993cb0cb9f192a9419f190626e5582a9f53..bd29d498fd48a3e9dfab4093e4fb822bdf7a5a87 100644 (file)
@@ -6,9 +6,11 @@
 
 #include "test/librbd/mock/MockAioImageRequestWQ.h"
 #include "test/librbd/mock/MockContextWQ.h"
+#include "test/librbd/mock/MockExclusiveLock.h"
 #include "test/librbd/mock/MockImageWatcher.h"
 #include "test/librbd/mock/MockJournal.h"
 #include "test/librbd/mock/MockObjectMap.h"
+#include "test/librbd/mock/MockReadahead.h"
 #include "common/RWLock.h"
 #include "librbd/ImageCtx.h"
 #include "gmock/gmock.h"
@@ -38,7 +40,8 @@ struct MockImageCtx {
       layout(image_ctx.layout),
       aio_work_queue(new MockAioImageRequestWQ()),
       op_work_queue(new MockContextWQ()),
-      image_watcher(NULL), object_map_ptr(NULL), journal(NULL),
+      parent(NULL), image_watcher(NULL), object_map(NULL),
+      exclusive_lock(NULL), journal(NULL),
       concurrent_management_ops(image_ctx.concurrent_management_ops),
       blacklist_on_break_lock(image_ctx.blacklist_on_break_lock),
       blacklist_expire_seconds(image_ctx.blacklist_expire_seconds)
@@ -87,13 +90,17 @@ struct MockImageCtx {
                               uint64_t in_size, parent_info parent,
                               uint8_t protection_status, uint64_t flags));
   MOCK_METHOD2(rm_snap, void(std::string in_snap_name, librados::snap_t id));
+
   MOCK_METHOD1(flush, void(Context *));
+  MOCK_METHOD1(flush_copyup, void(Context *));
+
+  MOCK_METHOD1(shut_down_cache, void(Context *));
 
   MOCK_CONST_METHOD1(test_features, bool(uint64_t test_features));
 
   MOCK_METHOD1(cancel_async_requests, void(Context*));
 
-  MOCK_METHOD0(create_object_map, MockObjectMap*());
+  MOCK_METHOD1(create_object_map, MockObjectMap*(uint64_t));
   MOCK_METHOD0(create_journal, MockJournal*());
 
   ImageCtx *image_ctx;
@@ -131,10 +138,13 @@ struct MockImageCtx {
   MockAioImageRequestWQ *aio_work_queue;
   MockContextWQ *op_work_queue;
 
-  MockImageWatcher *image_watcher;
-  MockObjectMap object_map;       // TODO replace with ptr
-  MockObjectMap *object_map_ptr;  // TODO
+  MockReadahead readahead;
 
+  MockImageCtx *parent;
+
+  MockImageWatcher *image_watcher;
+  MockObjectMap *object_map;
+  MockExclusiveLock *exclusive_lock;
   MockJournal *journal;
 
   int concurrent_management_ops;
index eaacaeb1bebc4744efd6815df04e9e1bbf57c3a7..20164eafa3cc8710da22fc0e5039be742f81fae2 100644 (file)
@@ -9,10 +9,12 @@
 namespace librbd {
 
 struct MockImageWatcher {
-  MOCK_CONST_METHOD0(is_lock_owner, bool());
-  MOCK_CONST_METHOD1(is_lock_supported, bool(const RWLock &));
-  MOCK_METHOD1(assert_header_locked, void (librados::ObjectWriteOperation *));
+  MOCK_METHOD0(unregister_watch, void());
 
+  MOCK_CONST_METHOD0(get_watch_handle, uint64_t());
+
+  MOCK_METHOD0(notify_acquired_lock, void());
+  MOCK_METHOD0(notify_released_lock, void());
   MOCK_METHOD0(notify_request_lock, void());
 };
 
index bde034f2aab5bb5defcedf0349efe3ac4a7b5d2b..78c036ce2130eb8373fb020fbd43bdacfd212714 100644 (file)
@@ -11,9 +11,10 @@ namespace librbd {
 struct MockObjectMap {
   MOCK_CONST_METHOD1(enabled, bool(const RWLock &object_map_lock));
 
+  MOCK_METHOD1(open, void(Context *on_finish));
+
   MOCK_METHOD1(lock, void(Context *on_finish));
   MOCK_METHOD1(unlock, void(Context *on_finish));
-  MOCK_METHOD2(refresh, void(uint64_t snap_id, Context *on_finish));
 
   MOCK_METHOD2(snapshot_add, void(uint64_t snap_id, Context *on_finish));
   MOCK_METHOD2(snapshot_remove, void(uint64_t snap_id, Context *on_finish));
diff --git a/src/test/librbd/mock/MockReadahead.h b/src/test/librbd/mock/MockReadahead.h
new file mode 100644 (file)
index 0000000..b73b462
--- /dev/null
@@ -0,0 +1,21 @@
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_TEST_LIBRBD_MOCK_READAHEAD_H
+#define CEPH_TEST_LIBRBD_MOCK_READAHEAD_H
+
+#include "include/int_types.h"
+#include "gmock/gmock.h"
+
+class Context;
+
+namespace librbd {
+
+struct MockReadahead {
+  MOCK_METHOD1(set_max_readahead_size, void(uint64_t));
+  MOCK_METHOD1(wait_for_pending, void(Context *));
+};
+
+} // namespace librbd
+
+#endif // CEPH_TEST_LIBRBD_MOCK_READAHEAD_H
index 043ad351f0e5f7898f4eeb2977e58a0dc6c43371..2af4517036a8bc997ddfe8e96cfa760b76f98d9f 100644 (file)
@@ -83,14 +83,6 @@ public:
       (*object_map)[i] = rand() % 3;
     }
   }
-
-  void when_apply_refresh_request(MockImageCtx &mock_image_ctx,
-                                 MockRefreshRequest *req) {
-    RWLock::WLocker snap_locker(mock_image_ctx.snap_lock);
-    RWLock::WLocker object_map_locker(mock_image_ctx.object_map_lock);
-    expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
-    req->apply();
-  }
 };
 
 TEST_F(TestMockObjectMapRefreshRequest, Success) {
@@ -110,10 +102,10 @@ TEST_F(TestMockObjectMapRefreshRequest, Success) {
   InSequence seq;
   expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
   expect_object_map_load(mock_image_ctx, &on_disk_object_map, 0);
+  expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
   req->send();
   ASSERT_EQ(0, ctx.wait());
 
-  when_apply_refresh_request(mock_image_ctx, req);
   ASSERT_EQ(on_disk_object_map, object_map);
 }
 
@@ -137,11 +129,10 @@ TEST_F(TestMockObjectMapRefreshRequest, LoadError) {
 
   MockInvalidateRequest invalidate_request;
   expect_invalidate_request(mock_image_ctx, invalidate_request);
+  expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
 
   req->send();
   ASSERT_EQ(0, ctx.wait());
-
-  when_apply_refresh_request(mock_image_ctx, req);
 }
 
 TEST_F(TestMockObjectMapRefreshRequest, LoadCorrupt) {
@@ -166,11 +157,10 @@ TEST_F(TestMockObjectMapRefreshRequest, LoadCorrupt) {
   expect_invalidate_request(mock_image_ctx, invalidate_request);
   expect_truncate_request(mock_image_ctx);
   expect_object_map_resize(mock_image_ctx, on_disk_object_map.size(), 0);
+  expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
 
   req->send();
   ASSERT_EQ(0, ctx.wait());
-
-  when_apply_refresh_request(mock_image_ctx, req);
 }
 
 TEST_F(TestMockObjectMapRefreshRequest, TooSmall) {
@@ -196,11 +186,10 @@ TEST_F(TestMockObjectMapRefreshRequest, TooSmall) {
   MockInvalidateRequest invalidate_request;
   expect_invalidate_request(mock_image_ctx, invalidate_request);
   expect_object_map_resize(mock_image_ctx, on_disk_object_map.size(), 0);
+  expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
 
   req->send();
   ASSERT_EQ(0, ctx.wait());
-
-  when_apply_refresh_request(mock_image_ctx, req);
 }
 
 TEST_F(TestMockObjectMapRefreshRequest, TooLarge) {
@@ -223,10 +212,9 @@ TEST_F(TestMockObjectMapRefreshRequest, TooLarge) {
   InSequence seq;
   expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
   expect_object_map_load(mock_image_ctx, &large_object_map, 0);
+  expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
   req->send();
   ASSERT_EQ(0, ctx.wait());
-
-  when_apply_refresh_request(mock_image_ctx, req);
 }
 
 TEST_F(TestMockObjectMapRefreshRequest, ResizeError) {
@@ -252,38 +240,10 @@ TEST_F(TestMockObjectMapRefreshRequest, ResizeError) {
   MockInvalidateRequest invalidate_request;
   expect_invalidate_request(mock_image_ctx, invalidate_request);
   expect_object_map_resize(mock_image_ctx, on_disk_object_map.size(), -ESTALE);
+  expect_get_image_size(mock_image_ctx, mock_image_ctx.image_ctx->size);
 
   req->send();
   ASSERT_EQ(0, ctx.wait());
-
-  when_apply_refresh_request(mock_image_ctx, req);
-}
-
-TEST_F(TestMockObjectMapRefreshRequest, StaleRefresh) {
-  librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
-  MockImageCtx mock_image_ctx(*ictx);
-
-  C_SaferCond ctx;
-  ceph::BitVector<2> object_map;
-  MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, &object_map,
-                                                   TEST_SNAP_ID, &ctx);
-  ASSERT_THROW(when_apply_refresh_request(mock_image_ctx, req),
-               ceph::FailedAssertion);
-}
-
-TEST_F(TestMockObjectMapRefreshRequest, Discard) {
-  librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
-  MockImageCtx mock_image_ctx(*ictx);
-
-  C_SaferCond ctx;
-  ceph::BitVector<2> object_map;
-  MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, &object_map,
-                                                   TEST_SNAP_ID, &ctx);
-  req->discard();
 }
 
 } // namespace object_map
index 8bc9f007d4fe82e3cf5b9644e3755b718f4790ab..197fabeb60b9aec8abd6fdae75c1a0bdc53539d7 100644 (file)
@@ -6,6 +6,7 @@
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "common/bit_vector.hpp"
 #include "librbd/internal.h"
+#include "librbd/ObjectMap.h"
 #include "librbd/object_map/ResizeRequest.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
index e3ebab31e513de862da47f485c4b533a99ada3aa..e76c1927de2dc329acc8c946dcfdeb6924e5a2aa 100644 (file)
@@ -6,6 +6,7 @@
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "common/bit_vector.hpp"
 #include "librbd/internal.h"
+#include "librbd/ObjectMap.h"
 #include "librbd/object_map/SnapshotCreateRequest.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
index 3bf622815d02ac7e315b7c04b92bba82c0393dd7..224a43d68d44b20beb75deb8f2b082df32508757 100644 (file)
@@ -5,7 +5,9 @@
 #include "test/librbd/test_support.h"
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "common/bit_vector.hpp"
+#include "librbd/ImageState.h"
 #include "librbd/internal.h"
+#include "librbd/ObjectMap.h"
 #include "librbd/object_map/SnapshotRemoveRequest.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
@@ -75,7 +77,7 @@ TEST_F(TestMockObjectMapSnapshotRemoveRequest, Success) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   uint64_t snap_id = ictx->snap_info.rbegin()->first;
   if (ictx->test_features(RBD_FEATURE_FAST_DIFF)) {
@@ -104,7 +106,7 @@ TEST_F(TestMockObjectMapSnapshotRemoveRequest, LoadMapError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   uint64_t snap_id = ictx->snap_info.rbegin()->first;
   expect_load_map(ictx, snap_id, -EINVAL);
@@ -131,7 +133,7 @@ TEST_F(TestMockObjectMapSnapshotRemoveRequest, RemoveSnapshotMissing) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   uint64_t snap_id = ictx->snap_info.rbegin()->first;
   expect_load_map(ictx, snap_id, 0);
@@ -158,7 +160,7 @@ TEST_F(TestMockObjectMapSnapshotRemoveRequest, RemoveSnapshotError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   uint64_t snap_id = ictx->snap_info.rbegin()->first;
   expect_load_map(ictx, snap_id, 0);
@@ -186,7 +188,7 @@ TEST_F(TestMockObjectMapSnapshotRemoveRequest, RemoveMapMissing) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   uint64_t snap_id = ictx->snap_info.rbegin()->first;
   if (ictx->test_features(RBD_FEATURE_FAST_DIFF)) {
@@ -215,7 +217,7 @@ TEST_F(TestMockObjectMapSnapshotRemoveRequest, RemoveMapError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   uint64_t snap_id = ictx->snap_info.rbegin()->first;
   if (ictx->test_features(RBD_FEATURE_FAST_DIFF)) {
@@ -244,7 +246,7 @@ TEST_F(TestMockObjectMapSnapshotRemoveRequest, ScrubCleanObjects) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   uint64_t snap_id = ictx->snap_info.rbegin()->first;
 
index 42782fbd087e071dc3a6ed591c3cf2877fb9efb5..25c615bf328ffc020dc3da89521f0aebe78ec328 100644 (file)
@@ -4,6 +4,7 @@
 #include "test/librbd/test_mock_fixture.h"
 #include "test/librbd/test_support.h"
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
+#include "librbd/ImageState.h"
 #include "librbd/internal.h"
 #include "librbd/ObjectMap.h"
 #include "librbd/object_map/SnapshotRollbackRequest.h"
@@ -66,7 +67,7 @@ TEST_F(TestMockObjectMapSnapshotRollbackRequest, Success) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   uint64_t snap_id = ictx->snap_info.rbegin()->first;
   expect_read_map(ictx, snap_id, 0);
@@ -87,7 +88,7 @@ TEST_F(TestMockObjectMapSnapshotRollbackRequest, ReadMapError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   uint64_t snap_id = ictx->snap_info.rbegin()->first;
   expect_read_map(ictx, snap_id, -ENOENT);
@@ -115,7 +116,7 @@ TEST_F(TestMockObjectMapSnapshotRollbackRequest, WriteMapError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   uint64_t snap_id = ictx->snap_info.rbegin()->first;
   expect_read_map(ictx, snap_id, 0);
index 902e4a17e51648e64be8ef4d3247a2e88b50ff77..bc5cafab9102e79e9f14c22b8733ffb8f57e4812 100644 (file)
@@ -5,7 +5,9 @@
 #include "test/librbd/test_support.h"
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "common/bit_vector.hpp"
+#include "librbd/ImageState.h"
 #include "librbd/internal.h"
+#include "librbd/ObjectMap.h"
 #include "librbd/object_map/UpdateRequest.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
@@ -168,7 +170,7 @@ TEST_F(TestMockObjectMapUpdateRequest, RebuildSnapOnDisk) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
   ASSERT_EQ(CEPH_NOSNAP, ictx->snap_id);
 
   uint64_t snap_id = ictx->snap_info.rbegin()->first;
index 8ae12d0b60f0189177cf9a80793feea95c11e765..d9c8cce9eae443564240200e267375e823911e6a 100644 (file)
@@ -7,6 +7,7 @@
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "common/bit_vector.hpp"
 #include "librbd/internal.h"
+#include "librbd/ObjectMap.h"
 #include "librbd/operation/SnapshotCreateRequest.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
@@ -34,10 +35,10 @@ public:
   }
 
   void expect_verify_lock_ownership(MockImageCtx &mock_image_ctx) {
-    EXPECT_CALL(*mock_image_ctx.image_watcher, is_lock_supported(_))
-                  .WillRepeatedly(Return(true));
-    EXPECT_CALL(*mock_image_ctx.image_watcher, is_lock_owner())
-                  .WillRepeatedly(Return(true));
+    if (mock_image_ctx.exclusive_lock != nullptr) {
+      EXPECT_CALL(*mock_image_ctx.exclusive_lock, is_lock_owner())
+                    .WillRepeatedly(Return(true));
+    }
   }
 
   void expect_allocate_snap_id(MockImageCtx &mock_image_ctx, int r) {
@@ -61,8 +62,9 @@ public:
   }
 
   void expect_snap_create(MockImageCtx &mock_image_ctx, int r) {
-    if (!mock_image_ctx.old_format) {
-      EXPECT_CALL(*mock_image_ctx.image_watcher, assert_header_locked(_))
+    if (!mock_image_ctx.old_format &&
+         mock_image_ctx.exclusive_lock != nullptr) {
+      EXPECT_CALL(*mock_image_ctx.exclusive_lock, assert_header_locked(_))
                     .Times(r == -ESTALE ? 2 : 1);
     }
 
@@ -81,11 +83,8 @@ public:
   }
 
   void expect_object_map_snap_create(MockImageCtx &mock_image_ctx) {
-    bool enabled = mock_image_ctx.image_ctx->test_features(RBD_FEATURE_OBJECT_MAP);
-    EXPECT_CALL(mock_image_ctx.object_map, enabled(_))
-                  .WillOnce(Return(enabled));
-    if (enabled) {
-      EXPECT_CALL(mock_image_ctx.object_map, snapshot_add(_, _))
+    if (mock_image_ctx.object_map != nullptr) {
+      EXPECT_CALL(*mock_image_ctx.object_map, snapshot_add(_, _))
                     .WillOnce(WithArg<1>(CompleteContext(
                       0, mock_image_ctx.image_ctx->op_work_queue)));
     }
@@ -111,6 +110,16 @@ TEST_F(TestMockOperationSnapshotCreateRequest, Success) {
 
   MockImageCtx mock_image_ctx(*ictx);
 
+  MockExclusiveLock mock_exclusive_lock;
+  if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+    mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
+  }
+
+  MockObjectMap mock_object_map;
+  if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
+    mock_image_ctx.object_map = &mock_object_map;
+  }
+
   expect_verify_lock_ownership(mock_image_ctx);
   expect_op_work_queue(mock_image_ctx);
 
@@ -138,6 +147,11 @@ TEST_F(TestMockOperationSnapshotCreateRequest, AllocateSnapIdError) {
 
   MockImageCtx mock_image_ctx(*ictx);
 
+  MockExclusiveLock mock_exclusive_lock;
+  if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+    mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
+  }
+
   expect_verify_lock_ownership(mock_image_ctx);
   expect_op_work_queue(mock_image_ctx);
 
@@ -162,6 +176,16 @@ TEST_F(TestMockOperationSnapshotCreateRequest, CreateSnapStale) {
 
   MockImageCtx mock_image_ctx(*ictx);
 
+  MockExclusiveLock mock_exclusive_lock;
+  if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+    mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
+  }
+
+  MockObjectMap mock_object_map;
+  if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
+    mock_image_ctx.object_map = &mock_object_map;
+  }
+
   expect_verify_lock_ownership(mock_image_ctx);
   expect_op_work_queue(mock_image_ctx);
 
@@ -188,6 +212,11 @@ TEST_F(TestMockOperationSnapshotCreateRequest, CreateSnapError) {
 
   MockImageCtx mock_image_ctx(*ictx);
 
+  MockExclusiveLock mock_exclusive_lock;
+  if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+    mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
+  }
+
   expect_verify_lock_ownership(mock_image_ctx);
   expect_op_work_queue(mock_image_ctx);
 
@@ -213,6 +242,11 @@ TEST_F(TestMockOperationSnapshotCreateRequest, ReleaseSnapIdError) {
 
   MockImageCtx mock_image_ctx(*ictx);
 
+  MockExclusiveLock mock_exclusive_lock;
+  if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+    mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
+  }
+
   expect_verify_lock_ownership(mock_image_ctx);
   expect_op_work_queue(mock_image_ctx);
 
index e77ceb22f87d84cb6b217be248aa5bb470530c50..3c64d2738811d4d3dde221421eb45fdb7ab3d2a1 100644 (file)
@@ -6,6 +6,7 @@
 #include "test/librbd/mock/MockImageCtx.h"
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "common/bit_vector.hpp"
+#include "librbd/ImageState.h"
 #include "librbd/internal.h"
 #include "librbd/operation/SnapshotProtectRequest.h"
 #include "gmock/gmock.h"
@@ -61,7 +62,7 @@ TEST_F(TestMockOperationSnapshotProtectRequest, Success) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
@@ -88,7 +89,7 @@ TEST_F(TestMockOperationSnapshotProtectRequest, GetSnapIdMissing) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
@@ -113,7 +114,7 @@ TEST_F(TestMockOperationSnapshotProtectRequest, IsSnapProtectedError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
@@ -139,7 +140,7 @@ TEST_F(TestMockOperationSnapshotProtectRequest, SnapAlreadyProtected) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
@@ -165,7 +166,7 @@ TEST_F(TestMockOperationSnapshotProtectRequest, SetProtectionStateError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
index 323f95b6bc56c00d572cd79f4af01b9edfed4e81..122f4bf1761b64f7a09fa5e19eb4340998a17625 100644 (file)
@@ -6,6 +6,7 @@
 #include "test/librbd/mock/MockImageCtx.h"
 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
 #include "common/bit_vector.hpp"
+#include "librbd/ImageState.h"
 #include "librbd/internal.h"
 #include "librbd/operation/SnapshotRemoveRequest.h"
 #include "gmock/gmock.h"
@@ -49,11 +50,8 @@ public:
   }
 
   void expect_object_map_snap_remove(MockImageCtx &mock_image_ctx, int r) {
-    bool enabled = mock_image_ctx.image_ctx->test_features(RBD_FEATURE_OBJECT_MAP);
-    EXPECT_CALL(mock_image_ctx.object_map, enabled(_))
-                  .WillOnce(Return(enabled));
-    if (enabled) {
-      EXPECT_CALL(mock_image_ctx.object_map, snapshot_remove(_, _))
+    if (mock_image_ctx.object_map != nullptr) {
+      EXPECT_CALL(*mock_image_ctx.object_map, snapshot_remove(_, _))
                     .WillOnce(WithArg<1>(CompleteContext(
                       r, mock_image_ctx.image_ctx->op_work_queue)));
     }
@@ -87,8 +85,10 @@ public:
       return;
     }
 
-    EXPECT_CALL(*mock_image_ctx.image_watcher, is_lock_owner())
-                  .WillRepeatedly(Return(false));
+    if (mock_image_ctx.exclusive_lock != nullptr) {
+      EXPECT_CALL(*mock_image_ctx.exclusive_lock, is_lock_owner())
+                    .WillRepeatedly(Return(false));
+    }
   }
 
   void expect_snap_remove(MockImageCtx &mock_image_ctx, int r) {
@@ -120,10 +120,20 @@ TEST_F(TestMockOperationSnapshotRemoveRequest, Success) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
+  MockExclusiveLock mock_exclusive_lock;
+  if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+    mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
+  }
+
+  MockObjectMap mock_object_map;
+  if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
+    mock_image_ctx.object_map = &mock_object_map;
+  }
+
   expect_op_work_queue(mock_image_ctx);
 
   ::testing::InSequence seq;
@@ -163,10 +173,20 @@ TEST_F(TestMockOperationSnapshotRemoveRequest, FlattenedCloneRemovesChild) {
 
   librbd::NoOpProgressContext prog_ctx;
   ASSERT_EQ(0, librbd::flatten(ictx, prog_ctx));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
+  MockExclusiveLock mock_exclusive_lock;
+  if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+    mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
+  }
+
+  MockObjectMap mock_object_map;
+  if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
+    mock_image_ctx.object_map = &mock_object_map;
+  }
+
   expect_op_work_queue(mock_image_ctx);
 
   uint64_t snap_id = ictx->snap_info.rbegin()->first;
@@ -194,10 +214,15 @@ TEST_F(TestMockOperationSnapshotRemoveRequest, ObjectMapSnapRemoveError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
+  MockObjectMap mock_object_map;
+  if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
+    mock_image_ctx.object_map = &mock_object_map;
+  }
+
   expect_op_work_queue(mock_image_ctx);
 
   ::testing::InSequence seq;
@@ -218,10 +243,15 @@ TEST_F(TestMockOperationSnapshotRemoveRequest, RemoveChildParentError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
+  MockObjectMap mock_object_map;
+  if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
+    mock_image_ctx.object_map = &mock_object_map;
+  }
+
   expect_op_work_queue(mock_image_ctx);
 
   ::testing::InSequence seq;
@@ -262,10 +292,15 @@ TEST_F(TestMockOperationSnapshotRemoveRequest, RemoveChildError) {
 
   librbd::NoOpProgressContext prog_ctx;
   ASSERT_EQ(0, librbd::flatten(ictx, prog_ctx));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
+  MockObjectMap mock_object_map;
+  if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
+    mock_image_ctx.object_map = &mock_object_map;
+  }
+
   expect_op_work_queue(mock_image_ctx);
 
   uint64_t snap_id = ictx->snap_info.rbegin()->first;
@@ -287,10 +322,20 @@ TEST_F(TestMockOperationSnapshotRemoveRequest, RemoveSnapError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
+  MockExclusiveLock mock_exclusive_lock;
+  if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+    mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
+  }
+
+  MockObjectMap mock_object_map;
+  if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
+    mock_image_ctx.object_map = &mock_object_map;
+  }
+
   expect_op_work_queue(mock_image_ctx);
 
   ::testing::InSequence seq;
index 7ec65b48ae0ed32987ea1bf7edc0bf9cb351d313..07cb296a41f29e8153b04e69c8d5008946753acf 100644 (file)
@@ -8,6 +8,7 @@
 #include "test/librados_test_stub/MockTestMemRadosClient.h"
 #include "include/rados/librados.hpp"
 #include "common/bit_vector.hpp"
+#include "librbd/ImageState.h"
 #include "librbd/internal.h"
 #include "librbd/operation/SnapshotUnprotectRequest.h"
 #include "gmock/gmock.h"
@@ -105,7 +106,7 @@ TEST_F(TestMockOperationSnapshotUnprotectRequest, Success) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
@@ -138,7 +139,7 @@ TEST_F(TestMockOperationSnapshotUnprotectRequest, GetSnapIdMissing) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
@@ -163,7 +164,7 @@ TEST_F(TestMockOperationSnapshotUnprotectRequest, IsSnapUnprotectedError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
@@ -189,7 +190,7 @@ TEST_F(TestMockOperationSnapshotUnprotectRequest, SnapAlreadyUnprotected) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
@@ -215,7 +216,7 @@ TEST_F(TestMockOperationSnapshotUnprotectRequest, SetProtectionStatusError) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
@@ -244,7 +245,7 @@ TEST_F(TestMockOperationSnapshotUnprotectRequest, ChildrenExist) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, librbd::snap_create(ictx, "snap1"));
-  ASSERT_EQ(0, librbd::ictx_check(ictx));
+  ASSERT_EQ(0, ictx->state->refresh_if_required());
 
   MockImageCtx mock_image_ctx(*ictx);
 
index 0bba8109d6a8e0631e9f2af2021ad38b98baf724..c816853ac4d8039e92f72590f37e31769299aa92 100644 (file)
@@ -45,44 +45,6 @@ public:
   {
   }
 
-  struct LockListener : public librbd::ImageWatcher::Listener {
-    Mutex lock;
-    Cond cond;
-    size_t releasing_lock_count;
-    size_t lock_updated_count;
-    bool lock_owner;
-
-    LockListener()
-      : lock("lock"), releasing_lock_count(0), lock_updated_count(0),
-        lock_owner(false) {
-    }
-
-    virtual bool handle_requested_lock() {
-      return true;
-    }
-    virtual void handle_lock_updated(
-        librbd::ImageWatcher::LockUpdateState state) {
-      Mutex::Locker locker(lock);
-      ++lock_updated_count;
-
-      switch (state) {
-      case librbd::ImageWatcher::LOCK_UPDATE_STATE_NOT_SUPPORTED:
-      case librbd::ImageWatcher::LOCK_UPDATE_STATE_UNLOCKED:
-      case librbd::ImageWatcher::LOCK_UPDATE_STATE_NOTIFICATION:
-        lock_owner = false;
-        break;
-      case librbd::ImageWatcher::LOCK_UPDATE_STATE_RELEASING:
-        lock_owner = false;
-        ++releasing_lock_count;
-        break;
-      case librbd::ImageWatcher::LOCK_UPDATE_STATE_LOCKED:
-        lock_owner = true;
-        break;
-      }
-      cond.Signal();
-    }
-  };
-
   class WatchCtx : public librados::WatchCtx2 {
   public:
     WatchCtx(TestImageWatcher &parent) : m_parent(parent), m_handle(0) {}
@@ -165,39 +127,11 @@ public:
     return 0;
   }
 
-  void register_lock_listener(librbd::ImageCtx &ictx) {
-    ictx.image_watcher->register_listener(&m_lock_listener);
-  }
-
   int register_image_watch(librbd::ImageCtx &ictx) {
     m_watch_ctx = new WatchCtx(*this);
     return m_watch_ctx->watch(ictx);
   }
 
-  bool wait_for_releasing_lock(librbd::ImageCtx &ictx) {
-    Mutex::Locker locker(m_lock_listener.lock);
-    while (m_lock_listener.releasing_lock_count == 0) {
-      if (m_lock_listener.cond.WaitInterval(ictx.cct, m_lock_listener.lock,
-                                            utime_t(10, 0)) != 0) {
-        return false;
-      }
-    }
-    m_lock_listener.releasing_lock_count = 0;
-    return true;
-  }
-
-  bool wait_for_lock_updated(librbd::ImageCtx &ictx) {
-    Mutex::Locker locker(m_lock_listener.lock);
-    while (m_lock_listener.lock_updated_count == 0) {
-      if (m_lock_listener.cond.WaitInterval(ictx.cct, m_lock_listener.lock,
-                                            utime_t(10, 0)) != 0) {
-        return false;
-      }
-    }
-    m_lock_listener.lock_updated_count = 0;
-    return true;
-  }
-
   bool wait_for_notifies(librbd::ImageCtx &ictx) {
     Mutex::Locker l(m_callback_lock);
     while (m_notifies.size() < m_notify_acks.size()) {
@@ -271,8 +205,6 @@ public:
 
   WatchCtx *m_watch_ctx;
 
-  LockListener m_lock_listener;
-
   NotifyOps m_notifies;
   NotifyOpPayloads m_notify_payloads;
   NotifyOpPayloads m_notify_acks;
@@ -357,487 +289,58 @@ struct RebuildObjectMapTask {
   }
 };
 
-TEST_F(TestImageWatcher, IsLockSupported) {
-  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
-  librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-  RWLock::WLocker l(ictx->owner_lock);
-  ASSERT_TRUE(ictx->image_watcher);
-  ASSERT_TRUE(ictx->image_watcher->is_lock_supported());
-
-  ictx->read_only = true;
-  ASSERT_FALSE(ictx->image_watcher->is_lock_supported());
-  ictx->read_only = false;
-
-  ictx->features &= ~RBD_FEATURE_EXCLUSIVE_LOCK;
-  ASSERT_FALSE(ictx->image_watcher->is_lock_supported());
-  ictx->features |= RBD_FEATURE_EXCLUSIVE_LOCK;
-
-  ictx->snap_id = 1234;
-  ASSERT_FALSE(ictx->image_watcher->is_lock_supported());
-  ictx->snap_id = CEPH_NOSNAP;
-}
-
-TEST_F(TestImageWatcher, TryLock) {
-  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
-  librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-  ASSERT_TRUE(ictx->image_watcher);
-
-  {
-    RWLock::WLocker l(ictx->owner_lock);
-    ASSERT_EQ(0, ictx->image_watcher->try_lock());
-    ASSERT_TRUE(ictx->image_watcher->is_lock_owner());
-  }
-
-  std::map<rados::cls::lock::locker_id_t,
-           rados::cls::lock::locker_info_t> lockers;
-  ClsLockType lock_type;
-  ASSERT_EQ(0, rados::cls::lock::get_lock_info(&m_ioctx, ictx->header_oid,
-                                              RBD_LOCK_NAME, &lockers,
-                                              &lock_type, NULL));
-  ASSERT_EQ(LOCK_EXCLUSIVE, lock_type);
-  ASSERT_EQ(1U, lockers.size());
-}
-
-TEST_F(TestImageWatcher, TryLockNotifyAnnounceLocked) {
+TEST_F(TestImageWatcher, NotifyRequestLock) {
   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
 
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
   ASSERT_EQ(0, register_image_watch(*ictx));
-  m_notify_acks = {{NOTIFY_OP_ACQUIRED_LOCK, {}}};
 
-  {
-    RWLock::WLocker l(ictx->owner_lock);
-    ASSERT_EQ(0, ictx->image_watcher->try_lock());
-  }
+  m_notify_acks = {{NOTIFY_OP_REQUEST_LOCK, {}}};
+  ictx->image_watcher->notify_request_lock();
 
   ASSERT_TRUE(wait_for_notifies(*ictx));
 
   NotifyOps expected_notify_ops;
-  expected_notify_ops += NOTIFY_OP_ACQUIRED_LOCK;
+  expected_notify_ops += NOTIFY_OP_REQUEST_LOCK;
   ASSERT_EQ(expected_notify_ops, m_notifies);
 }
 
-TEST_F(TestImageWatcher, TryLockWithTimedOutOwner) {
-  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
-  // use new Rados connection due to blacklisting
-  librados::Rados rados;
-  ASSERT_EQ("", connect_cluster_pp(rados));
-
-  librados::IoCtx io_ctx;
-  ASSERT_EQ(0, rados.ioctx_create(_pool_name.c_str(), io_ctx));
-  librbd::ImageCtx *ictx = new librbd::ImageCtx(m_image_name.c_str(), "", NULL,
-                                               io_ctx, false);
-  ASSERT_EQ(0, librbd::open_image(ictx));
-  ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE, "auto 1234"));
-  librbd::close_image(ictx);
-  io_ctx.close();
-
-  // no watcher on the locked image means we can break the lock
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-  RWLock::WLocker l(ictx->owner_lock);
-  ASSERT_EQ(0, ictx->image_watcher->try_lock());
-  ASSERT_TRUE(ictx->image_watcher->is_lock_owner());
-
-  rados.test_blacklist_self(false);
-}
-
-TEST_F(TestImageWatcher, TryLockWithUserExclusiveLock) {
-  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
-  librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
-  ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE, "manually locked"));
-
-  RWLock::WLocker l(ictx->owner_lock);
-  ASSERT_EQ(-EBUSY, ictx->image_watcher->try_lock());
-  ASSERT_FALSE(ictx->image_watcher->is_lock_owner());
-
-  ASSERT_EQ(0, unlock_image());
-  ASSERT_EQ(0, ictx->image_watcher->try_lock());
-  ASSERT_TRUE(ictx->image_watcher->is_lock_owner());
-}
-
-TEST_F(TestImageWatcher, TryLockWithUserSharedLocked) {
-  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
-  librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
-  ASSERT_EQ(0, lock_image(*ictx, LOCK_SHARED, "manually locked"));
-
-  RWLock::WLocker l(ictx->owner_lock);
-  ASSERT_EQ(-EBUSY, ictx->image_watcher->try_lock());
-  ASSERT_FALSE(ictx->image_watcher->is_lock_owner());
-
-  ASSERT_EQ(0, unlock_image());
-  ASSERT_EQ(0, ictx->image_watcher->try_lock());
-  ASSERT_TRUE(ictx->image_watcher->is_lock_owner());
-}
-
-TEST_F(TestImageWatcher, ReleaseLockNotLocked) {
-  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
-  librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-
-  RWLock::WLocker l(ictx->owner_lock);
-  ASSERT_EQ(0, ictx->image_watcher->release_lock());
-}
-
-TEST_F(TestImageWatcher, ReleaseLockNotifies) {
+TEST_F(TestImageWatcher, NotifyReleasedLock) {
   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
 
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
   ASSERT_EQ(0, register_image_watch(*ictx));
-  m_notify_acks = {{NOTIFY_OP_ACQUIRED_LOCK, {}}};
 
-  {
-    RWLock::WLocker l(ictx->owner_lock);
-    ASSERT_EQ(0, ictx->image_watcher->try_lock());
-  }
-  ASSERT_TRUE(wait_for_notifies(*ictx));
+  m_notify_acks = {{NOTIFY_OP_RELEASED_LOCK, {}}};
+  ictx->image_watcher->notify_released_lock();
 
-  m_notify_acks += std::make_pair(NOTIFY_OP_RELEASED_LOCK, bufferlist());
-  {
-    RWLock::WLocker l(ictx->owner_lock);
-    ASSERT_EQ(0, ictx->image_watcher->release_lock());
-  }
   ASSERT_TRUE(wait_for_notifies(*ictx));
 
   NotifyOps expected_notify_ops;
-  expected_notify_ops += NOTIFY_OP_ACQUIRED_LOCK, NOTIFY_OP_RELEASED_LOCK;
+  expected_notify_ops += NOTIFY_OP_RELEASED_LOCK;
   ASSERT_EQ(expected_notify_ops, m_notifies);
 }
 
-TEST_F(TestImageWatcher, ReleaseLockBrokenLock) {
+TEST_F(TestImageWatcher, NotifyAcquiredLock) {
   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
 
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  RWLock::WLocker l(ictx->owner_lock);
-  ASSERT_EQ(0, ictx->image_watcher->try_lock());
-
-  std::map<rados::cls::lock::locker_id_t,
-           rados::cls::lock::locker_info_t> lockers;
-  ClsLockType lock_type;
-  ASSERT_EQ(0, rados::cls::lock::get_lock_info(&m_ioctx, ictx->header_oid,
-                                               RBD_LOCK_NAME, &lockers,
-                                               &lock_type, NULL));
-  ASSERT_EQ(1U, lockers.size());
-  ASSERT_EQ(0, rados::cls::lock::break_lock(&m_ioctx, ictx->header_oid,
-                                           RBD_LOCK_NAME,
-                                           lockers.begin()->first.cookie,
-                                           lockers.begin()->first.locker));
-
-  ASSERT_EQ(0, ictx->image_watcher->release_lock());
-}
-
-TEST_F(TestImageWatcher, RequestLock) {
-  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
-  librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_EQ(0, register_image_watch(*ictx));
 
-  register_lock_listener(*ictx);
   m_notify_acks = {{NOTIFY_OP_ACQUIRED_LOCK, {}}};
-
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    ictx->image_watcher->request_lock();
-  }
+  ictx->image_watcher->notify_acquired_lock();
 
   ASSERT_TRUE(wait_for_notifies(*ictx));
-  NotifyOps expected_notify_ops;
-  expected_notify_ops += NOTIFY_OP_ACQUIRED_LOCK;
-  ASSERT_EQ(expected_notify_ops, m_notifies);
 
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    ASSERT_TRUE(ictx->image_watcher->is_lock_owner());
-  }
-}
-
-TEST_F(TestImageWatcher, RequestLockFromPeer) {
-  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
-  librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-  ASSERT_EQ(0, register_image_watch(*ictx));
-  ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
-                         "auto " + stringify(m_watch_ctx->get_handle())));
-
-  register_lock_listener(*ictx);
-  m_notify_acks = {{NOTIFY_OP_REQUEST_LOCK, create_response_message(0)}};
-
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    ictx->image_watcher->request_lock();
-  }
-
-  ASSERT_TRUE(wait_for_notifies(*ictx));
   NotifyOps expected_notify_ops;
-  expected_notify_ops += NOTIFY_OP_REQUEST_LOCK;
-  ASSERT_EQ(expected_notify_ops, m_notifies);
-
-  ASSERT_EQ(0, unlock_image());
-
-  {
-    Mutex::Locker l(m_callback_lock);
-    m_notifies.clear();
-    m_notify_acks = {{NOTIFY_OP_RELEASED_LOCK,{}}};
-  }
-
-  bufferlist bl;
-  {
-    ENCODE_START(1, 1, bl);
-    ::encode(NOTIFY_OP_RELEASED_LOCK, bl);
-    ENCODE_FINISH(bl);
-  }
-  ASSERT_EQ(0, m_ioctx.notify2(ictx->header_oid, bl, 5000, NULL));
-  ASSERT_TRUE(wait_for_lock_updated(*ictx));
-
-  {
-    Mutex::Locker l(m_callback_lock);
-    m_notifies.clear();
-    m_notify_acks = {{NOTIFY_OP_ACQUIRED_LOCK, {}}};
-  }
-
-  {
-    RWLock::RLocker owner_lock(ictx->owner_lock);
-    ictx->image_watcher->request_lock();
-  }
-
-  ASSERT_TRUE(wait_for_notifies(*ictx));
-  expected_notify_ops.clear();
   expected_notify_ops += NOTIFY_OP_ACQUIRED_LOCK;
   ASSERT_EQ(expected_notify_ops, m_notifies);
-
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    ASSERT_TRUE(ictx->image_watcher->is_lock_owner());
-  }
-}
-
-TEST_F(TestImageWatcher, RequestLockTimedOut) {
-  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
-  librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-  ASSERT_EQ(0, register_image_watch(*ictx));
-  ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
-                         "auto " + stringify(m_watch_ctx->get_handle())));
-
-  register_lock_listener(*ictx);
-  m_notify_acks = {{NOTIFY_OP_REQUEST_LOCK, {}}};
-
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    ictx->image_watcher->request_lock();
-  }
-
-  ASSERT_TRUE(wait_for_notifies(*ictx));
-  NotifyOps expected_notify_ops;
-  expected_notify_ops += NOTIFY_OP_REQUEST_LOCK;
-  ASSERT_EQ(expected_notify_ops, m_notifies);
-
-  // should resend when empty ack returned
-  {
-    Mutex::Locker l(m_callback_lock);
-    m_notifies.clear();
-  }
-  ASSERT_TRUE(wait_for_notifies(*ictx));
-
-  {
-    Mutex::Locker l(m_callback_lock);
-    ASSERT_EQ(0, unlock_image());
-    m_notifies.clear();
-    m_notify_acks = {{NOTIFY_OP_ACQUIRED_LOCK, {}}};
-  }
-
-  ASSERT_TRUE(wait_for_notifies(*ictx));
-  ASSERT_TRUE(wait_for_lock_updated(*ictx));
-
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    ASSERT_TRUE(ictx->image_watcher->is_lock_owner());
-  }
-}
-
-TEST_F(TestImageWatcher, RequestLockIgnored) {
-  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
-  librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-  ASSERT_EQ(0, register_image_watch(*ictx));
-  ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
-                         "auto " + stringify(m_watch_ctx->get_handle())));
-
-  register_lock_listener(*ictx);
-  m_notify_acks = {{NOTIFY_OP_REQUEST_LOCK, create_response_message(0)}};
-
-  int orig_notify_timeout = ictx->cct->_conf->client_notify_timeout;
-  ictx->cct->_conf->set_val("client_notify_timeout", "0");
-  BOOST_SCOPE_EXIT( (ictx)(orig_notify_timeout) ) {
-    ictx->cct->_conf->set_val("client_notify_timeout",
-                              stringify(orig_notify_timeout));
-  } BOOST_SCOPE_EXIT_END;
-
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    ictx->image_watcher->request_lock();
-  }
-
-  ASSERT_TRUE(wait_for_notifies(*ictx));
-  NotifyOps expected_notify_ops;
-  expected_notify_ops += NOTIFY_OP_REQUEST_LOCK;
-  ASSERT_EQ(expected_notify_ops, m_notifies);
-
-  // after the request times out -- it will be resent
-  {
-    Mutex::Locker l(m_callback_lock);
-    m_notifies.clear();
-  }
-  ASSERT_TRUE(wait_for_notifies(*ictx));
-  ASSERT_EQ(expected_notify_ops, m_notifies);
-
-  {
-    Mutex::Locker l(m_callback_lock);
-    ASSERT_EQ(0, unlock_image());
-    m_notifies.clear();
-    m_notify_acks = {{NOTIFY_OP_ACQUIRED_LOCK, {}}};
-  }
-
-  ASSERT_TRUE(wait_for_notifies(*ictx));
-  ASSERT_TRUE(wait_for_lock_updated(*ictx));
-
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    ASSERT_TRUE(ictx->image_watcher->is_lock_owner());
-  }
-}
-
-TEST_F(TestImageWatcher, RequestLockTryLockRace) {
-  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
-  librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-  ASSERT_EQ(0, register_image_watch(*ictx));
-  ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE,
-                          "auto " + stringify(m_watch_ctx->get_handle())));
-
-  register_lock_listener(*ictx);
-  m_notify_acks = {{NOTIFY_OP_REQUEST_LOCK, create_response_message(0)}};
-
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    ictx->image_watcher->request_lock();
-  }
-
-  ASSERT_TRUE(wait_for_notifies(*ictx));
-  NotifyOps expected_notify_ops;
-  expected_notify_ops += NOTIFY_OP_REQUEST_LOCK;
-  ASSERT_EQ(expected_notify_ops, m_notifies);
-
-  {
-    Mutex::Locker l(m_callback_lock);
-    m_notifies.clear();
-    m_notify_acks = {{NOTIFY_OP_RELEASED_LOCK, {}}};
-  }
-
-  bufferlist bl;
-  {
-    ENCODE_START(1, 1, bl);
-    ::encode(NOTIFY_OP_RELEASED_LOCK, bl);
-    ENCODE_FINISH(bl);
-  }
-  ASSERT_EQ(0, m_ioctx.notify2(ictx->header_oid, bl, 5000, NULL));
-
-  // after losing race -- it will re-request
-  ASSERT_TRUE(wait_for_notifies(*ictx));
-
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    ASSERT_FALSE(ictx->image_watcher->is_lock_owner());
-  }
-
-  {
-    Mutex::Locker l(m_callback_lock);
-    ASSERT_EQ(0, unlock_image());
-    m_notifies.clear();
-    m_notify_acks = {{NOTIFY_OP_RELEASED_LOCK, {}}};
-  }
-
-  ASSERT_EQ(0, m_ioctx.notify2(ictx->header_oid, bl, 5000, NULL));
-  ASSERT_TRUE(wait_for_lock_updated(*ictx));
-
-  {
-    Mutex::Locker l(m_callback_lock);
-    m_notifies.clear();
-    m_notify_acks = {{NOTIFY_OP_ACQUIRED_LOCK, {}}};
-  }
-
-  {
-    RWLock::RLocker owner_lock(ictx->owner_lock);
-    ictx->image_watcher->request_lock();
-  }
-
-  ASSERT_TRUE(wait_for_lock_updated(*ictx));
-  ASSERT_TRUE(wait_for_notifies(*ictx));
-
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    ASSERT_TRUE(ictx->image_watcher->is_lock_owner());
-  }
-}
-
-TEST_F(TestImageWatcher, RequestLockTryLockFailed) {
-  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
-  librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-  ASSERT_EQ(0, register_image_watch(*ictx));
-  ASSERT_EQ(0, lock_image(*ictx, LOCK_SHARED, "manually 1234"));
-
-  register_lock_listener(*ictx);
-  m_notify_acks = {{NOTIFY_OP_REQUEST_LOCK, {}}};
-
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    ictx->image_watcher->request_lock();
-  }
-
-  ASSERT_TRUE(wait_for_notifies(*ictx));
-  NotifyOps expected_notify_ops;
-  expected_notify_ops += NOTIFY_OP_REQUEST_LOCK;
-  ASSERT_EQ(expected_notify_ops, m_notifies);
-
-  // should resend when error encountered
-  {
-    Mutex::Locker l(m_callback_lock);
-    m_notifies.clear();
-  }
-  ASSERT_TRUE(wait_for_notifies(*ictx));
-
-  {
-    Mutex::Locker l(m_callback_lock);
-    ASSERT_EQ(0, unlock_image());
-    m_notifies.clear();
-    m_notify_acks = {{NOTIFY_OP_ACQUIRED_LOCK, {}}};
-  }
-
-  ASSERT_TRUE(wait_for_notifies(*ictx));
 }
 
 TEST_F(TestImageWatcher, NotifyHeaderUpdate) {
@@ -1216,47 +719,3 @@ TEST_F(TestImageWatcher, NotifyAsyncRequestTimedOut) {
   ASSERT_EQ(-ERESTART, flatten_task.result);
 }
 
-TEST_F(TestImageWatcher, PeerRequestsLock) {
-  REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
-
-  librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-  ASSERT_EQ(0, register_image_watch(*ictx));
-
-  register_lock_listener(*ictx);
-  m_notify_acks = {{NOTIFY_OP_ACQUIRED_LOCK, {}}};
-
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    ictx->image_watcher->request_lock();
-  }
-
-  ASSERT_TRUE(wait_for_notifies(*ictx));
-
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    ASSERT_TRUE(ictx->image_watcher->is_lock_owner());
-  }
-
-  // if journaling is enabled, ensure we wait for it to replay since
-  // it will block our peer request
-  std::string buffer(256, '1');
-  ictx->aio_work_queue->write(0, buffer.size(), buffer.c_str(), 0);
-
-  {
-    Mutex::Locker l(m_callback_lock);
-    m_notifies.clear();
-    m_notify_acks = {{NOTIFY_OP_RELEASED_LOCK, {}}};
-  }
-
-  bufferlist bl;
-  {
-    ENCODE_START(1, 1, bl);
-    ::encode(NOTIFY_OP_REQUEST_LOCK, bl);
-    ENCODE_FINISH(bl);
-  }
-  ASSERT_EQ(0, m_ioctx.notify2(ictx->header_oid, bl, 5000, NULL));
-
-  ASSERT_TRUE(wait_for_releasing_lock(*ictx));
-  ASSERT_TRUE(wait_for_notifies(*ictx));
-}
index 0b6374763f9d87402ee0a08283c212dd5d6dc055..c5a6ad63d4148598cb47aee72dd5f92504430951 100644 (file)
@@ -6,6 +6,7 @@
 #include "librbd/AioCompletion.h"
 #include "librbd/AioImageRequest.h"
 #include "librbd/AioImageRequestWQ.h"
+#include "librbd/ExclusiveLock.h"
 #include "librbd/ImageCtx.h"
 #include "librbd/ImageWatcher.h"
 #include "librbd/Journal.h"
@@ -17,38 +18,13 @@ void register_test_journal_replay() {
 class TestJournalReplay : public TestFixture {
 public:
 
-  struct Listener : public librbd::ImageWatcher::Listener{
-    Mutex lock;
-    Cond cond;
-
-    Listener() : lock("TestJournalReplay::Listener::lock") {
-    }
-    virtual bool handle_requested_lock() {
-      return true;
-    }
-    virtual void handle_releasing_lock() {
-    }
-    virtual void handle_lock_updated(
-        librbd::ImageWatcher::LockUpdateState state) {
-      Mutex::Locker locker(lock);
-      cond.Signal();
-    }
-  };
-
-  void wait_for_lock_owner(librbd::ImageCtx *ictx) {
-    Listener listener;
-    ictx->image_watcher->register_listener(&listener);
+  int when_acquired_lock(librbd::ImageCtx *ictx) {
+    C_SaferCond lock_ctx;
     {
-      RWLock::RLocker owner_locker(ictx->owner_lock);
-      while (!ictx->image_watcher->is_lock_owner()) {
-        ictx->owner_lock.put_read();
-        listener.lock.Lock();
-        listener.cond.Wait(listener.lock);
-        listener.lock.Unlock();
-        ictx->owner_lock.get_read();
-      }
+      RWLock::WLocker owner_locker(ictx->owner_lock);
+      ictx->exclusive_lock->request_lock(&lock_ctx);
     }
-    ictx->image_watcher->unregister_listener(&listener);
+    return lock_ctx.wait();
   }
 };
 
@@ -59,7 +35,6 @@ TEST_F(TestJournalReplay, AioDiscardEvent) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ictx->features &= ~RBD_FEATURE_JOURNALING;
-  ASSERT_EQ(0, ictx->close_journal(true));
 
   std::string payload(4096, '1');
   librbd::AioCompletion *aio_comp = new librbd::AioCompletion();
@@ -84,14 +59,7 @@ TEST_F(TestJournalReplay, AioDiscardEvent) {
 
   // inject a discard operation into the journal
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
-  {
-    RWLock::WLocker owner_locker(ictx->owner_lock);
-    ictx->image_watcher->request_lock();
-  }
-  wait_for_lock_owner(ictx);
-
-  ictx->journal->open();
-  ictx->journal->wait_for_journal_ready();
+  ASSERT_EQ(0, when_acquired_lock(ictx));
 
   librbd::journal::EventEntry event_entry(
     librbd::journal::AioDiscardEvent(0, payload.size()));
@@ -100,11 +68,10 @@ TEST_F(TestJournalReplay, AioDiscardEvent) {
     RWLock::RLocker owner_locker(ictx->owner_lock);
     ictx->journal->append_io_event(NULL, event_entry, requests, 0, 0, true);
   }
-  ASSERT_EQ(0, ictx->journal->close());
 
   // re-open the journal so that it replays the new entry
-  ictx->journal->open();
-  ictx->journal->wait_for_journal_ready();
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+  ASSERT_EQ(0, when_acquired_lock(ictx));
 
   aio_comp = new librbd::AioCompletion();
   ictx->aio_work_queue->aio_read(aio_comp, 0, read_payload.size(),
@@ -120,14 +87,7 @@ TEST_F(TestJournalReplay, AioWriteEvent) {
   // inject a write operation into the journal
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
-  {
-    RWLock::WLocker owner_locker(ictx->owner_lock);
-    ictx->image_watcher->request_lock();
-  }
-  wait_for_lock_owner(ictx);
-
-  ictx->journal->open();
-  ictx->journal->wait_for_journal_ready();
+  ASSERT_EQ(0, when_acquired_lock(ictx));
 
   std::string payload(4096, '1');
   bufferlist payload_bl;
@@ -139,11 +99,10 @@ TEST_F(TestJournalReplay, AioWriteEvent) {
     RWLock::RLocker owner_locker(ictx->owner_lock);
     ictx->journal->append_io_event(NULL, event_entry, requests, 0, 0, true);
   }
-  ASSERT_EQ(0, ictx->journal->close());
 
   // re-open the journal so that it replays the new entry
-  ictx->journal->open();
-  ictx->journal->wait_for_journal_ready();
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+  ASSERT_EQ(0, when_acquired_lock(ictx));
 
   std::string read_payload(4096, '\0');
   librbd::AioCompletion *aio_comp = new librbd::AioCompletion();
@@ -159,15 +118,9 @@ TEST_F(TestJournalReplay, AioFlushEvent) {
 
   // inject a flush operation into the journal
   librbd::ImageCtx *ictx;
-  ASSERT_EQ(0, open_image(m_image_name, &ictx));
-  {
-    RWLock::WLocker owner_locker(ictx->owner_lock);
-    ictx->image_watcher->request_lock();
-  }
-  wait_for_lock_owner(ictx);
 
-  ictx->journal->open();
-  ictx->journal->wait_for_journal_ready();
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+  ASSERT_EQ(0, when_acquired_lock(ictx));
 
   librbd::journal::AioFlushEvent aio_flush_event;
   librbd::journal::EventEntry event_entry(aio_flush_event);
@@ -176,7 +129,6 @@ TEST_F(TestJournalReplay, AioFlushEvent) {
     RWLock::RLocker owner_locker(ictx->owner_lock);
     ictx->journal->append_io_event(NULL, event_entry, requests, 0, 0, true);
   }
-  ASSERT_EQ(0, ictx->journal->close());
 
   // start an AIO write op
   librbd::Journal *journal = ictx->journal;
@@ -192,8 +144,8 @@ TEST_F(TestJournalReplay, AioFlushEvent) {
   ictx->journal = journal;
 
   // re-open the journal so that it replays the new entry
-  ictx->journal->open();
-  ictx->journal->wait_for_journal_ready();
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+  ASSERT_EQ(0, when_acquired_lock(ictx));
 
   ASSERT_TRUE(aio_comp->is_complete());
   ASSERT_EQ(0, aio_comp->wait_for_complete());
index 5457b9974fd1d204778b6c1e2815010af83b3632..b3b19e45ccd30bf76299510959cc5f030a0efa5e 100644 (file)
@@ -2,6 +2,7 @@
 // vim: ts=8 sw=2 smarttab
 #include "test/librbd/test_fixture.h"
 #include "test/librbd/test_support.h"
+#include "librbd/ExclusiveLock.h"
 #include "librbd/ImageCtx.h"
 #include "librbd/ImageWatcher.h"
 #include "librbd/internal.h"
@@ -14,6 +15,13 @@ void register_test_object_map() {
 
 class TestObjectMap : public TestFixture {
 public:
+
+  int when_open_object_map(librbd::ImageCtx *ictx) {
+    C_SaferCond ctx;
+    librbd::ObjectMap object_map(*ictx, ictx->snap_id);
+    object_map.open(&ctx);
+    return ctx.wait();
+  }
 };
 
 TEST_F(TestObjectMap, RefreshInvalidatesWhenCorrupt) {
@@ -23,21 +31,19 @@ TEST_F(TestObjectMap, RefreshInvalidatesWhenCorrupt) {
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_FALSE(ictx->test_flags(RBD_FLAG_OBJECT_MAP_INVALID));
 
+  C_SaferCond lock_ctx;
   {
     RWLock::WLocker owner_locker(ictx->owner_lock);
-    ASSERT_EQ(0, ictx->image_watcher->try_lock());
+    ictx->exclusive_lock->try_lock(&lock_ctx);
   }
+  ASSERT_EQ(0, lock_ctx.wait());
 
   std::string oid = librbd::ObjectMap::object_map_name(ictx->id, CEPH_NOSNAP);
   bufferlist bl;
   bl.append("corrupt");
   ASSERT_EQ(0, ictx->data_ctx.write_full(oid, bl));
 
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    RWLock::WLocker snap_locker(ictx->snap_lock);
-    ictx->object_map.refresh(CEPH_NOSNAP);
-  }
+  ASSERT_EQ(0, when_open_object_map(ictx));
   ASSERT_TRUE(ictx->test_flags(RBD_FLAG_OBJECT_MAP_INVALID));
 }
 
@@ -48,10 +54,12 @@ TEST_F(TestObjectMap, RefreshInvalidatesWhenTooSmall) {
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_FALSE(ictx->test_flags(RBD_FLAG_OBJECT_MAP_INVALID));
 
+  C_SaferCond lock_ctx;
   {
     RWLock::WLocker owner_locker(ictx->owner_lock);
-    ASSERT_EQ(0, ictx->image_watcher->try_lock());
+    ictx->exclusive_lock->try_lock(&lock_ctx);
   }
+  ASSERT_EQ(0, lock_ctx.wait());
 
   librados::ObjectWriteOperation op;
   librbd::cls_client::object_map_resize(&op, 0, OBJECT_NONEXISTENT);
@@ -59,11 +67,7 @@ TEST_F(TestObjectMap, RefreshInvalidatesWhenTooSmall) {
   std::string oid = librbd::ObjectMap::object_map_name(ictx->id, CEPH_NOSNAP);
   ASSERT_EQ(0, ictx->data_ctx.operate(oid, &op));
 
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    RWLock::WLocker snap_locker(ictx->snap_lock);
-    ictx->object_map.refresh(CEPH_NOSNAP);
-  }
+  ASSERT_EQ(0, when_open_object_map(ictx));
   ASSERT_TRUE(ictx->test_flags(RBD_FLAG_OBJECT_MAP_INVALID));
 }
 
@@ -74,21 +78,19 @@ TEST_F(TestObjectMap, InvalidateFlagOnDisk) {
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
   ASSERT_FALSE(ictx->test_flags(RBD_FLAG_OBJECT_MAP_INVALID));
 
+  C_SaferCond lock_ctx;
   {
     RWLock::WLocker owner_locker(ictx->owner_lock);
-    ASSERT_EQ(0, ictx->image_watcher->try_lock());
+    ictx->exclusive_lock->try_lock(&lock_ctx);
   }
+  ASSERT_EQ(0, lock_ctx.wait());
 
   std::string oid = librbd::ObjectMap::object_map_name(ictx->id, CEPH_NOSNAP);
   bufferlist bl;
   bl.append("corrupt");
   ASSERT_EQ(0, ictx->data_ctx.write_full(oid, bl));
 
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    RWLock::WLocker snap_locker(ictx->snap_lock);
-    ictx->object_map.refresh(CEPH_NOSNAP);
-  }
+  ASSERT_EQ(0, when_open_object_map(ictx));
   ASSERT_TRUE(ictx->test_flags(RBD_FLAG_OBJECT_MAP_INVALID));
 
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
@@ -110,11 +112,7 @@ TEST_F(TestObjectMap, InvalidateFlagInMemoryOnly) {
   corrupt_bl.append("corrupt");
   ASSERT_EQ(0, ictx->data_ctx.write_full(oid, corrupt_bl));
 
-  {
-    RWLock::RLocker owner_locker(ictx->owner_lock);
-    RWLock::WLocker snap_locker(ictx->snap_lock);
-    ictx->object_map.refresh(CEPH_NOSNAP);
-  }
+  ASSERT_EQ(0, when_open_object_map(ictx));
   ASSERT_TRUE(ictx->test_flags(RBD_FLAG_OBJECT_MAP_INVALID));
 
   ASSERT_EQ(0, ictx->data_ctx.write_full(oid, valid_bl));
index 9be0f1b93f8038630b427bf381312112829f215e..8c6a4b9e3925ea0025f8377bace10ad523e4c444 100644 (file)
@@ -4,6 +4,8 @@
 #include "test/librbd/test_support.h"
 #include "include/stringify.h"
 #include "librbd/AioImageRequestWQ.h"
+#include "librbd/ExclusiveLock.h"
+#include "librbd/ImageState.h"
 #include "librbd/ImageWatcher.h"
 #include "cls/lock/cls_lock_client.h"
 #include "cls/lock/cls_lock_types.h"
@@ -46,7 +48,7 @@ void TestFixture::TearDown() {
   unlock_image();
   for (std::set<librbd::ImageCtx *>::iterator iter = m_ictxs.begin();
        iter != m_ictxs.end(); ++iter) {
-    librbd::close_image(*iter);
+    (*iter)->state->close();
   }
 
   m_ioctx.close();
@@ -56,12 +58,14 @@ int TestFixture::open_image(const std::string &image_name,
                            librbd::ImageCtx **ictx) {
   *ictx = new librbd::ImageCtx(image_name.c_str(), "", NULL, m_ioctx, false);
   m_ictxs.insert(*ictx);
-  return librbd::open_image(*ictx);
+
+  return (*ictx)->state->open();
 }
 
 void TestFixture::close_image(librbd::ImageCtx *ictx) {
   m_ictxs.erase(ictx);
-  librbd::close_image(ictx);
+
+  ictx->state->close();
 }
 
 int TestFixture::lock_image(librbd::ImageCtx &ictx, ClsLockType lock_type,
@@ -93,5 +97,6 @@ int TestFixture::acquire_exclusive_lock(librbd::ImageCtx &ictx) {
   }
 
   RWLock::RLocker owner_locker(ictx.owner_lock);
-  return ictx.image_watcher->is_lock_owner() ? 0 : -EINVAL;
+  assert(ictx.exclusive_lock != nullptr);
+  return ictx.exclusive_lock->is_lock_owner() ? 0 : -EINVAL;
 }
index f8f5702d267be36232b5a3dfbb85b7df48000cab..d2884c6fed724eb5c837e9caaa8628761d02bf31 100644 (file)
@@ -5,6 +5,7 @@
 #include "librbd/AioCompletion.h"
 #include "librbd/AioImageRequest.h"
 #include "librbd/AioImageRequestWQ.h"
+#include "librbd/ExclusiveLock.h"
 #include "librbd/ImageWatcher.h"
 #include "librbd/internal.h"
 #include "librbd/ObjectMap.h"
@@ -79,11 +80,12 @@ TEST_F(TestInternal, IsExclusiveLockOwner) {
   ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx, &is_owner));
   ASSERT_FALSE(is_owner);
 
+  C_SaferCond ctx;
   {
     RWLock::WLocker l(ictx->owner_lock);
-    ASSERT_EQ(0, ictx->image_watcher->try_lock());
+    ictx->exclusive_lock->try_lock(&ctx);
   }
-
+  ASSERT_EQ(0, ctx.wait());
   ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx, &is_owner));
   ASSERT_TRUE(is_owner);
 }
@@ -295,10 +297,16 @@ TEST_F(TestInternal, CancelAsyncResize) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
+  C_SaferCond ctx;
   {
     RWLock::WLocker l(ictx->owner_lock);
-    ASSERT_EQ(0, ictx->image_watcher->try_lock());
-    ASSERT_TRUE(ictx->image_watcher->is_lock_owner());
+    ictx->exclusive_lock->try_lock(&ctx);
+  }
+
+  ASSERT_EQ(0, ctx.wait());
+  {
+    RWLock::RLocker owner_locker(ictx->owner_lock);
+    ASSERT_TRUE(ictx->exclusive_lock->is_lock_owner());
   }
 
   uint64_t size;
@@ -331,12 +339,16 @@ TEST_F(TestInternal, MultipleResize) {
   librbd::ImageCtx *ictx;
   ASSERT_EQ(0, open_image(m_image_name, &ictx));
 
-  {
-    RWLock::WLocker l(ictx->owner_lock);
-    if (ictx->image_watcher->is_lock_supported()) {
-      ASSERT_EQ(0, ictx->image_watcher->try_lock());
-      ASSERT_TRUE(ictx->image_watcher->is_lock_owner());
+  if (ictx->exclusive_lock != nullptr) {
+    C_SaferCond ctx;
+    {
+      RWLock::WLocker l(ictx->owner_lock);
+      ictx->exclusive_lock->try_lock(&ctx);
     }
+
+    RWLock::RLocker owner_locker(ictx->owner_lock);
+    ASSERT_EQ(0, ctx.wait());
+    ASSERT_TRUE(ictx->exclusive_lock->is_lock_owner());
   }
 
   uint64_t size;
@@ -506,8 +518,7 @@ TEST_F(TestInternal, SnapshotCopyup)
   bufferlist read_bl;
   read_bl.push_back(read_ptr);
 
-  std::list<std::string> snaps = boost::assign::list_of(
-    "snap1")("snap2")("");
+  std::list<std::string> snaps = {"snap1", "snap2", ""};
   for (std::list<std::string>::iterator it = snaps.begin();
        it != snaps.end(); ++it) {
     const char *snap_name = it->empty() ? NULL : it->c_str();
@@ -530,8 +541,14 @@ TEST_F(TestInternal, SnapshotCopyup)
           it != snaps.begin() && snap_name != NULL) {
         state = OBJECT_EXISTS_CLEAN;
       }
+
+      librbd::ObjectMap object_map(*ictx2, ictx2->snap_id);
+      C_SaferCond ctx;
+      object_map.open(&ctx);
+      ASSERT_EQ(0, ctx.wait());
+
       RWLock::WLocker object_map_locker(ictx2->object_map_lock);
-      ASSERT_EQ(state, ictx2->object_map[0]);
+      ASSERT_EQ(state, object_map[0]);
     }
   }
 }
index 59da12d57573c8a490c5e3b74560457568020e2d..7b84d359d2c8bcc75731cb813a86a8e0723e64c9 100644 (file)
@@ -2826,16 +2826,16 @@ TEST_F(TestLibRBD, RebuildObjectMapViaLockOwner)
   librbd::Image image1;
   ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
 
-  uint64_t flags;
-  ASSERT_EQ(0, image1.get_flags(&flags));
-  ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
-
   bool lock_owner;
   bl.clear();
   ASSERT_EQ(0, image1.write(0, 0, bl));
   ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
   ASSERT_TRUE(lock_owner);
 
+  uint64_t flags;
+  ASSERT_EQ(0, image1.get_flags(&flags));
+  ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
+
   librbd::Image image2;
   ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL));
   ASSERT_EQ(0, image2.is_exclusive_lock_owner(&lock_owner));
@@ -3406,6 +3406,12 @@ TEST_F(TestLibRBD, RebuildObjectMap)
   librbd::Image image1;
   ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL));
 
+  bool lock_owner;
+  bl.clear();
+  ASSERT_EQ(0, image1.write(0, 0, bl));
+  ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner));
+  ASSERT_TRUE(lock_owner);
+
   uint64_t flags;
   ASSERT_EQ(0, image1.get_flags(&flags));
   ASSERT_TRUE((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0);
index 29ba0eccf46a5d7d0e99e3dedc0a03b9227b1957..56b2701295c006d73b18d09240b576227e6bc9b4 100644 (file)
@@ -58,6 +58,7 @@ namespace librbd {
 using ::testing::_;
 using ::testing::Invoke;
 using ::testing::InSequence;
+using ::testing::Return;
 
 class TestMockExclusiveLock : public TestMockFixture {
 public:
@@ -65,6 +66,11 @@ public:
   typedef exclusive_lock::AcquireRequest<MockImageCtx> MockAcquireRequest;
   typedef exclusive_lock::ReleaseRequest<MockImageCtx> MockReleaseRequest;
 
+  void expect_get_watch_handle(MockImageCtx &mock_image_ctx) {
+    EXPECT_CALL(*mock_image_ctx.image_watcher, get_watch_handle())
+                  .WillRepeatedly(Return(1234567890));
+  }
+
   void expect_block_writes(MockImageCtx &mock_image_ctx) {
     EXPECT_CALL(*mock_image_ctx.aio_work_queue, block_writes(_))
                   .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
@@ -76,9 +82,11 @@ public:
 
   void expect_acquire_lock(MockImageCtx &mock_image_ctx,
                            MockAcquireRequest &acquire_request, int r) {
+    expect_get_watch_handle(mock_image_ctx);
     EXPECT_CALL(acquire_request, send())
                   .WillOnce(FinishRequest(&acquire_request, r, &mock_image_ctx));
     if (r == 0) {
+      expect_notify_acquired_lock(mock_image_ctx);
       expect_unblock_writes(mock_image_ctx);
     }
   }
@@ -94,6 +102,10 @@ public:
     if (!shutting_down && r < 0) {
       expect_unblock_writes(mock_image_ctx);
     }
+    if (r == 0) {
+      expect_notify_released_lock(mock_image_ctx);
+      expect_writes_empty(mock_image_ctx);
+    }
   }
 
   void expect_notify_request_lock(MockImageCtx &mock_image_ctx,
@@ -103,6 +115,21 @@ public:
                                          &MockExclusiveLock::handle_lock_released));
   }
 
+  void expect_notify_acquired_lock(MockImageCtx &mock_image_ctx) {
+    EXPECT_CALL(*mock_image_ctx.image_watcher, notify_acquired_lock())
+                  .Times(1);
+  }
+
+  void expect_notify_released_lock(MockImageCtx &mock_image_ctx) {
+    EXPECT_CALL(*mock_image_ctx.image_watcher, notify_released_lock())
+                  .Times(1);
+  }
+
+  void expect_writes_empty(MockImageCtx &mock_image_ctx) {
+    EXPECT_CALL(*mock_image_ctx.aio_work_queue, writes_empty())
+                  .WillRepeatedly(Return(true));
+  }
+
   int when_init(MockImageCtx &mock_image_ctx,
                 MockExclusiveLock &exclusive_lock) {
     C_SaferCond ctx;
@@ -110,7 +137,6 @@ public:
       RWLock::WLocker owner_locker(mock_image_ctx.owner_lock);
       exclusive_lock.init(&ctx);
     }
-    exclusive_lock.set_watch_handle(123);
     return ctx.wait();
   }
 
@@ -127,7 +153,7 @@ public:
                      MockExclusiveLock &exclusive_lock) {
     C_SaferCond ctx;
     {
-      RWLock::WLocker owner_locker(mock_image_ctx.owner_lock);
+      RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
       exclusive_lock.request_lock(&ctx);
     }
     return ctx.wait();
@@ -188,6 +214,7 @@ TEST_F(TestMockExclusiveLock, StateTransitions) {
   ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock));
 
   MockReleaseRequest shutdown_release;
+  expect_op_work_queue(mock_image_ctx);
   expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
   ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
   ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
@@ -213,6 +240,7 @@ TEST_F(TestMockExclusiveLock, TryLockLockedState) {
   ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock));
 
   MockReleaseRequest shutdown_release;
+  expect_op_work_queue(mock_image_ctx);
   expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
   ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
 }
@@ -260,6 +288,7 @@ TEST_F(TestMockExclusiveLock, TryLockBusy) {
   ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
 
   expect_unblock_writes(mock_image_ctx);
+  expect_op_work_queue(mock_image_ctx);
   ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
 }
 
@@ -284,6 +313,7 @@ TEST_F(TestMockExclusiveLock, TryLockError) {
   ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
 
   expect_unblock_writes(mock_image_ctx);
+  expect_op_work_queue(mock_image_ctx);
   ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
 }
 
@@ -306,6 +336,7 @@ TEST_F(TestMockExclusiveLock, RequestLockLockedState) {
   ASSERT_EQ(0, when_try_lock(mock_image_ctx, exclusive_lock));
 
   MockReleaseRequest shutdown_release;
+  expect_op_work_queue(mock_image_ctx);
   expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
   ASSERT_EQ(0, when_request_lock(mock_image_ctx, exclusive_lock));
 
@@ -334,6 +365,7 @@ TEST_F(TestMockExclusiveLock, RequestLockBlacklist) {
   ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
 
   expect_unblock_writes(mock_image_ctx);
+  expect_op_work_queue(mock_image_ctx);
   ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
 }
 
@@ -362,6 +394,7 @@ TEST_F(TestMockExclusiveLock, RequestLockBusy) {
   ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock));
 
   MockReleaseRequest shutdown_release;
+  expect_op_work_queue(mock_image_ctx);
   expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
   ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
 }
@@ -391,6 +424,7 @@ TEST_F(TestMockExclusiveLock, RequestLockError) {
   ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock));
 
   MockReleaseRequest shutdown_release;
+  expect_op_work_queue(mock_image_ctx);
   expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
   ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
 }
@@ -412,6 +446,7 @@ TEST_F(TestMockExclusiveLock, ReleaseLockUnlockedState) {
   ASSERT_EQ(0, when_release_lock(mock_image_ctx, exclusive_lock));
 
   expect_unblock_writes(mock_image_ctx);
+  expect_op_work_queue(mock_image_ctx);
   ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
 }
 
@@ -440,6 +475,7 @@ TEST_F(TestMockExclusiveLock, ReleaseLockError) {
   ASSERT_TRUE(is_lock_owner(mock_image_ctx, exclusive_lock));
 
   MockReleaseRequest shutdown_release;
+  expect_op_work_queue(mock_image_ctx);
   expect_release_lock(mock_image_ctx, shutdown_release, 0, true);
   ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
   ASSERT_FALSE(is_lock_owner(mock_image_ctx, exclusive_lock));
@@ -461,6 +497,7 @@ TEST_F(TestMockExclusiveLock, ConcurrentRequests) {
 
   MockAcquireRequest try_lock_acquire;
   C_SaferCond wait_for_send_ctx1;
+  expect_get_watch_handle(mock_image_ctx);
   EXPECT_CALL(try_lock_acquire, send())
                 .WillOnce(Notify(&wait_for_send_ctx1));
 
@@ -472,6 +509,8 @@ TEST_F(TestMockExclusiveLock, ConcurrentRequests) {
   expect_block_writes(mock_image_ctx);
   EXPECT_CALL(release, send())
                 .WillOnce(Notify(&wait_for_send_ctx2));
+  expect_notify_released_lock(mock_image_ctx);
+  expect_writes_empty(mock_image_ctx);
 
   C_SaferCond try_request_ctx1;
   {
@@ -482,7 +521,7 @@ TEST_F(TestMockExclusiveLock, ConcurrentRequests) {
   C_SaferCond request_lock_ctx1;
   C_SaferCond request_lock_ctx2;
   {
-    RWLock::WLocker owner_locker(mock_image_ctx.owner_lock);
+    RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
     exclusive_lock.request_lock(&request_lock_ctx1);
     exclusive_lock.request_lock(&request_lock_ctx2);
   }
@@ -495,7 +534,7 @@ TEST_F(TestMockExclusiveLock, ConcurrentRequests) {
 
   C_SaferCond request_lock_ctx3;
   {
-    RWLock::WLocker owner_locker(mock_image_ctx.owner_lock);
+    RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
     exclusive_lock.request_lock(&request_lock_ctx3);
   }
 
@@ -515,6 +554,7 @@ TEST_F(TestMockExclusiveLock, ConcurrentRequests) {
   ASSERT_EQ(0, release_lock_ctx1.wait());
 
   expect_unblock_writes(mock_image_ctx);
+  expect_op_work_queue(mock_image_ctx);
   ASSERT_EQ(0, when_shut_down(mock_image_ctx, exclusive_lock));
 }