1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <android-base/strings.h>
16 #include <gflags/gflags.h>
17
18 #include <fcntl.h>
19 #include <linux/fs.h>
20 #include <linux/memfd.h>
21 #include <sys/ioctl.h>
22 #include <sys/stat.h>
23 #include <sys/syscall.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26
27 #include <chrono>
28 #include <iostream>
29 #include <memory>
30 #include <string_view>
31
32 #include <android-base/file.h>
33 #include <android-base/properties.h>
34 #include <android-base/unique_fd.h>
35 #include <fs_mgr/file_wait.h>
36 #include <gtest/gtest.h>
37 #include <libdm/dm.h>
38 #include <libdm/loop_control.h>
39 #include <libsnapshot/cow_writer.h>
40 #include <snapuserd/snapuserd_client.h>
41 #include <storage_literals/storage_literals.h>
42
43 #include "snapuserd_core.h"
44
45 DEFINE_string(force_config, "", "Force testing mode with iouring disabled");
46
47 namespace android {
48 namespace snapshot {
49
50 using namespace android::storage_literals;
51 using android::base::unique_fd;
52 using LoopDevice = android::dm::LoopDevice;
53 using namespace std::chrono_literals;
54 using namespace android::dm;
55 using namespace std;
56
57 static constexpr char kSnapuserdSocketTest[] = "snapuserdTest";
58
59 class Tempdevice {
60 public:
Tempdevice(const std::string & name,const DmTable & table)61 Tempdevice(const std::string& name, const DmTable& table)
62 : dm_(DeviceMapper::Instance()), name_(name), valid_(false) {
63 valid_ = dm_.CreateDevice(name, table, &path_, std::chrono::seconds(5));
64 }
Tempdevice(Tempdevice && other)65 Tempdevice(Tempdevice&& other) noexcept
66 : dm_(other.dm_), name_(other.name_), path_(other.path_), valid_(other.valid_) {
67 other.valid_ = false;
68 }
~Tempdevice()69 ~Tempdevice() {
70 if (valid_) {
71 dm_.DeleteDevice(name_);
72 }
73 }
Destroy()74 bool Destroy() {
75 if (!valid_) {
76 return false;
77 }
78 valid_ = false;
79 return dm_.DeleteDevice(name_);
80 }
path() const81 const std::string& path() const { return path_; }
name() const82 const std::string& name() const { return name_; }
valid() const83 bool valid() const { return valid_; }
84
85 Tempdevice(const Tempdevice&) = delete;
86 Tempdevice& operator=(const Tempdevice&) = delete;
87
operator =(Tempdevice && other)88 Tempdevice& operator=(Tempdevice&& other) noexcept {
89 name_ = other.name_;
90 valid_ = other.valid_;
91 other.valid_ = false;
92 return *this;
93 }
94
95 private:
96 DeviceMapper& dm_;
97 std::string name_;
98 std::string path_;
99 bool valid_;
100 };
101
102 class SnapuserTest final {
103 public:
104 bool Setup();
105 bool SetupOrderedOps();
106 bool SetupOrderedOpsInverted();
107 bool SetupCopyOverlap_1();
108 bool SetupCopyOverlap_2();
109 bool Merge();
110 void ValidateMerge();
111 void ReadSnapshotDeviceAndValidate();
112 void Shutdown();
113 void MergeInterrupt();
114 void MergeInterruptFixed(int duration);
115 void MergeInterruptRandomly(int max_duration);
116 void StartMerge();
117 void CheckMergeCompletion();
118
119 static const uint64_t kSectorSize = 512;
120
121 private:
122 void SetupImpl();
123
124 void SimulateDaemonRestart();
125
126 void CreateCowDevice();
127 void CreateCowDeviceOrderedOps();
128 void CreateCowDeviceOrderedOpsInverted();
129 void CreateCowDeviceWithCopyOverlap_1();
130 void CreateCowDeviceWithCopyOverlap_2();
131 bool SetupDaemon();
132 void CreateBaseDevice();
133 void InitCowDevice();
134 void SetDeviceControlName();
135 void InitDaemon();
136 void CreateDmUserDevice();
137 void StartSnapuserdDaemon();
138
139 unique_ptr<LoopDevice> base_loop_;
140 unique_ptr<Tempdevice> dmuser_dev_;
141
142 std::string system_device_ctrl_name_;
143 std::string system_device_name_;
144
145 unique_fd base_fd_;
146 std::unique_ptr<TemporaryFile> cow_system_;
147 std::unique_ptr<SnapuserdClient> client_;
148 std::unique_ptr<uint8_t[]> orig_buffer_;
149 std::unique_ptr<uint8_t[]> merged_buffer_;
150 bool setup_ok_ = false;
151 bool merge_ok_ = false;
152 size_t size_ = 100_MiB;
153 int cow_num_sectors_;
154 int total_base_size_;
155 };
156
CreateTempFile(const std::string & name,size_t size)157 static unique_fd CreateTempFile(const std::string& name, size_t size) {
158 unique_fd fd(syscall(__NR_memfd_create, name.c_str(), MFD_ALLOW_SEALING));
159 if (fd < 0) {
160 return {};
161 }
162 if (size) {
163 if (ftruncate(fd, size) < 0) {
164 perror("ftruncate");
165 return {};
166 }
167 if (fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK) < 0) {
168 perror("fcntl");
169 return {};
170 }
171 }
172 return fd;
173 }
174
Shutdown()175 void SnapuserTest::Shutdown() {
176 ASSERT_TRUE(dmuser_dev_->Destroy());
177
178 auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_;
179 ASSERT_TRUE(client_->WaitForDeviceDelete(system_device_ctrl_name_));
180 ASSERT_TRUE(android::fs_mgr::WaitForFileDeleted(misc_device, 10s));
181 ASSERT_TRUE(client_->DetachSnapuserd());
182 }
183
Setup()184 bool SnapuserTest::Setup() {
185 SetupImpl();
186 return setup_ok_;
187 }
188
SetupOrderedOps()189 bool SnapuserTest::SetupOrderedOps() {
190 CreateBaseDevice();
191 CreateCowDeviceOrderedOps();
192 return SetupDaemon();
193 }
194
SetupOrderedOpsInverted()195 bool SnapuserTest::SetupOrderedOpsInverted() {
196 CreateBaseDevice();
197 CreateCowDeviceOrderedOpsInverted();
198 return SetupDaemon();
199 }
200
SetupCopyOverlap_1()201 bool SnapuserTest::SetupCopyOverlap_1() {
202 CreateBaseDevice();
203 CreateCowDeviceWithCopyOverlap_1();
204 return SetupDaemon();
205 }
206
SetupCopyOverlap_2()207 bool SnapuserTest::SetupCopyOverlap_2() {
208 CreateBaseDevice();
209 CreateCowDeviceWithCopyOverlap_2();
210 return SetupDaemon();
211 }
212
SetupDaemon()213 bool SnapuserTest::SetupDaemon() {
214 SetDeviceControlName();
215
216 StartSnapuserdDaemon();
217
218 CreateDmUserDevice();
219 InitCowDevice();
220 InitDaemon();
221
222 setup_ok_ = true;
223
224 return setup_ok_;
225 }
226
StartSnapuserdDaemon()227 void SnapuserTest::StartSnapuserdDaemon() {
228 pid_t pid = fork();
229 ASSERT_GE(pid, 0);
230 if (pid == 0) {
231 std::string arg0 = "/system/bin/snapuserd";
232 std::string arg1 = "-socket="s + kSnapuserdSocketTest;
233 char* const argv[] = {arg0.data(), arg1.data(), nullptr};
234 ASSERT_GE(execv(arg0.c_str(), argv), 0);
235 } else {
236 client_ = SnapuserdClient::Connect(kSnapuserdSocketTest, 10s);
237 ASSERT_NE(client_, nullptr);
238 }
239 }
240
CreateBaseDevice()241 void SnapuserTest::CreateBaseDevice() {
242 unique_fd rnd_fd;
243
244 total_base_size_ = (size_ * 5);
245 base_fd_ = CreateTempFile("base_device", total_base_size_);
246 ASSERT_GE(base_fd_, 0);
247
248 rnd_fd.reset(open("/dev/random", O_RDONLY));
249 ASSERT_TRUE(rnd_fd > 0);
250
251 std::unique_ptr<uint8_t[]> random_buffer = std::make_unique<uint8_t[]>(1_MiB);
252
253 for (size_t j = 0; j < ((total_base_size_) / 1_MiB); j++) {
254 ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), 1_MiB, 0), true);
255 ASSERT_EQ(android::base::WriteFully(base_fd_, random_buffer.get(), 1_MiB), true);
256 }
257
258 ASSERT_EQ(lseek(base_fd_, 0, SEEK_SET), 0);
259
260 base_loop_ = std::make_unique<LoopDevice>(base_fd_, 10s);
261 ASSERT_TRUE(base_loop_->valid());
262 }
263
ReadSnapshotDeviceAndValidate()264 void SnapuserTest::ReadSnapshotDeviceAndValidate() {
265 unique_fd fd(open(dmuser_dev_->path().c_str(), O_RDONLY));
266 ASSERT_GE(fd, 0);
267 std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(size_);
268
269 // COPY
270 loff_t offset = 0;
271 ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
272 ASSERT_EQ(memcmp(snapuserd_buffer.get(), orig_buffer_.get(), size_), 0);
273
274 // REPLACE
275 offset += size_;
276 ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
277 ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + size_, size_), 0);
278
279 // ZERO
280 offset += size_;
281 ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
282 ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 2), size_), 0);
283
284 // REPLACE
285 offset += size_;
286 ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
287 ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 3), size_), 0);
288
289 // XOR
290 offset += size_;
291 ASSERT_EQ(ReadFullyAtOffset(fd, snapuserd_buffer.get(), size_, offset), true);
292 ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 4), size_), 0);
293 }
294
CreateCowDeviceWithCopyOverlap_2()295 void SnapuserTest::CreateCowDeviceWithCopyOverlap_2() {
296 std::string path = android::base::GetExecutableDirectory();
297 cow_system_ = std::make_unique<TemporaryFile>(path);
298
299 CowOptions options;
300 options.compression = "gz";
301 CowWriter writer(options);
302
303 ASSERT_TRUE(writer.Initialize(cow_system_->fd));
304
305 size_t num_blocks = size_ / options.block_size;
306 size_t x = num_blocks;
307 size_t blk_src_copy = 0;
308
309 // Create overlapping copy operations
310 while (1) {
311 ASSERT_TRUE(writer.AddCopy(blk_src_copy, blk_src_copy + 1));
312 x -= 1;
313 if (x == 1) {
314 break;
315 }
316 blk_src_copy += 1;
317 }
318
319 // Flush operations
320 ASSERT_TRUE(writer.Finalize());
321
322 // Construct the buffer required for validation
323 orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
324
325 // Read the entire base device
326 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
327 true);
328
329 // Merged operations required for validation
330 int block_size = 4096;
331 x = num_blocks;
332 loff_t src_offset = block_size;
333 loff_t dest_offset = 0;
334
335 while (1) {
336 memmove((char*)orig_buffer_.get() + dest_offset, (char*)orig_buffer_.get() + src_offset,
337 block_size);
338 x -= 1;
339 if (x == 1) {
340 break;
341 }
342 src_offset += block_size;
343 dest_offset += block_size;
344 }
345 }
346
CreateCowDeviceWithCopyOverlap_1()347 void SnapuserTest::CreateCowDeviceWithCopyOverlap_1() {
348 std::string path = android::base::GetExecutableDirectory();
349 cow_system_ = std::make_unique<TemporaryFile>(path);
350
351 CowOptions options;
352 options.compression = "gz";
353 CowWriter writer(options);
354
355 ASSERT_TRUE(writer.Initialize(cow_system_->fd));
356
357 size_t num_blocks = size_ / options.block_size;
358 size_t x = num_blocks;
359 size_t blk_src_copy = num_blocks - 1;
360
361 // Create overlapping copy operations
362 while (1) {
363 ASSERT_TRUE(writer.AddCopy(blk_src_copy + 1, blk_src_copy));
364 x -= 1;
365 if (x == 0) {
366 ASSERT_EQ(blk_src_copy, 0);
367 break;
368 }
369 blk_src_copy -= 1;
370 }
371
372 // Flush operations
373 ASSERT_TRUE(writer.Finalize());
374
375 // Construct the buffer required for validation
376 orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
377
378 // Read the entire base device
379 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
380 true);
381
382 // Merged operations
383 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), options.block_size, 0),
384 true);
385 ASSERT_EQ(android::base::ReadFullyAtOffset(
386 base_fd_, (char*)orig_buffer_.get() + options.block_size, size_, 0),
387 true);
388 }
389
CreateCowDeviceOrderedOpsInverted()390 void SnapuserTest::CreateCowDeviceOrderedOpsInverted() {
391 unique_fd rnd_fd;
392 loff_t offset = 0;
393
394 std::string path = android::base::GetExecutableDirectory();
395 cow_system_ = std::make_unique<TemporaryFile>(path);
396
397 rnd_fd.reset(open("/dev/random", O_RDONLY));
398 ASSERT_TRUE(rnd_fd > 0);
399
400 std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
401
402 // Fill random data
403 for (size_t j = 0; j < (size_ / 1_MiB); j++) {
404 ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
405 true);
406
407 offset += 1_MiB;
408 }
409
410 CowOptions options;
411 options.compression = "gz";
412 CowWriter writer(options);
413
414 ASSERT_TRUE(writer.Initialize(cow_system_->fd));
415
416 size_t num_blocks = size_ / options.block_size;
417 size_t blk_end_copy = num_blocks * 3;
418 size_t source_blk = num_blocks - 1;
419 size_t blk_src_copy = blk_end_copy - 1;
420 uint16_t xor_offset = 5;
421
422 size_t x = num_blocks;
423 while (1) {
424 ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy));
425 x -= 1;
426 if (x == 0) {
427 break;
428 }
429 source_blk -= 1;
430 blk_src_copy -= 1;
431 }
432
433 for (size_t i = num_blocks; i > 0; i--) {
434 ASSERT_TRUE(writer.AddXorBlocks(num_blocks + i - 1,
435 &random_buffer_1_.get()[options.block_size * (i - 1)],
436 options.block_size, 2 * num_blocks + i - 1, xor_offset));
437 }
438 // Flush operations
439 ASSERT_TRUE(writer.Finalize());
440 // Construct the buffer required for validation
441 orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
442 // Read the entire base device
443 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
444 true);
445 // Merged Buffer
446 memmove(orig_buffer_.get(), (char*)orig_buffer_.get() + 2 * size_, size_);
447 memmove(orig_buffer_.get() + size_, (char*)orig_buffer_.get() + 2 * size_ + xor_offset, size_);
448 for (int i = 0; i < size_; i++) {
449 orig_buffer_.get()[size_ + i] ^= random_buffer_1_.get()[i];
450 }
451 }
452
CreateCowDeviceOrderedOps()453 void SnapuserTest::CreateCowDeviceOrderedOps() {
454 unique_fd rnd_fd;
455 loff_t offset = 0;
456
457 std::string path = android::base::GetExecutableDirectory();
458 cow_system_ = std::make_unique<TemporaryFile>(path);
459
460 rnd_fd.reset(open("/dev/random", O_RDONLY));
461 ASSERT_TRUE(rnd_fd > 0);
462
463 std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
464
465 // Fill random data
466 for (size_t j = 0; j < (size_ / 1_MiB); j++) {
467 ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
468 true);
469
470 offset += 1_MiB;
471 }
472 memset(random_buffer_1_.get(), 0, size_);
473
474 CowOptions options;
475 options.compression = "gz";
476 CowWriter writer(options);
477
478 ASSERT_TRUE(writer.Initialize(cow_system_->fd));
479
480 size_t num_blocks = size_ / options.block_size;
481 size_t x = num_blocks;
482 size_t source_blk = 0;
483 size_t blk_src_copy = 2 * num_blocks;
484 uint16_t xor_offset = 5;
485
486 while (1) {
487 ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy));
488
489 x -= 1;
490 if (x == 0) {
491 break;
492 }
493 source_blk += 1;
494 blk_src_copy += 1;
495 }
496
497 ASSERT_TRUE(writer.AddXorBlocks(num_blocks, random_buffer_1_.get(), size_, 2 * num_blocks,
498 xor_offset));
499 // Flush operations
500 ASSERT_TRUE(writer.Finalize());
501 // Construct the buffer required for validation
502 orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
503 // Read the entire base device
504 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
505 true);
506 // Merged Buffer
507 memmove(orig_buffer_.get(), (char*)orig_buffer_.get() + 2 * size_, size_);
508 memmove(orig_buffer_.get() + size_, (char*)orig_buffer_.get() + 2 * size_ + xor_offset, size_);
509 for (int i = 0; i < size_; i++) {
510 orig_buffer_.get()[size_ + i] ^= random_buffer_1_.get()[i];
511 }
512 }
513
CreateCowDevice()514 void SnapuserTest::CreateCowDevice() {
515 unique_fd rnd_fd;
516 loff_t offset = 0;
517
518 std::string path = android::base::GetExecutableDirectory();
519 cow_system_ = std::make_unique<TemporaryFile>(path);
520
521 rnd_fd.reset(open("/dev/random", O_RDONLY));
522 ASSERT_TRUE(rnd_fd > 0);
523
524 std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
525
526 // Fill random data
527 for (size_t j = 0; j < (size_ / 1_MiB); j++) {
528 ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
529 true);
530
531 offset += 1_MiB;
532 }
533
534 CowOptions options;
535 options.compression = "gz";
536 CowWriter writer(options);
537
538 ASSERT_TRUE(writer.Initialize(cow_system_->fd));
539
540 size_t num_blocks = size_ / options.block_size;
541 size_t blk_end_copy = num_blocks * 2;
542 size_t source_blk = num_blocks - 1;
543 size_t blk_src_copy = blk_end_copy - 1;
544
545 uint32_t sequence[num_blocks * 2];
546 // Sequence for Copy ops
547 for (int i = 0; i < num_blocks; i++) {
548 sequence[i] = num_blocks - 1 - i;
549 }
550 // Sequence for Xor ops
551 for (int i = 0; i < num_blocks; i++) {
552 sequence[num_blocks + i] = 5 * num_blocks - 1 - i;
553 }
554 ASSERT_TRUE(writer.AddSequenceData(2 * num_blocks, sequence));
555
556 size_t x = num_blocks;
557 while (1) {
558 ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy));
559 x -= 1;
560 if (x == 0) {
561 break;
562 }
563 source_blk -= 1;
564 blk_src_copy -= 1;
565 }
566
567 source_blk = num_blocks;
568 blk_src_copy = blk_end_copy;
569
570 ASSERT_TRUE(writer.AddRawBlocks(source_blk, random_buffer_1_.get(), size_));
571
572 size_t blk_zero_copy_start = source_blk + num_blocks;
573 size_t blk_zero_copy_end = blk_zero_copy_start + num_blocks;
574
575 ASSERT_TRUE(writer.AddZeroBlocks(blk_zero_copy_start, num_blocks));
576
577 size_t blk_random2_replace_start = blk_zero_copy_end;
578
579 ASSERT_TRUE(writer.AddRawBlocks(blk_random2_replace_start, random_buffer_1_.get(), size_));
580
581 size_t blk_xor_start = blk_random2_replace_start + num_blocks;
582 size_t xor_offset = BLOCK_SZ / 2;
583 ASSERT_TRUE(writer.AddXorBlocks(blk_xor_start, random_buffer_1_.get(), size_, num_blocks,
584 xor_offset));
585
586 // Flush operations
587 ASSERT_TRUE(writer.Finalize());
588 // Construct the buffer required for validation
589 orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
590 std::string zero_buffer(size_, 0);
591 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), size_, size_), true);
592 memcpy((char*)orig_buffer_.get() + size_, random_buffer_1_.get(), size_);
593 memcpy((char*)orig_buffer_.get() + (size_ * 2), (void*)zero_buffer.c_str(), size_);
594 memcpy((char*)orig_buffer_.get() + (size_ * 3), random_buffer_1_.get(), size_);
595 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, &orig_buffer_.get()[size_ * 4], size_,
596 size_ + xor_offset),
597 true);
598 for (int i = 0; i < size_; i++) {
599 orig_buffer_.get()[(size_ * 4) + i] =
600 (uint8_t)(orig_buffer_.get()[(size_ * 4) + i] ^ random_buffer_1_.get()[i]);
601 }
602 }
603
InitCowDevice()604 void SnapuserTest::InitCowDevice() {
605 uint64_t num_sectors = client_->InitDmUserCow(system_device_ctrl_name_, cow_system_->path,
606 base_loop_->device(), base_loop_->device());
607 ASSERT_NE(num_sectors, 0);
608 }
609
SetDeviceControlName()610 void SnapuserTest::SetDeviceControlName() {
611 system_device_name_.clear();
612 system_device_ctrl_name_.clear();
613
614 std::string str(cow_system_->path);
615 std::size_t found = str.find_last_of("/\\");
616 ASSERT_NE(found, std::string::npos);
617 system_device_name_ = str.substr(found + 1);
618
619 system_device_ctrl_name_ = system_device_name_ + "-ctrl";
620 }
621
CreateDmUserDevice()622 void SnapuserTest::CreateDmUserDevice() {
623 unique_fd fd(TEMP_FAILURE_RETRY(open(base_loop_->device().c_str(), O_RDONLY | O_CLOEXEC)));
624 ASSERT_TRUE(fd > 0);
625
626 uint64_t dev_sz = get_block_device_size(fd.get());
627 ASSERT_TRUE(dev_sz > 0);
628
629 cow_num_sectors_ = dev_sz >> 9;
630
631 DmTable dmuser_table;
632 ASSERT_TRUE(dmuser_table.AddTarget(
633 std::make_unique<DmTargetUser>(0, cow_num_sectors_, system_device_ctrl_name_)));
634 ASSERT_TRUE(dmuser_table.valid());
635
636 dmuser_dev_ = std::make_unique<Tempdevice>(system_device_name_, dmuser_table);
637 ASSERT_TRUE(dmuser_dev_->valid());
638 ASSERT_FALSE(dmuser_dev_->path().empty());
639
640 auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_;
641 ASSERT_TRUE(android::fs_mgr::WaitForFile(misc_device, 10s));
642 }
643
InitDaemon()644 void SnapuserTest::InitDaemon() {
645 bool ok = client_->AttachDmUser(system_device_ctrl_name_);
646 ASSERT_TRUE(ok);
647 }
648
CheckMergeCompletion()649 void SnapuserTest::CheckMergeCompletion() {
650 while (true) {
651 double percentage = client_->GetMergePercent();
652 if ((int)percentage == 100) {
653 break;
654 }
655
656 std::this_thread::sleep_for(1s);
657 }
658 }
659
SetupImpl()660 void SnapuserTest::SetupImpl() {
661 CreateBaseDevice();
662 CreateCowDevice();
663
664 SetDeviceControlName();
665
666 StartSnapuserdDaemon();
667
668 CreateDmUserDevice();
669 InitCowDevice();
670 InitDaemon();
671
672 setup_ok_ = true;
673 }
674
Merge()675 bool SnapuserTest::Merge() {
676 StartMerge();
677 CheckMergeCompletion();
678 merge_ok_ = true;
679 return merge_ok_;
680 }
681
StartMerge()682 void SnapuserTest::StartMerge() {
683 bool ok = client_->InitiateMerge(system_device_ctrl_name_);
684 ASSERT_TRUE(ok);
685 }
686
ValidateMerge()687 void SnapuserTest::ValidateMerge() {
688 merged_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
689 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, merged_buffer_.get(), total_base_size_, 0),
690 true);
691 ASSERT_EQ(memcmp(merged_buffer_.get(), orig_buffer_.get(), total_base_size_), 0);
692 }
693
SimulateDaemonRestart()694 void SnapuserTest::SimulateDaemonRestart() {
695 Shutdown();
696 std::this_thread::sleep_for(500ms);
697 SetDeviceControlName();
698 StartSnapuserdDaemon();
699 CreateDmUserDevice();
700 InitCowDevice();
701 InitDaemon();
702 }
703
MergeInterruptRandomly(int max_duration)704 void SnapuserTest::MergeInterruptRandomly(int max_duration) {
705 std::srand(std::time(nullptr));
706 StartMerge();
707
708 for (int i = 0; i < 20; i++) {
709 int duration = std::rand() % max_duration;
710 std::this_thread::sleep_for(std::chrono::milliseconds(duration));
711 SimulateDaemonRestart();
712 StartMerge();
713 }
714
715 SimulateDaemonRestart();
716 ASSERT_TRUE(Merge());
717 }
718
MergeInterruptFixed(int duration)719 void SnapuserTest::MergeInterruptFixed(int duration) {
720 StartMerge();
721
722 for (int i = 0; i < 25; i++) {
723 std::this_thread::sleep_for(std::chrono::milliseconds(duration));
724 SimulateDaemonRestart();
725 StartMerge();
726 }
727
728 SimulateDaemonRestart();
729 ASSERT_TRUE(Merge());
730 }
731
MergeInterrupt()732 void SnapuserTest::MergeInterrupt() {
733 // Interrupt merge at various intervals
734 StartMerge();
735 std::this_thread::sleep_for(250ms);
736 SimulateDaemonRestart();
737
738 StartMerge();
739 std::this_thread::sleep_for(250ms);
740 SimulateDaemonRestart();
741
742 StartMerge();
743 std::this_thread::sleep_for(150ms);
744 SimulateDaemonRestart();
745
746 StartMerge();
747 std::this_thread::sleep_for(100ms);
748 SimulateDaemonRestart();
749
750 StartMerge();
751 std::this_thread::sleep_for(800ms);
752 SimulateDaemonRestart();
753
754 StartMerge();
755 std::this_thread::sleep_for(600ms);
756 SimulateDaemonRestart();
757
758 ASSERT_TRUE(Merge());
759 }
760
TEST(Snapuserd_Test,Snapshot_IO_TEST)761 TEST(Snapuserd_Test, Snapshot_IO_TEST) {
762 SnapuserTest harness;
763 ASSERT_TRUE(harness.Setup());
764 // I/O before merge
765 harness.ReadSnapshotDeviceAndValidate();
766 ASSERT_TRUE(harness.Merge());
767 harness.ValidateMerge();
768 // I/O after merge - daemon should read directly
769 // from base device
770 harness.ReadSnapshotDeviceAndValidate();
771 harness.Shutdown();
772 }
773
TEST(Snapuserd_Test,Snapshot_MERGE_IO_TEST)774 TEST(Snapuserd_Test, Snapshot_MERGE_IO_TEST) {
775 SnapuserTest harness;
776 ASSERT_TRUE(harness.Setup());
777 // Issue I/O before merge begins
778 std::async(std::launch::async, &SnapuserTest::ReadSnapshotDeviceAndValidate, &harness);
779 // Start the merge
780 ASSERT_TRUE(harness.Merge());
781 harness.ValidateMerge();
782 harness.Shutdown();
783 }
784
TEST(Snapuserd_Test,Snapshot_MERGE_IO_TEST_1)785 TEST(Snapuserd_Test, Snapshot_MERGE_IO_TEST_1) {
786 SnapuserTest harness;
787 ASSERT_TRUE(harness.Setup());
788 // Start the merge
789 harness.StartMerge();
790 // Issue I/O in parallel when merge is in-progress
791 std::async(std::launch::async, &SnapuserTest::ReadSnapshotDeviceAndValidate, &harness);
792 harness.CheckMergeCompletion();
793 harness.ValidateMerge();
794 harness.Shutdown();
795 }
796
TEST(Snapuserd_Test,Snapshot_Merge_Resume)797 TEST(Snapuserd_Test, Snapshot_Merge_Resume) {
798 SnapuserTest harness;
799 ASSERT_TRUE(harness.Setup());
800 harness.MergeInterrupt();
801 harness.ValidateMerge();
802 harness.Shutdown();
803 }
804
TEST(Snapuserd_Test,Snapshot_COPY_Overlap_TEST_1)805 TEST(Snapuserd_Test, Snapshot_COPY_Overlap_TEST_1) {
806 SnapuserTest harness;
807 ASSERT_TRUE(harness.SetupCopyOverlap_1());
808 ASSERT_TRUE(harness.Merge());
809 harness.ValidateMerge();
810 harness.Shutdown();
811 }
812
TEST(Snapuserd_Test,Snapshot_COPY_Overlap_TEST_2)813 TEST(Snapuserd_Test, Snapshot_COPY_Overlap_TEST_2) {
814 SnapuserTest harness;
815 ASSERT_TRUE(harness.SetupCopyOverlap_2());
816 ASSERT_TRUE(harness.Merge());
817 harness.ValidateMerge();
818 harness.Shutdown();
819 }
820
TEST(Snapuserd_Test,Snapshot_COPY_Overlap_Merge_Resume_TEST)821 TEST(Snapuserd_Test, Snapshot_COPY_Overlap_Merge_Resume_TEST) {
822 SnapuserTest harness;
823 ASSERT_TRUE(harness.SetupCopyOverlap_1());
824 harness.MergeInterrupt();
825 harness.ValidateMerge();
826 harness.Shutdown();
827 }
828
TEST(Snapuserd_Test,Snapshot_Merge_Crash_Fixed_Ordered)829 TEST(Snapuserd_Test, Snapshot_Merge_Crash_Fixed_Ordered) {
830 SnapuserTest harness;
831 ASSERT_TRUE(harness.SetupOrderedOps());
832 harness.MergeInterruptFixed(300);
833 harness.ValidateMerge();
834 harness.Shutdown();
835 }
836
TEST(Snapuserd_Test,Snapshot_Merge_Crash_Random_Ordered)837 TEST(Snapuserd_Test, Snapshot_Merge_Crash_Random_Ordered) {
838 SnapuserTest harness;
839 ASSERT_TRUE(harness.SetupOrderedOps());
840 harness.MergeInterruptRandomly(500);
841 harness.ValidateMerge();
842 harness.Shutdown();
843 }
844
TEST(Snapuserd_Test,Snapshot_Merge_Crash_Fixed_Inverted)845 TEST(Snapuserd_Test, Snapshot_Merge_Crash_Fixed_Inverted) {
846 SnapuserTest harness;
847 ASSERT_TRUE(harness.SetupOrderedOpsInverted());
848 harness.MergeInterruptFixed(50);
849 harness.ValidateMerge();
850 harness.Shutdown();
851 }
852
TEST(Snapuserd_Test,Snapshot_Merge_Crash_Random_Inverted)853 TEST(Snapuserd_Test, Snapshot_Merge_Crash_Random_Inverted) {
854 SnapuserTest harness;
855 ASSERT_TRUE(harness.SetupOrderedOpsInverted());
856 harness.MergeInterruptRandomly(50);
857 harness.ValidateMerge();
858 harness.Shutdown();
859 }
860
861 } // namespace snapshot
862 } // namespace android
863
main(int argc,char ** argv)864 int main(int argc, char** argv) {
865 ::testing::InitGoogleTest(&argc, argv);
866
867 gflags::ParseCommandLineFlags(&argc, &argv, false);
868
869 android::base::SetProperty("ctl.stop", "snapuserd");
870
871 if (FLAGS_force_config == "iouring_disabled") {
872 if (!android::base::SetProperty("snapuserd.test.io_uring.force_disable", "1")) {
873 return testing::AssertionFailure()
874 << "Failed to disable property: snapuserd.test.io_uring.disabled";
875 }
876 }
877
878 int ret = RUN_ALL_TESTS();
879
880 if (FLAGS_force_config == "iouring_disabled") {
881 android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0");
882 }
883
884 return ret;
885 }
886