1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "test/librbd/test_mock_fixture.h"
5 #include "test/librbd/test_support.h"
6 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
7 #include "common/bit_vector.hpp"
8 #include "librbd/ImageState.h"
9 #include "librbd/internal.h"
10 #include "librbd/ObjectMap.h"
11 #include "librbd/object_map/SnapshotRemoveRequest.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
16 namespace object_map
{
19 using ::testing::DoDefault
;
20 using ::testing::Return
;
21 using ::testing::StrEq
;
23 class TestMockObjectMapSnapshotRemoveRequest
: public TestMockFixture
{
25 void expect_load_map(librbd::ImageCtx
*ictx
, uint64_t snap_id
, int r
) {
26 std::string
snap_oid(ObjectMap
<>::object_map_name(ictx
->id
, snap_id
));
28 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
29 exec(snap_oid
, _
, StrEq("rbd"), StrEq("object_map_load"), _
, _
, _
))
32 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
33 exec(snap_oid
, _
, StrEq("rbd"), StrEq("object_map_load"), _
, _
, _
))
34 .WillOnce(DoDefault());
38 void expect_remove_snapshot(librbd::ImageCtx
*ictx
, int r
) {
39 std::string
oid(ObjectMap
<>::object_map_name(ictx
->id
, CEPH_NOSNAP
));
41 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
42 exec(oid
, _
, StrEq("lock"), StrEq("assert_locked"), _
, _
, _
))
45 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
46 exec(oid
, _
, StrEq("lock"), StrEq("assert_locked"), _
, _
, _
))
47 .WillOnce(DoDefault());
48 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
49 exec(oid
, _
, StrEq("rbd"), StrEq("object_map_snap_remove"), _
, _
, _
))
50 .WillOnce(DoDefault());
54 void expect_remove_map(librbd::ImageCtx
*ictx
, uint64_t snap_id
, int r
) {
55 std::string
snap_oid(ObjectMap
<>::object_map_name(ictx
->id
, snap_id
));
57 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
), remove(snap_oid
, _
))
60 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
), remove(snap_oid
, _
))
61 .WillOnce(DoDefault());
65 void expect_invalidate(librbd::ImageCtx
*ictx
) {
66 EXPECT_CALL(get_mock_io_ctx(ictx
->md_ctx
),
67 exec(ictx
->header_oid
, _
, StrEq("rbd"), StrEq("set_flags"), _
, _
, _
))
68 .WillOnce(DoDefault());
72 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, Success
) {
73 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
75 librbd::ImageCtx
*ictx
;
76 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
77 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
78 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
80 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
81 if (ictx
->test_features(RBD_FEATURE_FAST_DIFF
)) {
82 expect_load_map(ictx
, snap_id
, 0);
83 expect_remove_snapshot(ictx
, 0);
85 expect_remove_map(ictx
, snap_id
, 0);
87 ceph::BitVector
<2> object_map
;
89 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
90 *ictx
, &object_map
, snap_id
, &cond_ctx
);
92 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
93 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
96 ASSERT_EQ(0, cond_ctx
.wait());
98 expect_unlock_exclusive_lock(*ictx
);
101 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, LoadMapMissing
) {
102 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
104 librbd::ImageCtx
*ictx
;
105 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
106 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
107 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
109 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
110 auto snap_it
= ictx
->snap_info
.find(snap_id
);
111 ASSERT_NE(ictx
->snap_info
.end(), snap_it
);
112 snap_it
->second
.flags
|= RBD_FLAG_OBJECT_MAP_INVALID
;
114 expect_load_map(ictx
, snap_id
, -ENOENT
);
116 ceph::BitVector
<2> object_map
;
117 C_SaferCond cond_ctx
;
118 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
119 *ictx
, &object_map
, snap_id
, &cond_ctx
);
121 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
122 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
125 ASSERT_EQ(0, cond_ctx
.wait());
128 // shouldn't invalidate the HEAD revision when we fail to load
129 // the already deleted snapshot
130 RWLock::RLocker
snap_locker(ictx
->snap_lock
);
132 ASSERT_EQ(0, ictx
->get_flags(CEPH_NOSNAP
, &flags
));
133 ASSERT_EQ(0U, flags
& RBD_FLAG_OBJECT_MAP_INVALID
);
136 expect_unlock_exclusive_lock(*ictx
);
139 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, LoadMapError
) {
140 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
142 librbd::ImageCtx
*ictx
;
143 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
144 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
145 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
147 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
148 expect_load_map(ictx
, snap_id
, -EINVAL
);
149 expect_invalidate(ictx
);
150 expect_remove_map(ictx
, snap_id
, 0);
152 ceph::BitVector
<2> object_map
;
153 C_SaferCond cond_ctx
;
154 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
155 *ictx
, &object_map
, snap_id
, &cond_ctx
);
157 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
158 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
161 ASSERT_EQ(0, cond_ctx
.wait());
163 expect_unlock_exclusive_lock(*ictx
);
166 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, RemoveSnapshotMissing
) {
167 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
169 librbd::ImageCtx
*ictx
;
170 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
171 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
172 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
174 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
175 expect_load_map(ictx
, snap_id
, 0);
176 expect_remove_snapshot(ictx
, -ENOENT
);
177 expect_remove_map(ictx
, snap_id
, 0);
179 ceph::BitVector
<2> object_map
;
180 C_SaferCond cond_ctx
;
181 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
182 *ictx
, &object_map
, snap_id
, &cond_ctx
);
184 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
185 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
188 ASSERT_EQ(0, cond_ctx
.wait());
190 expect_unlock_exclusive_lock(*ictx
);
193 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, RemoveSnapshotError
) {
194 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
196 librbd::ImageCtx
*ictx
;
197 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
198 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
199 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
201 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
202 expect_load_map(ictx
, snap_id
, 0);
203 expect_remove_snapshot(ictx
, -EINVAL
);
204 expect_invalidate(ictx
);
205 expect_remove_map(ictx
, snap_id
, 0);
207 ceph::BitVector
<2> object_map
;
208 C_SaferCond cond_ctx
;
209 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
210 *ictx
, &object_map
, snap_id
, &cond_ctx
);
212 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
213 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
216 ASSERT_EQ(0, cond_ctx
.wait());
218 expect_unlock_exclusive_lock(*ictx
);
221 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, RemoveMapMissing
) {
222 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
224 librbd::ImageCtx
*ictx
;
225 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
226 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
227 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
229 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
230 if (ictx
->test_features(RBD_FEATURE_FAST_DIFF
)) {
231 expect_load_map(ictx
, snap_id
, 0);
232 expect_remove_snapshot(ictx
, 0);
234 expect_remove_map(ictx
, snap_id
, -ENOENT
);
236 ceph::BitVector
<2> object_map
;
237 C_SaferCond cond_ctx
;
238 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
239 *ictx
, &object_map
, snap_id
, &cond_ctx
);
241 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
242 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
245 ASSERT_EQ(0, cond_ctx
.wait());
247 expect_unlock_exclusive_lock(*ictx
);
250 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, RemoveMapError
) {
251 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
253 librbd::ImageCtx
*ictx
;
254 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
255 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
256 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
258 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
259 if (ictx
->test_features(RBD_FEATURE_FAST_DIFF
)) {
260 expect_load_map(ictx
, snap_id
, 0);
261 expect_remove_snapshot(ictx
, 0);
263 expect_remove_map(ictx
, snap_id
, -EINVAL
);
265 ceph::BitVector
<2> object_map
;
266 C_SaferCond cond_ctx
;
267 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
268 *ictx
, &object_map
, snap_id
, &cond_ctx
);
270 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
271 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
274 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
276 expect_unlock_exclusive_lock(*ictx
);
279 TEST_F(TestMockObjectMapSnapshotRemoveRequest
, ScrubCleanObjects
) {
280 REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF
);
282 librbd::ImageCtx
*ictx
;
283 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
284 librbd::NoOpProgressContext prog_ctx
;
285 uint64_t size
= 4294967296; // 4GB = 1024 * 4MB
286 ASSERT_EQ(0, resize(ictx
, size
));
288 // update image objectmap for snap inherit
289 ceph::BitVector
<2> object_map
;
290 object_map
.resize(1024);
291 for (uint64_t i
= 512; i
< object_map
.size(); ++i
) {
292 object_map
[i
] = i
% 2 == 0 ? OBJECT_EXISTS
: OBJECT_NONEXISTENT
;
295 C_SaferCond cond_ctx1
;
297 librbd::ObjectMap
<ImageCtx
> om(*ictx
, ictx
->snap_id
);
298 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
299 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
300 om
.set_object_map(object_map
);
301 om
.aio_save(&cond_ctx1
);
303 ASSERT_EQ(0, cond_ctx1
.wait());
304 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
305 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
307 // simutate the image objectmap state after creating snap
308 for (uint64_t i
= 512; i
< object_map
.size(); ++i
) {
309 object_map
[i
] = i
% 2 == 0 ? OBJECT_EXISTS_CLEAN
: OBJECT_NONEXISTENT
;
312 C_SaferCond cond_ctx2
;
313 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
314 AsyncRequest
<> *request
= new SnapshotRemoveRequest(
315 *ictx
, &object_map
, snap_id
, &cond_ctx2
);
317 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
318 RWLock::WLocker
snap_locker(ictx
->snap_lock
);
321 ASSERT_EQ(0, cond_ctx2
.wait());
323 for (uint64_t i
= 512; i
< object_map
.size(); ++i
) {
324 ASSERT_EQ(i
% 2 == 0 ? OBJECT_EXISTS
: OBJECT_NONEXISTENT
,
329 } // namespace object_map
330 } // namespace librbd