]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
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 "include/interval_set.h" | |
f67539c2 | 6 | #include "include/neorados/RADOS.hpp" |
11fdf7f2 TL |
7 | #include "include/rbd/librbd.hpp" |
8 | #include "include/rbd/object_map_types.h" | |
f67539c2 | 9 | #include "librbd/AsioEngine.h" |
11fdf7f2 TL |
10 | #include "librbd/ImageCtx.h" |
11 | #include "librbd/ImageState.h" | |
12 | #include "librbd/internal.h" | |
13 | #include "librbd/Operations.h" | |
14 | #include "librbd/api/Image.h" | |
f67539c2 | 15 | #include "librbd/api/Io.h" |
11fdf7f2 | 16 | #include "librbd/deep_copy/ObjectCopyRequest.h" |
cd265ab1 | 17 | #include "librbd/deep_copy/Utils.h" |
11fdf7f2 | 18 | #include "librbd/io/ReadResult.h" |
f67539c2 | 19 | #include "librbd/io/Utils.h" |
11fdf7f2 TL |
20 | #include "test/librados_test_stub/MockTestMemIoCtxImpl.h" |
21 | #include "test/librbd/mock/MockImageCtx.h" | |
22 | #include "test/librbd/test_support.h" | |
23 | ||
24 | namespace librbd { | |
25 | namespace { | |
26 | ||
27 | struct MockTestImageCtx : public librbd::MockImageCtx { | |
28 | explicit MockTestImageCtx(librbd::ImageCtx &image_ctx) | |
29 | : librbd::MockImageCtx(image_ctx) { | |
30 | } | |
31 | ||
32 | MockTestImageCtx *parent = nullptr; | |
33 | }; | |
34 | ||
35 | } // anonymous namespace | |
36 | ||
37 | namespace util { | |
38 | ||
39 | inline ImageCtx* get_image_ctx(MockTestImageCtx* image_ctx) { | |
40 | return image_ctx->image_ctx; | |
41 | } | |
42 | ||
43 | } // namespace util | |
44 | ||
45 | namespace io { | |
f67539c2 | 46 | namespace util { |
11fdf7f2 | 47 | |
1e59de90 TL |
48 | template <> |
49 | void area_to_object_extents(MockTestImageCtx* image_ctx, uint64_t offset, | |
50 | uint64_t length, ImageArea area, | |
51 | uint64_t buffer_offset, | |
52 | striper::LightweightObjectExtents* object_extents) { | |
f67539c2 TL |
53 | Striper::file_to_extents(image_ctx->cct, &image_ctx->layout, offset, length, |
54 | 0, buffer_offset, object_extents); | |
55 | } | |
11fdf7f2 | 56 | |
1e59de90 TL |
57 | template <> |
58 | std::pair<Extents, ImageArea> object_to_area_extents( | |
59 | MockTestImageCtx* image_ctx, uint64_t object_no, | |
60 | const Extents& object_extents) { | |
61 | Extents extents; | |
62 | for (auto [off, len] : object_extents) { | |
63 | Striper::extent_to_file(image_ctx->cct, &image_ctx->layout, object_no, off, | |
64 | len, extents); | |
65 | } | |
66 | return {std::move(extents), ImageArea::DATA}; | |
f67539c2 | 67 | } |
11fdf7f2 | 68 | |
f67539c2 | 69 | } // namespace util |
11fdf7f2 TL |
70 | } // namespace io |
71 | ||
72 | } // namespace librbd | |
73 | ||
74 | // template definitions | |
75 | #include "librbd/deep_copy/ObjectCopyRequest.cc" | |
76 | template class librbd::deep_copy::ObjectCopyRequest<librbd::MockTestImageCtx>; | |
77 | ||
81eedcae | 78 | static bool operator==(const SnapContext& rhs, const SnapContext& lhs) { |
11fdf7f2 TL |
79 | return (rhs.seq == lhs.seq && rhs.snaps == lhs.snaps); |
80 | } | |
81 | ||
82 | namespace librbd { | |
83 | namespace deep_copy { | |
84 | ||
85 | using ::testing::_; | |
86 | using ::testing::DoAll; | |
87 | using ::testing::DoDefault; | |
88 | using ::testing::InSequence; | |
89 | using ::testing::Invoke; | |
90 | using ::testing::Return; | |
91 | using ::testing::ReturnNew; | |
92 | using ::testing::WithArg; | |
93 | ||
94 | namespace { | |
95 | ||
96 | void scribble(librbd::ImageCtx *image_ctx, int num_ops, size_t max_size, | |
97 | interval_set<uint64_t> *what) | |
98 | { | |
99 | uint64_t object_size = 1 << image_ctx->order; | |
100 | for (int i = 0; i < num_ops; i++) { | |
101 | uint64_t off = rand() % (object_size - max_size + 1); | |
102 | uint64_t len = 1 + rand() % max_size; | |
103 | std::cout << __func__ << ": off=" << off << ", len=" << len << std::endl; | |
104 | ||
105 | bufferlist bl; | |
106 | bl.append(std::string(len, '1')); | |
107 | ||
f67539c2 | 108 | int r = api::Io<>::write(*image_ctx, off, len, std::move(bl), 0); |
11fdf7f2 TL |
109 | ASSERT_EQ(static_cast<int>(len), r); |
110 | ||
111 | interval_set<uint64_t> w; | |
112 | w.insert(off, len); | |
113 | what->union_of(w); | |
114 | } | |
115 | std::cout << " wrote " << *what << std::endl; | |
116 | } | |
117 | ||
118 | } // anonymous namespace | |
119 | ||
f67539c2 TL |
120 | |
121 | MATCHER(IsListSnaps, "") { | |
122 | auto req = boost::get<io::ImageDispatchSpec::ListSnaps>(&arg->request); | |
123 | return (req != nullptr); | |
124 | } | |
125 | ||
126 | MATCHER_P2(IsRead, snap_id, image_interval, "") { | |
127 | auto req = boost::get<io::ImageDispatchSpec::Read>(&arg->request); | |
128 | if (req == nullptr || | |
129 | arg->io_context->read_snap().value_or(CEPH_NOSNAP) != snap_id) { | |
130 | return false; | |
131 | } | |
132 | ||
133 | // ensure the read request encloses the full snapshot delta | |
134 | interval_set<uint64_t> expected_interval(image_interval); | |
135 | interval_set<uint64_t> read_interval; | |
136 | for (auto &image_extent : arg->image_extents) { | |
137 | read_interval.insert(image_extent.first, image_extent.second); | |
138 | } | |
139 | ||
140 | interval_set<uint64_t> intersection; | |
141 | intersection.intersection_of(expected_interval, read_interval); | |
142 | expected_interval.subtract(intersection); | |
143 | return expected_interval.empty(); | |
144 | } | |
145 | ||
11fdf7f2 TL |
146 | class TestMockDeepCopyObjectCopyRequest : public TestMockFixture { |
147 | public: | |
148 | typedef ObjectCopyRequest<librbd::MockTestImageCtx> MockObjectCopyRequest; | |
149 | ||
150 | librbd::ImageCtx *m_src_image_ctx; | |
151 | librbd::ImageCtx *m_dst_image_ctx; | |
f67539c2 TL |
152 | |
153 | std::shared_ptr<librbd::AsioEngine> m_asio_engine; | |
154 | asio::ContextWQ *m_work_queue; | |
11fdf7f2 TL |
155 | |
156 | SnapMap m_snap_map; | |
cd265ab1 | 157 | SnapSeqs m_snap_seqs; |
11fdf7f2 TL |
158 | std::vector<librados::snap_t> m_src_snap_ids; |
159 | std::vector<librados::snap_t> m_dst_snap_ids; | |
160 | ||
161 | void SetUp() override { | |
162 | TestMockFixture::SetUp(); | |
163 | ||
164 | ASSERT_EQ(0, open_image(m_image_name, &m_src_image_ctx)); | |
165 | ||
166 | librbd::NoOpProgressContext no_op; | |
167 | m_image_size = 1 << m_src_image_ctx->order; | |
168 | ASSERT_EQ(0, m_src_image_ctx->operations->resize(m_image_size, true, no_op)); | |
169 | ||
170 | librbd::RBD rbd; | |
171 | std::string dst_image_name = get_temp_image_name(); | |
172 | ASSERT_EQ(0, create_image_pp(rbd, m_ioctx, dst_image_name, m_image_size)); | |
173 | ASSERT_EQ(0, open_image(dst_image_name, &m_dst_image_ctx)); | |
174 | ||
f67539c2 TL |
175 | m_asio_engine = std::make_shared<librbd::AsioEngine>( |
176 | m_src_image_ctx->md_ctx); | |
177 | m_work_queue = m_asio_engine->get_work_queue(); | |
11fdf7f2 TL |
178 | } |
179 | ||
180 | bool is_fast_diff(librbd::MockImageCtx &mock_image_ctx) { | |
181 | return (mock_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0; | |
182 | } | |
183 | ||
184 | void prepare_exclusive_lock(librbd::MockImageCtx &mock_image_ctx, | |
185 | librbd::MockExclusiveLock &mock_exclusive_lock) { | |
186 | if ((mock_image_ctx.features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) { | |
187 | return; | |
188 | } | |
189 | mock_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
190 | } | |
191 | ||
192 | void expect_get_object_count(librbd::MockImageCtx& mock_image_ctx) { | |
193 | EXPECT_CALL(mock_image_ctx, get_object_count(_)) | |
194 | .WillRepeatedly(Invoke([&mock_image_ctx](librados::snap_t snap_id) { | |
195 | return mock_image_ctx.image_ctx->get_object_count(snap_id); | |
196 | })); | |
197 | } | |
198 | ||
199 | void expect_test_features(librbd::MockImageCtx &mock_image_ctx) { | |
200 | EXPECT_CALL(mock_image_ctx, test_features(_)) | |
201 | .WillRepeatedly(WithArg<0>(Invoke([&mock_image_ctx](uint64_t features) { | |
202 | return (mock_image_ctx.features & features) != 0; | |
203 | }))); | |
204 | } | |
205 | ||
206 | void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) { | |
207 | if ((m_src_image_ctx->features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) { | |
208 | return; | |
209 | } | |
9f95a23c | 210 | EXPECT_CALL(mock_exclusive_lock, start_op(_)).WillOnce(Return(new LambdaContext([](int){}))); |
11fdf7f2 TL |
211 | } |
212 | ||
f67539c2 TL |
213 | void expect_list_snaps(librbd::MockTestImageCtx &mock_image_ctx, int r) { |
214 | EXPECT_CALL(*mock_image_ctx.io_image_dispatcher, send(IsListSnaps())) | |
215 | .WillOnce(Invoke( | |
216 | [&mock_image_ctx, r](io::ImageDispatchSpec* spec) { | |
217 | if (r < 0) { | |
218 | spec->fail(r); | |
219 | return; | |
220 | } | |
221 | ||
222 | spec->image_dispatcher = | |
223 | mock_image_ctx.image_ctx->io_image_dispatcher; | |
224 | mock_image_ctx.image_ctx->io_image_dispatcher->send(spec); | |
225 | })); | |
11fdf7f2 TL |
226 | } |
227 | ||
228 | void expect_get_object_name(librbd::MockTestImageCtx &mock_image_ctx) { | |
229 | EXPECT_CALL(mock_image_ctx, get_object_name(0)) | |
230 | .WillOnce(Return(mock_image_ctx.image_ctx->get_object_name(0))); | |
231 | } | |
232 | ||
233 | MockObjectCopyRequest *create_request( | |
234 | librbd::MockTestImageCtx &mock_src_image_ctx, | |
9f95a23c TL |
235 | librbd::MockTestImageCtx &mock_dst_image_ctx, |
236 | librados::snap_t src_snap_id_start, | |
cd265ab1 | 237 | librados::snap_t src_snap_id_end, |
9f95a23c | 238 | librados::snap_t dst_snap_id_start, |
f67539c2 | 239 | uint32_t flags, Context *on_finish) { |
cd265ab1 TL |
240 | SnapMap snap_map; |
241 | util::compute_snap_map(mock_dst_image_ctx.cct, src_snap_id_start, | |
242 | src_snap_id_end, m_dst_snap_ids, m_snap_seqs, | |
243 | &snap_map); | |
244 | ||
11fdf7f2 | 245 | expect_get_object_name(mock_dst_image_ctx); |
11fdf7f2 | 246 | return new MockObjectCopyRequest(&mock_src_image_ctx, &mock_dst_image_ctx, |
9f95a23c | 247 | src_snap_id_start, dst_snap_id_start, |
f67539c2 | 248 | snap_map, 0, flags, nullptr, on_finish); |
11fdf7f2 TL |
249 | } |
250 | ||
f67539c2 TL |
251 | void expect_read(librbd::MockTestImageCtx& mock_image_ctx, |
252 | uint64_t snap_id, uint64_t offset, uint64_t length, int r) { | |
253 | interval_set<uint64_t> extents; | |
254 | extents.insert(offset, length); | |
255 | expect_read(mock_image_ctx, snap_id, extents, r); | |
11fdf7f2 TL |
256 | } |
257 | ||
f67539c2 | 258 | void expect_read(librbd::MockTestImageCtx& mock_image_ctx, uint64_t snap_id, |
11fdf7f2 | 259 | const interval_set<uint64_t> &extents, int r) { |
f67539c2 TL |
260 | EXPECT_CALL(*mock_image_ctx.io_image_dispatcher, |
261 | send(IsRead(snap_id, extents))) | |
262 | .WillOnce(Invoke( | |
263 | [&mock_image_ctx, r](io::ImageDispatchSpec* spec) { | |
264 | if (r < 0) { | |
265 | spec->fail(r); | |
266 | return; | |
267 | } | |
268 | ||
269 | spec->image_dispatcher = | |
270 | mock_image_ctx.image_ctx->io_image_dispatcher; | |
271 | mock_image_ctx.image_ctx->io_image_dispatcher->send(spec); | |
272 | })); | |
11fdf7f2 TL |
273 | } |
274 | ||
275 | void expect_write(librados::MockTestMemIoCtxImpl &mock_io_ctx, | |
276 | uint64_t offset, uint64_t length, | |
277 | const SnapContext &snapc, int r) { | |
278 | auto &expect = EXPECT_CALL(mock_io_ctx, write(_, _, length, offset, snapc)); | |
279 | if (r < 0) { | |
280 | expect.WillOnce(Return(r)); | |
281 | } else { | |
282 | expect.WillOnce(DoDefault()); | |
283 | } | |
284 | } | |
285 | ||
286 | void expect_write(librados::MockTestMemIoCtxImpl &mock_io_ctx, | |
287 | const interval_set<uint64_t> &extents, | |
288 | const SnapContext &snapc, int r) { | |
289 | for (auto extent : extents) { | |
290 | expect_write(mock_io_ctx, extent.first, extent.second, snapc, r); | |
291 | if (r < 0) { | |
292 | break; | |
293 | } | |
294 | } | |
295 | } | |
296 | ||
297 | void expect_truncate(librados::MockTestMemIoCtxImpl &mock_io_ctx, | |
298 | uint64_t offset, int r) { | |
299 | auto &expect = EXPECT_CALL(mock_io_ctx, truncate(_, offset, _)); | |
300 | if (r < 0) { | |
301 | expect.WillOnce(Return(r)); | |
302 | } else { | |
303 | expect.WillOnce(DoDefault()); | |
304 | } | |
305 | } | |
306 | ||
307 | void expect_remove(librados::MockTestMemIoCtxImpl &mock_io_ctx, int r) { | |
308 | auto &expect = EXPECT_CALL(mock_io_ctx, remove(_, _)); | |
309 | if (r < 0) { | |
310 | expect.WillOnce(Return(r)); | |
311 | } else { | |
312 | expect.WillOnce(DoDefault()); | |
313 | } | |
314 | } | |
315 | ||
316 | void expect_update_object_map(librbd::MockTestImageCtx &mock_image_ctx, | |
317 | librbd::MockObjectMap &mock_object_map, | |
318 | librados::snap_t snap_id, uint8_t state, | |
319 | int r) { | |
320 | if (mock_image_ctx.image_ctx->object_map != nullptr) { | |
321 | auto &expect = EXPECT_CALL(mock_object_map, aio_update(snap_id, 0, 1, state, _, _, false, _)); | |
322 | if (r < 0) { | |
323 | expect.WillOnce(DoAll(WithArg<7>(Invoke([this, r](Context *ctx) { | |
324 | m_work_queue->queue(ctx, r); | |
325 | })), | |
326 | Return(true))); | |
327 | } else { | |
328 | expect.WillOnce(DoAll(WithArg<7>(Invoke([&mock_image_ctx, snap_id, state](Context *ctx) { | |
9f95a23c | 329 | ceph_assert(ceph_mutex_is_locked(mock_image_ctx.image_ctx->image_lock)); |
11fdf7f2 TL |
330 | mock_image_ctx.image_ctx->object_map->aio_update<Context>( |
331 | snap_id, 0, 1, state, boost::none, {}, false, ctx); | |
332 | })), | |
333 | Return(true))); | |
334 | } | |
335 | } | |
336 | } | |
337 | ||
f67539c2 TL |
338 | void expect_prepare_copyup(MockTestImageCtx& mock_image_ctx, int r = 0) { |
339 | EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, | |
340 | prepare_copyup(_, _)).WillOnce(Return(r)); | |
341 | } | |
342 | ||
11fdf7f2 TL |
343 | int create_snap(librbd::ImageCtx *image_ctx, const char* snap_name, |
344 | librados::snap_t *snap_id) { | |
f67539c2 | 345 | NoOpProgressContext prog_ctx; |
11fdf7f2 | 346 | int r = image_ctx->operations->snap_create( |
f67539c2 | 347 | cls::rbd::UserSnapshotNamespace(), snap_name, 0, prog_ctx); |
11fdf7f2 TL |
348 | if (r < 0) { |
349 | return r; | |
350 | } | |
351 | ||
352 | r = image_ctx->state->refresh(); | |
353 | if (r < 0) { | |
354 | return r; | |
355 | } | |
356 | ||
357 | if (image_ctx->snap_ids.count({cls::rbd::UserSnapshotNamespace(), | |
358 | snap_name}) == 0) { | |
359 | return -ENOENT; | |
360 | } | |
361 | ||
362 | if (snap_id != nullptr) { | |
363 | *snap_id = image_ctx->snap_ids[{cls::rbd::UserSnapshotNamespace(), | |
364 | snap_name}]; | |
365 | } | |
366 | return 0; | |
367 | } | |
368 | ||
369 | int create_snap(const char* snap_name) { | |
370 | librados::snap_t src_snap_id; | |
371 | int r = create_snap(m_src_image_ctx, snap_name, &src_snap_id); | |
372 | if (r < 0) { | |
373 | return r; | |
374 | } | |
375 | ||
376 | librados::snap_t dst_snap_id; | |
377 | r = create_snap(m_dst_image_ctx, snap_name, &dst_snap_id); | |
378 | if (r < 0) { | |
379 | return r; | |
380 | } | |
381 | ||
382 | // collection of all existing snaps in dst image | |
383 | SnapIds dst_snap_ids({dst_snap_id}); | |
384 | if (!m_snap_map.empty()) { | |
385 | dst_snap_ids.insert(dst_snap_ids.end(), | |
386 | m_snap_map.rbegin()->second.begin(), | |
387 | m_snap_map.rbegin()->second.end()); | |
388 | } | |
389 | m_snap_map[src_snap_id] = dst_snap_ids; | |
cd265ab1 | 390 | m_snap_seqs[src_snap_id] = dst_snap_id; |
11fdf7f2 TL |
391 | m_src_snap_ids.push_back(src_snap_id); |
392 | m_dst_snap_ids.push_back(dst_snap_id); | |
393 | ||
394 | return 0; | |
395 | } | |
396 | ||
397 | std::string get_snap_name(librbd::ImageCtx *image_ctx, | |
398 | librados::snap_t snap_id) { | |
399 | auto it = std::find_if(image_ctx->snap_ids.begin(), | |
400 | image_ctx->snap_ids.end(), | |
401 | [snap_id](const std::pair<std::pair<cls::rbd::SnapshotNamespace, | |
402 | std::string>, | |
403 | librados::snap_t> &pair) { | |
404 | return (pair.second == snap_id); | |
405 | }); | |
406 | if (it == image_ctx->snap_ids.end()) { | |
407 | return ""; | |
408 | } | |
409 | return it->first.second; | |
410 | } | |
411 | ||
9f95a23c TL |
412 | int copy_objects() { |
413 | int r; | |
414 | uint64_t object_size = 1 << m_src_image_ctx->order; | |
415 | ||
416 | bufferlist bl; | |
417 | bl.append(std::string(object_size, '1')); | |
f67539c2 TL |
418 | r = api::Io<>::read(*m_src_image_ctx, 0, object_size, |
419 | librbd::io::ReadResult{&bl}, 0); | |
9f95a23c TL |
420 | if (r < 0) { |
421 | return r; | |
422 | } | |
423 | ||
f67539c2 | 424 | r = api::Io<>::write(*m_dst_image_ctx, 0, object_size, std::move(bl), 0); |
9f95a23c TL |
425 | if (r < 0) { |
426 | return r; | |
427 | } | |
428 | ||
429 | return 0; | |
430 | } | |
431 | ||
11fdf7f2 TL |
432 | int compare_objects() { |
433 | SnapMap snap_map(m_snap_map); | |
434 | if (snap_map.empty()) { | |
435 | return -ENOENT; | |
436 | } | |
437 | ||
438 | int r; | |
439 | uint64_t object_size = 1 << m_src_image_ctx->order; | |
440 | while (!snap_map.empty()) { | |
441 | librados::snap_t src_snap_id = snap_map.begin()->first; | |
442 | librados::snap_t dst_snap_id = *snap_map.begin()->second.begin(); | |
443 | snap_map.erase(snap_map.begin()); | |
444 | ||
445 | std::string snap_name = get_snap_name(m_src_image_ctx, src_snap_id); | |
446 | if (snap_name.empty()) { | |
447 | return -ENOENT; | |
448 | } | |
449 | ||
450 | std::cout << "comparing '" << snap_name << " (" << src_snap_id | |
451 | << " to " << dst_snap_id << ")" << std::endl; | |
452 | ||
453 | r = librbd::api::Image<>::snap_set(m_src_image_ctx, | |
454 | cls::rbd::UserSnapshotNamespace(), | |
455 | snap_name.c_str()); | |
456 | if (r < 0) { | |
457 | return r; | |
458 | } | |
459 | ||
460 | r = librbd::api::Image<>::snap_set(m_dst_image_ctx, | |
461 | cls::rbd::UserSnapshotNamespace(), | |
462 | snap_name.c_str()); | |
463 | if (r < 0) { | |
464 | return r; | |
465 | } | |
466 | ||
467 | bufferlist src_bl; | |
468 | src_bl.append(std::string(object_size, '1')); | |
f67539c2 TL |
469 | r = api::Io<>::read( |
470 | *m_src_image_ctx, 0, object_size, librbd::io::ReadResult{&src_bl}, 0); | |
11fdf7f2 TL |
471 | if (r < 0) { |
472 | return r; | |
473 | } | |
474 | ||
475 | bufferlist dst_bl; | |
476 | dst_bl.append(std::string(object_size, '1')); | |
f67539c2 TL |
477 | r = api::Io<>::read( |
478 | *m_dst_image_ctx, 0, object_size, librbd::io::ReadResult{&dst_bl}, 0); | |
11fdf7f2 TL |
479 | if (r < 0) { |
480 | return r; | |
481 | } | |
482 | ||
483 | if (!src_bl.contents_equal(dst_bl)) { | |
9f95a23c TL |
484 | std::cout << "src block: " << std::endl; src_bl.hexdump(std::cout); |
485 | std::cout << "dst block: " << std::endl; dst_bl.hexdump(std::cout); | |
11fdf7f2 TL |
486 | return -EBADMSG; |
487 | } | |
488 | } | |
489 | ||
490 | r = librbd::api::Image<>::snap_set(m_src_image_ctx, | |
491 | cls::rbd::UserSnapshotNamespace(), | |
492 | nullptr); | |
493 | if (r < 0) { | |
494 | return r; | |
495 | } | |
496 | r = librbd::api::Image<>::snap_set(m_dst_image_ctx, | |
497 | cls::rbd::UserSnapshotNamespace(), | |
498 | nullptr); | |
499 | if (r < 0) { | |
500 | return r; | |
501 | } | |
502 | ||
503 | return 0; | |
504 | } | |
505 | }; | |
506 | ||
507 | TEST_F(TestMockDeepCopyObjectCopyRequest, DNE) { | |
508 | ASSERT_EQ(0, create_snap("copy")); | |
509 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
510 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
511 | ||
512 | librbd::MockExclusiveLock mock_exclusive_lock; | |
513 | prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock); | |
514 | ||
515 | librbd::MockObjectMap mock_object_map; | |
516 | mock_dst_image_ctx.object_map = &mock_object_map; | |
f67539c2 | 517 | expect_op_work_queue(mock_src_image_ctx); |
11fdf7f2 | 518 | expect_test_features(mock_dst_image_ctx); |
81eedcae | 519 | expect_get_object_count(mock_dst_image_ctx); |
11fdf7f2 TL |
520 | |
521 | C_SaferCond ctx; | |
522 | MockObjectCopyRequest *request = create_request(mock_src_image_ctx, | |
cd265ab1 | 523 | mock_dst_image_ctx, 0, |
f67539c2 | 524 | CEPH_NOSNAP, 0, 0, &ctx); |
11fdf7f2 TL |
525 | |
526 | InSequence seq; | |
f67539c2 | 527 | expect_list_snaps(mock_src_image_ctx, -ENOENT); |
11fdf7f2 TL |
528 | |
529 | request->send(); | |
530 | ASSERT_EQ(-ENOENT, ctx.wait()); | |
531 | } | |
532 | ||
533 | TEST_F(TestMockDeepCopyObjectCopyRequest, Write) { | |
534 | // scribble some data | |
535 | interval_set<uint64_t> one; | |
536 | scribble(m_src_image_ctx, 10, 102400, &one); | |
537 | ||
538 | ASSERT_EQ(0, create_snap("copy")); | |
539 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
540 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
541 | ||
542 | librbd::MockExclusiveLock mock_exclusive_lock; | |
543 | prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock); | |
544 | ||
545 | librbd::MockObjectMap mock_object_map; | |
546 | mock_dst_image_ctx.object_map = &mock_object_map; | |
547 | ||
f67539c2 | 548 | expect_op_work_queue(mock_src_image_ctx); |
11fdf7f2 | 549 | expect_test_features(mock_dst_image_ctx); |
81eedcae | 550 | expect_get_object_count(mock_dst_image_ctx); |
11fdf7f2 TL |
551 | |
552 | C_SaferCond ctx; | |
553 | MockObjectCopyRequest *request = create_request(mock_src_image_ctx, | |
cd265ab1 | 554 | mock_dst_image_ctx, 0, |
f67539c2 | 555 | CEPH_NOSNAP, 0, 0, &ctx); |
11fdf7f2 | 556 | |
11fdf7f2 TL |
557 | librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx( |
558 | request->get_dst_io_ctx())); | |
559 | ||
560 | InSequence seq; | |
f67539c2 TL |
561 | expect_list_snaps(mock_src_image_ctx, 0); |
562 | expect_read(mock_src_image_ctx, m_src_snap_ids[0], 0, one.range_end(), 0); | |
11fdf7f2 | 563 | expect_start_op(mock_exclusive_lock); |
11fdf7f2 TL |
564 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, |
565 | m_dst_snap_ids[0], OBJECT_EXISTS, 0); | |
f67539c2 | 566 | expect_prepare_copyup(mock_dst_image_ctx); |
cd265ab1 TL |
567 | expect_start_op(mock_exclusive_lock); |
568 | expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0); | |
11fdf7f2 TL |
569 | |
570 | request->send(); | |
571 | ASSERT_EQ(0, ctx.wait()); | |
572 | ASSERT_EQ(0, compare_objects()); | |
573 | } | |
574 | ||
11fdf7f2 TL |
575 | TEST_F(TestMockDeepCopyObjectCopyRequest, ReadError) { |
576 | // scribble some data | |
577 | interval_set<uint64_t> one; | |
578 | scribble(m_src_image_ctx, 10, 102400, &one); | |
579 | ||
580 | ASSERT_EQ(0, create_snap("copy")); | |
581 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
582 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
583 | ||
584 | librbd::MockExclusiveLock mock_exclusive_lock; | |
585 | prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock); | |
586 | ||
587 | librbd::MockObjectMap mock_object_map; | |
588 | mock_dst_image_ctx.object_map = &mock_object_map; | |
589 | ||
f67539c2 | 590 | expect_op_work_queue(mock_src_image_ctx); |
11fdf7f2 | 591 | expect_test_features(mock_dst_image_ctx); |
f67539c2 | 592 | expect_get_object_count(mock_dst_image_ctx); |
11fdf7f2 TL |
593 | |
594 | C_SaferCond ctx; | |
595 | MockObjectCopyRequest *request = create_request(mock_src_image_ctx, | |
cd265ab1 | 596 | mock_dst_image_ctx, 0, |
f67539c2 | 597 | CEPH_NOSNAP, 0, 0, &ctx); |
11fdf7f2 TL |
598 | |
599 | InSequence seq; | |
f67539c2 TL |
600 | expect_list_snaps(mock_src_image_ctx, 0); |
601 | expect_read(mock_src_image_ctx, m_src_snap_ids[0], 0, one.range_end(), | |
602 | -EINVAL); | |
11fdf7f2 TL |
603 | |
604 | request->send(); | |
605 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
606 | } | |
607 | ||
608 | TEST_F(TestMockDeepCopyObjectCopyRequest, WriteError) { | |
609 | // scribble some data | |
610 | interval_set<uint64_t> one; | |
611 | scribble(m_src_image_ctx, 10, 102400, &one); | |
612 | ||
613 | ASSERT_EQ(0, create_snap("copy")); | |
614 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
615 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
616 | ||
617 | librbd::MockExclusiveLock mock_exclusive_lock; | |
618 | prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock); | |
619 | ||
620 | librbd::MockObjectMap mock_object_map; | |
621 | mock_dst_image_ctx.object_map = &mock_object_map; | |
622 | ||
f67539c2 | 623 | expect_op_work_queue(mock_src_image_ctx); |
11fdf7f2 | 624 | expect_test_features(mock_dst_image_ctx); |
81eedcae | 625 | expect_get_object_count(mock_dst_image_ctx); |
11fdf7f2 TL |
626 | |
627 | C_SaferCond ctx; | |
628 | MockObjectCopyRequest *request = create_request(mock_src_image_ctx, | |
cd265ab1 | 629 | mock_dst_image_ctx, 0, |
f67539c2 | 630 | CEPH_NOSNAP, 0, 0, &ctx); |
11fdf7f2 | 631 | |
11fdf7f2 TL |
632 | librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx( |
633 | request->get_dst_io_ctx())); | |
634 | ||
635 | InSequence seq; | |
f67539c2 TL |
636 | expect_list_snaps(mock_src_image_ctx, 0); |
637 | expect_read(mock_src_image_ctx, m_src_snap_ids[0], 0, one.range_end(), 0); | |
cd265ab1 TL |
638 | |
639 | expect_start_op(mock_exclusive_lock); | |
640 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
641 | m_dst_snap_ids[0], OBJECT_EXISTS, 0); | |
642 | ||
f67539c2 | 643 | expect_prepare_copyup(mock_dst_image_ctx); |
11fdf7f2 TL |
644 | expect_start_op(mock_exclusive_lock); |
645 | expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, -EINVAL); | |
646 | ||
647 | request->send(); | |
648 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
649 | } | |
650 | ||
651 | TEST_F(TestMockDeepCopyObjectCopyRequest, WriteSnaps) { | |
652 | // scribble some data | |
653 | interval_set<uint64_t> one; | |
654 | scribble(m_src_image_ctx, 10, 102400, &one); | |
655 | ASSERT_EQ(0, create_snap("one")); | |
656 | ||
657 | interval_set<uint64_t> two; | |
658 | scribble(m_src_image_ctx, 10, 102400, &two); | |
659 | ASSERT_EQ(0, create_snap("two")); | |
660 | ||
661 | if (one.range_end() < two.range_end()) { | |
662 | interval_set<uint64_t> resize_diff; | |
663 | resize_diff.insert(one.range_end(), two.range_end() - one.range_end()); | |
664 | two.union_of(resize_diff); | |
665 | } | |
666 | ||
667 | ASSERT_EQ(0, create_snap("copy")); | |
668 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
669 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
670 | ||
671 | librbd::MockExclusiveLock mock_exclusive_lock; | |
672 | prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock); | |
673 | ||
674 | librbd::MockObjectMap mock_object_map; | |
675 | mock_dst_image_ctx.object_map = &mock_object_map; | |
676 | ||
f67539c2 | 677 | expect_op_work_queue(mock_src_image_ctx); |
11fdf7f2 | 678 | expect_test_features(mock_dst_image_ctx); |
81eedcae | 679 | expect_get_object_count(mock_dst_image_ctx); |
11fdf7f2 TL |
680 | |
681 | C_SaferCond ctx; | |
682 | MockObjectCopyRequest *request = create_request(mock_src_image_ctx, | |
cd265ab1 | 683 | mock_dst_image_ctx, 0, |
f67539c2 | 684 | CEPH_NOSNAP, 0, 0, &ctx); |
11fdf7f2 | 685 | |
11fdf7f2 TL |
686 | librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx( |
687 | request->get_dst_io_ctx())); | |
688 | ||
689 | InSequence seq; | |
f67539c2 TL |
690 | expect_list_snaps(mock_src_image_ctx, 0); |
691 | expect_read(mock_src_image_ctx, m_src_snap_ids[0], 0, one.range_end(), 0); | |
692 | expect_read(mock_src_image_ctx, m_src_snap_ids[2], two, 0); | |
11fdf7f2 TL |
693 | expect_start_op(mock_exclusive_lock); |
694 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
695 | m_dst_snap_ids[0], OBJECT_EXISTS, 0); | |
696 | expect_start_op(mock_exclusive_lock); | |
697 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
698 | m_dst_snap_ids[1], OBJECT_EXISTS, 0); | |
699 | expect_start_op(mock_exclusive_lock); | |
700 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
701 | m_dst_snap_ids[2], is_fast_diff(mock_dst_image_ctx) ? | |
702 | OBJECT_EXISTS_CLEAN : OBJECT_EXISTS, 0); | |
f67539c2 | 703 | expect_prepare_copyup(mock_dst_image_ctx); |
cd265ab1 TL |
704 | expect_start_op(mock_exclusive_lock); |
705 | expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0); | |
706 | expect_start_op(mock_exclusive_lock); | |
707 | expect_write(mock_dst_io_ctx, two, | |
708 | {m_dst_snap_ids[0], {m_dst_snap_ids[0]}}, 0); | |
709 | ||
11fdf7f2 TL |
710 | request->send(); |
711 | ASSERT_EQ(0, ctx.wait()); | |
712 | ASSERT_EQ(0, compare_objects()); | |
713 | } | |
714 | ||
715 | TEST_F(TestMockDeepCopyObjectCopyRequest, Trim) { | |
716 | ASSERT_EQ(0, m_src_image_ctx->operations->metadata_set( | |
717 | "conf_rbd_skip_partial_discard", "false")); | |
718 | m_src_image_ctx->discard_granularity_bytes = 0; | |
719 | ||
720 | // scribble some data | |
721 | interval_set<uint64_t> one; | |
722 | scribble(m_src_image_ctx, 10, 102400, &one); | |
723 | ASSERT_EQ(0, create_snap("one")); | |
724 | ||
725 | // trim the object | |
726 | uint64_t trim_offset = rand() % one.range_end(); | |
f67539c2 TL |
727 | ASSERT_LE(0, api::Io<>::discard( |
728 | *m_src_image_ctx, trim_offset, one.range_end() - trim_offset, | |
11fdf7f2 TL |
729 | m_src_image_ctx->discard_granularity_bytes)); |
730 | ASSERT_EQ(0, create_snap("copy")); | |
731 | ||
732 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
733 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
734 | ||
735 | librbd::MockExclusiveLock mock_exclusive_lock; | |
736 | prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock); | |
737 | ||
738 | librbd::MockObjectMap mock_object_map; | |
739 | mock_dst_image_ctx.object_map = &mock_object_map; | |
740 | ||
f67539c2 | 741 | expect_op_work_queue(mock_src_image_ctx); |
11fdf7f2 | 742 | expect_test_features(mock_dst_image_ctx); |
81eedcae | 743 | expect_get_object_count(mock_dst_image_ctx); |
11fdf7f2 TL |
744 | |
745 | C_SaferCond ctx; | |
746 | MockObjectCopyRequest *request = create_request(mock_src_image_ctx, | |
cd265ab1 | 747 | mock_dst_image_ctx, 0, |
f67539c2 | 748 | CEPH_NOSNAP, 0, 0, &ctx); |
11fdf7f2 | 749 | |
11fdf7f2 TL |
750 | librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx( |
751 | request->get_dst_io_ctx())); | |
752 | ||
753 | InSequence seq; | |
f67539c2 TL |
754 | expect_list_snaps(mock_src_image_ctx, 0); |
755 | expect_read(mock_src_image_ctx, m_src_snap_ids[0], 0, one.range_end(), 0); | |
11fdf7f2 TL |
756 | expect_start_op(mock_exclusive_lock); |
757 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
758 | m_dst_snap_ids[0], OBJECT_EXISTS, 0); | |
759 | expect_start_op(mock_exclusive_lock); | |
760 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
761 | m_dst_snap_ids[1], OBJECT_EXISTS, 0); | |
f67539c2 | 762 | expect_prepare_copyup(mock_dst_image_ctx); |
cd265ab1 TL |
763 | expect_start_op(mock_exclusive_lock); |
764 | expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0); | |
765 | expect_start_op(mock_exclusive_lock); | |
766 | expect_truncate(mock_dst_io_ctx, trim_offset, 0); | |
767 | ||
11fdf7f2 TL |
768 | request->send(); |
769 | ASSERT_EQ(0, ctx.wait()); | |
770 | ASSERT_EQ(0, compare_objects()); | |
771 | } | |
772 | ||
773 | TEST_F(TestMockDeepCopyObjectCopyRequest, Remove) { | |
774 | // scribble some data | |
775 | interval_set<uint64_t> one; | |
776 | scribble(m_src_image_ctx, 10, 102400, &one); | |
777 | ASSERT_EQ(0, create_snap("one")); | |
778 | ASSERT_EQ(0, create_snap("two")); | |
779 | ||
780 | // remove the object | |
781 | uint64_t object_size = 1 << m_src_image_ctx->order; | |
f67539c2 TL |
782 | ASSERT_LE(0, api::Io<>::discard( |
783 | *m_src_image_ctx, 0, object_size, | |
784 | m_src_image_ctx->discard_granularity_bytes)); | |
11fdf7f2 TL |
785 | ASSERT_EQ(0, create_snap("copy")); |
786 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
787 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
788 | ||
789 | librbd::MockExclusiveLock mock_exclusive_lock; | |
790 | prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock); | |
791 | ||
792 | librbd::MockObjectMap mock_object_map; | |
793 | mock_dst_image_ctx.object_map = &mock_object_map; | |
794 | ||
f67539c2 | 795 | expect_op_work_queue(mock_src_image_ctx); |
11fdf7f2 | 796 | expect_test_features(mock_dst_image_ctx); |
81eedcae | 797 | expect_get_object_count(mock_dst_image_ctx); |
11fdf7f2 TL |
798 | |
799 | C_SaferCond ctx; | |
800 | MockObjectCopyRequest *request = create_request(mock_src_image_ctx, | |
cd265ab1 | 801 | mock_dst_image_ctx, 0, |
f67539c2 | 802 | CEPH_NOSNAP, 0, 0, &ctx); |
11fdf7f2 | 803 | |
11fdf7f2 TL |
804 | librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx( |
805 | request->get_dst_io_ctx())); | |
806 | ||
807 | InSequence seq; | |
f67539c2 TL |
808 | expect_list_snaps(mock_src_image_ctx, 0); |
809 | expect_read(mock_src_image_ctx, m_src_snap_ids[1], 0, one.range_end(), 0); | |
cd265ab1 | 810 | |
11fdf7f2 TL |
811 | expect_start_op(mock_exclusive_lock); |
812 | uint8_t state = OBJECT_EXISTS; | |
813 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
814 | m_dst_snap_ids[0], state, 0); | |
815 | expect_start_op(mock_exclusive_lock); | |
816 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
817 | m_dst_snap_ids[1], is_fast_diff(mock_dst_image_ctx) ? | |
818 | OBJECT_EXISTS_CLEAN : OBJECT_EXISTS, 0); | |
819 | ||
f67539c2 | 820 | expect_prepare_copyup(mock_dst_image_ctx); |
cd265ab1 TL |
821 | expect_start_op(mock_exclusive_lock); |
822 | expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0); | |
823 | expect_start_op(mock_exclusive_lock); | |
824 | expect_remove(mock_dst_io_ctx, 0); | |
825 | ||
11fdf7f2 TL |
826 | request->send(); |
827 | ASSERT_EQ(0, ctx.wait()); | |
828 | ASSERT_EQ(0, compare_objects()); | |
829 | } | |
830 | ||
831 | TEST_F(TestMockDeepCopyObjectCopyRequest, ObjectMapUpdateError) { | |
832 | REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP); | |
833 | ||
834 | // scribble some data | |
835 | interval_set<uint64_t> one; | |
836 | scribble(m_src_image_ctx, 10, 102400, &one); | |
837 | ||
838 | ASSERT_EQ(0, create_snap("copy")); | |
839 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
840 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
841 | ||
842 | librbd::MockExclusiveLock mock_exclusive_lock; | |
843 | prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock); | |
844 | ||
845 | librbd::MockObjectMap mock_object_map; | |
846 | mock_dst_image_ctx.object_map = &mock_object_map; | |
847 | ||
f67539c2 | 848 | expect_op_work_queue(mock_src_image_ctx); |
11fdf7f2 | 849 | expect_test_features(mock_dst_image_ctx); |
81eedcae | 850 | expect_get_object_count(mock_dst_image_ctx); |
11fdf7f2 TL |
851 | |
852 | C_SaferCond ctx; | |
853 | MockObjectCopyRequest *request = create_request(mock_src_image_ctx, | |
cd265ab1 | 854 | mock_dst_image_ctx, 0, |
f67539c2 | 855 | CEPH_NOSNAP, 0, 0, &ctx); |
11fdf7f2 TL |
856 | |
857 | InSequence seq; | |
f67539c2 TL |
858 | expect_list_snaps(mock_src_image_ctx, 0); |
859 | expect_read(mock_src_image_ctx, m_src_snap_ids[0], 0, one.range_end(), 0); | |
860 | expect_start_op(mock_exclusive_lock); | |
861 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
862 | m_dst_snap_ids[0], OBJECT_EXISTS, -EBLOCKLISTED); | |
863 | ||
864 | request->send(); | |
865 | ASSERT_EQ(-EBLOCKLISTED, ctx.wait()); | |
866 | } | |
cd265ab1 | 867 | |
f67539c2 TL |
868 | TEST_F(TestMockDeepCopyObjectCopyRequest, PrepareCopyupError) { |
869 | // scribble some data | |
870 | interval_set<uint64_t> one; | |
871 | scribble(m_src_image_ctx, 10, 102400, &one); | |
872 | ||
873 | ASSERT_EQ(0, create_snap("copy")); | |
874 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
875 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
876 | ||
877 | librbd::MockExclusiveLock mock_exclusive_lock; | |
878 | prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock); | |
879 | ||
880 | librbd::MockObjectMap mock_object_map; | |
881 | mock_dst_image_ctx.object_map = &mock_object_map; | |
882 | ||
883 | expect_op_work_queue(mock_src_image_ctx); | |
884 | expect_test_features(mock_dst_image_ctx); | |
885 | expect_get_object_count(mock_dst_image_ctx); | |
886 | ||
887 | C_SaferCond ctx; | |
888 | MockObjectCopyRequest *request = create_request(mock_src_image_ctx, | |
889 | mock_dst_image_ctx, 0, | |
890 | CEPH_NOSNAP, 0, 0, &ctx); | |
891 | ||
892 | InSequence seq; | |
893 | expect_list_snaps(mock_src_image_ctx, 0); | |
894 | expect_read(mock_src_image_ctx, m_src_snap_ids[0], 0, one.range_end(), 0); | |
cd265ab1 | 895 | |
11fdf7f2 TL |
896 | expect_start_op(mock_exclusive_lock); |
897 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
f67539c2 TL |
898 | m_dst_snap_ids[0], OBJECT_EXISTS, 0); |
899 | ||
900 | expect_prepare_copyup(mock_dst_image_ctx, -EIO); | |
11fdf7f2 TL |
901 | |
902 | request->send(); | |
f67539c2 | 903 | ASSERT_EQ(-EIO, ctx.wait()); |
11fdf7f2 TL |
904 | } |
905 | ||
9f95a23c TL |
906 | TEST_F(TestMockDeepCopyObjectCopyRequest, WriteSnapsStart) { |
907 | // scribble some data | |
908 | interval_set<uint64_t> one; | |
909 | scribble(m_src_image_ctx, 10, 102400, &one); | |
910 | ASSERT_EQ(0, copy_objects()); | |
911 | ASSERT_EQ(0, create_snap("one")); | |
912 | ||
913 | auto src_snap_id_start = m_src_image_ctx->snaps[0]; | |
914 | auto dst_snap_id_start = m_dst_image_ctx->snaps[0]; | |
915 | ||
916 | interval_set<uint64_t> two; | |
917 | scribble(m_src_image_ctx, 10, 102400, &two); | |
918 | ASSERT_EQ(0, create_snap("two")); | |
919 | ||
920 | interval_set<uint64_t> three; | |
921 | scribble(m_src_image_ctx, 10, 102400, &three); | |
922 | ASSERT_EQ(0, create_snap("three")); | |
923 | ||
924 | auto max_extent = one.range_end(); | |
925 | if (max_extent < two.range_end()) { | |
926 | interval_set<uint64_t> resize_diff; | |
927 | resize_diff.insert(max_extent, two.range_end() - max_extent); | |
928 | two.union_of(resize_diff); | |
929 | } | |
930 | ||
931 | max_extent = std::max(max_extent, two.range_end()); | |
932 | if (max_extent < three.range_end()) { | |
933 | interval_set<uint64_t> resize_diff; | |
934 | resize_diff.insert(max_extent, three.range_end() - max_extent); | |
935 | three.union_of(resize_diff); | |
936 | } | |
937 | ||
938 | interval_set<uint64_t> four; | |
939 | scribble(m_src_image_ctx, 10, 102400, &four); | |
940 | ||
941 | // map should begin after src start and src end's dst snap seqs should | |
942 | // point to HEAD revision | |
cd265ab1 TL |
943 | m_snap_seqs.rbegin()->second = CEPH_NOSNAP; |
944 | m_dst_snap_ids.pop_back(); | |
9f95a23c TL |
945 | |
946 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
947 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
948 | ||
949 | librbd::MockExclusiveLock mock_exclusive_lock; | |
950 | prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock); | |
951 | ||
952 | librbd::MockObjectMap mock_object_map; | |
953 | mock_dst_image_ctx.object_map = &mock_object_map; | |
954 | ||
f67539c2 | 955 | expect_op_work_queue(mock_src_image_ctx); |
9f95a23c TL |
956 | expect_test_features(mock_dst_image_ctx); |
957 | expect_get_object_count(mock_dst_image_ctx); | |
958 | ||
959 | C_SaferCond ctx; | |
960 | MockObjectCopyRequest *request = create_request(mock_src_image_ctx, | |
961 | mock_dst_image_ctx, | |
962 | src_snap_id_start, | |
cd265ab1 | 963 | CEPH_NOSNAP, |
9f95a23c | 964 | dst_snap_id_start, |
f67539c2 | 965 | 0, &ctx); |
9f95a23c | 966 | |
9f95a23c TL |
967 | librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx( |
968 | request->get_dst_io_ctx())); | |
969 | ||
970 | InSequence seq; | |
f67539c2 | 971 | expect_list_snaps(mock_src_image_ctx, 0); |
9f95a23c | 972 | |
f67539c2 TL |
973 | expect_read(mock_src_image_ctx, m_src_snap_ids[1], two, 0); |
974 | expect_read(mock_src_image_ctx, m_src_snap_ids[2], three, 0); | |
9f95a23c | 975 | |
cd265ab1 TL |
976 | expect_start_op(mock_exclusive_lock); |
977 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
978 | m_dst_snap_ids[1], OBJECT_EXISTS, 0); | |
979 | ||
980 | expect_start_op(mock_exclusive_lock); | |
981 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
982 | CEPH_NOSNAP, OBJECT_EXISTS, 0); | |
983 | ||
f67539c2 | 984 | expect_prepare_copyup(mock_dst_image_ctx); |
9f95a23c TL |
985 | expect_start_op(mock_exclusive_lock); |
986 | expect_write(mock_dst_io_ctx, two, | |
987 | {m_dst_snap_ids[0], {m_dst_snap_ids[0]}}, 0); | |
988 | ||
989 | expect_start_op(mock_exclusive_lock); | |
990 | expect_write(mock_dst_io_ctx, three, | |
991 | {m_dst_snap_ids[1], {m_dst_snap_ids[1], m_dst_snap_ids[0]}}, 0); | |
992 | ||
cd265ab1 TL |
993 | request->send(); |
994 | ASSERT_EQ(0, ctx.wait()); | |
995 | ASSERT_EQ(0, compare_objects()); | |
996 | } | |
997 | ||
998 | TEST_F(TestMockDeepCopyObjectCopyRequest, Incremental) { | |
999 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
1000 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
1001 | ||
1002 | librbd::MockExclusiveLock mock_exclusive_lock; | |
1003 | prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock); | |
1004 | ||
1005 | librbd::MockObjectMap mock_object_map; | |
1006 | mock_dst_image_ctx.object_map = &mock_object_map; | |
1007 | ||
1008 | expect_op_work_queue(mock_src_image_ctx); | |
1009 | expect_test_features(mock_dst_image_ctx); | |
1010 | expect_get_object_count(mock_dst_image_ctx); | |
1011 | ||
1012 | // scribble some data | |
1013 | interval_set<uint64_t> one; | |
1014 | scribble(m_src_image_ctx, 10, 102400, &one); | |
1015 | ASSERT_EQ(0, create_snap("snap1")); | |
1016 | mock_dst_image_ctx.snaps = m_dst_image_ctx->snaps; | |
1017 | ||
1018 | InSequence seq; | |
1019 | ||
1020 | C_SaferCond ctx1; | |
1021 | auto request1 = create_request(mock_src_image_ctx, mock_dst_image_ctx, | |
f67539c2 | 1022 | 0, m_src_snap_ids[0], 0, 0, &ctx1); |
cd265ab1 | 1023 | |
f67539c2 | 1024 | expect_list_snaps(mock_src_image_ctx, 0); |
cd265ab1 | 1025 | |
f67539c2 | 1026 | expect_read(mock_src_image_ctx, m_src_snap_ids[0], 0, one.range_end(), 0); |
cd265ab1 | 1027 | |
9f95a23c TL |
1028 | expect_start_op(mock_exclusive_lock); |
1029 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
cd265ab1 TL |
1030 | m_dst_snap_ids[0], OBJECT_EXISTS, 0); |
1031 | ||
f67539c2 | 1032 | librados::MockTestMemIoCtxImpl &mock_dst_io_ctx(get_mock_io_ctx( |
cd265ab1 | 1033 | request1->get_dst_io_ctx())); |
f67539c2 | 1034 | expect_prepare_copyup(mock_dst_image_ctx); |
cd265ab1 | 1035 | expect_start_op(mock_exclusive_lock); |
f67539c2 | 1036 | expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0); |
cd265ab1 TL |
1037 | |
1038 | request1->send(); | |
1039 | ASSERT_EQ(0, ctx1.wait()); | |
1040 | ||
1041 | // clean (no-updates) snapshots | |
1042 | ASSERT_EQ(0, create_snap("snap2")); | |
1043 | ASSERT_EQ(0, create_snap("snap3")); | |
1044 | mock_dst_image_ctx.snaps = m_dst_image_ctx->snaps; | |
1045 | ||
1046 | C_SaferCond ctx2; | |
1047 | auto request2 = create_request(mock_src_image_ctx, mock_dst_image_ctx, | |
1048 | m_src_snap_ids[0], m_src_snap_ids[2], | |
f67539c2 | 1049 | m_dst_snap_ids[0], 0, &ctx2); |
9f95a23c | 1050 | |
f67539c2 | 1051 | expect_list_snaps(mock_src_image_ctx, 0); |
9f95a23c TL |
1052 | expect_start_op(mock_exclusive_lock); |
1053 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
cd265ab1 TL |
1054 | m_dst_snap_ids[1], |
1055 | is_fast_diff(mock_dst_image_ctx) ? | |
1056 | OBJECT_EXISTS_CLEAN : OBJECT_EXISTS, 0); | |
1057 | expect_start_op(mock_exclusive_lock); | |
1058 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
1059 | m_dst_snap_ids[2], | |
1060 | is_fast_diff(mock_dst_image_ctx) ? | |
1061 | OBJECT_EXISTS_CLEAN : OBJECT_EXISTS, 0); | |
9f95a23c | 1062 | |
cd265ab1 TL |
1063 | request2->send(); |
1064 | ASSERT_EQ(0, ctx2.wait()); | |
9f95a23c TL |
1065 | ASSERT_EQ(0, compare_objects()); |
1066 | } | |
1067 | ||
f67539c2 TL |
1068 | TEST_F(TestMockDeepCopyObjectCopyRequest, SkipSnapList) { |
1069 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
1070 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
1071 | ||
1072 | librbd::MockExclusiveLock mock_exclusive_lock; | |
1073 | prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock); | |
1074 | ||
1075 | librbd::MockObjectMap mock_object_map; | |
1076 | mock_dst_image_ctx.object_map = &mock_object_map; | |
1077 | ||
1078 | expect_op_work_queue(mock_src_image_ctx); | |
1079 | expect_test_features(mock_dst_image_ctx); | |
1080 | expect_get_object_count(mock_dst_image_ctx); | |
1081 | ||
1082 | ASSERT_EQ(0, create_snap("snap1")); | |
1083 | mock_dst_image_ctx.snaps = m_dst_image_ctx->snaps; | |
1084 | ||
1085 | InSequence seq; | |
1086 | ||
1087 | // clean (no-updates) snapshots | |
1088 | ASSERT_EQ(0, create_snap("snap2")); | |
1089 | mock_dst_image_ctx.snaps = m_dst_image_ctx->snaps; | |
1090 | ||
1091 | C_SaferCond ctx; | |
1092 | auto request = create_request(mock_src_image_ctx, mock_dst_image_ctx, | |
1093 | m_src_snap_ids[0], m_src_snap_ids[1], | |
1094 | m_dst_snap_ids[0], | |
1095 | OBJECT_COPY_REQUEST_FLAG_EXISTS_CLEAN, &ctx); | |
1096 | ||
1097 | expect_start_op(mock_exclusive_lock); | |
1098 | expect_update_object_map(mock_dst_image_ctx, mock_object_map, | |
1099 | m_dst_snap_ids[1], | |
1100 | is_fast_diff(mock_dst_image_ctx) ? | |
1101 | OBJECT_EXISTS_CLEAN : OBJECT_EXISTS, 0); | |
1102 | ||
1103 | request->send(); | |
1104 | ASSERT_EQ(0, ctx.wait()); | |
1105 | } | |
1106 | ||
11fdf7f2 TL |
1107 | } // namespace deep_copy |
1108 | } // namespace librbd |