]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/io/test_mock_ObjectRequest.cc
update sources to 12.2.10
[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"
13#include "librbd/io/ImageRequest.h"
14#include "librbd/io/ObjectRequest.h"
15
16namespace librbd {
17namespace {
18
19struct MockTestImageCtx : public MockImageCtx {
20 MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
21 }
22};
23
24} // anonymous namespace
25
26namespace util {
27
28inline ImageCtx *get_image_ctx(MockImageCtx *image_ctx) {
29 return image_ctx->image_ctx;
30}
31
32} // namespace util
33
34namespace io {
35
36template <>
37struct CopyupRequest<librbd::MockImageCtx> {
38 MOCK_METHOD0(send, void());
39 MOCK_METHOD1(append_request, void(AbstractObjectWriteRequest<librbd::MockTestImageCtx>*));
40};
41
42template <>
43struct 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
57template <>
58struct 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
73CopyupRequest<librbd::MockTestImageCtx>* CopyupRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
74ImageRequest<librbd::MockTestImageCtx>* ImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
75
76} // namespace io
77} // namespace librbd
78
79#include "librbd/io/ObjectRequest.cc"
80
81namespace librbd {
82namespace io {
83
84using ::testing::_;
85using ::testing::DoDefault;
86using ::testing::InSequence;
87using ::testing::Invoke;
88using ::testing::Return;
89using ::testing::WithArg;
90using ::testing::WithArgs;
91
92struct 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,
91327a77
AA
235 current_state, _, false, _))
236 .WillOnce(WithArg<7>(Invoke([&mock_image_ctx, updated, ret_val](Context *ctx) {
b32b8144
FG
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
94b18763
FG
292 void expect_create(MockTestImageCtx &mock_image_ctx, bool exclusive) {
293 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx), create(_, exclusive))
294 .Times(1);
295 }
296
b32b8144
FG
297 void expect_truncate(MockTestImageCtx &mock_image_ctx, int offset, int r) {
298 auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
299 truncate(_, offset, _));
300 if (r < 0) {
301 expect.WillOnce(Return(r));
302 } else {
303 expect.WillOnce(DoDefault());
304 }
305 }
306
307 void expect_zero(MockTestImageCtx &mock_image_ctx, int offset, int length,
308 int r) {
309 auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
310 zero(_, offset, length, _));
311 if (r < 0) {
312 expect.WillOnce(Return(r));
313 } else {
314 expect.WillOnce(DoDefault());
315 }
316 }
317
318 void expect_cmpext(MockTestImageCtx &mock_image_ctx, int offset, int r) {
319 auto &expect = EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
320 cmpext(_, offset, _));
321 if (r < 0) {
322 expect.WillOnce(Return(r));
323 } else {
324 expect.WillOnce(DoDefault());
325 }
326 }
327};
328
329TEST_F(TestMockIoObjectRequest, Read) {
330 librbd::ImageCtx *ictx;
331 ASSERT_EQ(0, open_image(m_image_name, &ictx));
332 ictx->sparse_read_threshold_bytes = 8096;
333
334 MockTestImageCtx mock_image_ctx(*ictx);
335 mock_image_ctx.object_cacher = nullptr;
336
337 MockObjectMap mock_object_map;
338 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
339 mock_image_ctx.object_map = &mock_object_map;
340 }
341
342 InSequence seq;
343 expect_object_may_exist(mock_image_ctx, 0, true);
344 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
345 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096,
346 std::string(4096, '1'), 0);
347
348 C_SaferCond ctx;
349 auto req = MockObjectReadRequest::create(
350 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0,
351 false, {}, &ctx);
352 req->send();
353 ASSERT_EQ(0, ctx.wait());
354}
355
356TEST_F(TestMockIoObjectRequest, SparseReadThreshold) {
357 librbd::ImageCtx *ictx;
358 ASSERT_EQ(0, open_image(m_image_name, &ictx));
359 ictx->sparse_read_threshold_bytes = ictx->get_object_size();
360
361 MockTestImageCtx mock_image_ctx(*ictx);
362 mock_image_ctx.object_cacher = nullptr;
363
364 MockObjectMap mock_object_map;
365 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
366 mock_image_ctx.object_map = &mock_object_map;
367 }
368
369 InSequence seq;
370 expect_object_may_exist(mock_image_ctx, 0, true);
371 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
372 expect_sparse_read(mock_image_ctx, ictx->get_object_name(0), 0,
373 ictx->sparse_read_threshold_bytes,
374 std::string(ictx->sparse_read_threshold_bytes, '1'), 0);
375
376 C_SaferCond ctx;
377 auto req = MockObjectReadRequest::create(
378 &mock_image_ctx, ictx->get_object_name(0), 0, 0,
379 ictx->sparse_read_threshold_bytes, CEPH_NOSNAP, 0, false, {}, &ctx);
380 req->send();
381 ASSERT_EQ(0, ctx.wait());
382}
383
384TEST_F(TestMockIoObjectRequest, ReadError) {
385 librbd::ImageCtx *ictx;
386 ASSERT_EQ(0, open_image(m_image_name, &ictx));
387 ictx->sparse_read_threshold_bytes = 8096;
388
389 MockTestImageCtx mock_image_ctx(*ictx);
390 mock_image_ctx.object_cacher = nullptr;
391
392 MockObjectMap mock_object_map;
393 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
394 mock_image_ctx.object_map = &mock_object_map;
395 }
396
397 InSequence seq;
398 expect_object_may_exist(mock_image_ctx, 0, true);
399 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
400 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -EPERM);
401
402 C_SaferCond ctx;
403 auto req = MockObjectReadRequest::create(
404 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0,
405 false, {}, &ctx);
406 req->send();
407 ASSERT_EQ(-EPERM, ctx.wait());
408}
409
410TEST_F(TestMockIoObjectRequest, CacheRead) {
411 librbd::ImageCtx *ictx;
412 ASSERT_EQ(0, open_image(m_image_name, &ictx));
413 ictx->sparse_read_threshold_bytes = 8096;
414
415 MockTestImageCtx mock_image_ctx(*ictx);
416 MockObjectMap mock_object_map;
417 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
418 mock_image_ctx.object_map = &mock_object_map;
419 }
420
421 expect_op_work_queue(mock_image_ctx);
422
423 InSequence seq;
424 expect_cache_read(mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096,
425 std::string(4096, '1'), 0);
426
427 C_SaferCond ctx;
428 auto req = MockObjectReadRequest::create(
429 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0,
430 false, {}, &ctx);
431 req->send();
432 ASSERT_EQ(0, ctx.wait());
433}
434
435TEST_F(TestMockIoObjectRequest, CacheReadError) {
436 librbd::ImageCtx *ictx;
437 ASSERT_EQ(0, open_image(m_image_name, &ictx));
438 ictx->sparse_read_threshold_bytes = 8096;
439
440 MockTestImageCtx mock_image_ctx(*ictx);
441 MockObjectMap mock_object_map;
442 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
443 mock_image_ctx.object_map = &mock_object_map;
444 }
445
446 expect_op_work_queue(mock_image_ctx);
447
448 InSequence seq;
449 expect_cache_read(mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096,
450 "", -EPERM);
451
452 C_SaferCond ctx;
453 auto req = MockObjectReadRequest::create(
454 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0,
455 false, {}, &ctx);
456 req->send();
457 ASSERT_EQ(-EPERM, ctx.wait());
458}
459
460TEST_F(TestMockIoObjectRequest, ParentRead) {
461 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
462
463 librbd::Image image;
464 librbd::RBD rbd;
465 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
466 ASSERT_EQ(0, image.snap_create("one"));
467 ASSERT_EQ(0, image.snap_protect("one"));
468 image.close();
469
470 std::string clone_name = get_temp_image_name();
471 int order = 0;
472 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
473 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
474
475 librbd::ImageCtx *ictx;
476 ASSERT_EQ(0, open_image(clone_name, &ictx));
477 ictx->sparse_read_threshold_bytes = 8096;
478 ictx->clone_copy_on_read = false;
479
480 MockTestImageCtx mock_image_ctx(*ictx);
481 mock_image_ctx.parent = &mock_image_ctx;
482 mock_image_ctx.object_cacher = nullptr;
483
484 MockObjectMap mock_object_map;
485 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
486 mock_image_ctx.object_map = &mock_object_map;
487 }
488
489 InSequence seq;
490 expect_object_may_exist(mock_image_ctx, 0, true);
491 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
492 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
493
494 MockImageRequest mock_image_request;
495 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
496 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
497 expect_aio_read(mock_image_request, {{0, 4096}}, 0);
498
499 C_SaferCond ctx;
500 auto req = MockObjectReadRequest::create(
501 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0,
502 false, {}, &ctx);
503 req->send();
504 ASSERT_EQ(0, ctx.wait());
505}
506
507TEST_F(TestMockIoObjectRequest, ParentReadError) {
508 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
509
510 librbd::Image image;
511 librbd::RBD rbd;
512 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
513 ASSERT_EQ(0, image.snap_create("one"));
514 ASSERT_EQ(0, image.snap_protect("one"));
515 image.close();
516
517 std::string clone_name = get_temp_image_name();
518 int order = 0;
519 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
520 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
521
522 librbd::ImageCtx *ictx;
523 ASSERT_EQ(0, open_image(clone_name, &ictx));
524 ictx->sparse_read_threshold_bytes = 8096;
525 ictx->clone_copy_on_read = false;
526
527 MockTestImageCtx mock_image_ctx(*ictx);
528 mock_image_ctx.parent = &mock_image_ctx;
529 mock_image_ctx.object_cacher = nullptr;
530
531 MockObjectMap mock_object_map;
532 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
533 mock_image_ctx.object_map = &mock_object_map;
534 }
535
536 InSequence seq;
537 expect_object_may_exist(mock_image_ctx, 0, true);
538 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
539 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
540
541 MockImageRequest mock_image_request;
542 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
543 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
544 expect_aio_read(mock_image_request, {{0, 4096}}, -EPERM);
545
546 C_SaferCond ctx;
547 auto req = MockObjectReadRequest::create(
548 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0,
549 false, {}, &ctx);
550 req->send();
551 ASSERT_EQ(-EPERM, ctx.wait());
552}
553
554TEST_F(TestMockIoObjectRequest, CacheInitiated) {
555 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
556
557 librbd::Image image;
558 librbd::RBD rbd;
559 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
560 ASSERT_EQ(0, image.snap_create("one"));
561 ASSERT_EQ(0, image.snap_protect("one"));
562 image.close();
563
564 std::string clone_name = get_temp_image_name();
565 int order = 0;
566 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
567 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
568
569 librbd::ImageCtx *ictx;
570 ASSERT_EQ(0, open_image(clone_name, &ictx));
571 ictx->sparse_read_threshold_bytes = 8096;
572 ictx->clone_copy_on_read = false;
573
574 MockTestImageCtx mock_image_ctx(*ictx);
575 mock_image_ctx.parent = &mock_image_ctx;
576
577 MockObjectMap mock_object_map;
578 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
579 mock_image_ctx.object_map = &mock_object_map;
580 }
581
582 InSequence seq;
583 expect_object_may_exist(mock_image_ctx, 0, true);
584 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
585 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
586
587 C_SaferCond ctx;
588 auto req = MockObjectReadRequest::create(
589 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0, true,
590 {}, &ctx);
591 req->send();
592 ASSERT_EQ(-ENOENT, ctx.wait());
593}
594
595TEST_F(TestMockIoObjectRequest, CopyOnRead) {
596 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
597
598 librbd::Image image;
599 librbd::RBD rbd;
600 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
601 ASSERT_EQ(0, image.snap_create("one"));
602 ASSERT_EQ(0, image.snap_protect("one"));
603 image.close();
604
605 std::string clone_name = get_temp_image_name();
606 int order = 0;
607 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
608 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
609
610 librbd::ImageCtx *ictx;
611 ASSERT_EQ(0, open_image(clone_name, &ictx));
612 ictx->sparse_read_threshold_bytes = 8096;
613 ictx->clone_copy_on_read = true;
614
615 MockTestImageCtx mock_image_ctx(*ictx);
616 mock_image_ctx.parent = &mock_image_ctx;
617 mock_image_ctx.object_cacher = nullptr;
618
619 MockObjectMap mock_object_map;
620 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
621 mock_image_ctx.object_map = &mock_object_map;
622 }
623
624 InSequence seq;
625 expect_object_may_exist(mock_image_ctx, 0, true);
626 expect_get_read_flags(mock_image_ctx, CEPH_NOSNAP, 0);
627 expect_read(mock_image_ctx, ictx->get_object_name(0), 0, 4096, "", -ENOENT);
628
629 MockImageRequest mock_image_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_aio_read(mock_image_request, {{0, 4096}}, 0);
633
634 MockCopyupRequest mock_copyup_request;
635 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
636 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
637 expect_copyup(mock_copyup_request, 0);
638
639 C_SaferCond ctx;
640 auto req = MockObjectReadRequest::create(
641 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, CEPH_NOSNAP, 0,
642 false, {}, &ctx);
643 req->send();
644 ASSERT_EQ(0, ctx.wait());
645}
646
647TEST_F(TestMockIoObjectRequest, Write) {
648 librbd::ImageCtx *ictx;
649 ASSERT_EQ(0, open_image(m_image_name, &ictx));
650
651 MockTestImageCtx mock_image_ctx(*ictx);
652 expect_get_object_size(mock_image_ctx);
653
654 MockExclusiveLock mock_exclusive_lock;
655 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
656 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
657 expect_is_lock_owner(mock_exclusive_lock);
658 }
659
660 MockObjectMap mock_object_map;
661 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
662 mock_image_ctx.object_map = &mock_object_map;
663 }
664
665 bufferlist bl;
666 bl.append(std::string(4096, '1'));
667
668 InSequence seq;
669 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
670 expect_object_may_exist(mock_image_ctx, 0, true);
671 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
672 expect_write(mock_image_ctx, 0, 4096, 0);
673
674 C_SaferCond ctx;
675 auto req = MockObjectWriteRequest::create_write(
676 &mock_image_ctx, ictx->get_object_name(0), 0, 0, bl, mock_image_ctx.snapc,
677 0, {}, &ctx);
678 req->send();
679 ASSERT_EQ(0, ctx.wait());
680}
681
682TEST_F(TestMockIoObjectRequest, WriteFull) {
683 librbd::ImageCtx *ictx;
684 ASSERT_EQ(0, open_image(m_image_name, &ictx));
685
686 MockTestImageCtx mock_image_ctx(*ictx);
687 expect_get_object_size(mock_image_ctx);
688
689 MockExclusiveLock mock_exclusive_lock;
690 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
691 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
692 expect_is_lock_owner(mock_exclusive_lock);
693 }
694
695 MockObjectMap mock_object_map;
696 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
697 mock_image_ctx.object_map = &mock_object_map;
698 }
699
700 bufferlist bl;
701 bl.append(std::string(ictx->get_object_size(), '1'));
702
703 InSequence seq;
704 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
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_write_full(mock_image_ctx, 0);
708
709 C_SaferCond ctx;
710 auto req = MockObjectWriteRequest::create_write(
711 &mock_image_ctx, ictx->get_object_name(0), 0, 0, bl, mock_image_ctx.snapc,
712 0, {}, &ctx);
713 req->send();
714 ASSERT_EQ(0, ctx.wait());
715}
716
717TEST_F(TestMockIoObjectRequest, WriteObjectMap) {
718 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
719
720 librbd::ImageCtx *ictx;
721 ASSERT_EQ(0, open_image(m_image_name, &ictx));
722
723 MockTestImageCtx mock_image_ctx(*ictx);
724 expect_op_work_queue(mock_image_ctx);
725 expect_get_object_size(mock_image_ctx);
726
727 MockExclusiveLock mock_exclusive_lock;
728 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
729 expect_is_lock_owner(mock_exclusive_lock);
730
731 MockObjectMap mock_object_map;
732 mock_image_ctx.object_map = &mock_object_map;
733
734 bufferlist bl;
735 bl.append(std::string(4096, '1'));
736
737 InSequence seq;
738 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
739 expect_object_may_exist(mock_image_ctx, 0, true);
740 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, true, 0);
741 expect_write(mock_image_ctx, 0, 4096, 0);
742
743 C_SaferCond ctx;
744 auto req = MockObjectWriteRequest::create_write(
745 &mock_image_ctx, ictx->get_object_name(0), 0, 0, bl, mock_image_ctx.snapc,
746 0, {}, &ctx);
747 req->send();
748 ASSERT_EQ(0, ctx.wait());
749}
750
751TEST_F(TestMockIoObjectRequest, WriteError) {
752 librbd::ImageCtx *ictx;
753 ASSERT_EQ(0, open_image(m_image_name, &ictx));
754
755 MockTestImageCtx mock_image_ctx(*ictx);
756 expect_get_object_size(mock_image_ctx);
757
758 bufferlist bl;
759 bl.append(std::string(4096, '1'));
760
761 InSequence seq;
762 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
763 expect_write(mock_image_ctx, 0, 4096, -EPERM);
764
765 C_SaferCond ctx;
766 auto req = MockObjectWriteRequest::create_write(
767 &mock_image_ctx, ictx->get_object_name(0), 0, 0, bl, mock_image_ctx.snapc,
768 0, {}, &ctx);
769 req->send();
770 ASSERT_EQ(-EPERM, ctx.wait());
771}
772
773TEST_F(TestMockIoObjectRequest, Copyup) {
774 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
775
776 librbd::Image image;
777 librbd::RBD rbd;
778 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
779 ASSERT_EQ(0, image.snap_create("one"));
780 ASSERT_EQ(0, image.snap_protect("one"));
781 image.close();
782
783 std::string clone_name = get_temp_image_name();
784 int order = 0;
785 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
786 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
787
788 librbd::ImageCtx *ictx;
789 ASSERT_EQ(0, open_image(clone_name, &ictx));
790
791 MockTestImageCtx mock_image_ctx(*ictx);
792 expect_get_object_size(mock_image_ctx);
793
794 MockExclusiveLock mock_exclusive_lock;
795 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
796 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
797 expect_is_lock_owner(mock_exclusive_lock);
798 }
799
800 MockObjectMap mock_object_map;
801 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
802 mock_image_ctx.object_map = &mock_object_map;
803 }
804
805 bufferlist bl;
806 bl.append(std::string(4096, '1'));
807
808 InSequence seq;
809 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
810 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
811 expect_object_may_exist(mock_image_ctx, 0, true);
812 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
813 expect_assert_exists(mock_image_ctx, -ENOENT);
814
815 MockAbstractObjectWriteRequest *write_request = nullptr;
816 MockCopyupRequest mock_copyup_request;
817 expect_copyup(mock_copyup_request, &write_request, 0);
818
819 C_SaferCond ctx;
820 auto req = MockObjectWriteRequest::create_write(
821 &mock_image_ctx, ictx->get_object_name(0), 0, 0, bl, mock_image_ctx.snapc,
822 0, {}, &ctx);
823 req->send();
824 ASSERT_EQ(0, ctx.wait());
825}
826
827TEST_F(TestMockIoObjectRequest, CopyupOptimization) {
828 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_OBJECT_MAP);
829
830 librbd::Image image;
831 librbd::RBD rbd;
832 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
833 ASSERT_EQ(0, image.snap_create("one"));
834 ASSERT_EQ(0, image.snap_protect("one"));
835 image.close();
836
837 std::string clone_name = get_temp_image_name();
838 int order = 0;
839 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
840 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
841
842 librbd::ImageCtx *ictx;
843 ASSERT_EQ(0, open_image(clone_name, &ictx));
844
845 MockTestImageCtx mock_image_ctx(*ictx);
846 expect_get_object_size(mock_image_ctx);
847
848 MockExclusiveLock mock_exclusive_lock;
849 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
850 expect_is_lock_owner(mock_exclusive_lock);
851
852 MockObjectMap mock_object_map;
853 mock_image_ctx.object_map = &mock_object_map;
854
855 bufferlist bl;
856 bl.append(std::string(4096, '1'));
857
858 InSequence seq;
859 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
860 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
861 expect_object_may_exist(mock_image_ctx, 0, false);
862
863 MockAbstractObjectWriteRequest *write_request = nullptr;
864 MockCopyupRequest mock_copyup_request;
865 expect_copyup(mock_copyup_request, &write_request, 0);
866
867 C_SaferCond ctx;
868 auto req = MockObjectWriteRequest::create_write(
869 &mock_image_ctx, ictx->get_object_name(0), 0, 0, bl, mock_image_ctx.snapc,
870 0, {}, &ctx);
871 req->send();
872 ASSERT_EQ(0, ctx.wait());
873}
874
875TEST_F(TestMockIoObjectRequest, CopyupError) {
876 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
877
878 librbd::Image image;
879 librbd::RBD rbd;
880 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
881 ASSERT_EQ(0, image.snap_create("one"));
882 ASSERT_EQ(0, image.snap_protect("one"));
883 image.close();
884
885 std::string clone_name = get_temp_image_name();
886 int order = 0;
887 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
888 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
889
890 librbd::ImageCtx *ictx;
891 ASSERT_EQ(0, open_image(clone_name, &ictx));
892
893 MockTestImageCtx mock_image_ctx(*ictx);
894 expect_get_object_size(mock_image_ctx);
895
896 bufferlist bl;
897 bl.append(std::string(4096, '1'));
898
899 InSequence seq;
900 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
901 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
902 expect_assert_exists(mock_image_ctx, -ENOENT);
903
904 MockAbstractObjectWriteRequest *write_request = nullptr;
905 MockCopyupRequest mock_copyup_request;
906 expect_copyup(mock_copyup_request, &write_request, -EPERM);
907
908 C_SaferCond ctx;
909 auto req = MockObjectWriteRequest::create_write(
910 &mock_image_ctx, ictx->get_object_name(0), 0, 0, bl, mock_image_ctx.snapc,
911 0, {}, &ctx);
912 req->send();
913 ASSERT_EQ(-EPERM, ctx.wait());
914}
915
916TEST_F(TestMockIoObjectRequest, DiscardRemove) {
917 librbd::ImageCtx *ictx;
918 ASSERT_EQ(0, open_image(m_image_name, &ictx));
919
920 MockTestImageCtx mock_image_ctx(*ictx);
921 expect_get_object_size(mock_image_ctx);
922
923 MockExclusiveLock mock_exclusive_lock;
924 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
925 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
926 expect_is_lock_owner(mock_exclusive_lock);
927 }
928
929 MockObjectMap mock_object_map;
930 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
931 mock_image_ctx.object_map = &mock_object_map;
932 }
933
934 InSequence seq;
935 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
936 expect_object_may_exist(mock_image_ctx, 0, true);
937 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_PENDING, {}, false, 0);
938 expect_remove(mock_image_ctx, 0);
939 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_NONEXISTENT,
940 OBJECT_PENDING, false, 0);
941
942 C_SaferCond ctx;
943 auto req = MockObjectDiscardRequest::create_discard(
944 &mock_image_ctx, ictx->get_object_name(0), 0, 0,
945 mock_image_ctx.get_object_size(), mock_image_ctx.snapc, false, true, {},
946 &ctx);
947 req->send();
948 ASSERT_EQ(0, ctx.wait());
949}
950
951TEST_F(TestMockIoObjectRequest, DiscardRemoveTruncate) {
952 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
953
954 librbd::Image image;
955 librbd::RBD rbd;
956 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
957 ASSERT_EQ(0, image.snap_create("one"));
958 ASSERT_EQ(0, image.snap_protect("one"));
94b18763
FG
959 uint64_t features;
960 ASSERT_EQ(0, image.features(&features));
b32b8144
FG
961 image.close();
962
963 std::string clone_name = get_temp_image_name();
964 int order = 0;
965 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
94b18763 966 clone_name.c_str(), features, &order));
b32b8144
FG
967
968 librbd::ImageCtx *ictx;
969 ASSERT_EQ(0, open_image(clone_name, &ictx));
970
971 MockTestImageCtx mock_image_ctx(*ictx);
972 expect_get_object_size(mock_image_ctx);
973
974 MockExclusiveLock mock_exclusive_lock;
975 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
976 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
977 expect_is_lock_owner(mock_exclusive_lock);
978 }
979
980 MockObjectMap mock_object_map;
981 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
982 mock_image_ctx.object_map = &mock_object_map;
983 }
984
985 InSequence seq;
986 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
987 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
94b18763
FG
988 expect_object_may_exist(mock_image_ctx, 0, false);
989 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
990 expect_create(mock_image_ctx, false);
b32b8144
FG
991 expect_truncate(mock_image_ctx, 0, 0);
992
993 C_SaferCond ctx;
994 auto req = MockObjectDiscardRequest::create_discard(
995 &mock_image_ctx, ictx->get_object_name(0), 0, 0,
996 mock_image_ctx.get_object_size(), mock_image_ctx.snapc, true, true, {},
997 &ctx);
998 req->send();
999 ASSERT_EQ(0, ctx.wait());
1000}
1001
1002TEST_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 C_SaferCond ctx;
1027 auto req = MockObjectDiscardRequest::create_discard(
1028 &mock_image_ctx, ictx->get_object_name(0), 0, 1,
1029 mock_image_ctx.get_object_size() - 1, mock_image_ctx.snapc, false, true, {},
1030 &ctx);
1031 req->send();
1032 ASSERT_EQ(0, ctx.wait());
1033}
1034
1035TEST_F(TestMockIoObjectRequest, DiscardZero) {
1036 librbd::ImageCtx *ictx;
1037 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1038
1039 MockTestImageCtx mock_image_ctx(*ictx);
1040 expect_get_object_size(mock_image_ctx);
1041
1042 MockExclusiveLock mock_exclusive_lock;
1043 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1044 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1045 expect_is_lock_owner(mock_exclusive_lock);
1046 }
1047
1048 MockObjectMap mock_object_map;
1049 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1050 mock_image_ctx.object_map = &mock_object_map;
1051 }
1052
1053 InSequence seq;
1054 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1055 expect_object_may_exist(mock_image_ctx, 0, true);
1056 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1057 expect_zero(mock_image_ctx, 1, 1, 0);
1058
1059 C_SaferCond ctx;
1060 auto req = MockObjectDiscardRequest::create_discard(
1061 &mock_image_ctx, ictx->get_object_name(0), 0, 1, 1, mock_image_ctx.snapc,
1062 false, true, {}, &ctx);
1063 req->send();
1064 ASSERT_EQ(0, ctx.wait());
1065}
1066
1067TEST_F(TestMockIoObjectRequest, DiscardDisableObjectMapUpdate) {
1068 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
1069
1070 librbd::ImageCtx *ictx;
1071 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1072
1073 MockTestImageCtx mock_image_ctx(*ictx);
1074 expect_get_object_size(mock_image_ctx);
1075
1076 MockExclusiveLock mock_exclusive_lock;
1077 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1078 expect_is_lock_owner(mock_exclusive_lock);
1079
1080 MockObjectMap mock_object_map;
1081 mock_image_ctx.object_map = &mock_object_map;
1082
1083 InSequence seq;
1084 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1085 expect_object_may_exist(mock_image_ctx, 0, true);
1086 expect_remove(mock_image_ctx, 0);
1087
1088 C_SaferCond ctx;
1089 auto req = MockObjectDiscardRequest::create_discard(
1090 &mock_image_ctx, ictx->get_object_name(0), 0, 0,
1091 mock_image_ctx.get_object_size(), mock_image_ctx.snapc, true, false, {},
1092 &ctx);
1093 req->send();
1094 ASSERT_EQ(0, ctx.wait());
1095}
1096
1097TEST_F(TestMockIoObjectRequest, DiscardNoOp) {
1098 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
1099
1100 librbd::ImageCtx *ictx;
1101 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1102
1103 MockTestImageCtx mock_image_ctx(*ictx);
1104 expect_op_work_queue(mock_image_ctx);
1105 expect_get_object_size(mock_image_ctx);
1106
1107 MockExclusiveLock mock_exclusive_lock;
1108 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1109 expect_is_lock_owner(mock_exclusive_lock);
1110
1111 MockObjectMap mock_object_map;
1112 mock_image_ctx.object_map = &mock_object_map;
1113
1114 InSequence seq;
1115 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1116 expect_object_may_exist(mock_image_ctx, 0, false);
1117
1118 C_SaferCond ctx;
1119 auto req = MockObjectDiscardRequest::create_discard(
1120 &mock_image_ctx, ictx->get_object_name(0), 0, 0,
1121 mock_image_ctx.get_object_size(), mock_image_ctx.snapc, true, false, {},
1122 &ctx);
1123 req->send();
1124 ASSERT_EQ(0, ctx.wait());
1125}
1126
1127TEST_F(TestMockIoObjectRequest, WriteSame) {
1128 librbd::ImageCtx *ictx;
1129 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1130
1131 MockTestImageCtx mock_image_ctx(*ictx);
1132 expect_get_object_size(mock_image_ctx);
1133
1134 MockExclusiveLock mock_exclusive_lock;
1135 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1136 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1137 expect_is_lock_owner(mock_exclusive_lock);
1138 }
1139
1140 MockObjectMap mock_object_map;
1141 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1142 mock_image_ctx.object_map = &mock_object_map;
1143 }
1144
1145 bufferlist bl;
1146 bl.append(std::string(4096, '1'));
1147
1148 InSequence seq;
1149 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1150 expect_object_may_exist(mock_image_ctx, 0, true);
1151 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1152 expect_writesame(mock_image_ctx, 0, 4096, 0);
1153
1154 C_SaferCond ctx;
1155 auto req = MockObjectWriteSameRequest::create_writesame(
1156 &mock_image_ctx, ictx->get_object_name(0), 0, 0, 4096, bl,
1157 mock_image_ctx.snapc, 0, {}, &ctx);
1158 req->send();
1159 ASSERT_EQ(0, ctx.wait());
1160}
1161
1162TEST_F(TestMockIoObjectRequest, CompareAndWrite) {
1163 librbd::ImageCtx *ictx;
1164 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1165
1166 MockTestImageCtx mock_image_ctx(*ictx);
1167 expect_get_object_size(mock_image_ctx);
1168
1169 MockExclusiveLock mock_exclusive_lock;
1170 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1171 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1172 expect_is_lock_owner(mock_exclusive_lock);
1173 }
1174
1175 MockObjectMap mock_object_map;
1176 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1177 mock_image_ctx.object_map = &mock_object_map;
1178 }
1179
1180 bufferlist cmp_bl;
1181 cmp_bl.append_zero(4096);
1182
1183 bufferlist bl;
1184 bl.append(std::string(4096, '1'));
1185
1186 InSequence seq;
1187 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1188 expect_object_may_exist(mock_image_ctx, 0, true);
1189 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1190 expect_cmpext(mock_image_ctx, 0, 0);
1191 expect_write(mock_image_ctx, 0, 4096, 0);
1192
1193 C_SaferCond ctx;
1194 uint64_t mismatch_offset;
1195 auto req = MockObjectWriteSameRequest::create_compare_and_write(
1196 &mock_image_ctx, ictx->get_object_name(0), 0, 0, cmp_bl, bl,
1197 mock_image_ctx.snapc, &mismatch_offset, 0, {}, &ctx);
1198 req->send();
1199 ASSERT_EQ(0, ctx.wait());
1200}
1201
1202TEST_F(TestMockIoObjectRequest, CompareAndWriteFull) {
1203 librbd::ImageCtx *ictx;
1204 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1205
1206 MockTestImageCtx mock_image_ctx(*ictx);
1207 expect_get_object_size(mock_image_ctx);
1208
1209 MockExclusiveLock mock_exclusive_lock;
1210 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1211 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1212 expect_is_lock_owner(mock_exclusive_lock);
1213 }
1214
1215 MockObjectMap mock_object_map;
1216 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1217 mock_image_ctx.object_map = &mock_object_map;
1218 }
1219
1220 bufferlist cmp_bl;
1221 cmp_bl.append_zero(ictx->get_object_size());
1222
1223 bufferlist bl;
1224 bl.append(std::string(ictx->get_object_size(), '1'));
1225
1226 InSequence seq;
1227 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1228 expect_object_may_exist(mock_image_ctx, 0, true);
1229 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1230 expect_cmpext(mock_image_ctx, 0, 0);
1231 expect_write_full(mock_image_ctx, 0);
1232
1233 C_SaferCond ctx;
1234 uint64_t mismatch_offset;
1235 auto req = MockObjectWriteSameRequest::create_compare_and_write(
1236 &mock_image_ctx, ictx->get_object_name(0), 0, 0, cmp_bl, bl,
1237 mock_image_ctx.snapc, &mismatch_offset, 0, {}, &ctx);
1238 req->send();
1239 ASSERT_EQ(0, ctx.wait());
1240}
1241
1242TEST_F(TestMockIoObjectRequest, CompareAndWriteCopyup) {
1243 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1244
1245 librbd::Image image;
1246 librbd::RBD rbd;
1247 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
1248 ASSERT_EQ(0, image.snap_create("one"));
1249 ASSERT_EQ(0, image.snap_protect("one"));
1250 image.close();
1251
1252 std::string clone_name = get_temp_image_name();
1253 int order = 0;
1254 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
1255 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
1256
1257 librbd::ImageCtx *ictx;
1258 ASSERT_EQ(0, open_image(clone_name, &ictx));
1259
1260 MockTestImageCtx mock_image_ctx(*ictx);
1261 expect_get_object_size(mock_image_ctx);
1262
1263 MockExclusiveLock mock_exclusive_lock;
1264 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1265 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1266 expect_is_lock_owner(mock_exclusive_lock);
1267 }
1268
1269 MockObjectMap mock_object_map;
1270 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1271 mock_image_ctx.object_map = &mock_object_map;
1272 }
1273
1274 bufferlist cmp_bl;
1275 cmp_bl.append_zero(4096);
1276
1277 bufferlist bl;
1278 bl.append(std::string(4096, '1'));
1279
1280 InSequence seq;
1281 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 4096, 0);
1282 expect_prune_parent_extents(mock_image_ctx, {{0, 4096}}, 4096, 4096);
1283 expect_object_may_exist(mock_image_ctx, 0, true);
1284 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1285 expect_assert_exists(mock_image_ctx, -ENOENT);
1286
1287 MockAbstractObjectWriteRequest *write_request = nullptr;
1288 MockCopyupRequest mock_copyup_request;
1289 expect_copyup(mock_copyup_request, &write_request, 0);
1290
1291 expect_assert_exists(mock_image_ctx, 0);
1292 expect_cmpext(mock_image_ctx, 0, 0);
1293 expect_write(mock_image_ctx, 0, 4096, 0);
1294
1295 C_SaferCond ctx;
1296 uint64_t mismatch_offset;
1297 auto req = MockObjectWriteSameRequest::create_compare_and_write(
1298 &mock_image_ctx, ictx->get_object_name(0), 0, 0, cmp_bl, bl,
1299 mock_image_ctx.snapc, &mismatch_offset, 0, {}, &ctx);
1300 req->send();
1301 ASSERT_EQ(0, ctx.wait());
1302}
1303
1304TEST_F(TestMockIoObjectRequest, CompareAndWriteMismatch) {
1305 librbd::ImageCtx *ictx;
1306 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1307
1308 MockTestImageCtx mock_image_ctx(*ictx);
1309 expect_get_object_size(mock_image_ctx);
1310
1311 MockExclusiveLock mock_exclusive_lock;
1312 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
1313 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
1314 expect_is_lock_owner(mock_exclusive_lock);
1315 }
1316
1317 MockObjectMap mock_object_map;
1318 if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
1319 mock_image_ctx.object_map = &mock_object_map;
1320 }
1321
1322 bufferlist cmp_bl;
1323 cmp_bl.append_zero(4096);
1324
1325 bufferlist bl;
1326 bl.append(std::string(4096, '1'));
1327
1328 InSequence seq;
1329 expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
1330 expect_object_may_exist(mock_image_ctx, 0, true);
1331 expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false, 0);
1332 expect_cmpext(mock_image_ctx, 0, -MAX_ERRNO - 1);
1333
1334 C_SaferCond ctx;
1335 uint64_t mismatch_offset;
1336 auto req = MockObjectWriteSameRequest::create_compare_and_write(
1337 &mock_image_ctx, ictx->get_object_name(0), 0, 0, cmp_bl, bl,
1338 mock_image_ctx.snapc, &mismatch_offset, 0, {}, &ctx);
1339 req->send();
1340 ASSERT_EQ(-EILSEQ, ctx.wait());
1341 ASSERT_EQ(1ULL, mismatch_offset);
1342}
1343
1344} // namespace io
1345} // namespace librbd
1346