]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "test/librbd/test_mock_fixture.h" | |
5 | #include "test/librbd/test_support.h" | |
6 | #include "test/librbd/mock/MockImageCtx.h" | |
7 | #include "test/librbd/mock/MockJournal.h" | |
8 | #include "test/librbd/mock/MockJournalPolicy.h" | |
9 | #include "test/librbd/mock/MockObjectMap.h" | |
10 | #include "test/librados_test_stub/MockTestMemIoCtxImpl.h" | |
11 | #include "test/librados_test_stub/MockTestMemRadosClient.h" | |
12 | #include "librbd/ImageState.h" | |
13 | #include "librbd/internal.h" | |
14 | #include "librbd/Operations.h" | |
15 | #include "librbd/image/RefreshRequest.h" | |
16 | #include "librbd/image/RefreshParentRequest.h" | |
17 | #include "gmock/gmock.h" | |
18 | #include "gtest/gtest.h" | |
19 | #include <arpa/inet.h> | |
20 | #include <list> | |
21 | #include <boost/scope_exit.hpp> | |
22 | ||
23 | namespace librbd { | |
24 | ||
25 | namespace { | |
26 | ||
27 | struct MockRefreshImageCtx : public MockImageCtx { | |
28 | MockRefreshImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) { | |
29 | } | |
30 | }; | |
31 | ||
32 | } // anonymous namespace | |
33 | ||
34 | namespace image { | |
35 | ||
36 | template <> | |
37 | struct RefreshParentRequest<MockRefreshImageCtx> { | |
38 | static RefreshParentRequest* s_instance; | |
39 | static RefreshParentRequest* create(MockRefreshImageCtx &mock_image_ctx, | |
40 | const ParentInfo& parent_md, | |
41 | Context *on_finish) { | |
42 | assert(s_instance != nullptr); | |
43 | s_instance->on_finish = on_finish; | |
44 | return s_instance; | |
45 | } | |
46 | static bool is_refresh_required(MockRefreshImageCtx &mock_image_ctx, | |
47 | const ParentInfo& parent_md) { | |
48 | assert(s_instance != nullptr); | |
49 | return s_instance->is_refresh_required(); | |
50 | } | |
51 | ||
52 | Context *on_finish = nullptr; | |
53 | ||
54 | RefreshParentRequest() { | |
55 | s_instance = this; | |
56 | } | |
57 | ||
58 | MOCK_CONST_METHOD0(is_refresh_required, bool()); | |
59 | MOCK_METHOD0(send, void()); | |
60 | MOCK_METHOD0(apply, void()); | |
61 | MOCK_METHOD1(finalize, void(Context *)); | |
62 | }; | |
63 | ||
64 | RefreshParentRequest<MockRefreshImageCtx>* RefreshParentRequest<MockRefreshImageCtx>::s_instance = nullptr; | |
65 | ||
66 | } // namespace image | |
67 | } // namespace librbd | |
68 | ||
69 | // template definitions | |
70 | #include "librbd/image/RefreshRequest.cc" | |
71 | template class librbd::image::RefreshRequest<librbd::MockRefreshImageCtx>; | |
72 | ||
73 | ACTION_P(TestFeatures, image_ctx) { | |
74 | return ((image_ctx->features & arg0) != 0); | |
75 | } | |
76 | ||
77 | ACTION_P(ShutDownExclusiveLock, image_ctx) { | |
78 | // shutting down exclusive lock will close object map and journal | |
79 | image_ctx->exclusive_lock = nullptr; | |
80 | image_ctx->object_map = nullptr; | |
81 | image_ctx->journal = nullptr; | |
82 | } | |
83 | ||
84 | namespace librbd { | |
85 | namespace image { | |
86 | ||
87 | using ::testing::_; | |
88 | using ::testing::DoAll; | |
89 | using ::testing::DoDefault; | |
90 | using ::testing::InSequence; | |
91 | using ::testing::Return; | |
92 | using ::testing::WithArg; | |
93 | using ::testing::StrEq; | |
94 | ||
95 | class TestMockImageRefreshRequest : public TestMockFixture { | |
96 | public: | |
97 | typedef RefreshRequest<MockRefreshImageCtx> MockRefreshRequest; | |
98 | typedef RefreshParentRequest<MockRefreshImageCtx> MockRefreshParentRequest; | |
99 | ||
224ce89b WB |
100 | void expect_set_require_lock(MockRefreshImageCtx &mock_image_ctx, |
101 | librbd::io::Direction direction, bool enabled) { | |
102 | EXPECT_CALL(*mock_image_ctx.io_work_queue, set_require_lock(direction, | |
103 | enabled)); | |
7c673cae FG |
104 | } |
105 | ||
106 | void expect_v1_read_header(MockRefreshImageCtx &mock_image_ctx, int r) { | |
107 | auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
108 | read(mock_image_ctx.header_oid, _, _, _)); | |
109 | if (r < 0) { | |
110 | expect.WillOnce(Return(r)); | |
111 | } else { | |
112 | expect.WillOnce(DoDefault()); | |
113 | } | |
114 | } | |
115 | ||
116 | void expect_v1_get_snapshots(MockRefreshImageCtx &mock_image_ctx, int r) { | |
117 | auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
118 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("snap_list"), _, _, _)); | |
119 | if (r < 0) { | |
120 | expect.WillOnce(Return(r)); | |
121 | } else { | |
122 | expect.WillOnce(DoDefault()); | |
123 | } | |
124 | } | |
125 | ||
126 | void expect_v1_get_locks(MockRefreshImageCtx &mock_image_ctx, int r) { | |
127 | auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
128 | exec(mock_image_ctx.header_oid, _, StrEq("lock"), StrEq("get_info"), _, _, _)); | |
129 | if (r < 0) { | |
130 | expect.WillOnce(Return(r)); | |
131 | } else { | |
132 | expect.WillOnce(DoDefault()); | |
133 | } | |
134 | } | |
135 | ||
136 | void expect_get_mutable_metadata(MockRefreshImageCtx &mock_image_ctx, int r) { | |
137 | auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
138 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_size"), _, _, _)); | |
139 | if (r < 0) { | |
140 | expect.WillOnce(Return(r)); | |
141 | } else { | |
142 | expect.WillOnce(DoDefault()); | |
143 | EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
144 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_features"), _, _, _)) | |
145 | .WillOnce(DoDefault()); | |
146 | EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
147 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_snapcontext"), _, _, _)) | |
148 | .WillOnce(DoDefault()); | |
149 | EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
150 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_parent"), _, _, _)) | |
151 | .WillOnce(DoDefault()); | |
152 | EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
153 | exec(mock_image_ctx.header_oid, _, StrEq("lock"), StrEq("get_info"), _, _, _)) | |
154 | .WillOnce(DoDefault()); | |
155 | } | |
156 | } | |
157 | ||
b32b8144 FG |
158 | void expect_get_metadata(MockRefreshImageCtx &mock_image_ctx, int r) { |
159 | auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
160 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("metadata_list"), _, _, _)); | |
161 | if (r < 0) { | |
162 | expect.WillOnce(Return(r)); | |
163 | } else { | |
164 | expect.WillOnce(DoDefault()); | |
165 | } | |
166 | } | |
167 | ||
7c673cae FG |
168 | void expect_get_flags(MockRefreshImageCtx &mock_image_ctx, int r) { |
169 | auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
170 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_flags"), _, _, _)); | |
171 | if (r < 0) { | |
172 | expect.WillOnce(Return(r)); | |
173 | } else { | |
174 | expect.WillOnce(DoDefault()); | |
175 | } | |
176 | } | |
177 | ||
178 | void expect_get_group(MockRefreshImageCtx &mock_image_ctx, int r) { | |
179 | auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
180 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), | |
181 | StrEq("image_get_group"), _, _, _)); | |
182 | if (r < 0) { | |
183 | expect.WillOnce(Return(r)); | |
184 | } else { | |
185 | expect.WillOnce(DoDefault()); | |
186 | } | |
187 | } | |
188 | ||
189 | ||
190 | void expect_get_snapshots(MockRefreshImageCtx &mock_image_ctx, int r) { | |
191 | auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
192 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_snapshot_name"), _, _, _)); | |
193 | if (r < 0) { | |
194 | expect.WillOnce(Return(r)); | |
195 | } else { | |
196 | expect.WillOnce(DoDefault()); | |
197 | EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
198 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_size"), _, _, _)) | |
199 | .WillOnce(DoDefault()); | |
200 | EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
201 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_parent"), _, _, _)) | |
202 | .WillOnce(DoDefault()); | |
203 | EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
204 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_protection_status"), _, _, _)) | |
205 | .WillOnce(DoDefault()); | |
206 | } | |
207 | } | |
208 | ||
209 | void expect_snap_timestamp_list(MockRefreshImageCtx &mock_image_ctx, int r) { | |
210 | auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
211 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_snapshot_timestamp"), _, _, _)); | |
212 | if (r < 0) { | |
213 | expect.WillOnce(Return(r)); | |
214 | } else { | |
215 | expect.WillOnce(DoDefault()); | |
216 | } | |
217 | } | |
218 | ||
219 | void expect_snap_namespace_list(MockRefreshImageCtx &mock_image_ctx, int r) { | |
220 | auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), | |
221 | exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("get_snapshot_namespace"), _, _, _)); | |
222 | if (r < 0) { | |
223 | expect.WillOnce(Return(r)); | |
224 | } else { | |
225 | expect.WillOnce(DoDefault()); | |
226 | } | |
227 | } | |
228 | ||
b32b8144 FG |
229 | void expect_apply_metadata(MockRefreshImageCtx &mock_image_ctx, |
230 | int r) { | |
231 | EXPECT_CALL(mock_image_ctx, apply_metadata(_, false)) | |
232 | .WillOnce(Return(r)); | |
233 | } | |
234 | ||
7c673cae FG |
235 | void expect_add_snap(MockRefreshImageCtx &mock_image_ctx, |
236 | const std::string &snap_name, uint64_t snap_id) { | |
237 | EXPECT_CALL(mock_image_ctx, add_snap(_, snap_name, snap_id, _, _, _, _, _)); | |
238 | } | |
239 | ||
240 | void expect_init_exclusive_lock(MockRefreshImageCtx &mock_image_ctx, | |
241 | MockExclusiveLock &mock_exclusive_lock, | |
242 | int r) { | |
243 | EXPECT_CALL(mock_image_ctx, create_exclusive_lock()) | |
244 | .WillOnce(Return(&mock_exclusive_lock)); | |
245 | EXPECT_CALL(mock_exclusive_lock, init(mock_image_ctx.features, _)) | |
246 | .WillOnce(WithArg<1>(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue))); | |
247 | } | |
248 | ||
249 | void expect_shut_down_exclusive_lock(MockRefreshImageCtx &mock_image_ctx, | |
250 | MockExclusiveLock &mock_exclusive_lock, | |
251 | int r) { | |
252 | EXPECT_CALL(mock_exclusive_lock, shut_down(_)) | |
253 | .WillOnce(DoAll(ShutDownExclusiveLock(&mock_image_ctx), | |
254 | CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue))); | |
255 | } | |
256 | ||
257 | void expect_init_layout(MockRefreshImageCtx &mock_image_ctx) { | |
258 | EXPECT_CALL(mock_image_ctx, init_layout()); | |
259 | } | |
260 | ||
261 | void expect_test_features(MockRefreshImageCtx &mock_image_ctx) { | |
262 | EXPECT_CALL(mock_image_ctx, test_features(_, _)) | |
263 | .WillRepeatedly(TestFeatures(&mock_image_ctx)); | |
264 | } | |
265 | ||
266 | void expect_refresh_parent_is_required(MockRefreshParentRequest &mock_refresh_parent_request, | |
267 | bool required) { | |
268 | EXPECT_CALL(mock_refresh_parent_request, is_refresh_required()) | |
269 | .WillRepeatedly(Return(required)); | |
270 | } | |
271 | ||
272 | void expect_refresh_parent_send(MockRefreshImageCtx &mock_image_ctx, | |
273 | MockRefreshParentRequest &mock_refresh_parent_request, | |
274 | int r) { | |
275 | EXPECT_CALL(mock_refresh_parent_request, send()) | |
276 | .WillOnce(FinishRequest(&mock_refresh_parent_request, r, | |
277 | &mock_image_ctx)); | |
278 | } | |
279 | ||
280 | void expect_refresh_parent_apply(MockRefreshParentRequest &mock_refresh_parent_request) { | |
281 | EXPECT_CALL(mock_refresh_parent_request, apply()); | |
282 | } | |
283 | ||
284 | void expect_refresh_parent_finalize(MockRefreshImageCtx &mock_image_ctx, | |
285 | MockRefreshParentRequest &mock_refresh_parent_request, | |
286 | int r) { | |
287 | EXPECT_CALL(mock_refresh_parent_request, finalize(_)) | |
288 | .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); | |
289 | } | |
290 | ||
291 | void expect_is_exclusive_lock_owner(MockExclusiveLock &mock_exclusive_lock, | |
292 | bool is_owner) { | |
293 | EXPECT_CALL(mock_exclusive_lock, is_lock_owner()).WillOnce(Return(is_owner)); | |
294 | } | |
295 | ||
296 | void expect_get_journal_policy(MockImageCtx &mock_image_ctx, | |
297 | MockJournalPolicy &mock_journal_policy) { | |
298 | EXPECT_CALL(mock_image_ctx, get_journal_policy()) | |
299 | .WillOnce(Return(&mock_journal_policy)); | |
300 | } | |
301 | ||
302 | void expect_journal_disabled(MockJournalPolicy &mock_journal_policy, | |
303 | bool disabled) { | |
304 | EXPECT_CALL(mock_journal_policy, journal_disabled()) | |
305 | .WillOnce(Return(disabled)); | |
306 | } | |
307 | ||
308 | void expect_open_journal(MockRefreshImageCtx &mock_image_ctx, | |
309 | MockJournal &mock_journal, int r) { | |
310 | EXPECT_CALL(mock_image_ctx, create_journal()) | |
311 | .WillOnce(Return(&mock_journal)); | |
312 | EXPECT_CALL(mock_journal, open(_)) | |
313 | .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); | |
314 | } | |
315 | ||
316 | void expect_close_journal(MockRefreshImageCtx &mock_image_ctx, | |
317 | MockJournal &mock_journal, int r) { | |
318 | EXPECT_CALL(mock_journal, close(_)) | |
319 | .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); | |
320 | } | |
321 | ||
322 | void expect_open_object_map(MockRefreshImageCtx &mock_image_ctx, | |
323 | MockObjectMap *mock_object_map, int r) { | |
324 | EXPECT_CALL(mock_image_ctx, create_object_map(_)) | |
325 | .WillOnce(Return(mock_object_map)); | |
326 | EXPECT_CALL(*mock_object_map, open(_)) | |
327 | .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); | |
328 | } | |
329 | ||
330 | void expect_close_object_map(MockRefreshImageCtx &mock_image_ctx, | |
331 | MockObjectMap &mock_object_map, int r) { | |
332 | EXPECT_CALL(mock_object_map, close(_)) | |
333 | .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); | |
334 | } | |
335 | ||
336 | void expect_get_snap_id(MockRefreshImageCtx &mock_image_ctx, | |
337 | const std::string &snap_name, | |
338 | uint64_t snap_id) { | |
339 | EXPECT_CALL(mock_image_ctx, | |
340 | get_snap_id(_, snap_name)).WillOnce(Return(snap_id)); | |
341 | } | |
342 | ||
343 | void expect_block_writes(MockImageCtx &mock_image_ctx, int r) { | |
344 | EXPECT_CALL(*mock_image_ctx.io_work_queue, block_writes(_)) | |
345 | .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); | |
346 | } | |
347 | ||
348 | void expect_unblock_writes(MockImageCtx &mock_image_ctx) { | |
349 | EXPECT_CALL(*mock_image_ctx.io_work_queue, unblock_writes()) | |
350 | .Times(1); | |
351 | } | |
352 | ||
353 | }; | |
354 | ||
355 | TEST_F(TestMockImageRefreshRequest, SuccessV1) { | |
356 | REQUIRE_FORMAT_V1(); | |
357 | ||
358 | librbd::ImageCtx *ictx; | |
359 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
360 | ||
361 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
362 | expect_op_work_queue(mock_image_ctx); | |
363 | expect_test_features(mock_image_ctx); | |
364 | ||
365 | InSequence seq; | |
366 | expect_v1_read_header(mock_image_ctx, 0); | |
367 | expect_v1_get_snapshots(mock_image_ctx, 0); | |
368 | expect_v1_get_locks(mock_image_ctx, 0); | |
369 | expect_init_layout(mock_image_ctx); | |
370 | ||
371 | C_SaferCond ctx; | |
372 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
373 | req->send(); | |
374 | ||
375 | ASSERT_EQ(0, ctx.wait()); | |
376 | } | |
377 | ||
378 | TEST_F(TestMockImageRefreshRequest, SuccessSnapshotV1) { | |
379 | REQUIRE_FORMAT_V1(); | |
380 | librbd::ImageCtx *ictx; | |
381 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
382 | ASSERT_EQ(0, snap_create(*ictx, "snap")); | |
383 | ASSERT_EQ(0, ictx->state->refresh()); | |
384 | ||
385 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
386 | expect_op_work_queue(mock_image_ctx); | |
387 | expect_test_features(mock_image_ctx); | |
388 | ||
389 | InSequence seq; | |
390 | expect_v1_read_header(mock_image_ctx, 0); | |
391 | expect_v1_get_snapshots(mock_image_ctx, 0); | |
392 | expect_v1_get_locks(mock_image_ctx, 0); | |
393 | expect_init_layout(mock_image_ctx); | |
394 | expect_add_snap(mock_image_ctx, "snap", ictx->snap_ids.begin()->second); | |
395 | ||
396 | C_SaferCond ctx; | |
397 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
398 | req->send(); | |
399 | ||
400 | ASSERT_EQ(0, ctx.wait()); | |
401 | } | |
402 | ||
403 | TEST_F(TestMockImageRefreshRequest, SuccessV2) { | |
404 | REQUIRE_FORMAT_V2(); | |
405 | ||
406 | librbd::ImageCtx *ictx; | |
407 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
408 | ||
409 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
410 | MockRefreshParentRequest mock_refresh_parent_request; | |
411 | MockExclusiveLock mock_exclusive_lock; | |
412 | expect_op_work_queue(mock_image_ctx); | |
413 | expect_test_features(mock_image_ctx); | |
414 | ||
415 | InSequence seq; | |
416 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
417 | expect_get_metadata(mock_image_ctx, 0); |
418 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
419 | expect_get_flags(mock_image_ctx, 0); |
420 | expect_get_group(mock_image_ctx, 0); | |
421 | expect_refresh_parent_is_required(mock_refresh_parent_request, false); | |
422 | if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { | |
423 | expect_init_exclusive_lock(mock_image_ctx, mock_exclusive_lock, 0); | |
424 | } | |
425 | ||
426 | C_SaferCond ctx; | |
427 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
428 | req->send(); | |
429 | ||
430 | ASSERT_EQ(0, ctx.wait()); | |
431 | } | |
432 | ||
433 | TEST_F(TestMockImageRefreshRequest, SuccessSnapshotV2) { | |
434 | REQUIRE_FORMAT_V2(); | |
435 | ||
436 | librbd::ImageCtx *ictx; | |
437 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
438 | ASSERT_EQ(0, snap_create(*ictx, "snap")); | |
439 | ||
440 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
441 | MockRefreshParentRequest mock_refresh_parent_request; | |
442 | MockExclusiveLock mock_exclusive_lock; | |
443 | expect_op_work_queue(mock_image_ctx); | |
444 | expect_test_features(mock_image_ctx); | |
445 | ||
446 | InSequence seq; | |
447 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
448 | expect_get_metadata(mock_image_ctx, 0); |
449 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
450 | expect_get_flags(mock_image_ctx, 0); |
451 | expect_get_flags(mock_image_ctx, 0); | |
452 | expect_get_group(mock_image_ctx, 0); | |
453 | expect_get_snapshots(mock_image_ctx, 0); | |
454 | expect_snap_timestamp_list(mock_image_ctx, 0); | |
455 | expect_snap_namespace_list(mock_image_ctx, 0); | |
456 | expect_refresh_parent_is_required(mock_refresh_parent_request, false); | |
457 | if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { | |
458 | expect_init_exclusive_lock(mock_image_ctx, mock_exclusive_lock, 0); | |
459 | } | |
460 | expect_add_snap(mock_image_ctx, "snap", ictx->snap_ids.begin()->second); | |
461 | ||
462 | C_SaferCond ctx; | |
463 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
464 | req->send(); | |
465 | ||
466 | ASSERT_EQ(0, ctx.wait()); | |
467 | } | |
468 | ||
469 | TEST_F(TestMockImageRefreshRequest, SuccessSetSnapshotV2) { | |
470 | REQUIRE_FORMAT_V2(); | |
471 | ||
472 | librbd::ImageCtx *ictx; | |
473 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
474 | ASSERT_EQ(0, snap_create(*ictx, "snap")); | |
475 | ASSERT_EQ(0, librbd::snap_set(ictx, cls::rbd::UserSnapshotNamespace(), "snap")); | |
476 | ||
477 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
478 | MockRefreshParentRequest mock_refresh_parent_request; | |
479 | MockObjectMap mock_object_map; | |
480 | expect_op_work_queue(mock_image_ctx); | |
481 | expect_test_features(mock_image_ctx); | |
482 | ||
483 | InSequence seq; | |
484 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
485 | expect_get_metadata(mock_image_ctx, 0); |
486 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
487 | expect_get_flags(mock_image_ctx, 0); |
488 | expect_get_flags(mock_image_ctx, 0); | |
489 | expect_get_group(mock_image_ctx, 0); | |
490 | expect_get_snapshots(mock_image_ctx, 0); | |
491 | expect_snap_timestamp_list(mock_image_ctx, 0); | |
492 | expect_snap_namespace_list(mock_image_ctx, 0); | |
493 | expect_refresh_parent_is_required(mock_refresh_parent_request, false); | |
494 | if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) { | |
495 | expect_open_object_map(mock_image_ctx, &mock_object_map, 0); | |
496 | } | |
497 | expect_add_snap(mock_image_ctx, "snap", ictx->snap_ids.begin()->second); | |
498 | expect_get_snap_id(mock_image_ctx, "snap", ictx->snap_ids.begin()->second); | |
499 | ||
500 | C_SaferCond ctx; | |
501 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
502 | req->send(); | |
503 | ||
504 | ASSERT_EQ(0, ctx.wait()); | |
505 | } | |
506 | ||
507 | TEST_F(TestMockImageRefreshRequest, SuccessChild) { | |
508 | REQUIRE_FEATURE(RBD_FEATURE_LAYERING); | |
509 | ||
510 | librbd::ImageCtx *ictx; | |
511 | librbd::ImageCtx *ictx2 = nullptr; | |
512 | std::string clone_name = get_temp_image_name(); | |
513 | ||
514 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
515 | ASSERT_EQ(0, snap_create(*ictx, "snap")); | |
516 | ASSERT_EQ(0, snap_protect(*ictx, "snap")); | |
517 | BOOST_SCOPE_EXIT_ALL((&)) { | |
518 | if (ictx2 != nullptr) { | |
519 | close_image(ictx2); | |
520 | } | |
521 | ||
522 | librbd::NoOpProgressContext no_op; | |
523 | ASSERT_EQ(0, librbd::remove(m_ioctx, clone_name, "", no_op)); | |
524 | ASSERT_EQ(0, ictx->operations->snap_unprotect(cls::rbd::UserSnapshotNamespace(), "snap")); | |
525 | }; | |
526 | ||
527 | int order = ictx->order; | |
528 | ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap", m_ioctx, | |
529 | clone_name.c_str(), ictx->features, &order, 0, 0)); | |
530 | ||
531 | ASSERT_EQ(0, open_image(clone_name, &ictx2)); | |
532 | ||
533 | MockRefreshImageCtx mock_image_ctx(*ictx2); | |
534 | MockRefreshParentRequest *mock_refresh_parent_request = new MockRefreshParentRequest(); | |
535 | MockExclusiveLock mock_exclusive_lock; | |
536 | expect_op_work_queue(mock_image_ctx); | |
537 | expect_test_features(mock_image_ctx); | |
538 | ||
539 | InSequence seq; | |
540 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
541 | expect_get_metadata(mock_image_ctx, 0); |
542 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
543 | expect_get_flags(mock_image_ctx, 0); |
544 | expect_get_group(mock_image_ctx, 0); | |
545 | expect_refresh_parent_is_required(*mock_refresh_parent_request, true); | |
546 | expect_refresh_parent_send(mock_image_ctx, *mock_refresh_parent_request, 0); | |
547 | if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { | |
548 | expect_init_exclusive_lock(mock_image_ctx, mock_exclusive_lock, 0); | |
549 | } | |
550 | expect_refresh_parent_apply(*mock_refresh_parent_request); | |
551 | expect_refresh_parent_finalize(mock_image_ctx, *mock_refresh_parent_request, 0); | |
552 | ||
553 | C_SaferCond ctx; | |
554 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
555 | req->send(); | |
556 | ||
557 | ASSERT_EQ(0, ctx.wait()); | |
558 | } | |
559 | ||
560 | TEST_F(TestMockImageRefreshRequest, SuccessChildDontOpenParent) { | |
561 | REQUIRE_FEATURE(RBD_FEATURE_LAYERING); | |
562 | ||
563 | librbd::ImageCtx *ictx; | |
564 | librbd::ImageCtx *ictx2 = nullptr; | |
565 | std::string clone_name = get_temp_image_name(); | |
566 | ||
567 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
568 | ASSERT_EQ(0, snap_create(*ictx, "snap")); | |
569 | ASSERT_EQ(0, snap_protect(*ictx, "snap")); | |
570 | BOOST_SCOPE_EXIT_ALL((&)) { | |
571 | if (ictx2 != nullptr) { | |
572 | close_image(ictx2); | |
573 | } | |
574 | ||
575 | librbd::NoOpProgressContext no_op; | |
576 | ASSERT_EQ(0, librbd::remove(m_ioctx, clone_name, "", no_op)); | |
577 | ASSERT_EQ(0, ictx->operations->snap_unprotect(cls::rbd::UserSnapshotNamespace(), "snap")); | |
578 | }; | |
579 | ||
580 | int order = ictx->order; | |
581 | ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap", m_ioctx, | |
582 | clone_name.c_str(), ictx->features, &order, 0, 0)); | |
583 | ||
584 | ASSERT_EQ(0, open_image(clone_name, &ictx2)); | |
585 | ||
586 | MockRefreshImageCtx mock_image_ctx(*ictx2); | |
587 | MockExclusiveLock mock_exclusive_lock; | |
588 | expect_op_work_queue(mock_image_ctx); | |
589 | expect_test_features(mock_image_ctx); | |
590 | ||
591 | InSequence seq; | |
592 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
593 | expect_get_metadata(mock_image_ctx, 0); |
594 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
595 | expect_get_flags(mock_image_ctx, 0); |
596 | expect_get_group(mock_image_ctx, 0); | |
597 | if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { | |
598 | expect_init_exclusive_lock(mock_image_ctx, mock_exclusive_lock, 0); | |
599 | } | |
600 | ||
601 | C_SaferCond ctx; | |
602 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, true, &ctx); | |
603 | req->send(); | |
604 | ||
605 | ASSERT_EQ(0, ctx.wait()); | |
606 | } | |
607 | ||
608 | TEST_F(TestMockImageRefreshRequest, DisableExclusiveLock) { | |
609 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
610 | ||
611 | librbd::ImageCtx *ictx; | |
612 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
613 | ||
614 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
615 | MockRefreshParentRequest mock_refresh_parent_request; | |
616 | ||
617 | MockExclusiveLock *mock_exclusive_lock = new MockExclusiveLock(); | |
618 | mock_image_ctx.exclusive_lock = mock_exclusive_lock; | |
619 | ||
620 | MockObjectMap mock_object_map; | |
621 | if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) { | |
622 | mock_image_ctx.object_map = &mock_object_map; | |
623 | } | |
624 | ||
625 | MockJournal mock_journal; | |
626 | if (ictx->test_features(RBD_FEATURE_JOURNALING)) { | |
627 | mock_image_ctx.journal = &mock_journal; | |
628 | } | |
629 | ||
630 | if (ictx->test_features(RBD_FEATURE_JOURNALING)) { | |
631 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_JOURNALING, | |
632 | false)); | |
633 | } | |
634 | ||
635 | if (ictx->test_features(RBD_FEATURE_FAST_DIFF)) { | |
636 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_FAST_DIFF, | |
637 | false)); | |
638 | } | |
639 | ||
640 | if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) { | |
641 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_OBJECT_MAP, | |
642 | false)); | |
643 | } | |
644 | ||
645 | if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { | |
646 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_EXCLUSIVE_LOCK, | |
647 | false)); | |
648 | } | |
649 | ||
650 | expect_op_work_queue(mock_image_ctx); | |
651 | expect_test_features(mock_image_ctx); | |
652 | ||
653 | // verify that exclusive lock is properly handled when object map | |
654 | // and journaling were never enabled (or active) | |
655 | InSequence seq; | |
656 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
657 | expect_get_metadata(mock_image_ctx, 0); |
658 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
659 | expect_get_flags(mock_image_ctx, 0); |
660 | expect_get_group(mock_image_ctx, 0); | |
661 | expect_refresh_parent_is_required(mock_refresh_parent_request, false); | |
7c673cae FG |
662 | expect_shut_down_exclusive_lock(mock_image_ctx, *mock_exclusive_lock, 0); |
663 | ||
664 | C_SaferCond ctx; | |
665 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
666 | req->send(); | |
667 | ||
668 | ASSERT_EQ(0, ctx.wait()); | |
669 | } | |
670 | ||
671 | TEST_F(TestMockImageRefreshRequest, DisableExclusiveLockWhileAcquiringLock) { | |
672 | REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); | |
673 | ||
674 | librbd::ImageCtx *ictx; | |
675 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
676 | ||
677 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
678 | MockRefreshParentRequest mock_refresh_parent_request; | |
679 | ||
680 | MockExclusiveLock mock_exclusive_lock; | |
681 | mock_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
682 | ||
683 | if (ictx->test_features(RBD_FEATURE_JOURNALING)) { | |
684 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_JOURNALING, | |
685 | false)); | |
686 | } | |
687 | ||
688 | if (ictx->test_features(RBD_FEATURE_FAST_DIFF)) { | |
689 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_FAST_DIFF, | |
690 | false)); | |
691 | } | |
692 | ||
693 | if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) { | |
694 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_OBJECT_MAP, | |
695 | false)); | |
696 | } | |
697 | ||
698 | if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { | |
699 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_EXCLUSIVE_LOCK, | |
700 | false)); | |
701 | } | |
702 | ||
703 | expect_op_work_queue(mock_image_ctx); | |
704 | expect_test_features(mock_image_ctx); | |
705 | ||
706 | // verify that exclusive lock is properly handled when object map | |
707 | // and journaling were never enabled (or active) | |
708 | InSequence seq; | |
709 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
710 | expect_get_metadata(mock_image_ctx, 0); |
711 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
712 | expect_get_flags(mock_image_ctx, 0); |
713 | expect_get_group(mock_image_ctx, 0); | |
714 | expect_refresh_parent_is_required(mock_refresh_parent_request, false); | |
715 | ||
716 | C_SaferCond ctx; | |
717 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, true, false, &ctx); | |
718 | req->send(); | |
719 | ||
720 | ASSERT_EQ(-ERESTART, ctx.wait()); | |
721 | } | |
722 | ||
723 | TEST_F(TestMockImageRefreshRequest, JournalDisabledByPolicy) { | |
724 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
725 | ||
726 | librbd::ImageCtx *ictx; | |
727 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
728 | ||
729 | if (ictx->test_features(RBD_FEATURE_FAST_DIFF)) { | |
730 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_FAST_DIFF, | |
731 | false)); | |
732 | } | |
733 | ||
734 | if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) { | |
735 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_OBJECT_MAP, | |
736 | false)); | |
737 | } | |
738 | ||
739 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
740 | MockRefreshParentRequest mock_refresh_parent_request; | |
741 | ||
742 | MockExclusiveLock mock_exclusive_lock; | |
743 | mock_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
744 | ||
745 | MockJournal mock_journal; | |
746 | ||
747 | expect_op_work_queue(mock_image_ctx); | |
748 | expect_test_features(mock_image_ctx); | |
749 | expect_is_exclusive_lock_owner(mock_exclusive_lock, true); | |
750 | ||
751 | InSequence seq; | |
752 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
753 | expect_get_metadata(mock_image_ctx, 0); |
754 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
755 | expect_get_flags(mock_image_ctx, 0); |
756 | expect_get_group(mock_image_ctx, 0); | |
757 | expect_refresh_parent_is_required(mock_refresh_parent_request, false); | |
758 | ||
759 | MockJournalPolicy mock_journal_policy; | |
760 | expect_get_journal_policy(mock_image_ctx, mock_journal_policy); | |
761 | expect_journal_disabled(mock_journal_policy, true); | |
762 | ||
763 | C_SaferCond ctx; | |
764 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
765 | req->send(); | |
766 | ||
767 | ASSERT_EQ(0, ctx.wait()); | |
768 | } | |
769 | ||
7c673cae FG |
770 | TEST_F(TestMockImageRefreshRequest, EnableJournalWithExclusiveLock) { |
771 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
772 | ||
773 | librbd::ImageCtx *ictx; | |
774 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
775 | ||
776 | if (ictx->test_features(RBD_FEATURE_FAST_DIFF)) { | |
777 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_FAST_DIFF, | |
778 | false)); | |
779 | } | |
780 | ||
781 | if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) { | |
782 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_OBJECT_MAP, | |
783 | false)); | |
784 | } | |
785 | ||
786 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
787 | MockRefreshParentRequest mock_refresh_parent_request; | |
788 | ||
789 | MockExclusiveLock mock_exclusive_lock; | |
790 | mock_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
791 | ||
792 | MockJournal mock_journal; | |
793 | ||
794 | expect_op_work_queue(mock_image_ctx); | |
795 | expect_test_features(mock_image_ctx); | |
796 | expect_is_exclusive_lock_owner(mock_exclusive_lock, true); | |
797 | ||
798 | // journal should be immediately opened if exclusive lock owned | |
799 | InSequence seq; | |
800 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
801 | expect_get_metadata(mock_image_ctx, 0); |
802 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
803 | expect_get_flags(mock_image_ctx, 0); |
804 | expect_get_group(mock_image_ctx, 0); | |
805 | expect_refresh_parent_is_required(mock_refresh_parent_request, false); | |
806 | ||
807 | MockJournalPolicy mock_journal_policy; | |
808 | expect_get_journal_policy(mock_image_ctx, mock_journal_policy); | |
809 | expect_journal_disabled(mock_journal_policy, false); | |
810 | expect_open_journal(mock_image_ctx, mock_journal, 0); | |
811 | ||
812 | C_SaferCond ctx; | |
813 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
814 | req->send(); | |
815 | ||
816 | ASSERT_EQ(0, ctx.wait()); | |
817 | } | |
818 | ||
819 | TEST_F(TestMockImageRefreshRequest, EnableJournalWithoutExclusiveLock) { | |
820 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
821 | ||
822 | librbd::ImageCtx *ictx; | |
823 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
824 | ||
825 | if (ictx->test_features(RBD_FEATURE_FAST_DIFF)) { | |
826 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_FAST_DIFF, | |
827 | false)); | |
828 | } | |
829 | ||
830 | if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) { | |
831 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_OBJECT_MAP, | |
832 | false)); | |
833 | } | |
834 | ||
835 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
836 | MockRefreshParentRequest mock_refresh_parent_request; | |
837 | ||
838 | MockExclusiveLock mock_exclusive_lock; | |
839 | mock_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
840 | ||
841 | expect_op_work_queue(mock_image_ctx); | |
842 | expect_test_features(mock_image_ctx); | |
843 | expect_is_exclusive_lock_owner(mock_exclusive_lock, false); | |
844 | ||
845 | // do not open the journal if exclusive lock is not owned | |
846 | InSequence seq; | |
847 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
848 | expect_get_metadata(mock_image_ctx, 0); |
849 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
850 | expect_get_flags(mock_image_ctx, 0); |
851 | expect_get_group(mock_image_ctx, 0); | |
852 | expect_refresh_parent_is_required(mock_refresh_parent_request, false); | |
224ce89b | 853 | expect_set_require_lock(mock_image_ctx, librbd::io::DIRECTION_BOTH, true); |
7c673cae FG |
854 | |
855 | C_SaferCond ctx; | |
856 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
857 | req->send(); | |
858 | ||
859 | ASSERT_EQ(0, ctx.wait()); | |
860 | } | |
861 | ||
862 | TEST_F(TestMockImageRefreshRequest, DisableJournal) { | |
863 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
864 | ||
865 | librbd::ImageCtx *ictx; | |
866 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
867 | ||
868 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
869 | MockRefreshParentRequest mock_refresh_parent_request; | |
870 | ||
871 | MockExclusiveLock mock_exclusive_lock; | |
872 | mock_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
873 | ||
874 | MockObjectMap mock_object_map; | |
875 | if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) { | |
876 | mock_image_ctx.object_map = &mock_object_map; | |
877 | } | |
878 | ||
879 | MockJournal *mock_journal = new MockJournal(); | |
880 | mock_image_ctx.journal = mock_journal; | |
881 | ||
882 | if (ictx->test_features(RBD_FEATURE_JOURNALING)) { | |
883 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_JOURNALING, | |
884 | false)); | |
885 | } | |
886 | ||
887 | expect_op_work_queue(mock_image_ctx); | |
888 | expect_test_features(mock_image_ctx); | |
889 | ||
890 | // verify journal is closed if feature disabled | |
891 | InSequence seq; | |
892 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
893 | expect_get_metadata(mock_image_ctx, 0); |
894 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
895 | expect_get_flags(mock_image_ctx, 0); |
896 | expect_get_group(mock_image_ctx, 0); | |
897 | expect_refresh_parent_is_required(mock_refresh_parent_request, false); | |
898 | expect_block_writes(mock_image_ctx, 0); | |
224ce89b WB |
899 | if (!mock_image_ctx.clone_copy_on_read) { |
900 | expect_set_require_lock(mock_image_ctx, librbd::io::DIRECTION_READ, false); | |
901 | } | |
7c673cae FG |
902 | expect_close_journal(mock_image_ctx, *mock_journal, 0); |
903 | expect_unblock_writes(mock_image_ctx); | |
904 | ||
905 | C_SaferCond ctx; | |
906 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
907 | req->send(); | |
908 | ||
909 | ASSERT_EQ(0, ctx.wait()); | |
910 | } | |
911 | ||
912 | TEST_F(TestMockImageRefreshRequest, EnableObjectMapWithExclusiveLock) { | |
913 | REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); | |
914 | ||
915 | librbd::ImageCtx *ictx; | |
916 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
917 | ||
918 | if (ictx->test_features(RBD_FEATURE_JOURNALING)) { | |
919 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_JOURNALING, | |
920 | false)); | |
921 | } | |
922 | ||
923 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
924 | MockRefreshParentRequest mock_refresh_parent_request; | |
925 | ||
926 | MockExclusiveLock mock_exclusive_lock; | |
927 | mock_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
928 | ||
929 | MockObjectMap mock_object_map; | |
930 | ||
931 | expect_op_work_queue(mock_image_ctx); | |
932 | expect_test_features(mock_image_ctx); | |
933 | expect_is_exclusive_lock_owner(mock_exclusive_lock, true); | |
934 | ||
935 | // object map should be immediately opened if exclusive lock owned | |
936 | InSequence seq; | |
937 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
938 | expect_get_metadata(mock_image_ctx, 0); |
939 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
940 | expect_get_flags(mock_image_ctx, 0); |
941 | expect_get_group(mock_image_ctx, 0); | |
942 | expect_refresh_parent_is_required(mock_refresh_parent_request, false); | |
943 | expect_open_object_map(mock_image_ctx, &mock_object_map, 0); | |
944 | ||
945 | C_SaferCond ctx; | |
946 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
947 | req->send(); | |
948 | ||
949 | ASSERT_EQ(0, ctx.wait()); | |
950 | } | |
951 | ||
952 | TEST_F(TestMockImageRefreshRequest, EnableObjectMapWithoutExclusiveLock) { | |
953 | REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); | |
954 | ||
955 | librbd::ImageCtx *ictx; | |
956 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
957 | ||
958 | if (ictx->test_features(RBD_FEATURE_JOURNALING)) { | |
959 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_JOURNALING, | |
960 | false)); | |
961 | } | |
962 | ||
963 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
964 | MockRefreshParentRequest mock_refresh_parent_request; | |
965 | ||
966 | MockExclusiveLock mock_exclusive_lock; | |
967 | mock_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
968 | ||
969 | expect_op_work_queue(mock_image_ctx); | |
970 | expect_test_features(mock_image_ctx); | |
971 | expect_is_exclusive_lock_owner(mock_exclusive_lock, false); | |
972 | ||
973 | // do not open the object map if exclusive lock is not owned | |
974 | InSequence seq; | |
975 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
976 | expect_get_metadata(mock_image_ctx, 0); |
977 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
978 | expect_get_flags(mock_image_ctx, 0); |
979 | expect_get_group(mock_image_ctx, 0); | |
980 | expect_refresh_parent_is_required(mock_refresh_parent_request, false); | |
981 | ||
982 | C_SaferCond ctx; | |
983 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
984 | req->send(); | |
985 | ||
986 | ASSERT_EQ(0, ctx.wait()); | |
987 | } | |
988 | ||
989 | TEST_F(TestMockImageRefreshRequest, DisableObjectMap) { | |
990 | REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); | |
991 | ||
992 | librbd::ImageCtx *ictx; | |
993 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
994 | ||
995 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
996 | MockRefreshParentRequest mock_refresh_parent_request; | |
997 | ||
998 | MockExclusiveLock mock_exclusive_lock; | |
999 | mock_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
1000 | ||
1001 | MockObjectMap *mock_object_map = new MockObjectMap(); | |
1002 | mock_image_ctx.object_map = mock_object_map; | |
1003 | ||
1004 | MockJournal mock_journal; | |
1005 | if (ictx->test_features(RBD_FEATURE_JOURNALING)) { | |
1006 | mock_image_ctx.journal = &mock_journal; | |
1007 | } | |
1008 | ||
1009 | if (ictx->test_features(RBD_FEATURE_FAST_DIFF)) { | |
1010 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_FAST_DIFF, | |
1011 | false)); | |
1012 | } | |
1013 | ||
1014 | if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) { | |
1015 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_OBJECT_MAP, | |
1016 | false)); | |
1017 | } | |
1018 | ||
1019 | expect_op_work_queue(mock_image_ctx); | |
1020 | expect_test_features(mock_image_ctx); | |
1021 | ||
1022 | // verify object map is closed if feature disabled | |
1023 | InSequence seq; | |
1024 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
1025 | expect_get_metadata(mock_image_ctx, 0); |
1026 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
1027 | expect_get_flags(mock_image_ctx, 0); |
1028 | expect_get_group(mock_image_ctx, 0); | |
1029 | expect_refresh_parent_is_required(mock_refresh_parent_request, false); | |
1030 | expect_close_object_map(mock_image_ctx, *mock_object_map, 0); | |
1031 | ||
1032 | C_SaferCond ctx; | |
1033 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
1034 | req->send(); | |
1035 | ||
1036 | ASSERT_EQ(0, ctx.wait()); | |
1037 | } | |
1038 | ||
1039 | TEST_F(TestMockImageRefreshRequest, OpenObjectMapError) { | |
1040 | REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); | |
1041 | ||
1042 | librbd::ImageCtx *ictx; | |
1043 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1044 | ||
1045 | if (ictx->test_features(RBD_FEATURE_JOURNALING)) { | |
1046 | ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_JOURNALING, | |
1047 | false)); | |
1048 | } | |
1049 | ||
1050 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
1051 | MockRefreshParentRequest mock_refresh_parent_request; | |
1052 | ||
1053 | MockExclusiveLock mock_exclusive_lock; | |
1054 | mock_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
1055 | ||
1056 | MockObjectMap *mock_object_map = new MockObjectMap(); | |
1057 | ||
1058 | expect_op_work_queue(mock_image_ctx); | |
1059 | expect_test_features(mock_image_ctx); | |
1060 | expect_is_exclusive_lock_owner(mock_exclusive_lock, true); | |
1061 | ||
1062 | // object map should be immediately opened if exclusive lock owned | |
1063 | InSequence seq; | |
1064 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
b32b8144 FG |
1065 | expect_get_metadata(mock_image_ctx, 0); |
1066 | expect_apply_metadata(mock_image_ctx, 0); | |
7c673cae FG |
1067 | expect_get_flags(mock_image_ctx, 0); |
1068 | expect_get_group(mock_image_ctx, 0); | |
1069 | expect_refresh_parent_is_required(mock_refresh_parent_request, false); | |
1070 | expect_open_object_map(mock_image_ctx, mock_object_map, -EFBIG); | |
1071 | ||
1072 | C_SaferCond ctx; | |
1073 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
1074 | req->send(); | |
1075 | ||
1076 | ASSERT_EQ(0, ctx.wait()); | |
1077 | ASSERT_EQ(nullptr, mock_image_ctx.object_map); | |
1078 | } | |
1079 | ||
b32b8144 FG |
1080 | TEST_F(TestMockImageRefreshRequest, ApplyMetadataError) { |
1081 | REQUIRE_FORMAT_V2(); | |
1082 | ||
1083 | librbd::ImageCtx *ictx; | |
1084 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1085 | ||
1086 | MockRefreshImageCtx mock_image_ctx(*ictx); | |
1087 | MockRefreshParentRequest mock_refresh_parent_request; | |
1088 | MockExclusiveLock mock_exclusive_lock; | |
1089 | expect_op_work_queue(mock_image_ctx); | |
1090 | expect_test_features(mock_image_ctx); | |
1091 | ||
1092 | InSequence seq; | |
1093 | expect_get_mutable_metadata(mock_image_ctx, 0); | |
1094 | expect_get_metadata(mock_image_ctx, 0); | |
1095 | expect_apply_metadata(mock_image_ctx, -EINVAL); | |
1096 | expect_get_flags(mock_image_ctx, 0); | |
1097 | expect_get_group(mock_image_ctx, 0); | |
1098 | expect_refresh_parent_is_required(mock_refresh_parent_request, false); | |
1099 | if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) { | |
1100 | expect_init_exclusive_lock(mock_image_ctx, mock_exclusive_lock, 0); | |
1101 | } | |
1102 | ||
1103 | C_SaferCond ctx; | |
1104 | MockRefreshRequest *req = new MockRefreshRequest(mock_image_ctx, false, false, &ctx); | |
1105 | req->send(); | |
1106 | ||
1107 | ASSERT_EQ(0, ctx.wait()); | |
1108 | } | |
1109 | ||
7c673cae FG |
1110 | } // namespace image |
1111 | } // namespace librbd |