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