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/rbd_mirror/test_fixture.h"
5    	#include "include/stringify.h"
6    	#include "include/rbd/librbd.hpp"
7    	#include "common/Cond.h"
8    	#include "journal/Journaler.h"
9    	#include "journal/Settings.h"
10   	#include "librbd/ExclusiveLock.h"
11   	#include "librbd/ImageCtx.h"
12   	#include "librbd/ImageState.h"
13   	#include "librbd/internal.h"
14   	#include "librbd/Operations.h"
15   	#include "librbd/io/AioCompletion.h"
16   	#include "librbd/io/ImageDispatchSpec.h"
17   	#include "librbd/io/ImageRequestWQ.h"
18   	#include "librbd/io/ReadResult.h"
19   	#include "librbd/journal/Types.h"
20   	#include "tools/rbd_mirror/ImageSync.h"
21   	#include "tools/rbd_mirror/InstanceWatcher.h"
22   	#include "tools/rbd_mirror/Threads.h"
23   	#include "tools/rbd_mirror/Throttler.h"
24   	
25   	void register_test_image_sync() {
26   	}
27   	
28   	namespace rbd {
29   	namespace mirror {
30   	
31   	namespace {
32   	
33   	int flush(librbd::ImageCtx *image_ctx) {
34   	  C_SaferCond ctx;
35   	  auto aio_comp = librbd::io::AioCompletion::create_and_start(
36   	    &ctx, image_ctx, librbd::io::AIO_TYPE_FLUSH);
37   	  auto req = librbd::io::ImageDispatchSpec<>::create_flush_request(
38   	    *image_ctx, aio_comp, librbd::io::FLUSH_SOURCE_INTERNAL, {});
39   	  req->send();
40   	  delete req;
41   	  return ctx.wait();
42   	}
43   	
44   	void scribble(librbd::ImageCtx *image_ctx, int num_ops, uint64_t max_size)
45   	{
46   	  max_size = std::min<uint64_t>(image_ctx->size, max_size);
47   	  for (int i=0; i<num_ops; i++) {
48   	    uint64_t off = rand() % (image_ctx->size - max_size + 1);
(1) Event dont_call: "rand" should not be used for security-related applications, because linear congruential algorithms are too easy to break.
(2) Event remediation: Use a compliant random number generator, such as "/dev/random" or "/dev/urandom" on Unix-like systems, and CNG (Cryptography API: Next Generation) on Windows.
49   	    uint64_t len = 1 + rand() % max_size;
50   	
51   	    if (rand() % 4 == 0) {
52   	      ASSERT_EQ((int)len,
53   	                image_ctx->io_work_queue->discard(
54   	                  off, len, image_ctx->discard_granularity_bytes));
55   	    } else {
56   	      bufferlist bl;
57   	      bl.append(std::string(len, '1'));
58   	      ASSERT_EQ((int)len, image_ctx->io_work_queue->write(off, len,
59   	                                                          std::move(bl), 0));
60   	    }
61   	  }
62   	
63   	  std::shared_lock owner_locker{image_ctx->owner_lock};
64   	  ASSERT_EQ(0, flush(image_ctx));
65   	}
66   	
67   	} // anonymous namespace
68   	class TestImageSync : public TestFixture {
69   	public:
70   	
71   	  void SetUp() override {
72   	    TestFixture::SetUp();
73   	    create_and_open(m_local_io_ctx, &m_local_image_ctx);
74   	    create_and_open(m_remote_io_ctx, &m_remote_image_ctx);
75   	
76   	    auto cct = reinterpret_cast<CephContext*>(m_local_io_ctx.cct());
77   	    m_image_sync_throttler = rbd::mirror::Throttler<>::create(
78   	        cct, "rbd_mirror_concurrent_image_syncs");
79   	
80   	    m_instance_watcher = rbd::mirror::InstanceWatcher<>::create(
81   	        m_local_io_ctx, m_threads->work_queue, nullptr, m_image_sync_throttler);
82   	    m_instance_watcher->handle_acquire_leader();
83   	
84   	    m_remote_journaler = new ::journal::Journaler(
85   	      m_threads->work_queue, m_threads->timer, &m_threads->timer_lock,
86   	      m_remote_io_ctx, m_remote_image_ctx->id, "mirror-uuid", {}, nullptr);
87   	
88   	    m_client_meta = {"image-id"};
89   	
90   	    librbd::journal::ClientData client_data(m_client_meta);
91   	    bufferlist client_data_bl;
92   	    encode(client_data, client_data_bl);
93   	
94   	    ASSERT_EQ(0, m_remote_journaler->register_client(client_data_bl));
95   	  }
96   	
97   	  void TearDown() override {
98   	    m_instance_watcher->handle_release_leader();
99   	
100  	    delete m_remote_journaler;
101  	    delete m_instance_watcher;
102  	    delete m_image_sync_throttler;
103  	
104  	    TestFixture::TearDown();
105  	  }
106  	
107  	  void create_and_open(librados::IoCtx &io_ctx, librbd::ImageCtx **image_ctx) {
108  	    librbd::RBD rbd;
109  	    ASSERT_EQ(0, create_image(rbd, io_ctx, m_image_name, m_image_size));
110  	    ASSERT_EQ(0, open_image(io_ctx, m_image_name, image_ctx));
111  	
112  	    C_SaferCond ctx;
113  	    {
114  	      std::shared_lock owner_locker{(*image_ctx)->owner_lock};
115  	      (*image_ctx)->exclusive_lock->try_acquire_lock(&ctx);
116  	    }
117  	    ASSERT_EQ(0, ctx.wait());
118  	    ASSERT_TRUE((*image_ctx)->exclusive_lock->is_lock_owner());
119  	  }
120  	
121  	  ImageSync<> *create_request(Context *ctx) {
122  	    return new ImageSync<>(m_local_image_ctx, m_remote_image_ctx,
123  	                           m_threads->timer, &m_threads->timer_lock,
124  	                           "mirror-uuid", m_remote_journaler, &m_client_meta,
125  	                           m_threads->work_queue, m_instance_watcher, ctx);
126  	  }
127  	
128  	  librbd::ImageCtx *m_remote_image_ctx;
129  	  librbd::ImageCtx *m_local_image_ctx;
130  	  rbd::mirror::Throttler<> *m_image_sync_throttler;
131  	  rbd::mirror::InstanceWatcher<> *m_instance_watcher;
132  	  ::journal::Journaler *m_remote_journaler;
133  	  librbd::journal::MirrorPeerClientMeta m_client_meta;
134  	};
135  	
136  	TEST_F(TestImageSync, Empty) {
137  	  C_SaferCond ctx;
138  	  ImageSync<> *request = create_request(&ctx);
139  	  request->send();
140  	  ASSERT_EQ(0, ctx.wait());
141  	
142  	  ASSERT_EQ(0U, m_client_meta.sync_points.size());
143  	  ASSERT_EQ(0, m_remote_image_ctx->state->refresh());
144  	  ASSERT_EQ(0U, m_remote_image_ctx->snap_ids.size());
145  	  ASSERT_EQ(0, m_local_image_ctx->state->refresh());
146  	  ASSERT_EQ(1U, m_local_image_ctx->snap_ids.size()); // deleted on journal replay
147  	}
148  	
149  	TEST_F(TestImageSync, Simple) {
150  	  scribble(m_remote_image_ctx, 10, 102400);
151  	
152  	  C_SaferCond ctx;
153  	  ImageSync<> *request = create_request(&ctx);
154  	  request->send();
155  	  ASSERT_EQ(0, ctx.wait());
156  	
157  	  int64_t object_size = std::min<int64_t>(
158  	    m_remote_image_ctx->size, 1 << m_remote_image_ctx->order);
159  	  bufferlist read_remote_bl;
160  	  read_remote_bl.append(std::string(object_size, '1'));
161  	  bufferlist read_local_bl;
162  	  read_local_bl.append(std::string(object_size, '1'));
163  	
164  	  for (uint64_t offset = 0; offset < m_remote_image_ctx->size;
165  	       offset += object_size) {
166  	    ASSERT_LE(0, m_remote_image_ctx->io_work_queue->read(
167  	                   offset, object_size,
168  	                   librbd::io::ReadResult{&read_remote_bl}, 0));
169  	    ASSERT_LE(0, m_local_image_ctx->io_work_queue->read(
170  	                   offset, object_size,
171  	                   librbd::io::ReadResult{&read_local_bl}, 0));
172  	    ASSERT_TRUE(read_remote_bl.contents_equal(read_local_bl));
173  	  }
174  	}
175  	
176  	TEST_F(TestImageSync, Resize) {
177  	  int64_t object_size = std::min<int64_t>(
178  	    m_remote_image_ctx->size, 1 << m_remote_image_ctx->order);
179  	
180  	  uint64_t off = 0;
181  	  uint64_t len = object_size / 10;
182  	
183  	  bufferlist bl;
184  	  bl.append(std::string(len, '1'));
185  	  ASSERT_EQ((int)len, m_remote_image_ctx->io_work_queue->write(off, len,
186  	                                                               std::move(bl),
187  	                                                               0));
188  	  {
189  	    std::shared_lock owner_locker{m_remote_image_ctx->owner_lock};
190  	    ASSERT_EQ(0, flush(m_remote_image_ctx));
191  	  }
192  	
193  	  ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap", nullptr));
194  	
195  	  uint64_t size = object_size - 1;
196  	  librbd::NoOpProgressContext no_op_progress_ctx;
197  	  ASSERT_EQ(0, m_remote_image_ctx->operations->resize(size, true,
198  	                                                      no_op_progress_ctx));
199  	
200  	  C_SaferCond ctx;
201  	  ImageSync<> *request = create_request(&ctx);
202  	  request->send();
203  	  ASSERT_EQ(0, ctx.wait());
204  	
205  	  bufferlist read_remote_bl;
206  	  read_remote_bl.append(std::string(len, '\0'));
207  	  bufferlist read_local_bl;
208  	  read_local_bl.append(std::string(len, '\0'));
209  	
210  	  ASSERT_LE(0, m_remote_image_ctx->io_work_queue->read(
211  	              off, len, librbd::io::ReadResult{&read_remote_bl}, 0));
212  	  ASSERT_LE(0, m_local_image_ctx->io_work_queue->read(
213  	              off, len, librbd::io::ReadResult{&read_local_bl}, 0));
214  	
215  	  ASSERT_TRUE(read_remote_bl.contents_equal(read_local_bl));
216  	}
217  	
218  	TEST_F(TestImageSync, Discard) {
219  	  int64_t object_size = std::min<int64_t>(
220  	    m_remote_image_ctx->size, 1 << m_remote_image_ctx->order);
221  	
222  	  uint64_t off = 0;
223  	  uint64_t len = object_size / 10;
224  	
225  	  bufferlist bl;
226  	  bl.append(std::string(len, '1'));
227  	  ASSERT_EQ((int)len, m_remote_image_ctx->io_work_queue->write(off, len,
228  	                                                               std::move(bl),
229  	                                                               0));
230  	  {
231  	    std::shared_lock owner_locker{m_remote_image_ctx->owner_lock};
232  	    ASSERT_EQ(0, flush(m_remote_image_ctx));
233  	  }
234  	
235  	  ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap", nullptr));
236  	
237  	  ASSERT_EQ((int)len - 2,
238  	            m_remote_image_ctx->io_work_queue->discard(
239  	              off + 1, len - 2, m_remote_image_ctx->discard_granularity_bytes));
240  	  {
241  	    std::shared_lock owner_locker{m_remote_image_ctx->owner_lock};
242  	    ASSERT_EQ(0, flush(m_remote_image_ctx));
243  	  }
244  	
245  	  C_SaferCond ctx;
246  	  ImageSync<> *request = create_request(&ctx);
247  	  request->send();
248  	  ASSERT_EQ(0, ctx.wait());
249  	
250  	  bufferlist read_remote_bl;
251  	  read_remote_bl.append(std::string(object_size, '\0'));
252  	  bufferlist read_local_bl;
253  	  read_local_bl.append(std::string(object_size, '\0'));
254  	
255  	  ASSERT_LE(0, m_remote_image_ctx->io_work_queue->read(
256  	              off, len, librbd::io::ReadResult{&read_remote_bl}, 0));
257  	  ASSERT_LE(0, m_local_image_ctx->io_work_queue->read(
258  	              off, len, librbd::io::ReadResult{&read_local_bl}, 0));
259  	
260  	  ASSERT_TRUE(read_remote_bl.contents_equal(read_local_bl));
261  	}
262  	
263  	TEST_F(TestImageSync, SnapshotStress) {
264  	  std::list<std::string> snap_names;
265  	
266  	  const int num_snaps = 4;
267  	  for (int idx = 0; idx <= num_snaps; ++idx) {
268  	    scribble(m_remote_image_ctx, 10, 102400);
269  	
270  	    librbd::NoOpProgressContext no_op_progress_ctx;
271  	    uint64_t size = 1 + rand() % m_image_size;
272  	    ASSERT_EQ(0, m_remote_image_ctx->operations->resize(size, true,
273  	                                                        no_op_progress_ctx));
274  	    ASSERT_EQ(0, m_remote_image_ctx->state->refresh());
275  	
276  	    if (idx < num_snaps) {
277  	      snap_names.push_back("snap" + stringify(idx + 1));
278  	      ASSERT_EQ(0, create_snap(m_remote_image_ctx, snap_names.back().c_str(),
279  	                               nullptr));
280  	    } else {
281  	      snap_names.push_back("");
282  	    }
283  	  }
284  	
285  	  C_SaferCond ctx;
286  	  ImageSync<> *request = create_request(&ctx);
287  	  request->send();
288  	  ASSERT_EQ(0, ctx.wait());
289  	
290  	  int64_t object_size = std::min<int64_t>(
291  	    m_remote_image_ctx->size, 1 << m_remote_image_ctx->order);
292  	  bufferlist read_remote_bl;
293  	  read_remote_bl.append(std::string(object_size, '1'));
294  	  bufferlist read_local_bl;
295  	  read_local_bl.append(std::string(object_size, '1'));
296  	
297  	  for (auto &snap_name : snap_names) {
298  	    uint64_t remote_snap_id;
299  	    {
300  	      std::shared_lock remote_image_locker{m_remote_image_ctx->image_lock};
301  	      remote_snap_id = m_remote_image_ctx->get_snap_id(
302  	        cls::rbd::UserSnapshotNamespace{}, snap_name);
303  	    }
304  	
305  	    uint64_t remote_size;
306  	    {
307  	      C_SaferCond ctx;
308  	      m_remote_image_ctx->state->snap_set(remote_snap_id, &ctx);
309  	      ASSERT_EQ(0, ctx.wait());
310  	
311  	      std::shared_lock remote_image_locker{m_remote_image_ctx->image_lock};
312  	      remote_size = m_remote_image_ctx->get_image_size(
313  	        m_remote_image_ctx->snap_id);
314  	    }
315  	
316  	    uint64_t local_snap_id;
317  	    {
318  	      std::shared_lock image_locker{m_local_image_ctx->image_lock};
319  	      local_snap_id = m_local_image_ctx->get_snap_id(
320  	        cls::rbd::UserSnapshotNamespace{}, snap_name);
321  	    }
322  	
323  	    uint64_t local_size;
324  	    {
325  	      C_SaferCond ctx;
326  	      m_local_image_ctx->state->snap_set(local_snap_id, &ctx);
327  	      ASSERT_EQ(0, ctx.wait());
328  	
329  	      std::shared_lock image_locker{m_local_image_ctx->image_lock};
330  	      local_size = m_local_image_ctx->get_image_size(
331  	        m_local_image_ctx->snap_id);
332  	      bool flags_set;
333  	      ASSERT_EQ(0, m_local_image_ctx->test_flags(m_local_image_ctx->snap_id,
334  	                                                 RBD_FLAG_OBJECT_MAP_INVALID,
335  	                                                 m_local_image_ctx->image_lock,
336  	                                                 &flags_set));
337  	      ASSERT_FALSE(flags_set);
338  	    }
339  	
340  	    ASSERT_EQ(remote_size, local_size);
341  	
342  	    for (uint64_t offset = 0; offset < remote_size; offset += object_size) {
343  	      ASSERT_LE(0, m_remote_image_ctx->io_work_queue->read(
344  	                     offset, object_size,
345  	                     librbd::io::ReadResult{&read_remote_bl}, 0));
346  	      ASSERT_LE(0, m_local_image_ctx->io_work_queue->read(
347  	                     offset, object_size,
348  	                     librbd::io::ReadResult{&read_local_bl}, 0));
349  	      ASSERT_TRUE(read_remote_bl.contents_equal(read_local_bl));
350  	    }
351  	  }
352  	}
353  	
354  	} // namespace mirror
355  	} // namespace rbd
356