]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/io/test_mock_ObjectRequest.cc
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / test / librbd / io / test_mock_ObjectRequest.cc
CommitLineData
b32b8144
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/MockObjectMap.h"
8#include "test/librbd/mock/cache/MockImageCache.h"
9#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
10#include "test/librados_test_stub/MockTestMemRadosClient.h"
11#include "include/rbd/librbd.hpp"
12#include "librbd/io/CopyupRequest.h"
f67539c2 13#include "librbd/io/ImageRequest.h"
b32b8144 14#include "librbd/io/ObjectRequest.h"
f91f0fd5 15#include "librbd/io/Utils.h"
b32b8144
FG
16
17namespace librbd {
18namespace {
19
20struct MockTestImageCtx : public MockImageCtx {
21 MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
22 }
23};
24
25} // anonymous namespace
26
27namespace util {
28
29inline ImageCtx *get_image_ctx(MockImageCtx *image_ctx) {
30 return image_ctx->image_ctx;
31}
32
33} // namespace util
34
35namespace io {
36
37template <>
38struct CopyupRequest<librbd::MockImageCtx> {
39 MOCK_METHOD0(send, void());
f67539c2
TL
40 MOCK_METHOD2(append_request, void(AbstractObjectWriteRequest<librbd::MockTestImageCtx>*,
41 const Extents&));
b32b8144
FG
42};
43
44template <>
45struct CopyupRequest<librbd::MockTestImageCtx> : public CopyupRequest<librbd::MockImageCtx> {
46 static CopyupRequest* s_instance;
47 static CopyupRequest* create(librbd::MockTestImageCtx *ictx,
9f95a23c 48 uint64_t objectno, Extents &&image_extents,
1e59de90
TL
49 ImageArea area,
50 const ZTracer::Trace& parent_trace) {
b32b8144
FG
51 return s_instance;
52 }
53
54 CopyupRequest() {
55 s_instance = this;
56 }
57};
58
f91f0fd5 59CopyupRequest<librbd::MockTestImageCtx>* CopyupRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
b32b8144 60
f67539c2
TL
61template <>
62struct ImageListSnapsRequest<librbd::MockTestImageCtx> {
63 static ImageListSnapsRequest* s_instance;
64
65 AioCompletion* aio_comp;
66 Extents image_extents;
67 SnapshotDelta* snapshot_delta;
68
69 ImageListSnapsRequest() {
70 s_instance = this;
71 }
72 ImageListSnapsRequest(
73 librbd::MockImageCtx& image_ctx, AioCompletion* aio_comp,
1e59de90
TL
74 Extents&& image_extents, ImageArea area, SnapIds&& snap_ids,
75 int list_snaps_flags, SnapshotDelta* snapshot_delta,
76 const ZTracer::Trace& parent_trace) {
f67539c2
TL
77 ceph_assert(s_instance != nullptr);
78 s_instance->aio_comp = aio_comp;
79 s_instance->image_extents = image_extents;
80 s_instance->snapshot_delta = snapshot_delta;
81 }
82
83
84 MOCK_METHOD0(execute_send, void());
85 void send() {
86 ceph_assert(s_instance != nullptr);
87 s_instance->execute_send();
88 }
89};
90
91ImageListSnapsRequest<librbd::MockTestImageCtx>* ImageListSnapsRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
92
f91f0fd5
TL
93namespace util {
94
1e59de90
TL
95template <>
96void area_to_object_extents(MockTestImageCtx* image_ctx, uint64_t offset,
97 uint64_t length, ImageArea area,
98 uint64_t buffer_offset,
99 striper::LightweightObjectExtents* object_extents) {
f67539c2
TL
100 Striper::file_to_extents(image_ctx->cct, &image_ctx->layout, offset, length,
101 0, buffer_offset, object_extents);
102}
103
1e59de90
TL
104template <>
105std::pair<Extents, ImageArea> object_to_area_extents(
106 MockTestImageCtx* image_ctx, uint64_t object_no,
107 const Extents& object_extents) {
108 Extents extents;
109 for (auto [off, len] : object_extents) {
110 Striper::extent_to_file(image_ctx->cct, &image_ctx->layout, object_no, off,
111 len, extents);
112 }
113 return {std::move(extents), ImageArea::DATA};
f67539c2
TL
114}
115
f91f0fd5 116namespace {
b32b8144 117
f91f0fd5
TL
118struct Mock {
119 static Mock* s_instance;
120
121 Mock() {
b32b8144
FG
122 s_instance = this;
123 }
f91f0fd5 124
f67539c2
TL
125 MOCK_METHOD6(read_parent,
126 void(librbd::MockTestImageCtx *, uint64_t, ReadExtents*,
127 librados::snap_t, const ZTracer::Trace &, Context*));
b32b8144
FG
128};
129
f91f0fd5
TL
130Mock *Mock::s_instance = nullptr;
131
132} // anonymous namespace
133
134template<> void read_parent(
f67539c2
TL
135 librbd::MockTestImageCtx *image_ctx, uint64_t object_no,
136 ReadExtents* extents, librados::snap_t snap_id,
137 const ZTracer::Trace &trace, Context* on_finish) {
138 Mock::s_instance->read_parent(image_ctx, object_no, extents, snap_id, trace,
139 on_finish);
f91f0fd5
TL
140}
141
142} // namespace util
b32b8144
FG
143
144} // namespace io
145} // namespace librbd
146
147#include "librbd/io/ObjectRequest.cc"
148
149namespace librbd {
150namespace io {
151
152using ::testing::_;
153using ::testing::DoDefault;
154using ::testing::InSequence;
155using ::testing::Invoke;
156using ::testing::Return;
157using ::testing::WithArg;
158using ::testing::WithArgs;
159
160struct TestMockIoObjectRequest : public TestMockFixture {
161 typedef ObjectRequest<librbd::MockTestImageCtx> MockObjectRequest;
162 typedef ObjectReadRequest<librbd::MockTestImageCtx> MockObjectReadRequest;
163 typedef ObjectWriteRequest<librbd::MockTestImageCtx> MockObjectWriteRequest;
164 typedef ObjectDiscardRequest<librbd::MockTestImageCtx> MockObjectDiscardRequest;
165 typedef ObjectWriteSameRequest<librbd::MockTestImageCtx> MockObjectWriteSameRequest;
166 typedef ObjectCompareAndWriteRequest<librbd::MockTestImageCtx> MockObjectCompareAndWriteRequest;
f67539c2 167 typedef ObjectListSnapsRequest<librbd::MockTestImageCtx> MockObjectListSnapsRequest;
b32b8144
FG
168 typedef AbstractObjectWriteRequest<librbd::MockTestImageCtx> MockAbstractObjectWriteRequest;
169 typedef CopyupRequest<librbd::MockTestImageCtx> MockCopyupRequest;
f67539c2 170 typedef ImageListSnapsRequest<librbd::MockTestImageCtx> MockImageListSnapsRequest;
f91f0fd5 171 typedef util::Mock MockUtils;
b32b8144
FG
172
173 void expect_object_may_exist(MockTestImageCtx &mock_image_ctx,
174 uint64_t object_no, bool exists) {
175 if (mock_image_ctx.object_map != nullptr) {
176 EXPECT_CALL(*mock_image_ctx.object_map, object_may_exist(object_no))
177 .WillOnce(Return(exists));
178 }
179 }
180
181 void expect_get_object_size(MockTestImageCtx &mock_image_ctx) {
182 EXPECT_CALL(mock_image_ctx, get_object_size()).WillRepeatedly(Return(
183 mock_image_ctx.layout.object_size));
184 }
185
186 void expect_get_parent_overlap(MockTestImageCtx &mock_image_ctx,
187 librados::snap_t snap_id, uint64_t overlap,
188 int r) {
189 EXPECT_CALL(mock_image_ctx, get_parent_overlap(snap_id, _))
190 .WillOnce(WithArg<1>(Invoke([overlap, r](uint64_t *o) {
191 *o = overlap;
192 return r;
193 })));
194 }
195
196 void expect_prune_parent_extents(MockTestImageCtx &mock_image_ctx,
197 const Extents& extents,
198 uint64_t overlap, uint64_t object_overlap) {
1e59de90 199 EXPECT_CALL(mock_image_ctx, prune_parent_extents(_, _, overlap, _))
b32b8144
FG
200 .WillOnce(WithArg<0>(Invoke([extents, object_overlap](Extents& e) {
201 e = extents;
202 return object_overlap;
203 })));
204 }
205
206 void expect_get_read_flags(MockTestImageCtx &mock_image_ctx,
207 librados::snap_t snap_id, int flags) {
208 EXPECT_CALL(mock_image_ctx, get_read_flags(snap_id))
209 .WillOnce(Return(flags));
210 }
211
212 void expect_is_lock_owner(MockExclusiveLock& mock_exclusive_lock) {
213 EXPECT_CALL(mock_exclusive_lock, is_lock_owner()).WillRepeatedly(
214 Return(true));
215 }
216
217 void expect_read(MockTestImageCtx &mock_image_ctx,
218 const std::string& oid, uint64_t off, uint64_t len,
219 const std::string& data, int r) {
220 bufferlist bl;
221 bl.append(data);
222
f67539c2
TL
223 auto& mock_io_ctx = librados::get_mock_io_ctx(
224 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
225 auto& expect = EXPECT_CALL(mock_io_ctx, read(oid, len, off, _, _, _));
b32b8144
FG
226 if (r < 0) {
227 expect.WillOnce(Return(r));
228 } else {
229 expect.WillOnce(WithArg<3>(Invoke([bl](bufferlist *out_bl) {
230 out_bl->append(bl);
231 return bl.length();
232 })));
233 }
234 }
235
236 void expect_sparse_read(MockTestImageCtx &mock_image_ctx,
237 const std::string& oid, uint64_t off, uint64_t len,
238 const std::string& data, int r) {
239 bufferlist bl;
240 bl.append(data);
241
f67539c2
TL
242 auto& mock_io_ctx = librados::get_mock_io_ctx(
243 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
244 auto& expect = EXPECT_CALL(mock_io_ctx,
245 sparse_read(oid, off, len, _, _, _));
b32b8144
FG
246 if (r < 0) {
247 expect.WillOnce(Return(r));
248 } else {
249 expect.WillOnce(WithArg<4>(Invoke([bl](bufferlist *out_bl) {
250 out_bl->append(bl);
251 return bl.length();
252 })));
253 }
254 }
255
f91f0fd5 256 void expect_read_parent(MockUtils &mock_utils, uint64_t object_no,
f67539c2 257 ReadExtents* extents, librados::snap_t snap_id,
f91f0fd5
TL
258 int r) {
259 EXPECT_CALL(mock_utils,
f67539c2
TL
260 read_parent(_, object_no, extents, snap_id, _, _))
261 .WillOnce(WithArg<5>(CompleteContext(r, static_cast<asio::ContextWQ*>(nullptr))));
b32b8144
FG
262 }
263
264 void expect_copyup(MockCopyupRequest& mock_copyup_request, int r) {
265 EXPECT_CALL(mock_copyup_request, send())
11fdf7f2 266 .WillOnce(Invoke([]() {}));
b32b8144
FG
267 }
268
269 void expect_copyup(MockCopyupRequest& mock_copyup_request,
270 MockAbstractObjectWriteRequest** write_request, int r) {
f67539c2
TL
271 EXPECT_CALL(mock_copyup_request, append_request(_, _))
272 .WillOnce(WithArg<0>(
273 Invoke([write_request](MockAbstractObjectWriteRequest *req) {
274 *write_request = req;
275 })));
b32b8144
FG
276 EXPECT_CALL(mock_copyup_request, send())
277 .WillOnce(Invoke([write_request, r]() {
278 (*write_request)->handle_copyup(r);
279 }));
280 }
281
282 void expect_object_map_update(MockTestImageCtx &mock_image_ctx,
283 uint64_t start_object, uint64_t end_object,
284 uint8_t state,
285 const boost::optional<uint8_t> &current_state,
286 bool updated, int ret_val) {
287 if (mock_image_ctx.object_map != nullptr) {
288 EXPECT_CALL(*mock_image_ctx.object_map,
289 aio_update(CEPH_NOSNAP, start_object, end_object, state,
91327a77
AA
290 current_state, _, false, _))
291 .WillOnce(WithArg<7>(Invoke([&mock_image_ctx, updated, ret_val](Context *ctx) {
b32b8144
FG
292 if (updated) {
293 mock_image_ctx.op_work_queue->queue(ctx, ret_val);
294 }
295 return updated;
296 })));
297 }
298 }
299
300 void expect_assert_exists(MockTestImageCtx &mock_image_ctx, int r) {
f67539c2
TL
301 auto& mock_io_ctx = librados::get_mock_io_ctx(
302 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
303 EXPECT_CALL(mock_io_ctx, assert_exists(_, _))
b32b8144
FG
304 .WillOnce(Return(r));
305 }
306
307 void expect_write(MockTestImageCtx &mock_image_ctx,
308 uint64_t offset, uint64_t length, int r) {
f67539c2
TL
309 auto& mock_io_ctx = librados::get_mock_io_ctx(
310 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
311 auto &expect = EXPECT_CALL(mock_io_ctx,
b32b8144
FG
312 write(_, _, length, offset, _));
313 if (r < 0) {
314 expect.WillOnce(Return(r));
315 } else {
316 expect.WillOnce(DoDefault());
317 }
318 }
319
320 void expect_write_full(MockTestImageCtx &mock_image_ctx, int r) {
f67539c2
TL
321 auto& mock_io_ctx = librados::get_mock_io_ctx(
322 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
323 auto &expect = EXPECT_CALL(mock_io_ctx, write_full(_, _, _));
b32b8144
FG
324 if (r < 0) {
325 expect.WillOnce(Return(r));
326 } else {
327 expect.WillOnce(DoDefault());
328 }
329 }
330
331 void expect_writesame(MockTestImageCtx &mock_image_ctx,
332 uint64_t offset, uint64_t length, int r) {
f67539c2
TL
333 auto& mock_io_ctx = librados::get_mock_io_ctx(
334 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
335 auto &expect = EXPECT_CALL(mock_io_ctx, writesame(_, _, length, offset, _));
b32b8144
FG
336 if (r < 0) {
337 expect.WillOnce(Return(r));
338 } else {
339 expect.WillOnce(DoDefault());
340 }
341 }
342
343 void expect_remove(MockTestImageCtx &mock_image_ctx, int r) {
f67539c2
TL
344 auto& mock_io_ctx = librados::get_mock_io_ctx(
345 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
346 auto &expect = EXPECT_CALL(mock_io_ctx, remove(_, _));
b32b8144
FG
347 if (r < 0) {
348 expect.WillOnce(Return(r));
349 } else {
350 expect.WillOnce(DoDefault());
351 }
352 }
353
94b18763 354 void expect_create(MockTestImageCtx &mock_image_ctx, bool exclusive) {
f67539c2
TL
355 auto& mock_io_ctx = librados::get_mock_io_ctx(
356 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
357 EXPECT_CALL(mock_io_ctx, create(_, exclusive, _))
94b18763
FG
358 .Times(1);
359 }
360
b32b8144 361 void expect_truncate(MockTestImageCtx &mock_image_ctx, int offset, int r) {
f67539c2
TL
362 auto& mock_io_ctx = librados::get_mock_io_ctx(
363 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
364 auto &expect = EXPECT_CALL(mock_io_ctx, truncate(_, offset, _));
b32b8144
FG
365 if (r < 0) {
366 expect.WillOnce(Return(r));
367 } else {
368 expect.WillOnce(DoDefault());
369 }
370 }
371
372 void expect_zero(MockTestImageCtx &mock_image_ctx, int offset, int length,
373 int r) {
f67539c2
TL
374 auto& mock_io_ctx = librados::get_mock_io_ctx(
375 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
376 auto &expect = EXPECT_CALL(mock_io_ctx, zero(_, offset, length, _));
b32b8144
FG
377 if (r < 0) {
378 expect.WillOnce(Return(r));
379 } else {
380 expect.WillOnce(DoDefault());
381 }
382 }
383
384 void expect_cmpext(MockTestImageCtx &mock_image_ctx, int offset, int r) {
f67539c2
TL
385 auto& mock_io_ctx = librados::get_mock_io_ctx(
386 mock_image_ctx.rados_api, *mock_image_ctx.get_data_io_context());
387 auto &expect = EXPECT_CALL(mock_io_ctx, cmpext(_, offset, _, _));
b32b8144
FG
388 if (r < 0) {
389 expect.WillOnce(Return(r));
390 } else {
391 expect.WillOnce(DoDefault());
392 }
393 }
f67539c2
TL
394
395 void expect_list_snaps(MockTestImageCtx &mock_image_ctx,
396 const librados::snap_set_t& snap_set, int r) {
397 auto io_context = *mock_image_ctx.get_data_io_context();
398 io_context.read_snap(CEPH_SNAPDIR);
399 auto& mock_io_ctx = librados::get_mock_io_ctx(mock_image_ctx.rados_api,
400 io_context);
401 EXPECT_CALL(mock_io_ctx, list_snaps(_, _))
402 .WillOnce(WithArg<1>(Invoke(
403 [snap_set, r](librados::snap_set_t* out_snap_set) {
404 *out_snap_set = snap_set;
405 return r;
406 })));
407 }
408
409 void expect_image_list_snaps(MockImageListSnapsRequest& req,
410 const Extents& image_extents,
411 const SnapshotDelta& image_snapshot_delta,
412 int r) {
413 EXPECT_CALL(req, execute_send())
414 .WillOnce(Invoke(
415 [&req, image_extents, image_snapshot_delta, r]() {
416 ASSERT_EQ(image_extents, req.image_extents);
417 *req.snapshot_delta = image_snapshot_delta;
418
419 auto aio_comp = req.aio_comp;
420 aio_comp->set_request_count(1);
421 aio_comp->add_request();
422 aio_comp->complete_request(r);
423 }));
424 }
b32b8144
FG
425};
426
427TEST_F(TestMockIoObjectRequest, Read) {
428 librbd::ImageCtx *ictx;
429 ASSERT_EQ(0, open_image(m_image_name, &ictx));
430 ictx->sparse_read_threshold_bytes = 8096;
431
432 MockTestImageCtx mock_image_ctx(*ictx);
b32b8144
FG
433
434 MockObjectMap mock_object_map;
435 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
436 mock_image_ctx.object_map = &mock_object_map;
437 }
438
439 InSequence seq;
440 expect_object_may_exist(mock_image_ctx, 0, true);
441 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
442 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096,
443 std::string(4096, '1'), 0);
f67539c2
TL
444 expect_read(mock_image_ctx, ictx->get_object_name(0), 8192, 4096,
445 std::string(4096, '2'), 0);
b32b8144
FG
446
447 C_SaferCond ctx;
f67539c2
TL
448 uint64_t version;
449 ReadExtents extents = {{0, 4096}, {8192, 4096}};
b32b8144 450 auto req = MockObjectReadRequest::create(
f67539c2
TL
451 &mock_image_ctx, 0, &extents,
452 mock_image_ctx.get_data_io_context(), 0, 0, {},
453 &version, &ctx);
b32b8144
FG
454 req->send();
455 ASSERT_EQ(0, ctx.wait());
f67539c2
TL
456
457 bufferlist expected_bl1;
458 expected_bl1.append(std::string(4096, '1'));
459 bufferlist expected_bl2;
460 expected_bl2.append(std::string(4096, '2'));
461
462 ASSERT_EQ(extents[0].extent_map.size(), 0);
463 ASSERT_EQ(extents[1].extent_map.size(), 0);
464 ASSERT_TRUE(extents[0].bl.contents_equal(expected_bl1));
465 ASSERT_TRUE(extents[1].bl.contents_equal(expected_bl2));
b32b8144
FG
466}
467
468TEST_F(TestMockIoObjectRequest, SparseReadThreshold) {
469 librbd::ImageCtx *ictx;
470 ASSERT_EQ(0, open_image(m_image_name, &ictx));
471 ictx->sparse_read_threshold_bytes = ictx->get_object_size();
472
473 MockTestImageCtx mock_image_ctx(*ictx);
b32b8144
FG
474
475 MockObjectMap mock_object_map;
476 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
477 mock_image_ctx.object_map = &mock_object_map;
478 }
479
480 InSequence seq;
481 expect_object_may_exist(mock_image_ctx, 0, true);
482 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
483 expect_sparse_read(mock_image_ctx, ictx->get_object_name(0), 0,
484 ictx->sparse_read_threshold_bytes,
485 std::string(ictx->sparse_read_threshold_bytes, '1'), 0);
486
487 C_SaferCond ctx;
f67539c2
TL
488
489 ReadExtents extents = {{0, ictx->sparse_read_threshold_bytes}};
b32b8144 490 auto req = MockObjectReadRequest::create(
f67539c2
TL
491 &mock_image_ctx, 0, &extents,
492 mock_image_ctx.get_data_io_context(), 0, 0, {}, nullptr, &ctx);
b32b8144
FG
493 req->send();
494 ASSERT_EQ(0, ctx.wait());
495}
496
497TEST_F(TestMockIoObjectRequest, ReadError) {
498 librbd::ImageCtx *ictx;
499 ASSERT_EQ(0, open_image(m_image_name, &ictx));
500 ictx->sparse_read_threshold_bytes = 8096;
501
502 MockTestImageCtx mock_image_ctx(*ictx);
b32b8144
FG
503
504 MockObjectMap mock_object_map;
505 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
506 mock_image_ctx.object_map = &mock_object_map;
507 }
508
509 InSequence seq;
510 expect_object_may_exist(mock_image_ctx, 0, true);
511 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
512 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -EPERM);
513
514 C_SaferCond ctx;
f67539c2 515 ReadExtents extents = {{0, 4096}};
b32b8144 516 auto req = MockObjectReadRequest::create(
f67539c2
TL
517 &mock_image_ctx, 0, &extents,
518 mock_image_ctx.get_data_io_context(), 0, 0, {},
519 nullptr, &ctx);
b32b8144
FG
520 req->send();
521 ASSERT_EQ(-EPERM, ctx.wait());
522}
523
524TEST_F(TestMockIoObjectRequest, ParentRead) {
525 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
526
527 librbd::Image image;
528 librbd::RBD rbd;
529 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
530 ASSERT_EQ(0, image.snap_create("one"));
531 ASSERT_EQ(0, image.snap_protect("one"));
532 image.close();
533
534 std::string clone_name = get_temp_image_name();
535 int order = 0;
536 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
537 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
538
539 librbd::ImageCtx *ictx;
540 ASSERT_EQ(0, open_image(clone_name, &ictx));
541 ictx->sparse_read_threshold_bytes = 8096;
542 ictx->clone_copy_on_read = false;
543
544 MockTestImageCtx mock_image_ctx(*ictx);
545 mock_image_ctx.parent = &mock_image_ctx;
b32b8144
FG
546
547 MockObjectMap mock_object_map;
548 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
549 mock_image_ctx.object_map = &mock_object_map;
550 }
551
552 InSequence seq;
553 expect_object_may_exist(mock_image_ctx, 0, true);
554 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
555 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
556
f91f0fd5 557 MockUtils mock_utils;
f67539c2
TL
558 ReadExtents extents = {{0, 4096}};
559 expect_read_parent(mock_utils, 0, &extents, CEPH_NOSNAP, 0);
b32b8144
FG
560
561 C_SaferCond ctx;
562 auto req = MockObjectReadRequest::create(
f67539c2
TL
563 &mock_image_ctx, 0, &extents,
564 mock_image_ctx.get_data_io_context(), 0, 0, {},
565 nullptr, &ctx);
b32b8144
FG
566 req->send();
567 ASSERT_EQ(0, ctx.wait());
568}
569
570TEST_F(TestMockIoObjectRequest, ParentReadError) {
571 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
572
573 librbd::Image image;
574 librbd::RBD rbd;
575 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
576 ASSERT_EQ(0, image.snap_create("one"));
577 ASSERT_EQ(0, image.snap_protect("one"));
578 image.close();
579
580 std::string clone_name = get_temp_image_name();
581 int order = 0;
582 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
583 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
584
585 librbd::ImageCtx *ictx;
586 ASSERT_EQ(0, open_image(clone_name, &ictx));
587 ictx->sparse_read_threshold_bytes = 8096;
588 ictx->clone_copy_on_read = false;
589
590 MockTestImageCtx mock_image_ctx(*ictx);
591 mock_image_ctx.parent = &mock_image_ctx;
b32b8144
FG
592
593 MockObjectMap mock_object_map;
594 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
595 mock_image_ctx.object_map = &mock_object_map;
596 }
597
598 InSequence seq;
599 expect_object_may_exist(mock_image_ctx, 0, true);
600 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
601 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
602
f91f0fd5 603 MockUtils mock_utils;
f67539c2
TL
604 ReadExtents extents = {{0, 4096}};
605 expect_read_parent(mock_utils, 0, &extents, CEPH_NOSNAP, -EPERM);
b32b8144
FG
606
607 C_SaferCond ctx;
608 auto req = MockObjectReadRequest::create(
f67539c2
TL
609 &mock_image_ctx, 0, &extents,
610 mock_image_ctx.get_data_io_context(), 0, 0, {},
611 nullptr, &ctx);
b32b8144
FG
612 req->send();
613 ASSERT_EQ(-EPERM, ctx.wait());
614}
615
f67539c2
TL
616TEST_F(TestMockIoObjectRequest, SkipParentRead) {
617 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
618
619 librbd::Image image;
620 librbd::RBD rbd;
621 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
622 ASSERT_EQ(0, image.snap_create("one"));
623 ASSERT_EQ(0, image.snap_protect("one"));
624 image.close();
625
626 std::string clone_name = get_temp_image_name();
627 int order = 0;
628 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
629 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
630
631 librbd::ImageCtx *ictx;
632 ASSERT_EQ(0, open_image(clone_name, &ictx));
633 ictx->sparse_read_threshold_bytes = 8096;
634 ictx->clone_copy_on_read = false;
635
636 MockTestImageCtx mock_image_ctx(*ictx);
637 mock_image_ctx.parent = &mock_image_ctx;
638
639 MockObjectMap mock_object_map;
640 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
641 mock_image_ctx.object_map = &mock_object_map;
642 }
643
644 InSequence seq;
645 expect_object_may_exist(mock_image_ctx, 0, true);
646 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
647 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
648
649 ReadExtents extents = {{0, 4096}};
650 C_SaferCond ctx;
651 auto req = MockObjectReadRequest::create(
652 &mock_image_ctx, 0, &extents, mock_image_ctx.get_data_io_context(), 0,
653 READ_FLAG_DISABLE_READ_FROM_PARENT, {}, nullptr, &ctx);
654 req->send();
655 ASSERT_EQ(-ENOENT, ctx.wait());
656}
657
b32b8144
FG
658TEST_F(TestMockIoObjectRequest, CopyOnRead) {
659 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
660
661 librbd::Image image;
662 librbd::RBD rbd;
663 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
664 ASSERT_EQ(0, image.snap_create("one"));
665 ASSERT_EQ(0, image.snap_protect("one"));
666 image.close();
667
668 std::string clone_name = get_temp_image_name();
669 int order = 0;
670 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
671 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
672
673 librbd::ImageCtx *ictx;
674 ASSERT_EQ(0, open_image(clone_name, &ictx));
675 ictx->sparse_read_threshold_bytes = 8096;
676 ictx->clone_copy_on_read = true;
677
678 MockTestImageCtx mock_image_ctx(*ictx);
679 mock_image_ctx.parent = &mock_image_ctx;
b32b8144
FG
680
681 MockObjectMap mock_object_map;
682 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
683 mock_image_ctx.object_map = &mock_object_map;
684 }
685
686 InSequence seq;
687 expect_object_may_exist(mock_image_ctx, 0, true);
688 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
689 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
690
f91f0fd5 691 MockUtils mock_utils;
f67539c2
TL
692 ReadExtents extents = {{0, 4096}};
693 expect_read_parent(mock_utils, 0, &extents, CEPH_NOSNAP, 0);
b32b8144
FG
694
695 MockCopyupRequest mock_copyup_request;
696 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
697 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
698 expect_copyup(mock_copyup_request, 0);
699
700 C_SaferCond ctx;
701 auto req = MockObjectReadRequest::create(
f67539c2
TL
702 &mock_image_ctx, 0, &extents,
703 mock_image_ctx.get_data_io_context(), 0, 0, {},
704 nullptr, &ctx);
b32b8144
FG
705 req->send();
706 ASSERT_EQ(0, ctx.wait());
707}
708
709TEST_F(TestMockIoObjectRequest, Write) {
710 librbd::ImageCtx *ictx;
711 ASSERT_EQ(0, open_image(m_image_name, &ictx));
712
713 MockTestImageCtx mock_image_ctx(*ictx);
714 expect_get_object_size(mock_image_ctx);
715
716 MockExclusiveLock mock_exclusive_lock;
717 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
718 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
719 expect_is_lock_owner(mock_exclusive_lock);
720 }
721
722 MockObjectMap mock_object_map;
723 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
724 mock_image_ctx.object_map = &mock_object_map;
725 }
726
727 bufferlist bl;
728 bl.append(std::string(4096, '1'));
729
730 InSequence seq;
731 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
732 expect_object_may_exist(mock_image_ctx, 0, true);
733 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
734 expect_write(mock_image_ctx, 0, 4096, 0);
735
736 C_SaferCond ctx;
737 auto req = MockObjectWriteRequest::create_write(
f67539c2
TL
738 &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.get_data_io_context(),
739 0, 0, std::nullopt, {}, &ctx);
b32b8144
FG
740 req->send();
741 ASSERT_EQ(0, ctx.wait());
742}
743
f67539c2
TL
744TEST_F(TestMockIoObjectRequest, WriteWithCreateExclusiveFlag) {
745 librbd::ImageCtx *ictx;
746 ASSERT_EQ(0, open_image(m_image_name, &ictx));
747
748 MockTestImageCtx mock_image_ctx(*ictx);
749 expect_get_object_size(mock_image_ctx);
750
751 MockExclusiveLock mock_exclusive_lock;
752 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
753 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
754 expect_is_lock_owner(mock_exclusive_lock);
755 }
756
757 MockObjectMap mock_object_map;
758 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
759 mock_image_ctx.object_map = &mock_object_map;
760 }
761
762 // exclusive create should succeed
763 {
764 bufferlist bl;
765 bl.append(std::string(4096, '1'));
766
767 InSequence seq;
768 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
769 expect_object_may_exist(mock_image_ctx, 0, true);
770 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false,
771 0);
772 expect_write(mock_image_ctx, 0, 4096, 0);
773
774 C_SaferCond ctx;
775 auto req = MockObjectWriteRequest::create_write(
776 &mock_image_ctx, 0, 0, std::move(bl),
777 mock_image_ctx.get_data_io_context(), 0,
778 OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE, std::nullopt, {}, &ctx);
779 req->send();
780 ASSERT_EQ(0, ctx.wait());
781 }
782
783 // exclusive create should fail since object already exists
784 {
785 bufferlist bl;
786 bl.append(std::string(4096, '1'));
787
788 InSequence seq;
789 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
790 expect_object_may_exist(mock_image_ctx, 0, true);
791 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false,
792 0);
793
794 C_SaferCond ctx;
795 auto req = MockObjectWriteRequest::create_write(
796 &mock_image_ctx, 0, 0, std::move(bl),
797 mock_image_ctx.get_data_io_context(), 0,
798 OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE, std::nullopt, {}, &ctx);
799 req->send();
800 ASSERT_EQ(-EEXIST, ctx.wait());
801 }
802}
803
804TEST_F(TestMockIoObjectRequest, WriteWithAssertVersion) {
805 librbd::ImageCtx *ictx;
806 ASSERT_EQ(0, open_image(m_image_name, &ictx));
807
808 MockTestImageCtx mock_image_ctx(*ictx);
809 expect_get_object_size(mock_image_ctx);
810
811 MockExclusiveLock mock_exclusive_lock;
812 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
813 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
814 expect_is_lock_owner(mock_exclusive_lock);
815 }
816
817 MockObjectMap mock_object_map;
818 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
819 mock_image_ctx.object_map = &mock_object_map;
820 }
821
822 // write an object
823 {
824 bufferlist bl;
825 bl.append(std::string(4096, '1'));
826
827 InSequence seq;
828 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
829 expect_object_may_exist(mock_image_ctx, 0, true);
830 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false,
831 0);
832 expect_write(mock_image_ctx, 0, 4096, 0);
833
834 C_SaferCond ctx;
835 auto req = MockObjectWriteRequest::create_write(
836 &mock_image_ctx, 0, 0, std::move(bl),
837 mock_image_ctx.get_data_io_context(), 0, 0,
838 std::nullopt, {}, &ctx);
839 req->send();
840 ASSERT_EQ(0, ctx.wait());
841 }
842
843 // assert version should succeed (version = 1)
844 {
845 bufferlist bl;
846 bl.append(std::string(4096, '1'));
847
848 InSequence seq;
849 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
850 expect_object_may_exist(mock_image_ctx, 0, true);
851 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false,
852 0);
853 expect_write(mock_image_ctx, 0, 4096, 0);
854
855 C_SaferCond ctx;
856 auto req = MockObjectWriteRequest::create_write(
857 &mock_image_ctx, 0, 0, std::move(bl),
858 mock_image_ctx.get_data_io_context(), 0, 0,
859 std::make_optional(1), {}, &ctx);
860 req->send();
861 ASSERT_EQ(0, ctx.wait());
862 }
863
864 // assert with wrong (lower) version (version = 2)
865 {
866 bufferlist bl;
867 bl.append(std::string(4096, '1'));
868
869 InSequence seq;
870 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
871 expect_object_may_exist(mock_image_ctx, 0, true);
872 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false,
873 0);
874
875 C_SaferCond ctx;
876 auto req = MockObjectWriteRequest::create_write(
877 &mock_image_ctx, 0, 0, std::move(bl),
878 mock_image_ctx.get_data_io_context(), 0, 0,
879 std::make_optional(1), {}, &ctx);
880 req->send();
881 ASSERT_EQ(-ERANGE, ctx.wait());
882 }
883
884 // assert with wrong (higher) version (version = 2)
885 {
886 bufferlist bl;
887 bl.append(std::string(4096, '1'));
888
889 InSequence seq;
890 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
891 expect_object_may_exist(mock_image_ctx, 0, true);
892 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false,
893 0);
894
895 C_SaferCond ctx;
896 auto req = MockObjectWriteRequest::create_write(
897 &mock_image_ctx, 0, 0, std::move(bl),
898 mock_image_ctx.get_data_io_context(), 0, 0, std::make_optional(3),
899 {}, &ctx);
900 req->send();
901 ASSERT_EQ(-EOVERFLOW, ctx.wait());
902 }
903}
904
b32b8144
FG
905TEST_F(TestMockIoObjectRequest, WriteFull) {
906 librbd::ImageCtx *ictx;
907 ASSERT_EQ(0, open_image(m_image_name, &ictx));
908
909 MockTestImageCtx mock_image_ctx(*ictx);
910 expect_get_object_size(mock_image_ctx);
911
912 MockExclusiveLock mock_exclusive_lock;
913 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
914 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
915 expect_is_lock_owner(mock_exclusive_lock);
916 }
917
918 MockObjectMap mock_object_map;
919 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
920 mock_image_ctx.object_map = &mock_object_map;
921 }
922
923 bufferlist bl;
924 bl.append(std::string(ictx->get_object_size(), '1'));
925
926 InSequence seq;
927 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
928 expect_object_may_exist(mock_image_ctx, 0, true);
929 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
930 expect_write_full(mock_image_ctx, 0);
931
932 C_SaferCond ctx;
933 auto req = MockObjectWriteRequest::create_write(
f67539c2
TL
934 &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.get_data_io_context(),
935 0, 0, std::nullopt, {}, &ctx);
b32b8144
FG
936 req->send();
937 ASSERT_EQ(0, ctx.wait());
938}
939
940TEST_F(TestMockIoObjectRequest, WriteObjectMap) {
941 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
942
943 librbd::ImageCtx *ictx;
944 ASSERT_EQ(0, open_image(m_image_name, &ictx));
945
946 MockTestImageCtx mock_image_ctx(*ictx);
947 expect_op_work_queue(mock_image_ctx);
948 expect_get_object_size(mock_image_ctx);
949
950 MockExclusiveLock mock_exclusive_lock;
951 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
952 expect_is_lock_owner(mock_exclusive_lock);
953
954 MockObjectMap mock_object_map;
955 mock_image_ctx.object_map = &mock_object_map;
956
957 bufferlist bl;
958 bl.append(std::string(4096, '1'));
959
960 InSequence seq;
961 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
962 expect_object_may_exist(mock_image_ctx, 0, true);
963 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, true, 0);
964 expect_write(mock_image_ctx, 0, 4096, 0);
965
966 C_SaferCond ctx;
967 auto req = MockObjectWriteRequest::create_write(
f67539c2
TL
968 &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.get_data_io_context(),
969 0, 0, std::nullopt, {}, &ctx);
b32b8144
FG
970 req->send();
971 ASSERT_EQ(0, ctx.wait());
972}
973
974TEST_F(TestMockIoObjectRequest, WriteError) {
975 librbd::ImageCtx *ictx;
976 ASSERT_EQ(0, open_image(m_image_name, &ictx));
977
978 MockTestImageCtx mock_image_ctx(*ictx);
979 expect_get_object_size(mock_image_ctx);
980
981 bufferlist bl;
982 bl.append(std::string(4096, '1'));
983
984 InSequence seq;
985 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
986 expect_write(mock_image_ctx, 0, 4096, -EPERM);
987
988 C_SaferCond ctx;
989 auto req = MockObjectWriteRequest::create_write(
f67539c2
TL
990 &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.get_data_io_context(),
991 0, 0, std::nullopt, {}, &ctx);
b32b8144
FG
992 req->send();
993 ASSERT_EQ(-EPERM, ctx.wait());
994}
995
996TEST_F(TestMockIoObjectRequest, Copyup) {
997 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
998
999 librbd::Image image;
1000 librbd::RBD rbd;
1001 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
1002 ASSERT_EQ(0, image.snap_create("one"));
1003 ASSERT_EQ(0, image.snap_protect("one"));
1004 image.close();
1005
1006 std::string clone_name = get_temp_image_name();
1007 int order = 0;
1008 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
1009 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
1010
1011 librbd::ImageCtx *ictx;
1012 ASSERT_EQ(0, open_image(clone_name, &ictx));
1013
1014 MockTestImageCtx mock_image_ctx(*ictx);
1015 expect_get_object_size(mock_image_ctx);
1016
1017 MockExclusiveLock mock_exclusive_lock;
1018 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1019 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1020 expect_is_lock_owner(mock_exclusive_lock);
1021 }
1022
1023 MockObjectMap mock_object_map;
1024 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1025 mock_image_ctx.object_map = &mock_object_map;
1026 }
1027
1028 bufferlist bl;
1029 bl.append(std::string(4096, '1'));
1030
1031 InSequence seq;
1032 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
1033 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
1034 expect_object_may_exist(mock_image_ctx, 0, true);
1035 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1036 expect_assert_exists(mock_image_ctx, -ENOENT);
1037
1038 MockAbstractObjectWriteRequest *write_request = nullptr;
1039 MockCopyupRequest mock_copyup_request;
1040 expect_copyup(mock_copyup_request, &write_request, 0);
1041
1042 C_SaferCond ctx;
1043 auto req = MockObjectWriteRequest::create_write(
f67539c2
TL
1044 &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.get_data_io_context(),
1045 0, 0, std::nullopt, {}, &ctx);
b32b8144
FG
1046 req->send();
1047 ASSERT_EQ(0, ctx.wait());
1048}
1049
81eedcae
TL
1050TEST_F(TestMockIoObjectRequest, CopyupRestart) {
1051 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1052
1053 librbd::Image image;
1054 librbd::RBD rbd;
1055 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
1056 ASSERT_EQ(0, image.snap_create("one"));
1057 ASSERT_EQ(0, image.snap_protect("one"));
1058 image.close();
1059
1060 std::string clone_name = get_temp_image_name();
1061 int order = 0;
1062 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
1063 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
1064
1065 librbd::ImageCtx *ictx;
1066 ASSERT_EQ(0, open_image(clone_name, &ictx));
1067
1068 MockTestImageCtx mock_image_ctx(*ictx);
1069 expect_get_object_size(mock_image_ctx);
1070
1071 MockExclusiveLock mock_exclusive_lock;
1072 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1073 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1074 expect_is_lock_owner(mock_exclusive_lock);
1075 }
1076
1077 MockObjectMap mock_object_map;
1078 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1079 mock_image_ctx.object_map = &mock_object_map;
1080 }
1081
1082 bufferlist bl;
1083 bl.append(std::string(4096, '1'));
1084
1085 InSequence seq;
1086 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
1087 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
1088 expect_object_may_exist(mock_image_ctx, 0, true);
1089 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1090 expect_assert_exists(mock_image_ctx, -ENOENT);
1091
1092 MockAbstractObjectWriteRequest *write_request = nullptr;
1093 MockCopyupRequest mock_copyup_request;
1094 expect_copyup(mock_copyup_request, &write_request, -ERESTART);
1095 expect_assert_exists(mock_image_ctx, 0);
1096 expect_write(mock_image_ctx, 0, 4096, 0);
1097
1098 C_SaferCond ctx;
1099 auto req = MockObjectWriteRequest::create_write(
f67539c2
TL
1100 &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.get_data_io_context(),
1101 0, 0, std::nullopt, {}, &ctx);
81eedcae
TL
1102 req->send();
1103 ASSERT_EQ(0, ctx.wait());
1104}
1105
b32b8144
FG
1106TEST_F(TestMockIoObjectRequest, CopyupOptimization) {
1107 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_OBJECT_MAP);
1108
1109 librbd::Image image;
1110 librbd::RBD rbd;
1111 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
1112 ASSERT_EQ(0, image.snap_create("one"));
1113 ASSERT_EQ(0, image.snap_protect("one"));
1114 image.close();
1115
1116 std::string clone_name = get_temp_image_name();
1117 int order = 0;
1118 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
1119 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
1120
1121 librbd::ImageCtx *ictx;
1122 ASSERT_EQ(0, open_image(clone_name, &ictx));
1123
1124 MockTestImageCtx mock_image_ctx(*ictx);
1125 expect_get_object_size(mock_image_ctx);
1126
1127 MockExclusiveLock mock_exclusive_lock;
1128 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1129 expect_is_lock_owner(mock_exclusive_lock);
1130
1131 MockObjectMap mock_object_map;
1132 mock_image_ctx.object_map = &mock_object_map;
1133
1134 bufferlist bl;
1135 bl.append(std::string(4096, '1'));
1136
1137 InSequence seq;
1138 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
1139 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
1140 expect_object_may_exist(mock_image_ctx, 0, false);
1141
1142 MockAbstractObjectWriteRequest *write_request = nullptr;
1143 MockCopyupRequest mock_copyup_request;
1144 expect_copyup(mock_copyup_request, &write_request, 0);
1145
1146 C_SaferCond ctx;
1147 auto req = MockObjectWriteRequest::create_write(
f67539c2
TL
1148 &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.get_data_io_context(),
1149 0, 0, std::nullopt, {}, &ctx);
b32b8144
FG
1150 req->send();
1151 ASSERT_EQ(0, ctx.wait());
1152}
1153
1154TEST_F(TestMockIoObjectRequest, CopyupError) {
1155 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1156
1157 librbd::Image image;
1158 librbd::RBD rbd;
1159 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
1160 ASSERT_EQ(0, image.snap_create("one"));
1161 ASSERT_EQ(0, image.snap_protect("one"));
1162 image.close();
1163
1164 std::string clone_name = get_temp_image_name();
1165 int order = 0;
1166 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
1167 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
1168
1169 librbd::ImageCtx *ictx;
1170 ASSERT_EQ(0, open_image(clone_name, &ictx));
1171
1172 MockTestImageCtx mock_image_ctx(*ictx);
1173 expect_get_object_size(mock_image_ctx);
1174
1175 bufferlist bl;
1176 bl.append(std::string(4096, '1'));
1177
1178 InSequence seq;
1179 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
1180 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
1181 expect_assert_exists(mock_image_ctx, -ENOENT);
1182
1183 MockAbstractObjectWriteRequest *write_request = nullptr;
1184 MockCopyupRequest mock_copyup_request;
1185 expect_copyup(mock_copyup_request, &write_request, -EPERM);
1186
1187 C_SaferCond ctx;
1188 auto req = MockObjectWriteRequest::create_write(
f67539c2
TL
1189 &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.get_data_io_context(),
1190 0, 0, std::nullopt, {}, &ctx);
b32b8144
FG
1191 req->send();
1192 ASSERT_EQ(-EPERM, ctx.wait());
1193}
1194
1195TEST_F(TestMockIoObjectRequest, DiscardRemove) {
1196 librbd::ImageCtx *ictx;
1197 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1198
1199 MockTestImageCtx mock_image_ctx(*ictx);
1200 expect_get_object_size(mock_image_ctx);
1201
1202 MockExclusiveLock mock_exclusive_lock;
1203 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1204 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1205 expect_is_lock_owner(mock_exclusive_lock);
1206 }
1207
1208 MockObjectMap mock_object_map;
1209 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1210 mock_image_ctx.object_map = &mock_object_map;
1211 }
1212
1213 InSequence seq;
1214 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1215 expect_object_may_exist(mock_image_ctx, 0, true);
1216 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_PENDING, {}, false, 0);
1217 expect_remove(mock_image_ctx, 0);
1218 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_NONEXISTENT,
1219 OBJECT_PENDING, false, 0);
1220
1221 C_SaferCond ctx;
1222 auto req = MockObjectDiscardRequest::create_discard(
9f95a23c 1223 &mock_image_ctx, 0, 0, mock_image_ctx.get_object_size(),
f67539c2 1224 mock_image_ctx.get_data_io_context(), 0, {}, &ctx);
b32b8144
FG
1225 req->send();
1226 ASSERT_EQ(0, ctx.wait());
1227}
1228
1229TEST_F(TestMockIoObjectRequest, DiscardRemoveTruncate) {
1230 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1231
1232 librbd::Image image;
1233 librbd::RBD rbd;
1234 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
1235 ASSERT_EQ(0, image.snap_create("one"));
1236 ASSERT_EQ(0, image.snap_protect("one"));
94b18763
FG
1237 uint64_t features;
1238 ASSERT_EQ(0, image.features(&features));
b32b8144
FG
1239 image.close();
1240
1241 std::string clone_name = get_temp_image_name();
1242 int order = 0;
1243 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
94b18763 1244 clone_name.c_str(), features, &order));
b32b8144
FG
1245
1246 librbd::ImageCtx *ictx;
1247 ASSERT_EQ(0, open_image(clone_name, &ictx));
1248
1249 MockTestImageCtx mock_image_ctx(*ictx);
1250 expect_get_object_size(mock_image_ctx);
1251
1252 MockExclusiveLock mock_exclusive_lock;
1253 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1254 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1255 expect_is_lock_owner(mock_exclusive_lock);
1256 }
1257
1258 MockObjectMap mock_object_map;
1259 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1260 mock_image_ctx.object_map = &mock_object_map;
1261 }
1262
1263 InSequence seq;
1264 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
1265 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
94b18763
FG
1266 expect_object_may_exist(mock_image_ctx, 0, false);
1267 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1268 expect_create(mock_image_ctx, false);
b32b8144
FG
1269 expect_truncate(mock_image_ctx, 0, 0);
1270
1271 C_SaferCond ctx;
1272 auto req = MockObjectDiscardRequest::create_discard(
9f95a23c 1273 &mock_image_ctx, 0, 0, mock_image_ctx.get_object_size(),
f67539c2
TL
1274 mock_image_ctx.get_data_io_context(),
1275 OBJECT_DISCARD_FLAG_DISABLE_CLONE_REMOVE, {}, &ctx);
11fdf7f2
TL
1276 req->send();
1277 ASSERT_EQ(0, ctx.wait());
1278}
1279
1280TEST_F(TestMockIoObjectRequest, DiscardTruncateAssertExists) {
1281 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1282
1283 librbd::Image image;
1284 librbd::RBD rbd;
1285 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
1286 ASSERT_EQ(0, image.snap_create("one"));
1287 ASSERT_EQ(0, image.snap_protect("one"));
1288 uint64_t features;
1289 ASSERT_EQ(0, image.features(&features));
1290 image.close();
1291
1292 std::string clone_name = get_temp_image_name();
1293 int order = 0;
1294 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
1295 clone_name.c_str(), features, &order));
1296 ASSERT_EQ(0, rbd.open(m_ioctx, image, clone_name.c_str(), NULL));
1297 ASSERT_EQ(0, image.snap_create("one"));
1298 image.close();
1299
1300 librbd::ImageCtx *ictx;
1301 ASSERT_EQ(0, open_image(clone_name, &ictx));
1302
1303 MockTestImageCtx mock_image_ctx(*ictx);
1304 expect_get_object_size(mock_image_ctx);
1305
1306 MockExclusiveLock mock_exclusive_lock;
1307 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1308 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1309 expect_is_lock_owner(mock_exclusive_lock);
1310 }
1311
1312 MockObjectMap mock_object_map;
1313 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1314 mock_image_ctx.object_map = &mock_object_map;
1315 }
1316
1317 InSequence seq;
1318 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
1319 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
1320 expect_object_may_exist(mock_image_ctx, 0, true);
1321 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1322 expect_assert_exists(mock_image_ctx, 0);
1323 expect_truncate(mock_image_ctx, 0, 0);
1324
9f95a23c
TL
1325 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx), create(_, _, _))
1326 .Times(0);
11fdf7f2
TL
1327
1328 C_SaferCond ctx;
1329 auto req = MockObjectDiscardRequest::create_discard(
9f95a23c 1330 &mock_image_ctx, 0, 0, mock_image_ctx.get_object_size(),
f67539c2
TL
1331 mock_image_ctx.get_data_io_context(),
1332 OBJECT_DISCARD_FLAG_DISABLE_CLONE_REMOVE, {}, &ctx);
b32b8144
FG
1333 req->send();
1334 ASSERT_EQ(0, ctx.wait());
1335}
1336
1337TEST_F(TestMockIoObjectRequest, DiscardTruncate) {
1338 librbd::ImageCtx *ictx;
1339 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1340
1341 MockTestImageCtx mock_image_ctx(*ictx);
1342 expect_get_object_size(mock_image_ctx);
1343
1344 MockExclusiveLock mock_exclusive_lock;
1345 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1346 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1347 expect_is_lock_owner(mock_exclusive_lock);
1348 }
1349
1350 MockObjectMap mock_object_map;
1351 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1352 mock_image_ctx.object_map = &mock_object_map;
1353 }
1354
1355 InSequence seq;
1356 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1357 expect_object_may_exist(mock_image_ctx, 0, true);
1358 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1359 expect_truncate(mock_image_ctx, 1, 0);
1360
9f95a23c
TL
1361 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx), create(_, _, _))
1362 .Times(0);
11fdf7f2 1363
b32b8144
FG
1364 C_SaferCond ctx;
1365 auto req = MockObjectDiscardRequest::create_discard(
9f95a23c 1366 &mock_image_ctx, 0, 1, mock_image_ctx.get_object_size() - 1,
f67539c2 1367 mock_image_ctx.get_data_io_context(), 0, {}, &ctx);
b32b8144
FG
1368 req->send();
1369 ASSERT_EQ(0, ctx.wait());
1370}
1371
1372TEST_F(TestMockIoObjectRequest, DiscardZero) {
1373 librbd::ImageCtx *ictx;
1374 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1375
1376 MockTestImageCtx mock_image_ctx(*ictx);
1377 expect_get_object_size(mock_image_ctx);
1378
1379 MockExclusiveLock mock_exclusive_lock;
1380 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1381 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1382 expect_is_lock_owner(mock_exclusive_lock);
1383 }
1384
1385 MockObjectMap mock_object_map;
1386 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1387 mock_image_ctx.object_map = &mock_object_map;
1388 }
1389
1390 InSequence seq;
1391 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1392 expect_object_may_exist(mock_image_ctx, 0, true);
1393 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1394 expect_zero(mock_image_ctx, 1, 1, 0);
1395
1396 C_SaferCond ctx;
1397 auto req = MockObjectDiscardRequest::create_discard(
f67539c2
TL
1398 &mock_image_ctx, 0, 1, 1, mock_image_ctx.get_data_io_context(), 0, {},
1399 &ctx);
b32b8144
FG
1400 req->send();
1401 ASSERT_EQ(0, ctx.wait());
1402}
1403
1404TEST_F(TestMockIoObjectRequest, DiscardDisableObjectMapUpdate) {
1405 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
1406
1407 librbd::ImageCtx *ictx;
1408 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1409
1410 MockTestImageCtx mock_image_ctx(*ictx);
1411 expect_get_object_size(mock_image_ctx);
1412
1413 MockExclusiveLock mock_exclusive_lock;
1414 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1415 expect_is_lock_owner(mock_exclusive_lock);
1416
1417 MockObjectMap mock_object_map;
1418 mock_image_ctx.object_map = &mock_object_map;
1419
1420 InSequence seq;
1421 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1422 expect_object_may_exist(mock_image_ctx, 0, true);
1423 expect_remove(mock_image_ctx, 0);
1424
1425 C_SaferCond ctx;
1426 auto req = MockObjectDiscardRequest::create_discard(
9f95a23c 1427 &mock_image_ctx, 0, 0, mock_image_ctx.get_object_size(),
f67539c2 1428 mock_image_ctx.get_data_io_context(),
11fdf7f2
TL
1429 OBJECT_DISCARD_FLAG_DISABLE_CLONE_REMOVE |
1430 OBJECT_DISCARD_FLAG_DISABLE_OBJECT_MAP_UPDATE, {}, &ctx);
b32b8144
FG
1431 req->send();
1432 ASSERT_EQ(0, ctx.wait());
1433}
1434
1435TEST_F(TestMockIoObjectRequest, DiscardNoOp) {
1436 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
1437
1438 librbd::ImageCtx *ictx;
1439 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1440
1441 MockTestImageCtx mock_image_ctx(*ictx);
1442 expect_op_work_queue(mock_image_ctx);
1443 expect_get_object_size(mock_image_ctx);
1444
1445 MockExclusiveLock mock_exclusive_lock;
1446 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1447 expect_is_lock_owner(mock_exclusive_lock);
1448
1449 MockObjectMap mock_object_map;
1450 mock_image_ctx.object_map = &mock_object_map;
1451
1452 InSequence seq;
1453 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1454 expect_object_may_exist(mock_image_ctx, 0, false);
1455
1456 C_SaferCond ctx;
1457 auto req = MockObjectDiscardRequest::create_discard(
9f95a23c 1458 &mock_image_ctx, 0, 0, mock_image_ctx.get_object_size(),
f67539c2 1459 mock_image_ctx.get_data_io_context(),
11fdf7f2
TL
1460 OBJECT_DISCARD_FLAG_DISABLE_CLONE_REMOVE |
1461 OBJECT_DISCARD_FLAG_DISABLE_OBJECT_MAP_UPDATE, {},
b32b8144
FG
1462 &ctx);
1463 req->send();
1464 ASSERT_EQ(0, ctx.wait());
1465}
1466
1467TEST_F(TestMockIoObjectRequest, WriteSame) {
1468 librbd::ImageCtx *ictx;
1469 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1470
1471 MockTestImageCtx mock_image_ctx(*ictx);
1472 expect_get_object_size(mock_image_ctx);
1473
1474 MockExclusiveLock mock_exclusive_lock;
1475 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1476 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1477 expect_is_lock_owner(mock_exclusive_lock);
1478 }
1479
1480 MockObjectMap mock_object_map;
1481 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1482 mock_image_ctx.object_map = &mock_object_map;
1483 }
1484
1485 bufferlist bl;
1486 bl.append(std::string(4096, '1'));
1487
1488 InSequence seq;
1489 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1490 expect_object_may_exist(mock_image_ctx, 0, true);
1491 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1492 expect_writesame(mock_image_ctx, 0, 4096, 0);
1493
1494 C_SaferCond ctx;
11fdf7f2 1495 auto req = MockObjectWriteSameRequest::create_write_same(
f67539c2
TL
1496 &mock_image_ctx, 0, 0, 4096, std::move(bl),
1497 mock_image_ctx.get_data_io_context(), 0, {}, &ctx);
b32b8144
FG
1498 req->send();
1499 ASSERT_EQ(0, ctx.wait());
1500}
1501
1502TEST_F(TestMockIoObjectRequest, CompareAndWrite) {
1503 librbd::ImageCtx *ictx;
1504 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1505
1506 MockTestImageCtx mock_image_ctx(*ictx);
1507 expect_get_object_size(mock_image_ctx);
1508
1509 MockExclusiveLock mock_exclusive_lock;
1510 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1511 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1512 expect_is_lock_owner(mock_exclusive_lock);
1513 }
1514
1515 MockObjectMap mock_object_map;
1516 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1517 mock_image_ctx.object_map = &mock_object_map;
1518 }
1519
1520 bufferlist cmp_bl;
1521 cmp_bl.append_zero(4096);
1522
1523 bufferlist bl;
1524 bl.append(std::string(4096, '1'));
1525
1526 InSequence seq;
1527 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1528 expect_object_may_exist(mock_image_ctx, 0, true);
1529 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1530 expect_cmpext(mock_image_ctx, 0, 0);
1531 expect_write(mock_image_ctx, 0, 4096, 0);
1532
1533 C_SaferCond ctx;
1534 uint64_t mismatch_offset;
1535 auto req = MockObjectWriteSameRequest::create_compare_and_write(
9f95a23c 1536 &mock_image_ctx, 0, 0, std::move(cmp_bl), std::move(bl),
f67539c2 1537 mock_image_ctx.get_data_io_context(), &mismatch_offset, 0, {}, &ctx);
b32b8144
FG
1538 req->send();
1539 ASSERT_EQ(0, ctx.wait());
1540}
1541
1542TEST_F(TestMockIoObjectRequest, CompareAndWriteFull) {
1543 librbd::ImageCtx *ictx;
1544 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1545
1546 MockTestImageCtx mock_image_ctx(*ictx);
1547 expect_get_object_size(mock_image_ctx);
1548
1549 MockExclusiveLock mock_exclusive_lock;
1550 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1551 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1552 expect_is_lock_owner(mock_exclusive_lock);
1553 }
1554
1555 MockObjectMap mock_object_map;
1556 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1557 mock_image_ctx.object_map = &mock_object_map;
1558 }
1559
1560 bufferlist cmp_bl;
1561 cmp_bl.append_zero(ictx->get_object_size());
1562
1563 bufferlist bl;
1564 bl.append(std::string(ictx->get_object_size(), '1'));
1565
1566 InSequence seq;
1567 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1568 expect_object_may_exist(mock_image_ctx, 0, true);
1569 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1570 expect_cmpext(mock_image_ctx, 0, 0);
1571 expect_write_full(mock_image_ctx, 0);
1572
1573 C_SaferCond ctx;
1574 uint64_t mismatch_offset;
1575 auto req = MockObjectWriteSameRequest::create_compare_and_write(
9f95a23c 1576 &mock_image_ctx, 0, 0, std::move(cmp_bl), std::move(bl),
f67539c2 1577 mock_image_ctx.get_data_io_context(), &mismatch_offset, 0, {}, &ctx);
b32b8144
FG
1578 req->send();
1579 ASSERT_EQ(0, ctx.wait());
1580}
1581
1582TEST_F(TestMockIoObjectRequest, CompareAndWriteCopyup) {
1583 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1584
1585 librbd::Image image;
1586 librbd::RBD rbd;
1587 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
1588 ASSERT_EQ(0, image.snap_create("one"));
1589 ASSERT_EQ(0, image.snap_protect("one"));
1590 image.close();
1591
1592 std::string clone_name = get_temp_image_name();
1593 int order = 0;
1594 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
1595 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
1596
1597 librbd::ImageCtx *ictx;
1598 ASSERT_EQ(0, open_image(clone_name, &ictx));
1599
1600 MockTestImageCtx mock_image_ctx(*ictx);
1601 expect_get_object_size(mock_image_ctx);
1602
1603 MockExclusiveLock mock_exclusive_lock;
1604 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1605 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1606 expect_is_lock_owner(mock_exclusive_lock);
1607 }
1608
1609 MockObjectMap mock_object_map;
1610 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1611 mock_image_ctx.object_map = &mock_object_map;
1612 }
1613
1614 bufferlist cmp_bl;
1615 cmp_bl.append_zero(4096);
1616
1617 bufferlist bl;
1618 bl.append(std::string(4096, '1'));
1619
1620 InSequence seq;
1621 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
1622 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
1623 expect_object_may_exist(mock_image_ctx, 0, true);
1624 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1625 expect_assert_exists(mock_image_ctx, -ENOENT);
1626
1627 MockAbstractObjectWriteRequest *write_request = nullptr;
1628 MockCopyupRequest mock_copyup_request;
1629 expect_copyup(mock_copyup_request, &write_request, 0);
1630
1631 expect_assert_exists(mock_image_ctx, 0);
1632 expect_cmpext(mock_image_ctx, 0, 0);
1633 expect_write(mock_image_ctx, 0, 4096, 0);
1634
1635 C_SaferCond ctx;
1636 uint64_t mismatch_offset;
1637 auto req = MockObjectWriteSameRequest::create_compare_and_write(
9f95a23c 1638 &mock_image_ctx, 0, 0, std::move(cmp_bl), std::move(bl),
f67539c2 1639 mock_image_ctx.get_data_io_context(), &mismatch_offset, 0, {}, &ctx);
b32b8144
FG
1640 req->send();
1641 ASSERT_EQ(0, ctx.wait());
1642}
1643
1644TEST_F(TestMockIoObjectRequest, CompareAndWriteMismatch) {
1645 librbd::ImageCtx *ictx;
1646 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1647
1648 MockTestImageCtx mock_image_ctx(*ictx);
1649 expect_get_object_size(mock_image_ctx);
1650
1651 MockExclusiveLock mock_exclusive_lock;
1652 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1653 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1654 expect_is_lock_owner(mock_exclusive_lock);
1655 }
1656
1657 MockObjectMap mock_object_map;
1658 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1659 mock_image_ctx.object_map = &mock_object_map;
1660 }
1661
1662 bufferlist cmp_bl;
1663 cmp_bl.append_zero(4096);
1664
1665 bufferlist bl;
1666 bl.append(std::string(4096, '1'));
1667
1668 InSequence seq;
1669 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1670 expect_object_may_exist(mock_image_ctx, 0, true);
1671 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1672 expect_cmpext(mock_image_ctx, 0, -MAX_ERRNO - 1);
1673
1674 C_SaferCond ctx;
1675 uint64_t mismatch_offset;
1676 auto req = MockObjectWriteSameRequest::create_compare_and_write(
9f95a23c 1677 &mock_image_ctx, 0, 0, std::move(cmp_bl), std::move(bl),
f67539c2 1678 mock_image_ctx.get_data_io_context(), &mismatch_offset, 0, {}, &ctx);
b32b8144
FG
1679 req->send();
1680 ASSERT_EQ(-EILSEQ, ctx.wait());
1681 ASSERT_EQ(1ULL, mismatch_offset);
1682}
1683
11fdf7f2
TL
1684TEST_F(TestMockIoObjectRequest, ObjectMapError) {
1685 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
1686
1687 librbd::ImageCtx *ictx;
1688 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1689
1690 MockTestImageCtx mock_image_ctx(*ictx);
1691 expect_op_work_queue(mock_image_ctx);
1692 expect_get_object_size(mock_image_ctx);
1693
1694 MockExclusiveLock mock_exclusive_lock;
1695 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1696 expect_is_lock_owner(mock_exclusive_lock);
1697
1698 MockObjectMap mock_object_map;
1699 mock_image_ctx.object_map = &mock_object_map;
1700
1701 bufferlist bl;
1702 bl.append(std::string(4096, '1'));
1703
1704 InSequence seq;
1705 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1706 expect_object_may_exist(mock_image_ctx, 0, true);
1707 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, true,
f67539c2 1708 -EBLOCKLISTED);
11fdf7f2
TL
1709
1710 C_SaferCond ctx;
1711 auto req = MockObjectWriteRequest::create_write(
f67539c2
TL
1712 &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.get_data_io_context(),
1713 0, 0, std::nullopt, {}, &ctx);
1714 req->send();
1715 ASSERT_EQ(-EBLOCKLISTED, ctx.wait());
1716}
1717
1718TEST_F(TestMockIoObjectRequest, ListSnaps) {
1719 librbd::ImageCtx *ictx;
1720 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1721
1722 MockTestImageCtx mock_image_ctx(*ictx);
1723 mock_image_ctx.snaps = {3, 4, 5, 6, 7};
1724
1725 librados::snap_set_t snap_set;
1726 snap_set.seq = 6;
1727 librados::clone_info_t clone_info;
1728
1729 clone_info.cloneid = 3;
1730 clone_info.snaps = {3};
1731 clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{
1732 {0, 4194304}};
1733 clone_info.size = 4194304;
1734 snap_set.clones.push_back(clone_info);
1735
1736 clone_info.cloneid = 4;
1737 clone_info.snaps = {4};
1738 clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{
1739 {278528, 4096}, {442368, 4096}, {1859584, 4096}, {2224128, 4096},
1740 {2756608, 4096}, {3227648, 4096}, {3739648, 4096}, {3903488, 4096}};
1741 clone_info.size = 4194304;
1742 snap_set.clones.push_back(clone_info);
1743
1744 clone_info.cloneid = 6;
1745 clone_info.snaps = {5, 6};
1746 clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{
1747 {425984, 4096}, {440320, 1024}, {1925120, 4096}, {2125824, 4096},
1748 {2215936, 5120}, {3067904, 4096}};
1749 clone_info.size = 3072000;
1750 snap_set.clones.push_back(clone_info);
1751
1752 clone_info.cloneid = CEPH_NOSNAP;
1753 clone_info.snaps = {};
1754 clone_info.overlap = {};
1755 clone_info.size = 4194304;
1756 snap_set.clones.push_back(clone_info);
1757
1758 expect_list_snaps(mock_image_ctx, snap_set, 0);
1759
1760 SnapshotDelta snapshot_delta;
1761 C_SaferCond ctx;
1762 auto req = MockObjectListSnapsRequest::create(
1763 &mock_image_ctx, 0,
1764 {{440320, 1024}, {2122728, 1024}, {2220032, 2048}, {3072000, 4096}},
1765 {3, 4, 5, 6, 7, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx);
11fdf7f2 1766 req->send();
f67539c2
TL
1767 ASSERT_EQ(0, ctx.wait());
1768
1769 SnapshotDelta expected_snapshot_delta;
1770 expected_snapshot_delta[{5,6}].insert(
1771 440320, 1024, {SPARSE_EXTENT_STATE_DATA, 1024});
1772 expected_snapshot_delta[{5,6}].insert(
1773 2122728, 1024, {SPARSE_EXTENT_STATE_DATA, 1024});
1774 expected_snapshot_delta[{5,6}].insert(
1775 2220032, 2048, {SPARSE_EXTENT_STATE_DATA, 2048});
1776 expected_snapshot_delta[{7,CEPH_NOSNAP}].insert(
1777 2122728, 1024, {SPARSE_EXTENT_STATE_DATA, 1024});
1778 expected_snapshot_delta[{7,CEPH_NOSNAP}].insert(
1779 2221056, 1024, {SPARSE_EXTENT_STATE_DATA, 1024});
1780 expected_snapshot_delta[{7,CEPH_NOSNAP}].insert(
1781 3072000, 4096, {SPARSE_EXTENT_STATE_DATA, 4096});
1782 expected_snapshot_delta[{5,5}].insert(
1783 3072000, 4096, {SPARSE_EXTENT_STATE_ZEROED, 4096});
1784 ASSERT_EQ(expected_snapshot_delta, snapshot_delta);
1785}
1786
1787TEST_F(TestMockIoObjectRequest, ListSnapsENOENT) {
1788 librbd::ImageCtx *ictx;
1789 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1790
1791 MockTestImageCtx mock_image_ctx(*ictx);
1792
1793 expect_list_snaps(mock_image_ctx, {}, -ENOENT);
1794
1795 SnapshotDelta snapshot_delta;
1796 C_SaferCond ctx;
1797 auto req = MockObjectListSnapsRequest::create(
1798 &mock_image_ctx, 0,
1799 {{440320, 1024}},
1800 {0, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx);
1801 req->send();
1802 ASSERT_EQ(0, ctx.wait());
1803
1804 SnapshotDelta expected_snapshot_delta;
1805 expected_snapshot_delta[{0,0}].insert(
1806 440320, 1024, {SPARSE_EXTENT_STATE_DNE, 1024});
1807 ASSERT_EQ(expected_snapshot_delta, snapshot_delta);
1808}
1809
1810TEST_F(TestMockIoObjectRequest, ListSnapsDNE) {
1811 librbd::ImageCtx *ictx;
1812 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1813
1814 MockTestImageCtx mock_image_ctx(*ictx);
1815 mock_image_ctx.snaps = {2, 3, 4};
1816
1817 librados::snap_set_t snap_set;
1818 snap_set.seq = 6;
1819 librados::clone_info_t clone_info;
1820
1821 clone_info.cloneid = 4;
1822 clone_info.snaps = {3, 4};
1823 clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{
1824 {0, 4194304}};
1825 clone_info.size = 4194304;
1826 snap_set.clones.push_back(clone_info);
1827
1828 expect_list_snaps(mock_image_ctx, snap_set, 0);
1829
1830 SnapshotDelta snapshot_delta;
1831 C_SaferCond ctx;
1832 auto req = MockObjectListSnapsRequest::create(
1833 &mock_image_ctx, 0,
1834 {{440320, 1024}},
1835 {2, 3, 4}, 0, {}, &snapshot_delta, &ctx);
1836 req->send();
1837 ASSERT_EQ(0, ctx.wait());
1838
1839 SnapshotDelta expected_snapshot_delta;
1840 expected_snapshot_delta[{2,2}].insert(
1841 440320, 1024, {SPARSE_EXTENT_STATE_DNE, 1024});
1842 expected_snapshot_delta[{3,4}].insert(
1843 440320, 1024, {SPARSE_EXTENT_STATE_DATA, 1024});
1844 ASSERT_EQ(expected_snapshot_delta, snapshot_delta);
1845}
1846
1847TEST_F(TestMockIoObjectRequest, ListSnapsEmpty) {
1848 librbd::ImageCtx *ictx;
1849 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1850
1851 MockTestImageCtx mock_image_ctx(*ictx);
1852
1853 expect_list_snaps(mock_image_ctx, {}, 0);
1854
1855 SnapshotDelta snapshot_delta;
1856 C_SaferCond ctx;
1857 auto req = MockObjectListSnapsRequest::create(
1858 &mock_image_ctx, 0,
1859 {{440320, 1024}},
1860 {0, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx);
1861 req->send();
1862 ASSERT_EQ(0, ctx.wait());
1863
1864 SnapshotDelta expected_snapshot_delta;
1865 expected_snapshot_delta[{0,0}].insert(
1866 440320, 1024, {SPARSE_EXTENT_STATE_ZEROED, 1024});
1867 ASSERT_EQ(expected_snapshot_delta, snapshot_delta);
1868}
1869
1870TEST_F(TestMockIoObjectRequest, ListSnapsError) {
1871 librbd::ImageCtx *ictx;
1872 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1873
1874 MockTestImageCtx mock_image_ctx(*ictx);
1875
1876 expect_list_snaps(mock_image_ctx, {}, -EPERM);
1877
1878 SnapshotDelta snapshot_delta;
1879 C_SaferCond ctx;
1880 auto req = MockObjectListSnapsRequest::create(
1881 &mock_image_ctx, 0,
1882 {{440320, 1024}, {2122728, 1024}, {2220032, 2048}, {3072000, 4096}},
1883 {3, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx);
1884 req->send();
1885 ASSERT_EQ(-EPERM, ctx.wait());
1886}
1887
1888TEST_F(TestMockIoObjectRequest, ListSnapsParent) {
1889 librbd::ImageCtx *ictx;
1890 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1891
1892 MockTestImageCtx mock_image_ctx(*ictx);
1893 mock_image_ctx.parent = &mock_image_ctx;
1894
1895 InSequence seq;
1896
1897 expect_list_snaps(mock_image_ctx, {}, -ENOENT);
1898
1899 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
1900 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
1901
1902 MockImageListSnapsRequest mock_image_list_snaps_request;
1903 SnapshotDelta image_snapshot_delta;
1904 image_snapshot_delta[{1,6}].insert(
1905 0, 1024, {SPARSE_EXTENT_STATE_DATA, 1024});
1906 expect_image_list_snaps(mock_image_list_snaps_request,
1907 {{0, 4096}}, image_snapshot_delta, 0);
1908
1909 SnapshotDelta snapshot_delta;
1910 C_SaferCond ctx;
1911 auto req = MockObjectListSnapsRequest::create(
1912 &mock_image_ctx, 0,
1913 {{440320, 1024}, {2122728, 1024}, {2220032, 2048}, {3072000, 4096}},
1914 {0, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx);
1915 req->send();
1916 ASSERT_EQ(0, ctx.wait());
1917
1918 SnapshotDelta expected_snapshot_delta;
1919 expected_snapshot_delta[{0,0}].insert(
1920 0, 1024, {SPARSE_EXTENT_STATE_DATA, 1024});
1921 ASSERT_EQ(expected_snapshot_delta, snapshot_delta);
1922}
1923
1924TEST_F(TestMockIoObjectRequest, ListSnapsWholeObject) {
1925 librbd::ImageCtx *ictx;
1926 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1927
1928 MockTestImageCtx mock_image_ctx(*ictx);
1929 mock_image_ctx.parent = &mock_image_ctx;
1930
1931 InSequence seq;
1932
1933 librados::snap_set_t snap_set;
1934 snap_set.seq = 3;
1935 librados::clone_info_t clone_info;
1936
1937 clone_info.cloneid = 3;
1938 clone_info.snaps = {3};
1939 clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 1}};
1940 clone_info.size = 4194304;
1941 snap_set.clones.push_back(clone_info);
1942
1943 clone_info.cloneid = CEPH_NOSNAP;
1944 clone_info.snaps = {};
1945 clone_info.overlap = {};
1946 clone_info.size = 4194304;
1947 snap_set.clones.push_back(clone_info);
1948
1949 expect_list_snaps(mock_image_ctx, snap_set, 0);
1950
1951 SnapshotDelta snapshot_delta;
1952 C_SaferCond ctx;
1953 auto req = MockObjectListSnapsRequest::create(
1954 &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size - 1}},
1955 {0, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx);
1956 req->send();
1957 ASSERT_EQ(0, ctx.wait());
1958
1959 SnapshotDelta expected_snapshot_delta;
1960 expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert(
1961 0, mock_image_ctx.layout.object_size - 1,
1962 {SPARSE_EXTENT_STATE_DATA, mock_image_ctx.layout.object_size - 1});
1963 ASSERT_EQ(expected_snapshot_delta, snapshot_delta);
11fdf7f2
TL
1964}
1965
b32b8144
FG
1966} // namespace io
1967} // namespace librbd
1968