]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/io/test_mock_ObjectRequest.cc
update sources to v12.2.3
[ceph.git] / ceph / src / test / librbd / io / test_mock_ObjectRequest.cc
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"
13 #include "librbd/io/ImageRequest.h"
14 #include "librbd/io/ObjectRequest.h"
15
16 namespace librbd {
17 namespace {
18
19 struct MockTestImageCtx : public MockImageCtx {
20 MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
21 }
22 };
23
24 } // anonymous namespace
25
26 namespace util {
27
28 inline ImageCtx *get_image_ctx(MockImageCtx *image_ctx) {
29 return image_ctx->image_ctx;
30 }
31
32 } // namespace util
33
34 namespace io {
35
36 template <>
37 struct CopyupRequest<librbd::MockImageCtx> {
38 MOCK_METHOD0(send, void());
39 MOCK_METHOD1(append_request, void(AbstractObjectWriteRequest<librbd::MockTestImageCtx>*));
40 };
41
42 template <>
43 struct CopyupRequest<librbd::MockTestImageCtx> : public CopyupRequest<librbd::MockImageCtx> {
44 static CopyupRequest* s_instance;
45 static CopyupRequest* create(librbd::MockTestImageCtx *ictx,
46 const std::string &oid, uint64_t objectno,
47 Extents &&image_extents,
48 const ZTracer::Trace &parent_trace) {
49 return s_instance;
50 }
51
52 CopyupRequest() {
53 s_instance = this;
54 }
55 };
56
57 template <>
58 struct ImageRequest<librbd::MockTestImageCtx> {
59 static ImageRequest *s_instance;
60 static void aio_read(librbd::MockImageCtx *ictx, AioCompletion *c,
61 Extents &&image_extents, ReadResult &&read_result,
62 int op_flags, const ZTracer::Trace &parent_trace) {
63 s_instance->aio_read(c, image_extents);
64 }
65
66 MOCK_METHOD2(aio_read, void(AioCompletion *, const Extents&));
67
68 ImageRequest() {
69 s_instance = this;
70 }
71 };
72
73 CopyupRequest<librbd::MockTestImageCtx>* CopyupRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
74 ImageRequest<librbd::MockTestImageCtx>* ImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
75
76 } // namespace io
77 } // namespace librbd
78
79 #include "librbd/io/ObjectRequest.cc"
80
81 namespace librbd {
82 namespace io {
83
84 using ::testing::_;
85 using ::testing::DoDefault;
86 using ::testing::InSequence;
87 using ::testing::Invoke;
88 using ::testing::Return;
89 using ::testing::WithArg;
90 using ::testing::WithArgs;
91
92 struct TestMockIoObjectRequest : public TestMockFixture {
93 typedef ObjectRequest<librbd::MockTestImageCtx> MockObjectRequest;
94 typedef ObjectReadRequest<librbd::MockTestImageCtx> MockObjectReadRequest;
95 typedef ObjectWriteRequest<librbd::MockTestImageCtx> MockObjectWriteRequest;
96 typedef ObjectDiscardRequest<librbd::MockTestImageCtx> MockObjectDiscardRequest;
97 typedef ObjectWriteSameRequest<librbd::MockTestImageCtx> MockObjectWriteSameRequest;
98 typedef ObjectCompareAndWriteRequest<librbd::MockTestImageCtx> MockObjectCompareAndWriteRequest;
99 typedef AbstractObjectWriteRequest<librbd::MockTestImageCtx> MockAbstractObjectWriteRequest;
100 typedef CopyupRequest<librbd::MockTestImageCtx> MockCopyupRequest;
101 typedef ImageRequest<librbd::MockTestImageCtx> MockImageRequest;
102
103 void expect_object_may_exist(MockTestImageCtx &mock_image_ctx,
104 uint64_t object_no, bool exists) {
105 if (mock_image_ctx.object_map != nullptr) {
106 EXPECT_CALL(*mock_image_ctx.object_map, object_may_exist(object_no))
107 .WillOnce(Return(exists));
108 }
109 }
110
111 void expect_get_object_size(MockTestImageCtx &mock_image_ctx) {
112 EXPECT_CALL(mock_image_ctx, get_object_size()).WillRepeatedly(Return(
113 mock_image_ctx.layout.object_size));
114 }
115
116 void expect_get_parent_overlap(MockTestImageCtx &mock_image_ctx,
117 librados::snap_t snap_id, uint64_t overlap,
118 int r) {
119 EXPECT_CALL(mock_image_ctx, get_parent_overlap(snap_id, _))
120 .WillOnce(WithArg<1>(Invoke([overlap, r](uint64_t *o) {
121 *o = overlap;
122 return r;
123 })));
124 }
125
126 void expect_prune_parent_extents(MockTestImageCtx &mock_image_ctx,
127 const Extents& extents,
128 uint64_t overlap, uint64_t object_overlap) {
129 EXPECT_CALL(mock_image_ctx, prune_parent_extents(_, overlap))
130 .WillOnce(WithArg<0>(Invoke([extents, object_overlap](Extents& e) {
131 e = extents;
132 return object_overlap;
133 })));
134 }
135
136 void expect_get_read_flags(MockTestImageCtx &mock_image_ctx,
137 librados::snap_t snap_id, int flags) {
138 EXPECT_CALL(mock_image_ctx, get_read_flags(snap_id))
139 .WillOnce(Return(flags));
140 }
141
142 void expect_is_lock_owner(MockExclusiveLock& mock_exclusive_lock) {
143 EXPECT_CALL(mock_exclusive_lock, is_lock_owner()).WillRepeatedly(
144 Return(true));
145 }
146
147 void expect_read(MockTestImageCtx &mock_image_ctx,
148 const std::string& oid, uint64_t off, uint64_t len,
149 const std::string& data, int r) {
150 bufferlist bl;
151 bl.append(data);
152
153 auto& expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
154 read(oid, len, off, _));
155 if (r < 0) {
156 expect.WillOnce(Return(r));
157 } else {
158 expect.WillOnce(WithArg<3>(Invoke([bl](bufferlist *out_bl) {
159 out_bl->append(bl);
160 return bl.length();
161 })));
162 }
163 }
164
165 void expect_sparse_read(MockTestImageCtx &mock_image_ctx,
166 const std::string& oid, uint64_t off, uint64_t len,
167 const std::string& data, int r) {
168 bufferlist bl;
169 bl.append(data);
170
171 auto& expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
172 sparse_read(oid, off, len, _, _));
173 if (r < 0) {
174 expect.WillOnce(Return(r));
175 } else {
176 expect.WillOnce(WithArg<4>(Invoke([bl](bufferlist *out_bl) {
177 out_bl->append(bl);
178 return bl.length();
179 })));
180 }
181 }
182
183 void expect_cache_read(MockTestImageCtx &mock_image_ctx,
184 const std::string& oid, uint64_t object_no,
185 uint64_t off, uint64_t len, const std::string& data,
186 int r) {
187 bufferlist bl;
188 bl.append(data);
189
190 EXPECT_CALL(mock_image_ctx, aio_read_from_cache({oid}, object_no, _, len,
191 off, _, _, _))
192 .WillOnce(WithArgs<2, 5>(Invoke([bl, r](bufferlist *out_bl,
193 Context *on_finish) {
194 out_bl->append(bl);
195 on_finish->complete(r);
196 })));
197 }
198
199 void expect_aio_read(MockImageRequest& mock_image_request,
200 Extents&& extents, int r) {
201 EXPECT_CALL(mock_image_request, aio_read(_, extents))
202 .WillOnce(WithArg<0>(Invoke([r](AioCompletion* aio_comp) {
203 aio_comp->set_request_count(1);
204 aio_comp->add_request();
205 aio_comp->complete_request(r);
206 })));
207 }
208
209 void expect_copyup(MockCopyupRequest& mock_copyup_request, int r) {
210 EXPECT_CALL(mock_copyup_request, send())
211 .WillOnce(Invoke([&mock_copyup_request, r]() {
212 }));
213 }
214
215 void expect_copyup(MockCopyupRequest& mock_copyup_request,
216 MockAbstractObjectWriteRequest** write_request, int r) {
217 EXPECT_CALL(mock_copyup_request, append_request(_))
218 .WillOnce(Invoke([write_request](MockAbstractObjectWriteRequest *req) {
219 *write_request = req;
220 }));
221 EXPECT_CALL(mock_copyup_request, send())
222 .WillOnce(Invoke([write_request, r]() {
223 (*write_request)->handle_copyup(r);
224 }));
225 }
226
227 void expect_object_map_update(MockTestImageCtx &mock_image_ctx,
228 uint64_t start_object, uint64_t end_object,
229 uint8_t state,
230 const boost::optional<uint8_t> &current_state,
231 bool updated, int ret_val) {
232 if (mock_image_ctx.object_map != nullptr) {
233 EXPECT_CALL(*mock_image_ctx.object_map,
234 aio_update(CEPH_NOSNAP, start_object, end_object, state,
235 current_state, _, _))
236 .WillOnce(WithArg<6>(Invoke([&mock_image_ctx, updated, ret_val](Context *ctx) {
237 if (updated) {
238 mock_image_ctx.op_work_queue->queue(ctx, ret_val);
239 }
240 return updated;
241 })));
242 }
243 }
244
245 void expect_assert_exists(MockTestImageCtx &mock_image_ctx, int r) {
246 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx), assert_exists(_))
247 .WillOnce(Return(r));
248 }
249
250 void expect_write(MockTestImageCtx &mock_image_ctx,
251 uint64_t offset, uint64_t length, int r) {
252 auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
253 write(_, _, length, offset, _));
254 if (r < 0) {
255 expect.WillOnce(Return(r));
256 } else {
257 expect.WillOnce(DoDefault());
258 }
259 }
260
261 void expect_write_full(MockTestImageCtx &mock_image_ctx, int r) {
262 auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
263 write_full(_, _, _));
264 if (r < 0) {
265 expect.WillOnce(Return(r));
266 } else {
267 expect.WillOnce(DoDefault());
268 }
269 }
270
271 void expect_writesame(MockTestImageCtx &mock_image_ctx,
272 uint64_t offset, uint64_t length, int r) {
273 auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
274 writesame(_, _, length, offset, _));
275 if (r < 0) {
276 expect.WillOnce(Return(r));
277 } else {
278 expect.WillOnce(DoDefault());
279 }
280 }
281
282 void expect_remove(MockTestImageCtx &mock_image_ctx, int r) {
283 auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
284 remove(_, _));
285 if (r < 0) {
286 expect.WillOnce(Return(r));
287 } else {
288 expect.WillOnce(DoDefault());
289 }
290 }
291
292 void expect_truncate(MockTestImageCtx &mock_image_ctx, int offset, int r) {
293 auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
294 truncate(_, offset, _));
295 if (r < 0) {
296 expect.WillOnce(Return(r));
297 } else {
298 expect.WillOnce(DoDefault());
299 }
300 }
301
302 void expect_zero(MockTestImageCtx &mock_image_ctx, int offset, int length,
303 int r) {
304 auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
305 zero(_, offset, length, _));
306 if (r < 0) {
307 expect.WillOnce(Return(r));
308 } else {
309 expect.WillOnce(DoDefault());
310 }
311 }
312
313 void expect_cmpext(MockTestImageCtx &mock_image_ctx, int offset, int r) {
314 auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
315 cmpext(_, offset, _));
316 if (r < 0) {
317 expect.WillOnce(Return(r));
318 } else {
319 expect.WillOnce(DoDefault());
320 }
321 }
322 };
323
324 TEST_F(TestMockIoObjectRequest, Read) {
325 librbd::ImageCtx *ictx;
326 ASSERT_EQ(0, open_image(m_image_name, &ictx));
327 ictx->sparse_read_threshold_bytes = 8096;
328
329 MockTestImageCtx mock_image_ctx(*ictx);
330 mock_image_ctx.object_cacher = nullptr;
331
332 MockObjectMap mock_object_map;
333 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
334 mock_image_ctx.object_map = &mock_object_map;
335 }
336
337 InSequence seq;
338 expect_object_may_exist(mock_image_ctx, 0, true);
339 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
340 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096,
341 std::string(4096, '1'), 0);
342
343 C_SaferCond ctx;
344 auto req = MockObjectReadRequest::create(
345 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0,
346 false, {}, &ctx);
347 req->send();
348 ASSERT_EQ(0, ctx.wait());
349 }
350
351 TEST_F(TestMockIoObjectRequest, SparseReadThreshold) {
352 librbd::ImageCtx *ictx;
353 ASSERT_EQ(0, open_image(m_image_name, &ictx));
354 ictx->sparse_read_threshold_bytes = ictx->get_object_size();
355
356 MockTestImageCtx mock_image_ctx(*ictx);
357 mock_image_ctx.object_cacher = nullptr;
358
359 MockObjectMap mock_object_map;
360 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
361 mock_image_ctx.object_map = &mock_object_map;
362 }
363
364 InSequence seq;
365 expect_object_may_exist(mock_image_ctx, 0, true);
366 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
367 expect_sparse_read(mock_image_ctx, ictx->get_object_name(0), 0,
368 ictx->sparse_read_threshold_bytes,
369 std::string(ictx->sparse_read_threshold_bytes, '1'), 0);
370
371 C_SaferCond ctx;
372 auto req = MockObjectReadRequest::create(
373 &mock_image_ctx, ictx->get_object_name(0), 0, 0,
374 ictx->sparse_read_threshold_bytes, CEPH_NOSNAP, 0, false, {}, &ctx);
375 req->send();
376 ASSERT_EQ(0, ctx.wait());
377 }
378
379 TEST_F(TestMockIoObjectRequest, ReadError) {
380 librbd::ImageCtx *ictx;
381 ASSERT_EQ(0, open_image(m_image_name, &ictx));
382 ictx->sparse_read_threshold_bytes = 8096;
383
384 MockTestImageCtx mock_image_ctx(*ictx);
385 mock_image_ctx.object_cacher = nullptr;
386
387 MockObjectMap mock_object_map;
388 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
389 mock_image_ctx.object_map = &mock_object_map;
390 }
391
392 InSequence seq;
393 expect_object_may_exist(mock_image_ctx, 0, true);
394 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
395 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -EPERM);
396
397 C_SaferCond ctx;
398 auto req = MockObjectReadRequest::create(
399 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0,
400 false, {}, &ctx);
401 req->send();
402 ASSERT_EQ(-EPERM, ctx.wait());
403 }
404
405 TEST_F(TestMockIoObjectRequest, CacheRead) {
406 librbd::ImageCtx *ictx;
407 ASSERT_EQ(0, open_image(m_image_name, &ictx));
408 ictx->sparse_read_threshold_bytes = 8096;
409
410 MockTestImageCtx mock_image_ctx(*ictx);
411 MockObjectMap mock_object_map;
412 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
413 mock_image_ctx.object_map = &mock_object_map;
414 }
415
416 expect_op_work_queue(mock_image_ctx);
417
418 InSequence seq;
419 expect_cache_read(mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096,
420 std::string(4096, '1'), 0);
421
422 C_SaferCond ctx;
423 auto req = MockObjectReadRequest::create(
424 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0,
425 false, {}, &ctx);
426 req->send();
427 ASSERT_EQ(0, ctx.wait());
428 }
429
430 TEST_F(TestMockIoObjectRequest, CacheReadError) {
431 librbd::ImageCtx *ictx;
432 ASSERT_EQ(0, open_image(m_image_name, &ictx));
433 ictx->sparse_read_threshold_bytes = 8096;
434
435 MockTestImageCtx mock_image_ctx(*ictx);
436 MockObjectMap mock_object_map;
437 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
438 mock_image_ctx.object_map = &mock_object_map;
439 }
440
441 expect_op_work_queue(mock_image_ctx);
442
443 InSequence seq;
444 expect_cache_read(mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096,
445 "", -EPERM);
446
447 C_SaferCond ctx;
448 auto req = MockObjectReadRequest::create(
449 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0,
450 false, {}, &ctx);
451 req->send();
452 ASSERT_EQ(-EPERM, ctx.wait());
453 }
454
455 TEST_F(TestMockIoObjectRequest, ParentRead) {
456 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
457
458 librbd::Image image;
459 librbd::RBD rbd;
460 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
461 ASSERT_EQ(0, image.snap_create("one"));
462 ASSERT_EQ(0, image.snap_protect("one"));
463 image.close();
464
465 std::string clone_name = get_temp_image_name();
466 int order = 0;
467 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
468 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
469
470 librbd::ImageCtx *ictx;
471 ASSERT_EQ(0, open_image(clone_name, &ictx));
472 ictx->sparse_read_threshold_bytes = 8096;
473 ictx->clone_copy_on_read = false;
474
475 MockTestImageCtx mock_image_ctx(*ictx);
476 mock_image_ctx.parent = &mock_image_ctx;
477 mock_image_ctx.object_cacher = nullptr;
478
479 MockObjectMap mock_object_map;
480 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
481 mock_image_ctx.object_map = &mock_object_map;
482 }
483
484 InSequence seq;
485 expect_object_may_exist(mock_image_ctx, 0, true);
486 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
487 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
488
489 MockImageRequest mock_image_request;
490 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
491 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
492 expect_aio_read(mock_image_request, {{0, 4096}}, 0);
493
494 C_SaferCond ctx;
495 auto req = MockObjectReadRequest::create(
496 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0,
497 false, {}, &ctx);
498 req->send();
499 ASSERT_EQ(0, ctx.wait());
500 }
501
502 TEST_F(TestMockIoObjectRequest, ParentReadError) {
503 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
504
505 librbd::Image image;
506 librbd::RBD rbd;
507 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
508 ASSERT_EQ(0, image.snap_create("one"));
509 ASSERT_EQ(0, image.snap_protect("one"));
510 image.close();
511
512 std::string clone_name = get_temp_image_name();
513 int order = 0;
514 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
515 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
516
517 librbd::ImageCtx *ictx;
518 ASSERT_EQ(0, open_image(clone_name, &ictx));
519 ictx->sparse_read_threshold_bytes = 8096;
520 ictx->clone_copy_on_read = false;
521
522 MockTestImageCtx mock_image_ctx(*ictx);
523 mock_image_ctx.parent = &mock_image_ctx;
524 mock_image_ctx.object_cacher = nullptr;
525
526 MockObjectMap mock_object_map;
527 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
528 mock_image_ctx.object_map = &mock_object_map;
529 }
530
531 InSequence seq;
532 expect_object_may_exist(mock_image_ctx, 0, true);
533 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
534 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
535
536 MockImageRequest mock_image_request;
537 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
538 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
539 expect_aio_read(mock_image_request, {{0, 4096}}, -EPERM);
540
541 C_SaferCond ctx;
542 auto req = MockObjectReadRequest::create(
543 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0,
544 false, {}, &ctx);
545 req->send();
546 ASSERT_EQ(-EPERM, ctx.wait());
547 }
548
549 TEST_F(TestMockIoObjectRequest, CacheInitiated) {
550 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
551
552 librbd::Image image;
553 librbd::RBD rbd;
554 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
555 ASSERT_EQ(0, image.snap_create("one"));
556 ASSERT_EQ(0, image.snap_protect("one"));
557 image.close();
558
559 std::string clone_name = get_temp_image_name();
560 int order = 0;
561 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
562 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
563
564 librbd::ImageCtx *ictx;
565 ASSERT_EQ(0, open_image(clone_name, &ictx));
566 ictx->sparse_read_threshold_bytes = 8096;
567 ictx->clone_copy_on_read = false;
568
569 MockTestImageCtx mock_image_ctx(*ictx);
570 mock_image_ctx.parent = &mock_image_ctx;
571
572 MockObjectMap mock_object_map;
573 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
574 mock_image_ctx.object_map = &mock_object_map;
575 }
576
577 InSequence seq;
578 expect_object_may_exist(mock_image_ctx, 0, true);
579 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
580 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
581
582 C_SaferCond ctx;
583 auto req = MockObjectReadRequest::create(
584 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0, true,
585 {}, &ctx);
586 req->send();
587 ASSERT_EQ(-ENOENT, ctx.wait());
588 }
589
590 TEST_F(TestMockIoObjectRequest, CopyOnRead) {
591 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
592
593 librbd::Image image;
594 librbd::RBD rbd;
595 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
596 ASSERT_EQ(0, image.snap_create("one"));
597 ASSERT_EQ(0, image.snap_protect("one"));
598 image.close();
599
600 std::string clone_name = get_temp_image_name();
601 int order = 0;
602 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
603 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
604
605 librbd::ImageCtx *ictx;
606 ASSERT_EQ(0, open_image(clone_name, &ictx));
607 ictx->sparse_read_threshold_bytes = 8096;
608 ictx->clone_copy_on_read = true;
609
610 MockTestImageCtx mock_image_ctx(*ictx);
611 mock_image_ctx.parent = &mock_image_ctx;
612 mock_image_ctx.object_cacher = nullptr;
613
614 MockObjectMap mock_object_map;
615 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
616 mock_image_ctx.object_map = &mock_object_map;
617 }
618
619 InSequence seq;
620 expect_object_may_exist(mock_image_ctx, 0, true);
621 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
622 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
623
624 MockImageRequest mock_image_request;
625 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
626 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
627 expect_aio_read(mock_image_request, {{0, 4096}}, 0);
628
629 MockCopyupRequest mock_copyup_request;
630 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
631 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
632 expect_copyup(mock_copyup_request, 0);
633
634 C_SaferCond ctx;
635 auto req = MockObjectReadRequest::create(
636 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0,
637 false, {}, &ctx);
638 req->send();
639 ASSERT_EQ(0, ctx.wait());
640 }
641
642 TEST_F(TestMockIoObjectRequest, Write) {
643 librbd::ImageCtx *ictx;
644 ASSERT_EQ(0, open_image(m_image_name, &ictx));
645
646 MockTestImageCtx mock_image_ctx(*ictx);
647 expect_get_object_size(mock_image_ctx);
648
649 MockExclusiveLock mock_exclusive_lock;
650 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
651 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
652 expect_is_lock_owner(mock_exclusive_lock);
653 }
654
655 MockObjectMap mock_object_map;
656 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
657 mock_image_ctx.object_map = &mock_object_map;
658 }
659
660 bufferlist bl;
661 bl.append(std::string(4096, '1'));
662
663 InSequence seq;
664 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
665 expect_object_may_exist(mock_image_ctx, 0, true);
666 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
667 expect_write(mock_image_ctx, 0, 4096, 0);
668
669 C_SaferCond ctx;
670 auto req = MockObjectWriteRequest::create_write(
671 &mock_image_ctx, ictx->get_object_name(0), 0, 0, bl, mock_image_ctx.snapc,
672 0, {}, &ctx);
673 req->send();
674 ASSERT_EQ(0, ctx.wait());
675 }
676
677 TEST_F(TestMockIoObjectRequest, WriteFull) {
678 librbd::ImageCtx *ictx;
679 ASSERT_EQ(0, open_image(m_image_name, &ictx));
680
681 MockTestImageCtx mock_image_ctx(*ictx);
682 expect_get_object_size(mock_image_ctx);
683
684 MockExclusiveLock mock_exclusive_lock;
685 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
686 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
687 expect_is_lock_owner(mock_exclusive_lock);
688 }
689
690 MockObjectMap mock_object_map;
691 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
692 mock_image_ctx.object_map = &mock_object_map;
693 }
694
695 bufferlist bl;
696 bl.append(std::string(ictx->get_object_size(), '1'));
697
698 InSequence seq;
699 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
700 expect_object_may_exist(mock_image_ctx, 0, true);
701 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
702 expect_write_full(mock_image_ctx, 0);
703
704 C_SaferCond ctx;
705 auto req = MockObjectWriteRequest::create_write(
706 &mock_image_ctx, ictx->get_object_name(0), 0, 0, bl, mock_image_ctx.snapc,
707 0, {}, &ctx);
708 req->send();
709 ASSERT_EQ(0, ctx.wait());
710 }
711
712 TEST_F(TestMockIoObjectRequest, WriteObjectMap) {
713 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
714
715 librbd::ImageCtx *ictx;
716 ASSERT_EQ(0, open_image(m_image_name, &ictx));
717
718 MockTestImageCtx mock_image_ctx(*ictx);
719 expect_op_work_queue(mock_image_ctx);
720 expect_get_object_size(mock_image_ctx);
721
722 MockExclusiveLock mock_exclusive_lock;
723 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
724 expect_is_lock_owner(mock_exclusive_lock);
725
726 MockObjectMap mock_object_map;
727 mock_image_ctx.object_map = &mock_object_map;
728
729 bufferlist bl;
730 bl.append(std::string(4096, '1'));
731
732 InSequence seq;
733 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
734 expect_object_may_exist(mock_image_ctx, 0, true);
735 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, true, 0);
736 expect_write(mock_image_ctx, 0, 4096, 0);
737
738 C_SaferCond ctx;
739 auto req = MockObjectWriteRequest::create_write(
740 &mock_image_ctx, ictx->get_object_name(0), 0, 0, bl, mock_image_ctx.snapc,
741 0, {}, &ctx);
742 req->send();
743 ASSERT_EQ(0, ctx.wait());
744 }
745
746 TEST_F(TestMockIoObjectRequest, WriteError) {
747 librbd::ImageCtx *ictx;
748 ASSERT_EQ(0, open_image(m_image_name, &ictx));
749
750 MockTestImageCtx mock_image_ctx(*ictx);
751 expect_get_object_size(mock_image_ctx);
752
753 bufferlist bl;
754 bl.append(std::string(4096, '1'));
755
756 InSequence seq;
757 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
758 expect_write(mock_image_ctx, 0, 4096, -EPERM);
759
760 C_SaferCond ctx;
761 auto req = MockObjectWriteRequest::create_write(
762 &mock_image_ctx, ictx->get_object_name(0), 0, 0, bl, mock_image_ctx.snapc,
763 0, {}, &ctx);
764 req->send();
765 ASSERT_EQ(-EPERM, ctx.wait());
766 }
767
768 TEST_F(TestMockIoObjectRequest, Copyup) {
769 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
770
771 librbd::Image image;
772 librbd::RBD rbd;
773 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
774 ASSERT_EQ(0, image.snap_create("one"));
775 ASSERT_EQ(0, image.snap_protect("one"));
776 image.close();
777
778 std::string clone_name = get_temp_image_name();
779 int order = 0;
780 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
781 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
782
783 librbd::ImageCtx *ictx;
784 ASSERT_EQ(0, open_image(clone_name, &ictx));
785
786 MockTestImageCtx mock_image_ctx(*ictx);
787 expect_get_object_size(mock_image_ctx);
788
789 MockExclusiveLock mock_exclusive_lock;
790 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
791 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
792 expect_is_lock_owner(mock_exclusive_lock);
793 }
794
795 MockObjectMap mock_object_map;
796 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
797 mock_image_ctx.object_map = &mock_object_map;
798 }
799
800 bufferlist bl;
801 bl.append(std::string(4096, '1'));
802
803 InSequence seq;
804 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
805 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
806 expect_object_may_exist(mock_image_ctx, 0, true);
807 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
808 expect_assert_exists(mock_image_ctx, -ENOENT);
809
810 MockAbstractObjectWriteRequest *write_request = nullptr;
811 MockCopyupRequest mock_copyup_request;
812 expect_copyup(mock_copyup_request, &write_request, 0);
813
814 C_SaferCond ctx;
815 auto req = MockObjectWriteRequest::create_write(
816 &mock_image_ctx, ictx->get_object_name(0), 0, 0, bl, mock_image_ctx.snapc,
817 0, {}, &ctx);
818 req->send();
819 ASSERT_EQ(0, ctx.wait());
820 }
821
822 TEST_F(TestMockIoObjectRequest, CopyupOptimization) {
823 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_OBJECT_MAP);
824
825 librbd::Image image;
826 librbd::RBD rbd;
827 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
828 ASSERT_EQ(0, image.snap_create("one"));
829 ASSERT_EQ(0, image.snap_protect("one"));
830 image.close();
831
832 std::string clone_name = get_temp_image_name();
833 int order = 0;
834 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
835 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
836
837 librbd::ImageCtx *ictx;
838 ASSERT_EQ(0, open_image(clone_name, &ictx));
839
840 MockTestImageCtx mock_image_ctx(*ictx);
841 expect_get_object_size(mock_image_ctx);
842
843 MockExclusiveLock mock_exclusive_lock;
844 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
845 expect_is_lock_owner(mock_exclusive_lock);
846
847 MockObjectMap mock_object_map;
848 mock_image_ctx.object_map = &mock_object_map;
849
850 bufferlist bl;
851 bl.append(std::string(4096, '1'));
852
853 InSequence seq;
854 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
855 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
856 expect_object_may_exist(mock_image_ctx, 0, false);
857
858 MockAbstractObjectWriteRequest *write_request = nullptr;
859 MockCopyupRequest mock_copyup_request;
860 expect_copyup(mock_copyup_request, &write_request, 0);
861
862 C_SaferCond ctx;
863 auto req = MockObjectWriteRequest::create_write(
864 &mock_image_ctx, ictx->get_object_name(0), 0, 0, bl, mock_image_ctx.snapc,
865 0, {}, &ctx);
866 req->send();
867 ASSERT_EQ(0, ctx.wait());
868 }
869
870 TEST_F(TestMockIoObjectRequest, CopyupError) {
871 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
872
873 librbd::Image image;
874 librbd::RBD rbd;
875 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
876 ASSERT_EQ(0, image.snap_create("one"));
877 ASSERT_EQ(0, image.snap_protect("one"));
878 image.close();
879
880 std::string clone_name = get_temp_image_name();
881 int order = 0;
882 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
883 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
884
885 librbd::ImageCtx *ictx;
886 ASSERT_EQ(0, open_image(clone_name, &ictx));
887
888 MockTestImageCtx mock_image_ctx(*ictx);
889 expect_get_object_size(mock_image_ctx);
890
891 bufferlist bl;
892 bl.append(std::string(4096, '1'));
893
894 InSequence seq;
895 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
896 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
897 expect_assert_exists(mock_image_ctx, -ENOENT);
898
899 MockAbstractObjectWriteRequest *write_request = nullptr;
900 MockCopyupRequest mock_copyup_request;
901 expect_copyup(mock_copyup_request, &write_request, -EPERM);
902
903 C_SaferCond ctx;
904 auto req = MockObjectWriteRequest::create_write(
905 &mock_image_ctx, ictx->get_object_name(0), 0, 0, bl, mock_image_ctx.snapc,
906 0, {}, &ctx);
907 req->send();
908 ASSERT_EQ(-EPERM, ctx.wait());
909 }
910
911 TEST_F(TestMockIoObjectRequest, DiscardRemove) {
912 librbd::ImageCtx *ictx;
913 ASSERT_EQ(0, open_image(m_image_name, &ictx));
914
915 MockTestImageCtx mock_image_ctx(*ictx);
916 expect_get_object_size(mock_image_ctx);
917
918 MockExclusiveLock mock_exclusive_lock;
919 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
920 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
921 expect_is_lock_owner(mock_exclusive_lock);
922 }
923
924 MockObjectMap mock_object_map;
925 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
926 mock_image_ctx.object_map = &mock_object_map;
927 }
928
929 InSequence seq;
930 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
931 expect_object_may_exist(mock_image_ctx, 0, true);
932 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_PENDING, {}, false, 0);
933 expect_remove(mock_image_ctx, 0);
934 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_NONEXISTENT,
935 OBJECT_PENDING, false, 0);
936
937 C_SaferCond ctx;
938 auto req = MockObjectDiscardRequest::create_discard(
939 &mock_image_ctx, ictx->get_object_name(0), 0, 0,
940 mock_image_ctx.get_object_size(), mock_image_ctx.snapc, false, true, {},
941 &ctx);
942 req->send();
943 ASSERT_EQ(0, ctx.wait());
944 }
945
946 TEST_F(TestMockIoObjectRequest, DiscardRemoveTruncate) {
947 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
948
949 librbd::Image image;
950 librbd::RBD rbd;
951 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
952 ASSERT_EQ(0, image.snap_create("one"));
953 ASSERT_EQ(0, image.snap_protect("one"));
954 image.close();
955
956 std::string clone_name = get_temp_image_name();
957 int order = 0;
958 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
959 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
960
961 librbd::ImageCtx *ictx;
962 ASSERT_EQ(0, open_image(clone_name, &ictx));
963
964 MockTestImageCtx mock_image_ctx(*ictx);
965 expect_get_object_size(mock_image_ctx);
966
967 MockExclusiveLock mock_exclusive_lock;
968 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
969 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
970 expect_is_lock_owner(mock_exclusive_lock);
971 }
972
973 MockObjectMap mock_object_map;
974 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
975 mock_image_ctx.object_map = &mock_object_map;
976 }
977
978 InSequence seq;
979 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
980 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
981 expect_object_may_exist(mock_image_ctx, 0, true);
982 expect_truncate(mock_image_ctx, 0, 0);
983
984 C_SaferCond ctx;
985 auto req = MockObjectDiscardRequest::create_discard(
986 &mock_image_ctx, ictx->get_object_name(0), 0, 0,
987 mock_image_ctx.get_object_size(), mock_image_ctx.snapc, true, true, {},
988 &ctx);
989 req->send();
990 ASSERT_EQ(0, ctx.wait());
991 }
992
993 TEST_F(TestMockIoObjectRequest, DiscardTruncate) {
994 librbd::ImageCtx *ictx;
995 ASSERT_EQ(0, open_image(m_image_name, &ictx));
996
997 MockTestImageCtx mock_image_ctx(*ictx);
998 expect_get_object_size(mock_image_ctx);
999
1000 MockExclusiveLock mock_exclusive_lock;
1001 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1002 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1003 expect_is_lock_owner(mock_exclusive_lock);
1004 }
1005
1006 MockObjectMap mock_object_map;
1007 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1008 mock_image_ctx.object_map = &mock_object_map;
1009 }
1010
1011 InSequence seq;
1012 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1013 expect_object_may_exist(mock_image_ctx, 0, true);
1014 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1015 expect_truncate(mock_image_ctx, 1, 0);
1016
1017 C_SaferCond ctx;
1018 auto req = MockObjectDiscardRequest::create_discard(
1019 &mock_image_ctx, ictx->get_object_name(0), 0, 1,
1020 mock_image_ctx.get_object_size() - 1, mock_image_ctx.snapc, false, true, {},
1021 &ctx);
1022 req->send();
1023 ASSERT_EQ(0, ctx.wait());
1024 }
1025
1026 TEST_F(TestMockIoObjectRequest, DiscardZero) {
1027 librbd::ImageCtx *ictx;
1028 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1029
1030 MockTestImageCtx mock_image_ctx(*ictx);
1031 expect_get_object_size(mock_image_ctx);
1032
1033 MockExclusiveLock mock_exclusive_lock;
1034 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1035 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1036 expect_is_lock_owner(mock_exclusive_lock);
1037 }
1038
1039 MockObjectMap mock_object_map;
1040 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1041 mock_image_ctx.object_map = &mock_object_map;
1042 }
1043
1044 InSequence seq;
1045 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1046 expect_object_may_exist(mock_image_ctx, 0, true);
1047 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1048 expect_zero(mock_image_ctx, 1, 1, 0);
1049
1050 C_SaferCond ctx;
1051 auto req = MockObjectDiscardRequest::create_discard(
1052 &mock_image_ctx, ictx->get_object_name(0), 0, 1, 1, mock_image_ctx.snapc,
1053 false, true, {}, &ctx);
1054 req->send();
1055 ASSERT_EQ(0, ctx.wait());
1056 }
1057
1058 TEST_F(TestMockIoObjectRequest, DiscardDisableObjectMapUpdate) {
1059 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
1060
1061 librbd::ImageCtx *ictx;
1062 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1063
1064 MockTestImageCtx mock_image_ctx(*ictx);
1065 expect_get_object_size(mock_image_ctx);
1066
1067 MockExclusiveLock mock_exclusive_lock;
1068 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1069 expect_is_lock_owner(mock_exclusive_lock);
1070
1071 MockObjectMap mock_object_map;
1072 mock_image_ctx.object_map = &mock_object_map;
1073
1074 InSequence seq;
1075 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1076 expect_object_may_exist(mock_image_ctx, 0, true);
1077 expect_remove(mock_image_ctx, 0);
1078
1079 C_SaferCond ctx;
1080 auto req = MockObjectDiscardRequest::create_discard(
1081 &mock_image_ctx, ictx->get_object_name(0), 0, 0,
1082 mock_image_ctx.get_object_size(), mock_image_ctx.snapc, true, false, {},
1083 &ctx);
1084 req->send();
1085 ASSERT_EQ(0, ctx.wait());
1086 }
1087
1088 TEST_F(TestMockIoObjectRequest, DiscardNoOp) {
1089 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
1090
1091 librbd::ImageCtx *ictx;
1092 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1093
1094 MockTestImageCtx mock_image_ctx(*ictx);
1095 expect_op_work_queue(mock_image_ctx);
1096 expect_get_object_size(mock_image_ctx);
1097
1098 MockExclusiveLock mock_exclusive_lock;
1099 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1100 expect_is_lock_owner(mock_exclusive_lock);
1101
1102 MockObjectMap mock_object_map;
1103 mock_image_ctx.object_map = &mock_object_map;
1104
1105 InSequence seq;
1106 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1107 expect_object_may_exist(mock_image_ctx, 0, false);
1108
1109 C_SaferCond ctx;
1110 auto req = MockObjectDiscardRequest::create_discard(
1111 &mock_image_ctx, ictx->get_object_name(0), 0, 0,
1112 mock_image_ctx.get_object_size(), mock_image_ctx.snapc, true, false, {},
1113 &ctx);
1114 req->send();
1115 ASSERT_EQ(0, ctx.wait());
1116 }
1117
1118 TEST_F(TestMockIoObjectRequest, WriteSame) {
1119 librbd::ImageCtx *ictx;
1120 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1121
1122 MockTestImageCtx mock_image_ctx(*ictx);
1123 expect_get_object_size(mock_image_ctx);
1124
1125 MockExclusiveLock mock_exclusive_lock;
1126 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1127 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1128 expect_is_lock_owner(mock_exclusive_lock);
1129 }
1130
1131 MockObjectMap mock_object_map;
1132 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1133 mock_image_ctx.object_map = &mock_object_map;
1134 }
1135
1136 bufferlist bl;
1137 bl.append(std::string(4096, '1'));
1138
1139 InSequence seq;
1140 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1141 expect_object_may_exist(mock_image_ctx, 0, true);
1142 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1143 expect_writesame(mock_image_ctx, 0, 4096, 0);
1144
1145 C_SaferCond ctx;
1146 auto req = MockObjectWriteSameRequest::create_writesame(
1147 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, bl,
1148 mock_image_ctx.snapc, 0, {}, &ctx);
1149 req->send();
1150 ASSERT_EQ(0, ctx.wait());
1151 }
1152
1153 TEST_F(TestMockIoObjectRequest, CompareAndWrite) {
1154 librbd::ImageCtx *ictx;
1155 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1156
1157 MockTestImageCtx mock_image_ctx(*ictx);
1158 expect_get_object_size(mock_image_ctx);
1159
1160 MockExclusiveLock mock_exclusive_lock;
1161 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1162 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1163 expect_is_lock_owner(mock_exclusive_lock);
1164 }
1165
1166 MockObjectMap mock_object_map;
1167 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1168 mock_image_ctx.object_map = &mock_object_map;
1169 }
1170
1171 bufferlist cmp_bl;
1172 cmp_bl.append_zero(4096);
1173
1174 bufferlist bl;
1175 bl.append(std::string(4096, '1'));
1176
1177 InSequence seq;
1178 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1179 expect_object_may_exist(mock_image_ctx, 0, true);
1180 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1181 expect_cmpext(mock_image_ctx, 0, 0);
1182 expect_write(mock_image_ctx, 0, 4096, 0);
1183
1184 C_SaferCond ctx;
1185 uint64_t mismatch_offset;
1186 auto req = MockObjectWriteSameRequest::create_compare_and_write(
1187 &mock_image_ctx, ictx->get_object_name(0), 0, 0, cmp_bl, bl,
1188 mock_image_ctx.snapc, &mismatch_offset, 0, {}, &ctx);
1189 req->send();
1190 ASSERT_EQ(0, ctx.wait());
1191 }
1192
1193 TEST_F(TestMockIoObjectRequest, CompareAndWriteFull) {
1194 librbd::ImageCtx *ictx;
1195 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1196
1197 MockTestImageCtx mock_image_ctx(*ictx);
1198 expect_get_object_size(mock_image_ctx);
1199
1200 MockExclusiveLock mock_exclusive_lock;
1201 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1202 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1203 expect_is_lock_owner(mock_exclusive_lock);
1204 }
1205
1206 MockObjectMap mock_object_map;
1207 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1208 mock_image_ctx.object_map = &mock_object_map;
1209 }
1210
1211 bufferlist cmp_bl;
1212 cmp_bl.append_zero(ictx->get_object_size());
1213
1214 bufferlist bl;
1215 bl.append(std::string(ictx->get_object_size(), '1'));
1216
1217 InSequence seq;
1218 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1219 expect_object_may_exist(mock_image_ctx, 0, true);
1220 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1221 expect_cmpext(mock_image_ctx, 0, 0);
1222 expect_write_full(mock_image_ctx, 0);
1223
1224 C_SaferCond ctx;
1225 uint64_t mismatch_offset;
1226 auto req = MockObjectWriteSameRequest::create_compare_and_write(
1227 &mock_image_ctx, ictx->get_object_name(0), 0, 0, cmp_bl, bl,
1228 mock_image_ctx.snapc, &mismatch_offset, 0, {}, &ctx);
1229 req->send();
1230 ASSERT_EQ(0, ctx.wait());
1231 }
1232
1233 TEST_F(TestMockIoObjectRequest, CompareAndWriteCopyup) {
1234 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1235
1236 librbd::Image image;
1237 librbd::RBD rbd;
1238 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
1239 ASSERT_EQ(0, image.snap_create("one"));
1240 ASSERT_EQ(0, image.snap_protect("one"));
1241 image.close();
1242
1243 std::string clone_name = get_temp_image_name();
1244 int order = 0;
1245 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
1246 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
1247
1248 librbd::ImageCtx *ictx;
1249 ASSERT_EQ(0, open_image(clone_name, &ictx));
1250
1251 MockTestImageCtx mock_image_ctx(*ictx);
1252 expect_get_object_size(mock_image_ctx);
1253
1254 MockExclusiveLock mock_exclusive_lock;
1255 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1256 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1257 expect_is_lock_owner(mock_exclusive_lock);
1258 }
1259
1260 MockObjectMap mock_object_map;
1261 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1262 mock_image_ctx.object_map = &mock_object_map;
1263 }
1264
1265 bufferlist cmp_bl;
1266 cmp_bl.append_zero(4096);
1267
1268 bufferlist bl;
1269 bl.append(std::string(4096, '1'));
1270
1271 InSequence seq;
1272 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
1273 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
1274 expect_object_may_exist(mock_image_ctx, 0, true);
1275 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1276 expect_assert_exists(mock_image_ctx, -ENOENT);
1277
1278 MockAbstractObjectWriteRequest *write_request = nullptr;
1279 MockCopyupRequest mock_copyup_request;
1280 expect_copyup(mock_copyup_request, &write_request, 0);
1281
1282 expect_assert_exists(mock_image_ctx, 0);
1283 expect_cmpext(mock_image_ctx, 0, 0);
1284 expect_write(mock_image_ctx, 0, 4096, 0);
1285
1286 C_SaferCond ctx;
1287 uint64_t mismatch_offset;
1288 auto req = MockObjectWriteSameRequest::create_compare_and_write(
1289 &mock_image_ctx, ictx->get_object_name(0), 0, 0, cmp_bl, bl,
1290 mock_image_ctx.snapc, &mismatch_offset, 0, {}, &ctx);
1291 req->send();
1292 ASSERT_EQ(0, ctx.wait());
1293 }
1294
1295 TEST_F(TestMockIoObjectRequest, CompareAndWriteMismatch) {
1296 librbd::ImageCtx *ictx;
1297 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1298
1299 MockTestImageCtx mock_image_ctx(*ictx);
1300 expect_get_object_size(mock_image_ctx);
1301
1302 MockExclusiveLock mock_exclusive_lock;
1303 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1304 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1305 expect_is_lock_owner(mock_exclusive_lock);
1306 }
1307
1308 MockObjectMap mock_object_map;
1309 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1310 mock_image_ctx.object_map = &mock_object_map;
1311 }
1312
1313 bufferlist cmp_bl;
1314 cmp_bl.append_zero(4096);
1315
1316 bufferlist bl;
1317 bl.append(std::string(4096, '1'));
1318
1319 InSequence seq;
1320 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1321 expect_object_may_exist(mock_image_ctx, 0, true);
1322 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1323 expect_cmpext(mock_image_ctx, 0, -MAX_ERRNO - 1);
1324
1325 C_SaferCond ctx;
1326 uint64_t mismatch_offset;
1327 auto req = MockObjectWriteSameRequest::create_compare_and_write(
1328 &mock_image_ctx, ictx->get_object_name(0), 0, 0, cmp_bl, bl,
1329 mock_image_ctx.snapc, &mismatch_offset, 0, {}, &ctx);
1330 req->send();
1331 ASSERT_EQ(-EILSEQ, ctx.wait());
1332 ASSERT_EQ(1ULL, mismatch_offset);
1333 }
1334
1335 } // namespace io
1336 } // namespace librbd
1337