]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
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/librados/test.h" | |
5 | #include "test/librbd/test_fixture.h" | |
6 | #include "test/librbd/test_support.h" | |
7 | #include "librbd/ImageState.h" | |
8 | #include "librbd/Operations.h" | |
9 | #include "librbd/api/Group.h" | |
10 | #include "librbd/api/Image.h" | |
f67539c2 | 11 | #include "librbd/api/Io.h" |
11fdf7f2 TL |
12 | #include "librbd/api/Migration.h" |
13 | #include "librbd/api/Mirror.h" | |
14 | #include "librbd/api/Namespace.h" | |
9f95a23c | 15 | #include "librbd/api/Snapshot.h" |
11fdf7f2 TL |
16 | #include "librbd/image/AttachChildRequest.h" |
17 | #include "librbd/image/AttachParentRequest.h" | |
18 | #include "librbd/internal.h" | |
11fdf7f2 | 19 | #include "librbd/io/ReadResult.h" |
9f95a23c | 20 | #include "common/Cond.h" |
11fdf7f2 TL |
21 | #include <boost/scope_exit.hpp> |
22 | ||
23 | void register_test_migration() { | |
24 | } | |
25 | ||
f67539c2 TL |
26 | namespace librbd { |
27 | ||
11fdf7f2 TL |
28 | struct TestMigration : public TestFixture { |
29 | static void SetUpTestCase() { | |
30 | TestFixture::SetUpTestCase(); | |
31 | ||
32 | _other_pool_name = get_temp_pool_name("test-librbd-"); | |
33 | ASSERT_EQ(0, _rados.pool_create(_other_pool_name.c_str())); | |
34 | } | |
35 | ||
36 | static void TearDownTestCase() { | |
37 | ASSERT_EQ(0, _rados.pool_delete(_other_pool_name.c_str())); | |
38 | ||
39 | TestFixture::TearDownTestCase(); | |
40 | } | |
41 | ||
42 | void SetUp() override { | |
43 | TestFixture::SetUp(); | |
44 | ||
45 | ASSERT_EQ(0, _rados.ioctx_create(_other_pool_name.c_str(), | |
46 | _other_pool_ioctx)); | |
47 | ||
48 | open_image(m_ioctx, m_image_name, &m_ictx); | |
49 | m_image_id = m_ictx->id; | |
50 | ||
51 | std::string ref_image_name = get_temp_image_name(); | |
52 | ASSERT_EQ(0, create_image_pp(m_rbd, m_ioctx, ref_image_name, m_ictx->size)); | |
53 | EXPECT_EQ(0, _rados.ioctx_create2(m_ioctx.get_id(), m_ref_ioctx)); | |
54 | open_image(m_ref_ioctx, ref_image_name, &m_ref_ictx); | |
55 | ||
56 | resize(20 * (1 << 22)); | |
57 | } | |
58 | ||
59 | void TearDown() override { | |
60 | if (m_ref_ictx != nullptr) { | |
61 | close_image(m_ref_ictx); | |
62 | } | |
63 | if (m_ictx != nullptr) { | |
64 | close_image(m_ictx); | |
65 | } | |
66 | ||
67 | _other_pool_ioctx.close(); | |
68 | ||
69 | TestFixture::TearDown(); | |
70 | } | |
71 | ||
72 | void compare(const std::string &description = "") { | |
20effc67 | 73 | std::vector<librbd::snap_info_t> src_snaps, dst_snaps; |
11fdf7f2 TL |
74 | |
75 | EXPECT_EQ(m_ref_ictx->size, m_ictx->size); | |
9f95a23c TL |
76 | EXPECT_EQ(0, librbd::api::Snapshot<>::list(m_ref_ictx, src_snaps)); |
77 | EXPECT_EQ(0, librbd::api::Snapshot<>::list(m_ictx, dst_snaps)); | |
11fdf7f2 TL |
78 | EXPECT_EQ(src_snaps.size(), dst_snaps.size()); |
79 | for (size_t i = 0; i <= src_snaps.size(); i++) { | |
80 | const char *src_snap_name = nullptr; | |
81 | const char *dst_snap_name = nullptr; | |
82 | if (i < src_snaps.size()) { | |
83 | EXPECT_EQ(src_snaps[i].name, dst_snaps[i].name); | |
84 | src_snap_name = src_snaps[i].name.c_str(); | |
85 | dst_snap_name = dst_snaps[i].name.c_str(); | |
86 | } | |
87 | EXPECT_EQ(0, librbd::api::Image<>::snap_set( | |
88 | m_ref_ictx, cls::rbd::UserSnapshotNamespace(), | |
89 | src_snap_name)); | |
90 | EXPECT_EQ(0, librbd::api::Image<>::snap_set( | |
91 | m_ictx, cls::rbd::UserSnapshotNamespace(), | |
92 | dst_snap_name)); | |
93 | compare_snaps( | |
94 | description + " snap: " + (src_snap_name ? src_snap_name : "null"), | |
95 | m_ref_ictx, m_ictx); | |
96 | } | |
97 | } | |
98 | ||
99 | void compare_snaps(const std::string &description, librbd::ImageCtx *src_ictx, | |
100 | librbd::ImageCtx *dst_ictx) { | |
101 | uint64_t src_size, dst_size; | |
102 | { | |
9f95a23c TL |
103 | std::shared_lock src_locker{src_ictx->image_lock}; |
104 | std::shared_lock dst_locker{dst_ictx->image_lock}; | |
11fdf7f2 TL |
105 | src_size = src_ictx->get_image_size(src_ictx->snap_id); |
106 | dst_size = dst_ictx->get_image_size(dst_ictx->snap_id); | |
107 | } | |
108 | if (src_size != dst_size) { | |
109 | std::cout << description << ": size differs" << std::endl; | |
110 | EXPECT_EQ(src_size, dst_size); | |
111 | } | |
112 | ||
113 | if (dst_ictx->test_features(RBD_FEATURE_LAYERING)) { | |
114 | bool flags_set; | |
9f95a23c | 115 | std::shared_lock dst_locker{dst_ictx->image_lock}; |
11fdf7f2 TL |
116 | EXPECT_EQ(0, dst_ictx->test_flags(dst_ictx->snap_id, |
117 | RBD_FLAG_OBJECT_MAP_INVALID, | |
9f95a23c | 118 | dst_ictx->image_lock, &flags_set)); |
11fdf7f2 TL |
119 | EXPECT_FALSE(flags_set); |
120 | } | |
121 | ||
122 | ssize_t read_size = 1 << src_ictx->order; | |
123 | uint64_t offset = 0; | |
124 | while (offset < src_size) { | |
125 | read_size = std::min(read_size, static_cast<ssize_t>(src_size - offset)); | |
126 | ||
127 | bufferptr src_ptr(read_size); | |
128 | bufferlist src_bl; | |
129 | src_bl.push_back(src_ptr); | |
130 | librbd::io::ReadResult src_result{&src_bl}; | |
f67539c2 TL |
131 | EXPECT_EQ(read_size, api::Io<>::read( |
132 | *src_ictx, offset, read_size, | |
133 | librbd::io::ReadResult{src_result}, 0)); | |
11fdf7f2 TL |
134 | |
135 | bufferptr dst_ptr(read_size); | |
136 | bufferlist dst_bl; | |
137 | dst_bl.push_back(dst_ptr); | |
138 | librbd::io::ReadResult dst_result{&dst_bl}; | |
f67539c2 TL |
139 | EXPECT_EQ(read_size, api::Io<>::read( |
140 | *dst_ictx, offset, read_size, | |
141 | librbd::io::ReadResult{dst_result}, 0)); | |
11fdf7f2 TL |
142 | |
143 | if (!src_bl.contents_equal(dst_bl)) { | |
144 | std::cout << description | |
145 | << ", block " << offset << "~" << read_size << " differs" | |
146 | << std::endl; | |
cd265ab1 TL |
147 | std::cout << "src block: " << src_ictx->id << ": " << std::endl; src_bl.hexdump(std::cout); |
148 | std::cout << "dst block: " << dst_ictx->id << ": " << std::endl; dst_bl.hexdump(std::cout); | |
11fdf7f2 TL |
149 | } |
150 | EXPECT_TRUE(src_bl.contents_equal(dst_bl)); | |
151 | offset += read_size; | |
152 | } | |
153 | } | |
154 | ||
155 | void open_image(librados::IoCtx& io_ctx, const std::string &name, | |
156 | const std::string &id, bool read_only, int flags, | |
157 | librbd::ImageCtx **ictx) { | |
158 | *ictx = new librbd::ImageCtx(name, id, nullptr, io_ctx, read_only); | |
159 | m_ictxs.insert(*ictx); | |
160 | ||
161 | ASSERT_EQ(0, (*ictx)->state->open(flags)); | |
162 | (*ictx)->discard_granularity_bytes = 0; | |
163 | } | |
164 | ||
165 | void open_image(librados::IoCtx& io_ctx, const std::string &name, | |
166 | librbd::ImageCtx **ictx) { | |
167 | open_image(io_ctx, name, "", false, 0, ictx); | |
168 | } | |
169 | ||
170 | void migration_prepare(librados::IoCtx& dst_io_ctx, | |
171 | const std::string &dst_name, int r = 0) { | |
172 | std::cout << __func__ << std::endl; | |
173 | ||
174 | close_image(m_ictx); | |
175 | m_ictx = nullptr; | |
176 | ||
177 | EXPECT_EQ(r, librbd::api::Migration<>::prepare(m_ioctx, m_image_name, | |
178 | dst_io_ctx, dst_name, | |
179 | m_opts)); | |
180 | if (r == 0) { | |
181 | open_image(dst_io_ctx, dst_name, &m_ictx); | |
182 | } else { | |
183 | open_image(m_ioctx, m_image_name, &m_ictx); | |
184 | } | |
185 | compare("after prepare"); | |
186 | } | |
187 | ||
188 | void migration_execute(librados::IoCtx& io_ctx, const std::string &name, | |
189 | int r = 0) { | |
190 | std::cout << __func__ << std::endl; | |
191 | ||
192 | librbd::NoOpProgressContext no_op; | |
193 | EXPECT_EQ(r, librbd::api::Migration<>::execute(io_ctx, name, no_op)); | |
194 | } | |
195 | ||
196 | void migration_abort(librados::IoCtx& io_ctx, const std::string &name, | |
197 | int r = 0) { | |
198 | std::cout << __func__ << std::endl; | |
199 | ||
200 | std::string dst_name = m_ictx->name; | |
201 | close_image(m_ictx); | |
202 | m_ictx = nullptr; | |
203 | ||
204 | librbd::NoOpProgressContext no_op; | |
205 | EXPECT_EQ(r, librbd::api::Migration<>::abort(io_ctx, name, no_op)); | |
206 | ||
207 | if (r == 0) { | |
208 | open_image(m_ioctx, m_image_name, &m_ictx); | |
209 | } else { | |
210 | open_image(m_ioctx, dst_name, &m_ictx); | |
211 | } | |
212 | ||
213 | compare("after abort"); | |
214 | } | |
215 | ||
216 | void migration_commit(librados::IoCtx& io_ctx, const std::string &name) { | |
217 | std::cout << __func__ << std::endl; | |
218 | ||
219 | librbd::NoOpProgressContext no_op; | |
220 | EXPECT_EQ(0, librbd::api::Migration<>::commit(io_ctx, name, no_op)); | |
221 | ||
222 | compare("after commit"); | |
223 | } | |
224 | ||
225 | void migration_status(librbd::image_migration_state_t state) { | |
226 | librbd::image_migration_status_t status; | |
227 | EXPECT_EQ(0, librbd::api::Migration<>::status(m_ioctx, m_image_name, | |
228 | &status)); | |
229 | EXPECT_EQ(status.source_pool_id, m_ioctx.get_id()); | |
230 | EXPECT_EQ(status.source_pool_namespace, m_ioctx.get_namespace()); | |
231 | EXPECT_EQ(status.source_image_name, m_image_name); | |
232 | EXPECT_EQ(status.source_image_id, m_image_id); | |
233 | EXPECT_EQ(status.dest_pool_id, m_ictx->md_ctx.get_id()); | |
234 | EXPECT_EQ(status.dest_pool_namespace, m_ictx->md_ctx.get_namespace()); | |
235 | EXPECT_EQ(status.dest_image_name, m_ictx->name); | |
236 | EXPECT_EQ(status.dest_image_id, m_ictx->id); | |
237 | EXPECT_EQ(status.state, state); | |
238 | } | |
239 | ||
240 | void migrate(librados::IoCtx& dst_io_ctx, const std::string &dst_name) { | |
241 | migration_prepare(dst_io_ctx, dst_name); | |
242 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
243 | migration_execute(dst_io_ctx, dst_name); | |
244 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
245 | migration_commit(dst_io_ctx, dst_name); | |
246 | } | |
247 | ||
248 | void write(uint64_t off, uint64_t len, char c) { | |
249 | std::cout << "write: " << c << " " << off << "~" << len << std::endl; | |
250 | ||
251 | bufferlist ref_bl; | |
252 | ref_bl.append(std::string(len, c)); | |
253 | ASSERT_EQ(static_cast<ssize_t>(len), | |
f67539c2 | 254 | api::Io<>::write(*m_ref_ictx, off, len, std::move(ref_bl), 0)); |
11fdf7f2 TL |
255 | bufferlist bl; |
256 | bl.append(std::string(len, c)); | |
257 | ASSERT_EQ(static_cast<ssize_t>(len), | |
f67539c2 | 258 | api::Io<>::write(*m_ictx, off, len, std::move(bl), 0)); |
11fdf7f2 TL |
259 | } |
260 | ||
261 | void discard(uint64_t off, uint64_t len) { | |
262 | std::cout << "discard: " << off << "~" << len << std::endl; | |
263 | ||
264 | ASSERT_EQ(static_cast<ssize_t>(len), | |
f67539c2 | 265 | api::Io<>::discard(*m_ref_ictx, off, len, false)); |
11fdf7f2 | 266 | ASSERT_EQ(static_cast<ssize_t>(len), |
f67539c2 | 267 | api::Io<>::discard(*m_ictx, off, len, false)); |
11fdf7f2 TL |
268 | } |
269 | ||
270 | void flush() { | |
f67539c2 TL |
271 | ASSERT_EQ(0, TestFixture::flush_writeback_cache(m_ref_ictx)); |
272 | ASSERT_EQ(0, TestFixture::flush_writeback_cache(m_ictx)); | |
11fdf7f2 TL |
273 | } |
274 | ||
275 | void snap_create(const std::string &snap_name) { | |
276 | std::cout << "snap_create: " << snap_name << std::endl; | |
277 | ||
278 | flush(); | |
279 | ||
280 | ASSERT_EQ(0, TestFixture::snap_create(*m_ref_ictx, snap_name)); | |
281 | ASSERT_EQ(0, TestFixture::snap_create(*m_ictx, snap_name)); | |
282 | } | |
283 | ||
284 | void snap_protect(const std::string &snap_name) { | |
285 | std::cout << "snap_protect: " << snap_name << std::endl; | |
286 | ||
287 | ASSERT_EQ(0, TestFixture::snap_protect(*m_ref_ictx, snap_name)); | |
288 | ASSERT_EQ(0, TestFixture::snap_protect(*m_ictx, snap_name)); | |
289 | } | |
290 | ||
291 | void clone(const std::string &snap_name) { | |
292 | snap_protect(snap_name); | |
293 | ||
294 | int order = m_ref_ictx->order; | |
295 | uint64_t features; | |
296 | ASSERT_EQ(0, librbd::get_features(m_ref_ictx, &features)); | |
11fdf7f2 TL |
297 | |
298 | std::string ref_clone_name = get_temp_image_name(); | |
299 | std::string clone_name = get_temp_image_name(); | |
300 | ||
301 | std::cout << "clone " << m_ictx->name << " -> " << clone_name | |
302 | << std::endl; | |
303 | ||
304 | ASSERT_EQ(0, librbd::clone(m_ref_ictx->md_ctx, m_ref_ictx->name.c_str(), | |
305 | snap_name.c_str(), m_ref_ioctx, | |
306 | ref_clone_name.c_str(), features, &order, | |
307 | m_ref_ictx->stripe_unit, | |
308 | m_ref_ictx->stripe_count)); | |
309 | ||
310 | ASSERT_EQ(0, librbd::clone(m_ictx->md_ctx, m_ictx->name.c_str(), | |
311 | snap_name.c_str(), m_ioctx, | |
312 | clone_name.c_str(), features, &order, | |
313 | m_ictx->stripe_unit, | |
314 | m_ictx->stripe_count)); | |
315 | ||
316 | close_image(m_ref_ictx); | |
317 | open_image(m_ref_ioctx, ref_clone_name, &m_ref_ictx); | |
318 | ||
319 | close_image(m_ictx); | |
320 | open_image(m_ioctx, clone_name, &m_ictx); | |
321 | m_image_name = m_ictx->name; | |
322 | m_image_id = m_ictx->id; | |
323 | } | |
324 | ||
325 | void resize(uint64_t size) { | |
326 | std::cout << "resize: " << size << std::endl; | |
327 | ||
328 | librbd::NoOpProgressContext no_op; | |
329 | ASSERT_EQ(0, m_ref_ictx->operations->resize(size, true, no_op)); | |
330 | ASSERT_EQ(0, m_ictx->operations->resize(size, true, no_op)); | |
331 | } | |
332 | ||
333 | void test_no_snaps() { | |
334 | uint64_t len = (1 << m_ictx->order) * 2 + 1; | |
335 | write(0 * len, len, '1'); | |
336 | write(2 * len, len, '1'); | |
337 | flush(); | |
338 | } | |
339 | ||
340 | void test_snaps() { | |
341 | uint64_t len = (1 << m_ictx->order) * 2 + 1; | |
342 | write(0 * len, len, '1'); | |
343 | snap_create("snap1"); | |
344 | write(1 * len, len, '1'); | |
345 | ||
346 | write(0 * len, 1000, 'X'); | |
347 | discard(1000 + 10, 1000); | |
348 | ||
349 | snap_create("snap2"); | |
350 | ||
351 | write(1 * len, 1000, 'X'); | |
352 | discard(2 * len + 10, 1000); | |
353 | ||
354 | uint64_t size = m_ictx->size; | |
355 | ||
356 | resize(size << 1); | |
357 | ||
358 | write(size - 1, len, '2'); | |
359 | ||
360 | snap_create("snap3"); | |
361 | ||
362 | resize(size); | |
363 | ||
364 | discard(size - 1, 1); | |
365 | ||
366 | flush(); | |
367 | } | |
368 | ||
369 | void test_clone() { | |
370 | uint64_t len = (1 << m_ictx->order) * 2 + 1; | |
371 | write(0 * len, len, 'X'); | |
372 | write(2 * len, len, 'X'); | |
373 | ||
374 | snap_create("snap"); | |
375 | clone("snap"); | |
376 | ||
377 | write(0, 1000, 'X'); | |
378 | discard(1010, 1000); | |
379 | ||
380 | snap_create("snap"); | |
381 | clone("snap"); | |
382 | ||
383 | write(1000, 1000, 'X'); | |
384 | discard(2010, 1000); | |
385 | ||
386 | flush(); | |
387 | } | |
388 | ||
389 | template <typename L> | |
390 | void test_migrate_parent(uint32_t clone_format, L&& test) { | |
391 | REQUIRE_FEATURE(RBD_FEATURE_LAYERING); | |
392 | ||
393 | std::string prev_clone_format; | |
394 | ASSERT_EQ(0, _rados.conf_get("rbd_default_clone_format", | |
395 | prev_clone_format)); | |
396 | ASSERT_EQ(0, _rados.conf_set("rbd_default_clone_format", | |
397 | stringify(clone_format).c_str())); | |
398 | BOOST_SCOPE_EXIT_TPL(&prev_clone_format) { | |
399 | _rados.conf_set("rbd_default_clone_format", prev_clone_format.c_str()); | |
400 | } BOOST_SCOPE_EXIT_END; | |
401 | ||
402 | write(0, 10, 'A'); | |
403 | snap_create("snap1"); | |
404 | snap_protect("snap1"); | |
405 | ||
406 | int order = m_ictx->order; | |
407 | uint64_t features; | |
408 | ASSERT_EQ(0, librbd::get_features(m_ictx, &features)); | |
11fdf7f2 TL |
409 | |
410 | std::string clone_name = get_temp_image_name(); | |
411 | ASSERT_EQ(0, librbd::clone(m_ictx->md_ctx, m_ictx->name.c_str(), "snap1", | |
412 | m_ioctx, clone_name.c_str(), features, &order, | |
413 | m_ictx->stripe_unit, m_ictx->stripe_count)); | |
414 | ||
415 | librbd::ImageCtx *child_ictx; | |
416 | open_image(m_ioctx, clone_name, &child_ictx); | |
417 | ||
418 | test(child_ictx); | |
419 | ||
420 | ASSERT_EQ(0, child_ictx->state->refresh()); | |
421 | ||
422 | bufferlist bl; | |
423 | bufferptr ptr(10); | |
424 | bl.push_back(ptr); | |
425 | librbd::io::ReadResult result{&bl}; | |
f67539c2 TL |
426 | ASSERT_EQ(10, api::Io<>::read( |
427 | *child_ictx, 0, 10, librbd::io::ReadResult{result}, 0)); | |
11fdf7f2 TL |
428 | bufferlist ref_bl; |
429 | ref_bl.append(std::string(10, 'A')); | |
430 | ASSERT_TRUE(ref_bl.contents_equal(bl)); | |
431 | close_image(child_ictx); | |
432 | } | |
433 | ||
434 | void test_stress(const std::string &snap_name_prefix = "snap", | |
435 | char start_char = 'A') { | |
436 | uint64_t initial_size = m_ictx->size; | |
437 | ||
438 | int nsnaps = 4; | |
439 | const char *c = getenv("TEST_RBD_MIGRATION_STRESS_NSNAPS"); | |
440 | if (c != NULL) { | |
441 | std::stringstream ss(c); | |
442 | ASSERT_TRUE(ss >> nsnaps); | |
443 | } | |
444 | ||
445 | int nwrites = 4; | |
446 | c = getenv("TEST_RBD_MIGRATION_STRESS_NWRITES"); | |
447 | if (c != NULL) { | |
448 | std::stringstream ss(c); | |
449 | ASSERT_TRUE(ss >> nwrites); | |
450 | } | |
451 | ||
452 | for (int i = 0; i < nsnaps; i++) { | |
453 | for (int j = 0; j < nwrites; j++) { | |
454 | size_t len = rand() % ((1 << m_ictx->order) * 2); | |
455 | ASSERT_GT(m_ictx->size, len); | |
456 | uint64_t off = std::min(static_cast<uint64_t>(rand() % m_ictx->size), | |
457 | static_cast<uint64_t>(m_ictx->size - len)); | |
458 | write(off, len, start_char + i); | |
459 | ||
460 | len = rand() % ((1 << m_ictx->order) * 2); | |
461 | ASSERT_GT(m_ictx->size, len); | |
462 | off = std::min(static_cast<uint64_t>(rand() % m_ictx->size), | |
463 | static_cast<uint64_t>(m_ictx->size - len)); | |
464 | discard(off, len); | |
465 | } | |
466 | ||
467 | std::string snap_name = snap_name_prefix + stringify(i); | |
468 | snap_create(snap_name); | |
469 | ||
470 | if (m_ictx->test_features(RBD_FEATURE_LAYERING) && | |
471 | !m_ictx->test_features(RBD_FEATURE_MIGRATING) && | |
472 | rand() % 4) { | |
473 | clone(snap_name); | |
474 | } | |
475 | ||
476 | if (rand() % 2) { | |
477 | librbd::NoOpProgressContext no_op; | |
478 | uint64_t new_size = initial_size + rand() % m_ictx->size; | |
479 | resize(new_size); | |
480 | ASSERT_EQ(new_size, m_ictx->size); | |
481 | } | |
482 | } | |
483 | flush(); | |
484 | } | |
485 | ||
486 | void test_stress2(bool concurrent) { | |
487 | test_stress(); | |
488 | ||
489 | migration_prepare(m_ioctx, m_image_name); | |
490 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
491 | ||
20effc67 | 492 | std::thread user([this]() { |
11fdf7f2 TL |
493 | test_stress("user", 'a'); |
494 | for (int i = 0; i < 5; i++) { | |
495 | uint64_t off = (i + 1) * m_ictx->size / 10; | |
496 | uint64_t len = m_ictx->size / 40; | |
497 | write(off, len, '1' + i); | |
498 | ||
499 | off += len / 4; | |
500 | len /= 2; | |
501 | discard(off, len); | |
502 | } | |
503 | flush(); | |
504 | }); | |
505 | ||
506 | if (concurrent) { | |
507 | librados::IoCtx io_ctx; | |
508 | EXPECT_EQ(0, _rados.ioctx_create2(m_ioctx.get_id(), io_ctx)); | |
509 | migration_execute(io_ctx, m_image_name); | |
510 | io_ctx.close(); | |
511 | user.join(); | |
512 | } else { | |
513 | user.join(); | |
514 | compare("before execute"); | |
515 | migration_execute(m_ioctx, m_image_name); | |
516 | } | |
517 | ||
518 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
519 | migration_commit(m_ioctx, m_image_name); | |
520 | } | |
521 | ||
522 | static std::string _other_pool_name; | |
523 | static librados::IoCtx _other_pool_ioctx; | |
524 | ||
525 | std::string m_image_id; | |
526 | librbd::ImageCtx *m_ictx = nullptr; | |
527 | librados::IoCtx m_ref_ioctx; | |
528 | librbd::ImageCtx *m_ref_ictx = nullptr; | |
529 | librbd::ImageOptions m_opts; | |
530 | }; | |
531 | ||
532 | std::string TestMigration::_other_pool_name; | |
533 | librados::IoCtx TestMigration::_other_pool_ioctx; | |
534 | ||
535 | TEST_F(TestMigration, Empty) | |
536 | { | |
537 | uint64_t features = m_ictx->features ^ RBD_FEATURE_LAYERING; | |
f67539c2 | 538 | features &= ~RBD_FEATURE_DIRTY_CACHE; |
11fdf7f2 TL |
539 | ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_FEATURES, features)); |
540 | ||
541 | migrate(m_ioctx, m_image_name); | |
542 | ||
543 | ASSERT_EQ(features, m_ictx->features); | |
544 | } | |
545 | ||
546 | TEST_F(TestMigration, OtherName) | |
547 | { | |
548 | std::string name = get_temp_image_name(); | |
549 | ||
550 | migrate(m_ioctx, name); | |
551 | ||
552 | ASSERT_EQ(name, m_ictx->name); | |
553 | } | |
554 | ||
555 | TEST_F(TestMigration, OtherPool) | |
556 | { | |
557 | migrate(_other_pool_ioctx, m_image_name); | |
558 | ||
559 | ASSERT_EQ(_other_pool_ioctx.get_id(), m_ictx->md_ctx.get_id()); | |
560 | } | |
561 | ||
562 | TEST_F(TestMigration, OtherNamespace) | |
563 | { | |
564 | ASSERT_EQ(0, librbd::api::Namespace<>::create(_other_pool_ioctx, "ns1")); | |
565 | _other_pool_ioctx.set_namespace("ns1"); | |
566 | ||
567 | migrate(_other_pool_ioctx, m_image_name); | |
568 | ||
569 | ASSERT_EQ(_other_pool_ioctx.get_id(), m_ictx->md_ctx.get_id()); | |
570 | ASSERT_EQ(_other_pool_ioctx.get_namespace(), m_ictx->md_ctx.get_namespace()); | |
571 | _other_pool_ioctx.set_namespace(""); | |
572 | } | |
573 | ||
574 | TEST_F(TestMigration, DataPool) | |
575 | { | |
576 | ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_DATA_POOL, | |
577 | _other_pool_ioctx.get_pool_name().c_str())); | |
578 | ||
579 | migrate(m_ioctx, m_image_name); | |
580 | ||
581 | ASSERT_EQ(_other_pool_ioctx.get_id(), m_ictx->data_ctx.get_id()); | |
582 | } | |
583 | ||
584 | TEST_F(TestMigration, AbortAfterPrepare) | |
585 | { | |
586 | migration_prepare(m_ioctx, m_image_name); | |
587 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
588 | migration_abort(m_ioctx, m_image_name); | |
589 | } | |
590 | ||
591 | TEST_F(TestMigration, AbortAfterFailedPrepare) | |
592 | { | |
593 | ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_DATA_POOL, "INVALID_POOL")); | |
594 | ||
595 | migration_prepare(m_ioctx, m_image_name, -ENOENT); | |
596 | ||
597 | // Migration is automatically aborted if prepare failed | |
598 | } | |
599 | ||
600 | TEST_F(TestMigration, AbortAfterExecute) | |
601 | { | |
602 | migration_prepare(m_ioctx, m_image_name); | |
603 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
604 | migration_execute(m_ioctx, m_image_name); | |
605 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
606 | migration_abort(m_ioctx, m_image_name); | |
607 | } | |
608 | ||
609 | TEST_F(TestMigration, OtherPoolAbortAfterExecute) | |
610 | { | |
611 | migration_prepare(_other_pool_ioctx, m_image_name); | |
612 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
613 | migration_execute(_other_pool_ioctx, m_image_name); | |
614 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
615 | migration_abort(_other_pool_ioctx, m_image_name); | |
616 | } | |
617 | ||
618 | TEST_F(TestMigration, OtherNamespaceAbortAfterExecute) | |
619 | { | |
620 | ASSERT_EQ(0, librbd::api::Namespace<>::create(_other_pool_ioctx, "ns2")); | |
621 | _other_pool_ioctx.set_namespace("ns2"); | |
622 | ||
623 | migration_prepare(_other_pool_ioctx, m_image_name); | |
624 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
625 | migration_execute(_other_pool_ioctx, m_image_name); | |
626 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
627 | migration_abort(_other_pool_ioctx, m_image_name); | |
628 | ||
629 | _other_pool_ioctx.set_namespace(""); | |
630 | ASSERT_EQ(0, librbd::api::Namespace<>::remove(_other_pool_ioctx, "ns2")); | |
631 | } | |
632 | ||
633 | TEST_F(TestMigration, MirroringSamePool) | |
634 | { | |
635 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
636 | ||
637 | ASSERT_EQ(0, librbd::api::Mirror<>::mode_set(m_ioctx, RBD_MIRROR_MODE_IMAGE)); | |
638 | ||
9f95a23c TL |
639 | ASSERT_EQ(0, librbd::api::Mirror<>::image_enable( |
640 | m_ictx, RBD_MIRROR_IMAGE_MODE_JOURNAL, false)); | |
11fdf7f2 TL |
641 | librbd::mirror_image_info_t info; |
642 | ASSERT_EQ(0, librbd::api::Mirror<>::image_get_info(m_ictx, &info)); | |
643 | ASSERT_EQ(RBD_MIRROR_IMAGE_ENABLED, info.state); | |
644 | ||
645 | migrate(m_ioctx, m_image_name); | |
646 | ||
647 | ASSERT_EQ(0, librbd::api::Mirror<>::image_get_info(m_ictx, &info)); | |
648 | ASSERT_EQ(RBD_MIRROR_IMAGE_ENABLED, info.state); | |
649 | } | |
650 | ||
651 | TEST_F(TestMigration, MirroringAbort) | |
652 | { | |
653 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
654 | ||
655 | ASSERT_EQ(0, librbd::api::Mirror<>::mode_set(m_ioctx, RBD_MIRROR_MODE_IMAGE)); | |
656 | ||
9f95a23c TL |
657 | ASSERT_EQ(0, librbd::api::Mirror<>::image_enable( |
658 | m_ictx, RBD_MIRROR_IMAGE_MODE_JOURNAL, false)); | |
11fdf7f2 TL |
659 | librbd::mirror_image_info_t info; |
660 | ASSERT_EQ(0, librbd::api::Mirror<>::image_get_info(m_ictx, &info)); | |
661 | ASSERT_EQ(RBD_MIRROR_IMAGE_ENABLED, info.state); | |
662 | ||
663 | migration_prepare(m_ioctx, m_image_name); | |
664 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
665 | ASSERT_EQ(0, librbd::api::Mirror<>::image_get_info(m_ictx, &info)); | |
666 | ASSERT_EQ(RBD_MIRROR_IMAGE_DISABLED, info.state); | |
667 | ||
668 | migration_abort(m_ioctx, m_image_name); | |
669 | ||
670 | ASSERT_EQ(0, librbd::api::Mirror<>::image_get_info(m_ictx, &info)); | |
671 | ASSERT_EQ(RBD_MIRROR_IMAGE_ENABLED, info.state); | |
672 | } | |
673 | ||
674 | TEST_F(TestMigration, MirroringOtherPoolDisabled) | |
675 | { | |
676 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
677 | ||
678 | ASSERT_EQ(0, librbd::api::Mirror<>::mode_set(m_ioctx, RBD_MIRROR_MODE_IMAGE)); | |
679 | ||
9f95a23c TL |
680 | ASSERT_EQ(0, librbd::api::Mirror<>::image_enable( |
681 | m_ictx, RBD_MIRROR_IMAGE_MODE_JOURNAL, false)); | |
11fdf7f2 TL |
682 | librbd::mirror_image_info_t info; |
683 | ASSERT_EQ(0, librbd::api::Mirror<>::image_get_info(m_ictx, &info)); | |
684 | ASSERT_EQ(RBD_MIRROR_IMAGE_ENABLED, info.state); | |
685 | ||
686 | migrate(_other_pool_ioctx, m_image_name); | |
687 | ||
688 | ASSERT_EQ(0, librbd::api::Mirror<>::image_get_info(m_ictx, &info)); | |
689 | ASSERT_EQ(RBD_MIRROR_IMAGE_DISABLED, info.state); | |
690 | } | |
691 | ||
692 | TEST_F(TestMigration, MirroringOtherPoolEnabled) | |
693 | { | |
694 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
695 | ||
696 | ASSERT_EQ(0, librbd::api::Mirror<>::mode_set(m_ioctx, RBD_MIRROR_MODE_IMAGE)); | |
697 | ASSERT_EQ(0, librbd::api::Mirror<>::mode_set(_other_pool_ioctx, | |
698 | RBD_MIRROR_MODE_IMAGE)); | |
699 | ||
9f95a23c TL |
700 | ASSERT_EQ(0, librbd::api::Mirror<>::image_enable( |
701 | m_ictx, RBD_MIRROR_IMAGE_MODE_JOURNAL, false)); | |
11fdf7f2 TL |
702 | librbd::mirror_image_info_t info; |
703 | ASSERT_EQ(0, librbd::api::Mirror<>::image_get_info(m_ictx, &info)); | |
704 | ASSERT_EQ(RBD_MIRROR_IMAGE_ENABLED, info.state); | |
705 | ||
706 | migrate(_other_pool_ioctx, m_image_name); | |
707 | ||
708 | ASSERT_EQ(0, librbd::api::Mirror<>::image_get_info(m_ictx, &info)); | |
709 | ASSERT_EQ(RBD_MIRROR_IMAGE_ENABLED, info.state); | |
710 | } | |
711 | ||
712 | TEST_F(TestMigration, MirroringPool) | |
713 | { | |
714 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
715 | ||
716 | ASSERT_EQ(0, librbd::api::Mirror<>::mode_set(_other_pool_ioctx, | |
717 | RBD_MIRROR_MODE_POOL)); | |
718 | librbd::mirror_image_info_t info; | |
719 | ASSERT_EQ(0, librbd::api::Mirror<>::image_get_info(m_ictx, &info)); | |
720 | ASSERT_EQ(RBD_MIRROR_IMAGE_DISABLED, info.state); | |
721 | ||
722 | migrate(_other_pool_ioctx, m_image_name); | |
723 | ||
724 | ASSERT_EQ(0, librbd::api::Mirror<>::image_get_info(m_ictx, &info)); | |
725 | ASSERT_EQ(RBD_MIRROR_IMAGE_ENABLED, info.state); | |
726 | } | |
727 | ||
728 | TEST_F(TestMigration, Group) | |
729 | { | |
730 | REQUIRE_FORMAT_V2(); | |
731 | ||
732 | ASSERT_EQ(0, librbd::api::Group<>::create(m_ioctx, "123")); | |
733 | ASSERT_EQ(0, librbd::api::Group<>::image_add(m_ioctx, "123", m_ioctx, | |
734 | m_image_name.c_str())); | |
735 | librbd::group_info_t info; | |
736 | ASSERT_EQ(0, librbd::api::Group<>::image_get_group(m_ictx, &info)); | |
737 | ||
738 | std::string name = get_temp_image_name(); | |
739 | ||
740 | migrate(m_ioctx, name); | |
741 | ||
742 | ASSERT_EQ(0, librbd::api::Group<>::image_get_group(m_ictx, &info)); | |
743 | ASSERT_EQ(info.name, "123"); | |
744 | ||
745 | ASSERT_EQ(0, librbd::api::Group<>::image_remove(m_ioctx, "123", m_ioctx, | |
746 | name.c_str())); | |
747 | ASSERT_EQ(0, librbd::api::Group<>::remove(m_ioctx, "123")); | |
748 | } | |
749 | ||
750 | TEST_F(TestMigration, GroupAbort) | |
751 | { | |
752 | REQUIRE_FORMAT_V2(); | |
753 | ||
754 | ASSERT_EQ(0, librbd::api::Group<>::create(m_ioctx, "123")); | |
755 | ASSERT_EQ(0, librbd::api::Group<>::image_add(m_ioctx, "123", m_ioctx, | |
756 | m_image_name.c_str())); | |
757 | librbd::group_info_t info; | |
758 | ASSERT_EQ(0, librbd::api::Group<>::image_get_group(m_ictx, &info)); | |
759 | ||
760 | std::string name = get_temp_image_name(); | |
761 | ||
762 | migration_prepare(m_ioctx, name); | |
763 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
764 | ||
765 | ASSERT_EQ(0, librbd::api::Group<>::image_get_group(m_ictx, &info)); | |
766 | ASSERT_EQ(info.name, "123"); | |
767 | ||
768 | migration_abort(m_ioctx, m_image_name); | |
769 | ||
770 | ASSERT_EQ(0, librbd::api::Group<>::image_get_group(m_ictx, &info)); | |
771 | ASSERT_EQ(info.name, "123"); | |
772 | ||
773 | ASSERT_EQ(0, librbd::api::Group<>::image_remove(m_ioctx, "123", m_ioctx, | |
774 | m_image_name.c_str())); | |
775 | ASSERT_EQ(0, librbd::api::Group<>::remove(m_ioctx, "123")); | |
776 | } | |
777 | ||
778 | TEST_F(TestMigration, NoSnaps) | |
779 | { | |
780 | test_no_snaps(); | |
781 | migrate(m_ioctx, m_image_name); | |
782 | } | |
783 | ||
784 | TEST_F(TestMigration, NoSnapsOtherPool) | |
785 | { | |
786 | test_no_snaps(); | |
787 | ||
788 | test_no_snaps(); | |
789 | migrate(_other_pool_ioctx, m_image_name); | |
790 | } | |
791 | ||
792 | TEST_F(TestMigration, NoSnapsDataPool) | |
793 | { | |
794 | test_no_snaps(); | |
795 | ||
796 | ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_DATA_POOL, | |
797 | _other_pool_ioctx.get_pool_name().c_str())); | |
798 | migrate(m_ioctx, m_image_name); | |
799 | ||
800 | EXPECT_EQ(_other_pool_ioctx.get_id(), m_ictx->data_ctx.get_id()); | |
801 | } | |
802 | ||
803 | TEST_F(TestMigration, NoSnapsShrinkAfterPrepare) | |
804 | { | |
805 | test_no_snaps(); | |
806 | ||
807 | migration_prepare(m_ioctx, m_image_name); | |
808 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
809 | ||
810 | resize(m_ictx->size >> 1); | |
811 | ||
812 | migration_execute(m_ioctx, m_image_name); | |
813 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
814 | migration_commit(m_ioctx, m_image_name); | |
815 | } | |
816 | ||
817 | TEST_F(TestMigration, NoSnapsShrinkToZeroBeforePrepare) | |
818 | { | |
819 | test_no_snaps(); | |
820 | resize(0); | |
821 | ||
822 | migrate(m_ioctx, m_image_name); | |
823 | } | |
824 | ||
825 | TEST_F(TestMigration, NoSnapsShrinkToZeroAfterPrepare) | |
826 | { | |
827 | test_no_snaps(); | |
828 | ||
829 | migration_prepare(m_ioctx, m_image_name); | |
830 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
831 | ||
832 | resize(0); | |
833 | ||
834 | migration_execute(m_ioctx, m_image_name); | |
835 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
836 | migration_commit(m_ioctx, m_image_name); | |
837 | } | |
838 | ||
839 | TEST_F(TestMigration, NoSnapsExpandAfterPrepare) | |
840 | { | |
841 | test_no_snaps(); | |
842 | ||
843 | migration_prepare(m_ioctx, m_image_name); | |
844 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
845 | ||
846 | resize(m_ictx->size << 1); | |
847 | ||
848 | migration_execute(m_ioctx, m_image_name); | |
849 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
850 | migration_commit(m_ioctx, m_image_name); | |
851 | } | |
852 | ||
853 | TEST_F(TestMigration, NoSnapsSnapAfterPrepare) | |
854 | { | |
855 | test_no_snaps(); | |
856 | ||
857 | migration_prepare(m_ioctx, m_image_name); | |
858 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
859 | ||
860 | snap_create("after_prepare_snap"); | |
861 | resize(m_ictx->size >> 1); | |
862 | write(0, 1000, '*'); | |
863 | ||
864 | migration_execute(m_ioctx, m_image_name); | |
865 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
866 | migration_commit(m_ioctx, m_image_name); | |
867 | } | |
868 | ||
869 | TEST_F(TestMigration, Snaps) | |
870 | { | |
871 | test_snaps(); | |
872 | migrate(m_ioctx, m_image_name); | |
873 | } | |
874 | ||
875 | TEST_F(TestMigration, SnapsOtherPool) | |
876 | { | |
877 | test_snaps(); | |
878 | ||
879 | test_no_snaps(); | |
880 | migrate(_other_pool_ioctx, m_image_name); | |
881 | ||
882 | EXPECT_EQ(_other_pool_ioctx.get_id(), m_ictx->md_ctx.get_id()); | |
883 | } | |
884 | ||
885 | TEST_F(TestMigration, SnapsDataPool) | |
886 | { | |
887 | test_snaps(); | |
888 | ||
889 | ASSERT_EQ(0, m_opts.set(RBD_IMAGE_OPTION_DATA_POOL, | |
890 | _other_pool_ioctx.get_pool_name().c_str())); | |
891 | migrate(m_ioctx, m_image_name); | |
892 | ||
893 | EXPECT_EQ(_other_pool_ioctx.get_id(), m_ictx->data_ctx.get_id()); | |
894 | } | |
895 | ||
896 | TEST_F(TestMigration, SnapsShrinkAfterPrepare) | |
897 | { | |
898 | test_snaps(); | |
899 | ||
900 | migration_prepare(m_ioctx, m_image_name); | |
901 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
902 | ||
903 | resize(m_ictx->size >> 1); | |
904 | ||
905 | migration_execute(m_ioctx, m_image_name); | |
906 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
907 | migration_commit(m_ioctx, m_image_name); | |
908 | } | |
909 | ||
910 | TEST_F(TestMigration, SnapsShrinkToZeroBeforePrepare) | |
911 | { | |
912 | test_snaps(); | |
913 | resize(0); | |
914 | ||
915 | migrate(m_ioctx, m_image_name); | |
916 | } | |
917 | ||
918 | TEST_F(TestMigration, SnapsShrinkToZeroAfterPrepare) | |
919 | { | |
920 | test_snaps(); | |
921 | ||
922 | migration_prepare(m_ioctx, m_image_name); | |
923 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
924 | ||
925 | resize(0); | |
926 | ||
927 | migration_execute(m_ioctx, m_image_name); | |
928 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
929 | migration_commit(m_ioctx, m_image_name); | |
930 | } | |
931 | ||
932 | TEST_F(TestMigration, SnapsExpandAfterPrepare) | |
933 | { | |
934 | test_snaps(); | |
935 | ||
936 | migration_prepare(m_ioctx, m_image_name); | |
937 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
938 | ||
939 | auto size = m_ictx->size; | |
940 | resize(size << 1); | |
941 | write(size, 1000, '*'); | |
942 | ||
943 | migration_execute(m_ioctx, m_image_name); | |
944 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
945 | migration_commit(m_ioctx, m_image_name); | |
946 | } | |
947 | ||
948 | TEST_F(TestMigration, SnapsExpandAfterPrepare2) | |
949 | { | |
950 | auto size = m_ictx->size; | |
951 | ||
952 | write(size >> 1, 10, 'X'); | |
953 | snap_create("snap1"); | |
954 | resize(size >> 1); | |
955 | ||
956 | migration_prepare(m_ioctx, m_image_name); | |
957 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
958 | ||
959 | resize(size); | |
960 | write(size >> 1, 5, 'Y'); | |
961 | ||
962 | compare("before execute"); | |
963 | ||
964 | migration_execute(m_ioctx, m_image_name); | |
965 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
966 | migration_commit(m_ioctx, m_image_name); | |
967 | } | |
968 | ||
969 | TEST_F(TestMigration, SnapsSnapAfterPrepare) | |
970 | { | |
971 | test_snaps(); | |
972 | ||
973 | migration_prepare(m_ioctx, m_image_name); | |
974 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
975 | ||
976 | auto ictx = new librbd::ImageCtx(m_ictx->name.c_str(), "", "snap3", m_ioctx, | |
977 | false); | |
978 | ASSERT_EQ(0, ictx->state->open(0)); | |
979 | EXPECT_EQ(0, librbd::api::Image<>::snap_set( | |
980 | m_ref_ictx, cls::rbd::UserSnapshotNamespace(), "snap3")); | |
981 | compare_snaps("opened after prepare snap3", m_ref_ictx, ictx); | |
982 | EXPECT_EQ(0, librbd::api::Image<>::snap_set( | |
983 | m_ref_ictx, cls::rbd::UserSnapshotNamespace(), nullptr)); | |
984 | EXPECT_EQ(0, ictx->state->close()); | |
985 | ||
986 | snap_create("after_prepare_snap"); | |
987 | resize(m_ictx->size >> 1); | |
988 | write(0, 1000, '*'); | |
989 | ||
990 | migration_execute(m_ioctx, m_image_name); | |
991 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
992 | migration_commit(m_ioctx, m_image_name); | |
993 | } | |
994 | ||
995 | TEST_F(TestMigration, SnapsSnapExpandAfterPrepare) | |
996 | { | |
997 | test_snaps(); | |
998 | ||
999 | migration_prepare(m_ioctx, m_image_name); | |
1000 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
1001 | ||
1002 | snap_create("after_prepare_snap"); | |
1003 | auto size = m_ictx->size; | |
1004 | resize(size << 1); | |
1005 | write(size, 1000, '*'); | |
1006 | ||
1007 | migration_execute(m_ioctx, m_image_name); | |
1008 | migration_status(RBD_IMAGE_MIGRATION_STATE_EXECUTED); | |
1009 | migration_commit(m_ioctx, m_image_name); | |
1010 | } | |
1011 | ||
1012 | TEST_F(TestMigration, Clone) | |
1013 | { | |
1014 | REQUIRE_FEATURE(RBD_FEATURE_LAYERING); | |
1015 | ||
1016 | test_clone(); | |
1017 | migrate(m_ioctx, m_image_name); | |
1018 | } | |
1019 | ||
1020 | TEST_F(TestMigration, CloneParent) { | |
1021 | REQUIRE_FEATURE(RBD_FEATURE_LAYERING); | |
1022 | ||
1023 | snap_create("snap"); | |
1024 | ||
1025 | librbd::linked_image_spec_t expected_parent_image; | |
1026 | expected_parent_image.image_id = m_ictx->id; | |
1027 | expected_parent_image.image_name = m_ictx->name; | |
1028 | ||
1029 | auto it = m_ictx->snap_ids.find({cls::rbd::UserSnapshotNamespace{}, "snap"}); | |
1030 | ASSERT_TRUE(it != m_ictx->snap_ids.end()); | |
1031 | ||
1032 | librbd::snap_spec_t expected_parent_snap; | |
1033 | expected_parent_snap.id = it->second; | |
1034 | ||
1035 | clone("snap"); | |
1036 | migration_prepare(m_ioctx, m_image_name); | |
1037 | ||
1038 | librbd::linked_image_spec_t parent_image; | |
1039 | librbd::snap_spec_t parent_snap; | |
1040 | ASSERT_EQ(0, librbd::api::Image<>::get_parent(m_ictx, &parent_image, | |
1041 | &parent_snap)); | |
1042 | ASSERT_EQ(expected_parent_image.image_id, parent_image.image_id); | |
1043 | ASSERT_EQ(expected_parent_image.image_name, parent_image.image_name); | |
1044 | ASSERT_EQ(expected_parent_snap.id, parent_snap.id); | |
1045 | ||
1046 | migration_abort(m_ioctx, m_image_name); | |
1047 | } | |
1048 | ||
1049 | ||
1050 | TEST_F(TestMigration, CloneUpdateAfterPrepare) | |
1051 | { | |
1052 | REQUIRE_FEATURE(RBD_FEATURE_LAYERING); | |
1053 | ||
1054 | write(0, 10, 'X'); | |
1055 | snap_create("snap"); | |
1056 | clone("snap"); | |
1057 | ||
1058 | migration_prepare(m_ioctx, m_image_name); | |
1059 | ||
1060 | write(0, 1, 'Y'); | |
1061 | ||
1062 | migration_execute(m_ioctx, m_image_name); | |
1063 | migration_commit(m_ioctx, m_image_name); | |
1064 | } | |
1065 | ||
1066 | TEST_F(TestMigration, TriggerAssertSnapcSeq) | |
1067 | { | |
1068 | auto size = m_ictx->size; | |
1069 | ||
1070 | write((size >> 1) + 0, 10, 'A'); | |
1071 | snap_create("snap1"); | |
1072 | write((size >> 1) + 1, 10, 'B'); | |
1073 | ||
1074 | migration_prepare(m_ioctx, m_image_name); | |
1075 | ||
1076 | // copyup => deep copy (first time) | |
1077 | write((size >> 1) + 2, 10, 'C'); | |
1078 | ||
1079 | // preserve data before resizing | |
1080 | snap_create("snap2"); | |
1081 | ||
1082 | // decrease head overlap | |
1083 | resize(size >> 1); | |
1084 | ||
1085 | // migrate object => deep copy (second time) => assert_snapc_seq => -ERANGE | |
1086 | migration_execute(m_ioctx, m_image_name); | |
1087 | migration_commit(m_ioctx, m_image_name); | |
1088 | } | |
1089 | ||
1090 | TEST_F(TestMigration, SnapTrimBeforePrepare) | |
1091 | { | |
1092 | auto size = m_ictx->size; | |
1093 | ||
1094 | write(size >> 1, 10, 'A'); | |
1095 | snap_create("snap1"); | |
1096 | resize(size >> 1); | |
1097 | ||
1098 | migration_prepare(m_ioctx, m_image_name); | |
1099 | ||
1100 | resize(size); | |
1101 | snap_create("snap3"); | |
1102 | write(size >> 1, 10, 'B'); | |
1103 | snap_create("snap4"); | |
1104 | resize(size >> 1); | |
1105 | ||
1106 | migration_execute(m_ioctx, m_image_name); | |
1107 | migration_commit(m_ioctx, m_image_name); | |
1108 | } | |
1109 | ||
f91f0fd5 TL |
1110 | TEST_F(TestMigration, AbortInUseImage) { |
1111 | migration_prepare(m_ioctx, m_image_name); | |
1112 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
1113 | ||
1114 | librbd::NoOpProgressContext no_op; | |
1115 | EXPECT_EQ(-EBUSY, librbd::api::Migration<>::abort(m_ioctx, m_ictx->name, | |
1116 | no_op)); | |
1117 | } | |
1118 | ||
1119 | TEST_F(TestMigration, AbortWithoutSnapshots) { | |
1120 | test_no_snaps(); | |
1121 | migration_prepare(m_ioctx, m_image_name); | |
1122 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
1123 | test_no_snaps(); | |
1124 | migration_abort(m_ioctx, m_image_name); | |
1125 | } | |
1126 | ||
1127 | TEST_F(TestMigration, AbortWithSnapshots) { | |
1128 | test_snaps(); | |
1129 | migration_prepare(m_ioctx, m_image_name); | |
1130 | migration_status(RBD_IMAGE_MIGRATION_STATE_PREPARED); | |
1131 | ||
1132 | test_no_snaps(); | |
1133 | flush(); | |
1134 | ASSERT_EQ(0, TestFixture::snap_create(*m_ictx, "dst-only-snap")); | |
1135 | ||
1136 | test_no_snaps(); | |
1137 | ||
1138 | migration_abort(m_ioctx, m_image_name); | |
1139 | } | |
1140 | ||
11fdf7f2 TL |
1141 | TEST_F(TestMigration, CloneV1Parent) |
1142 | { | |
1143 | const uint32_t CLONE_FORMAT = 1; | |
1144 | test_migrate_parent( | |
1145 | CLONE_FORMAT, [this](librbd::ImageCtx *) { | |
1146 | migrate(m_ioctx, m_image_name); | |
1147 | }); | |
1148 | } | |
1149 | ||
1150 | TEST_F(TestMigration, CloneV2Parent) | |
1151 | { | |
1152 | const uint32_t CLONE_FORMAT = 2; | |
1153 | test_migrate_parent( | |
1154 | CLONE_FORMAT, [this](librbd::ImageCtx *) { | |
1155 | migrate(m_ioctx, m_image_name); | |
1156 | }); | |
1157 | } | |
1158 | ||
1159 | TEST_F(TestMigration, CloneV1ParentAbort) | |
1160 | { | |
1161 | const uint32_t CLONE_FORMAT = 1; | |
1162 | test_migrate_parent( | |
1163 | CLONE_FORMAT, [this](librbd::ImageCtx *) { | |
1164 | migration_prepare(m_ioctx, m_image_name); | |
1165 | migration_abort(m_ioctx, m_image_name); | |
1166 | }); | |
1167 | } | |
1168 | ||
1169 | TEST_F(TestMigration, CloneV2ParentAbort) | |
1170 | { | |
1171 | const uint32_t CLONE_FORMAT = 2; | |
1172 | test_migrate_parent( | |
1173 | CLONE_FORMAT, [this](librbd::ImageCtx *) { | |
1174 | migration_prepare(m_ioctx, m_image_name); | |
1175 | migration_abort(m_ioctx, m_image_name); | |
1176 | }); | |
1177 | } | |
1178 | ||
1179 | TEST_F(TestMigration, CloneV1ParentAbortFixIncompleteChildReattach) | |
1180 | { | |
1181 | const uint32_t CLONE_FORMAT = 1; | |
1182 | test_migrate_parent( | |
1183 | CLONE_FORMAT, [this](librbd::ImageCtx *child_ictx) { | |
1184 | auto src_image_id = m_ictx->id; | |
1185 | migration_prepare(m_ioctx, m_image_name); | |
1186 | // Attach the child to both source and destination | |
1187 | // to emulate a crash when re-attaching the child | |
1188 | librbd::ImageCtx *src_ictx; | |
1189 | open_image(m_ioctx, "", src_image_id, false, | |
1190 | librbd::OPEN_FLAG_IGNORE_MIGRATING, &src_ictx); | |
1191 | C_SaferCond cond; | |
1192 | auto req = librbd::image::AttachChildRequest<>::create( | |
1193 | child_ictx, src_ictx, src_ictx->snaps[0], nullptr, 0, | |
1194 | CLONE_FORMAT, &cond); | |
1195 | req->send(); | |
1196 | ASSERT_EQ(0, cond.wait()); | |
1197 | close_image(src_ictx); | |
1198 | migration_abort(m_ioctx, m_image_name); | |
1199 | }); | |
1200 | } | |
1201 | ||
1202 | TEST_F(TestMigration, CloneV1ParentAbortFixParentReattach) | |
1203 | { | |
1204 | const uint32_t CLONE_FORMAT = 1; | |
1205 | test_migrate_parent( | |
1206 | CLONE_FORMAT, [this](librbd::ImageCtx *child_ictx) { | |
1207 | auto src_image_id = m_ictx->id; | |
1208 | migration_prepare(m_ioctx, m_image_name); | |
1209 | // Re-attach the child back to the source to emulate a crash | |
1210 | // after the parent reattach but before the child reattach | |
1211 | librbd::ImageCtx *src_ictx; | |
1212 | open_image(m_ioctx, "", src_image_id, false, | |
1213 | librbd::OPEN_FLAG_IGNORE_MIGRATING, &src_ictx); | |
1214 | C_SaferCond cond; | |
1215 | auto req = librbd::image::AttachChildRequest<>::create( | |
1216 | child_ictx, src_ictx, src_ictx->snaps[0], m_ictx, | |
1217 | m_ictx->snaps[0], CLONE_FORMAT, &cond); | |
1218 | req->send(); | |
1219 | ASSERT_EQ(0, cond.wait()); | |
1220 | close_image(src_ictx); | |
1221 | migration_abort(m_ioctx, m_image_name); | |
1222 | }); | |
1223 | } | |
1224 | ||
1225 | TEST_F(TestMigration, CloneV1ParentAbortRelinkNotNeeded) | |
1226 | { | |
1227 | const uint32_t CLONE_FORMAT = 1; | |
1228 | test_migrate_parent( | |
1229 | CLONE_FORMAT, [this](librbd::ImageCtx *child_ictx) { | |
1230 | auto src_image_id = m_ictx->id; | |
1231 | auto parent_spec = child_ictx->parent_md.spec; | |
1232 | parent_spec.image_id = m_ictx->id; | |
1233 | parent_spec.snap_id = m_ictx->snaps[0]; | |
1234 | auto parent_overlap = child_ictx->parent_md.overlap; | |
1235 | migration_prepare(m_ioctx, m_image_name); | |
1236 | // Relink the child back to emulate a crash | |
1237 | // before relinking the child | |
1238 | C_SaferCond cond; | |
1239 | auto req = librbd::image::AttachParentRequest<>::create( | |
1240 | *child_ictx, parent_spec, parent_overlap, true, &cond); | |
1241 | req->send(); | |
1242 | ASSERT_EQ(0, cond.wait()); | |
1243 | librbd::ImageCtx *src_ictx; | |
1244 | open_image(m_ioctx, "", src_image_id, false, | |
1245 | librbd::OPEN_FLAG_IGNORE_MIGRATING, &src_ictx); | |
1246 | C_SaferCond cond1; | |
1247 | auto req1 = librbd::image::AttachChildRequest<>::create( | |
1248 | child_ictx, src_ictx, src_ictx->snaps[0], m_ictx, | |
1249 | m_ictx->snaps[0], CLONE_FORMAT, &cond1); | |
1250 | req1->send(); | |
1251 | ASSERT_EQ(0, cond1.wait()); | |
1252 | close_image(src_ictx); | |
1253 | migration_abort(m_ioctx, m_image_name); | |
1254 | }); | |
1255 | } | |
1256 | ||
1257 | TEST_F(TestMigration, CloneV2ParentAbortFixIncompleteChildReattach) | |
1258 | { | |
1259 | const uint32_t CLONE_FORMAT = 2; | |
1260 | test_migrate_parent( | |
1261 | CLONE_FORMAT, [this](librbd::ImageCtx *child_ictx) { | |
1262 | auto src_image_id = m_ictx->id; | |
1263 | migration_prepare(m_ioctx, m_image_name); | |
1264 | // Attach the child to both source and destination | |
1265 | // to emulate a crash when re-attaching the child | |
1266 | librbd::ImageCtx *src_ictx; | |
1267 | open_image(m_ioctx, "", src_image_id, false, | |
1268 | librbd::OPEN_FLAG_IGNORE_MIGRATING, &src_ictx); | |
1269 | C_SaferCond cond; | |
1270 | auto req = librbd::image::AttachChildRequest<>::create( | |
1271 | child_ictx, src_ictx, src_ictx->snaps[0], nullptr, 0, | |
1272 | CLONE_FORMAT, &cond); | |
1273 | req->send(); | |
1274 | ASSERT_EQ(0, cond.wait()); | |
1275 | close_image(src_ictx); | |
1276 | migration_abort(m_ioctx, m_image_name); | |
1277 | }); | |
1278 | } | |
1279 | ||
1280 | TEST_F(TestMigration, CloneV2ParentAbortFixParentReattach) | |
1281 | { | |
1282 | const uint32_t CLONE_FORMAT = 2; | |
1283 | test_migrate_parent( | |
1284 | CLONE_FORMAT, [this](librbd::ImageCtx *child_ictx) { | |
1285 | auto src_image_id = m_ictx->id; | |
1286 | migration_prepare(m_ioctx, m_image_name); | |
1287 | // Re-attach the child back to the source to emulate a crash | |
1288 | // after the parent reattach but before the child reattach | |
1289 | librbd::ImageCtx *src_ictx; | |
1290 | open_image(m_ioctx, "", src_image_id, false, | |
1291 | librbd::OPEN_FLAG_IGNORE_MIGRATING, &src_ictx); | |
1292 | C_SaferCond cond; | |
1293 | auto req = librbd::image::AttachChildRequest<>::create( | |
1294 | child_ictx, src_ictx, src_ictx->snaps[0], m_ictx, | |
1295 | m_ictx->snaps[0], CLONE_FORMAT, &cond); | |
1296 | req->send(); | |
1297 | ASSERT_EQ(0, cond.wait()); | |
1298 | close_image(src_ictx); | |
1299 | migration_abort(m_ioctx, m_image_name); | |
1300 | }); | |
1301 | } | |
1302 | ||
1303 | TEST_F(TestMigration, CloneV2ParentAbortRelinkNotNeeded) | |
1304 | { | |
1305 | const uint32_t CLONE_FORMAT = 2; | |
1306 | test_migrate_parent( | |
1307 | CLONE_FORMAT, [this](librbd::ImageCtx *child_ictx) { | |
1308 | auto src_image_id = m_ictx->id; | |
1309 | auto parent_spec = child_ictx->parent_md.spec; | |
1310 | parent_spec.image_id = m_ictx->id; | |
1311 | parent_spec.snap_id = m_ictx->snaps[0]; | |
1312 | auto parent_overlap = child_ictx->parent_md.overlap; | |
1313 | migration_prepare(m_ioctx, m_image_name); | |
1314 | // Relink the child back to emulate a crash | |
1315 | // before relinking the child | |
1316 | C_SaferCond cond; | |
1317 | auto req = librbd::image::AttachParentRequest<>::create( | |
1318 | *child_ictx, parent_spec, parent_overlap, true, &cond); | |
1319 | req->send(); | |
1320 | ASSERT_EQ(0, cond.wait()); | |
1321 | librbd::ImageCtx *src_ictx; | |
1322 | open_image(m_ioctx, "", src_image_id, false, | |
1323 | librbd::OPEN_FLAG_IGNORE_MIGRATING, &src_ictx); | |
1324 | C_SaferCond cond1; | |
1325 | auto req1 = librbd::image::AttachChildRequest<>::create( | |
1326 | child_ictx, src_ictx, src_ictx->snaps[0], m_ictx, | |
1327 | m_ictx->snaps[0], CLONE_FORMAT, &cond1); | |
1328 | req1->send(); | |
1329 | ASSERT_EQ(0, cond1.wait()); | |
1330 | close_image(src_ictx); | |
1331 | migration_abort(m_ioctx, m_image_name); | |
1332 | }); | |
1333 | } | |
1334 | ||
1335 | TEST_F(TestMigration, StressNoMigrate) | |
1336 | { | |
1337 | test_stress(); | |
1338 | ||
1339 | compare(); | |
1340 | } | |
1341 | ||
1342 | TEST_F(TestMigration, Stress) | |
1343 | { | |
1344 | test_stress(); | |
1345 | ||
1346 | migrate(m_ioctx, m_image_name); | |
1347 | } | |
1348 | ||
1349 | TEST_F(TestMigration, Stress2) | |
1350 | { | |
1351 | test_stress2(false); | |
1352 | } | |
1353 | ||
1354 | TEST_F(TestMigration, StressLive) | |
1355 | { | |
1356 | test_stress2(true); | |
1357 | } | |
f67539c2 TL |
1358 | |
1359 | } // namespace librbd |