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