1 //
2 // Copyright (C) 2020 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include <errno.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 
22 #include <chrono>
23 #include <iostream>
24 #include <random>
25 #include <string>
26 #include <thread>
27 #include <vector>
28 
29 #include <android-base/file.h>
30 #include <android-base/parsedouble.h>
31 #include <android-base/stringprintf.h>
32 #include <android-base/strings.h>
33 #include <android-base/unique_fd.h>
34 #include <ext4_utils/ext4_utils.h>
35 #include <fstab/fstab.h>
36 #include <libdm/dm.h>
37 #include <libfiemap/image_manager.h>
38 
39 using namespace std::chrono_literals;
40 using namespace std::string_literals;
41 using android::base::borrowed_fd;
42 using android::base::unique_fd;
43 using android::dm::DeviceMapper;
44 using android::dm::DmDeviceState;
45 using android::dm::DmTable;
46 using android::dm::DmTargetSnapshot;
47 using android::dm::SnapshotStorageMode;
48 using android::fiemap::ImageManager;
49 using android::fs_mgr::Fstab;
50 
51 namespace android {
52 namespace snapshot {
53 
usage()54 static void usage() {
55     std::cerr << "Usage:\n";
56     std::cerr << "  create <orig-payload> <new-payload>\n";
57     std::cerr << "\n";
58     std::cerr << "  Create a snapshot device containing the contents of\n";
59     std::cerr << "  orig-payload, and then write the contents of new-payload.\n";
60     std::cerr << "  The original files are not modified.\n";
61     std::cerr << "\n";
62     std::cerr << "  merge <fail-rate>\n";
63     std::cerr << "\n";
64     std::cerr << "  Merge the snapshot previously started by create, and wait\n";
65     std::cerr << "  for it to complete. Once done, it is compared to the\n";
66     std::cerr << "  new-payload for consistency. The original files are not \n";
67     std::cerr << "  modified. If a fail-rate is passed (as a fraction between 0\n";
68     std::cerr << "  and 100), every 10ms the device has that percent change of\n";
69     std::cerr << "  injecting a kernel crash.\n";
70     std::cerr << "\n";
71     std::cerr << "  check <new-payload>\n";
72     std::cerr << "  Verify that all artifacts are correct after a merge\n";
73     std::cerr << "  completes.\n";
74     std::cerr << "\n";
75     std::cerr << "  cleanup\n";
76     std::cerr << "  Remove all ImageManager artifacts from create/merge.\n";
77 }
78 
79 class PowerTest final {
80   public:
81     PowerTest();
82     bool Run(int argc, char** argv);
83 
84   private:
85     bool OpenImageManager();
86     bool Create(int argc, char** argv);
87     bool Merge(int argc, char** argv);
88     bool Check(int argc, char** argv);
89     bool Cleanup();
90     bool CleanupImage(const std::string& name);
91     bool SetupImages(const std::string& first_file, borrowed_fd second_fd);
92     bool MapImages();
93     bool MapSnapshot(SnapshotStorageMode mode);
94     bool GetMergeStatus(DmTargetSnapshot::Status* status);
95 
96     static constexpr char kSnapshotName[] = "snapshot-power-test";
97     static constexpr char kSnapshotImageName[] = "snapshot-power-test-image";
98     static constexpr char kSnapshotCowName[] = "snapshot-power-test-cow";
99 
100     DeviceMapper& dm_;
101     std::unique_ptr<ImageManager> images_;
102     std::string image_path_;
103     std::string cow_path_;
104     std::string snapshot_path_;
105 };
106 
PowerTest()107 PowerTest::PowerTest() : dm_(DeviceMapper::Instance()) {}
108 
109 bool PowerTest::Run([[maybe_unused]] int argc, [[maybe_unused]] char** argv) {
110     if (!OpenImageManager()) {
111         return false;
112     }
113 
114     if (argc < 2) {
115         usage();
116         return false;
117     }
118     if (argv[1] == "create"s) {
119         return Create(argc, argv);
120     } else if (argv[1] == "merge"s) {
121         return Merge(argc, argv);
122     } else if (argv[1] == "check"s) {
123         return Check(argc, argv);
124     } else if (argv[1] == "cleanup"s) {
125         return Cleanup();
126     } else {
127         usage();
128         return false;
129     }
130 }
131 
OpenImageManager()132 bool PowerTest::OpenImageManager() {
133     std::vector<std::string> dirs = {
134             "/data/gsi/test",
135             "/metadata/gsi/test",
136     };
137     for (const auto& dir : dirs) {
138         if (mkdir(dir.c_str(), 0700) && errno != EEXIST) {
139             std::cerr << "mkdir " << dir << ": " << strerror(errno) << "\n";
140             return false;
141         }
142     }
143 
144     images_ = ImageManager::Open("/metadata/gsi/test", "/data/gsi/test");
145     if (!images_) {
146         std::cerr << "Could not open ImageManager\n";
147         return false;
148     }
149     return true;
150 }
151 
Create(int argc,char ** argv)152 bool PowerTest::Create(int argc, char** argv) {
153     if (argc < 4) {
154         usage();
155         return false;
156     }
157 
158     std::string first = argv[2];
159     std::string second = argv[3];
160 
161     unique_fd second_fd(open(second.c_str(), O_RDONLY));
162     if (second_fd < 0) {
163         std::cerr << "open " << second << ": " << strerror(errno) << "\n";
164         return false;
165     }
166 
167     if (!Cleanup()) {
168         return false;
169     }
170     if (!SetupImages(first, second_fd)) {
171         return false;
172     }
173     if (!MapSnapshot(SnapshotStorageMode::Persistent)) {
174         return false;
175     }
176 
177     struct stat s;
178     if (fstat(second_fd, &s)) {
179         std::cerr << "fstat " << second << ": " << strerror(errno) << "\n";
180         return false;
181     }
182 
183     unique_fd snap_fd(open(snapshot_path_.c_str(), O_WRONLY));
184     if (snap_fd < 0) {
185         std::cerr << "open " << snapshot_path_ << ": " << strerror(errno) << "\n";
186         return false;
187     }
188 
189     uint8_t chunk[4096];
190     uint64_t written = 0;
191     while (written < s.st_size) {
192         uint64_t remaining = s.st_size - written;
193         size_t bytes = (size_t)std::min((uint64_t)sizeof(chunk), remaining);
194         if (!android::base::ReadFully(second_fd, chunk, bytes)) {
195             std::cerr << "read " << second << ": " << strerror(errno) << "\n";
196             return false;
197         }
198         if (!android::base::WriteFully(snap_fd, chunk, bytes)) {
199             std::cerr << "write " << snapshot_path_ << ": " << strerror(errno) << "\n";
200             return false;
201         }
202         written += bytes;
203     }
204     if (fsync(snap_fd)) {
205         std::cerr << "fsync: " << strerror(errno) << "\n";
206         return false;
207     }
208 
209     sync();
210 
211     snap_fd = {};
212     if (!dm_.DeleteDeviceIfExists(kSnapshotName)) {
213         std::cerr << "could not delete dm device " << kSnapshotName << "\n";
214         return false;
215     }
216     if (!images_->UnmapImageIfExists(kSnapshotImageName)) {
217         std::cerr << "failed to unmap " << kSnapshotImageName << "\n";
218         return false;
219     }
220     if (!images_->UnmapImageIfExists(kSnapshotCowName)) {
221         std::cerr << "failed to unmap " << kSnapshotImageName << "\n";
222         return false;
223     }
224     return true;
225 }
226 
Cleanup()227 bool PowerTest::Cleanup() {
228     if (!dm_.DeleteDeviceIfExists(kSnapshotName)) {
229         std::cerr << "could not delete dm device " << kSnapshotName << "\n";
230         return false;
231     }
232     if (!CleanupImage(kSnapshotImageName) || !CleanupImage(kSnapshotCowName)) {
233         return false;
234     }
235     return true;
236 }
237 
CleanupImage(const std::string & name)238 bool PowerTest::CleanupImage(const std::string& name) {
239     if (!images_->UnmapImageIfExists(name)) {
240         std::cerr << "failed to unmap " << name << "\n";
241         return false;
242     }
243     if (images_->BackingImageExists(name) && !images_->DeleteBackingImage(name)) {
244         std::cerr << "failed to delete " << name << "\n";
245         return false;
246     }
247     return true;
248 }
249 
SetupImages(const std::string & first,borrowed_fd second_fd)250 bool PowerTest::SetupImages(const std::string& first, borrowed_fd second_fd) {
251     unique_fd first_fd(open(first.c_str(), O_RDONLY));
252     if (first_fd < 0) {
253         std::cerr << "open " << first << ": " << strerror(errno) << "\n";
254         return false;
255     }
256 
257     struct stat s1, s2;
258     if (fstat(first_fd.get(), &s1)) {
259         std::cerr << "first stat: " << strerror(errno) << "\n";
260         return false;
261     }
262     if (fstat(second_fd.get(), &s2)) {
263         std::cerr << "second stat: " << strerror(errno) << "\n";
264         return false;
265     }
266 
267     // Pick the bigger size of both images, rounding up to the nearest block.
268     uint64_t s1_size = (s1.st_size + 4095) & ~uint64_t(4095);
269     uint64_t s2_size = (s2.st_size + 4095) & ~uint64_t(4095);
270     uint64_t image_size = std::max(s1_size, s2_size) + (1024 * 1024 * 128);
271     if (!images_->CreateBackingImage(kSnapshotImageName, image_size, 0, nullptr)) {
272         std::cerr << "failed to create " << kSnapshotImageName << "\n";
273         return false;
274     }
275     // Use the same size for the cow.
276     if (!images_->CreateBackingImage(kSnapshotCowName, image_size, 0, nullptr)) {
277         std::cerr << "failed to create " << kSnapshotCowName << "\n";
278         return false;
279     }
280     if (!MapImages()) {
281         return false;
282     }
283 
284     unique_fd image_fd(open(image_path_.c_str(), O_WRONLY));
285     if (image_fd < 0) {
286         std::cerr << "open: " << image_path_ << ": " << strerror(errno) << "\n";
287         return false;
288     }
289 
290     uint8_t chunk[4096];
291     uint64_t written = 0;
292     while (written < s1.st_size) {
293         uint64_t remaining = s1.st_size - written;
294         size_t bytes = (size_t)std::min((uint64_t)sizeof(chunk), remaining);
295         if (!android::base::ReadFully(first_fd, chunk, bytes)) {
296             std::cerr << "read: " << strerror(errno) << "\n";
297             return false;
298         }
299         if (!android::base::WriteFully(image_fd, chunk, bytes)) {
300             std::cerr << "write: " << strerror(errno) << "\n";
301             return false;
302         }
303         written += bytes;
304     }
305     if (fsync(image_fd)) {
306         std::cerr << "fsync: " << strerror(errno) << "\n";
307         return false;
308     }
309 
310     // Zero the first block of the COW.
311     unique_fd cow_fd(open(cow_path_.c_str(), O_WRONLY));
312     if (cow_fd < 0) {
313         std::cerr << "open: " << cow_path_ << ": " << strerror(errno) << "\n";
314         return false;
315     }
316 
317     memset(chunk, 0, sizeof(chunk));
318     if (!android::base::WriteFully(cow_fd, chunk, sizeof(chunk))) {
319         std::cerr << "read: " << strerror(errno) << "\n";
320         return false;
321     }
322     if (fsync(cow_fd)) {
323         std::cerr << "fsync: " << strerror(errno) << "\n";
324         return false;
325     }
326     return true;
327 }
328 
MapImages()329 bool PowerTest::MapImages() {
330     if (!images_->MapImageDevice(kSnapshotImageName, 10s, &image_path_)) {
331         std::cerr << "failed to map " << kSnapshotImageName << "\n";
332         return false;
333     }
334     if (!images_->MapImageDevice(kSnapshotCowName, 10s, &cow_path_)) {
335         std::cerr << "failed to map " << kSnapshotCowName << "\n";
336         return false;
337     }
338     return true;
339 }
340 
MapSnapshot(SnapshotStorageMode mode)341 bool PowerTest::MapSnapshot(SnapshotStorageMode mode) {
342     uint64_t sectors;
343     {
344         unique_fd fd(open(image_path_.c_str(), O_RDONLY));
345         if (fd < 0) {
346             std::cerr << "open: " << image_path_ << ": " << strerror(errno) << "\n";
347             return false;
348         }
349         sectors = get_block_device_size(fd) / 512;
350     }
351 
352     DmTable table;
353     table.Emplace<DmTargetSnapshot>(0, sectors, image_path_, cow_path_, mode, 8);
354     if (!dm_.CreateDevice(kSnapshotName, table, &snapshot_path_, 10s)) {
355         std::cerr << "failed to create snapshot device\n";
356         return false;
357     }
358     return true;
359 }
360 
GetMergeStatus(DmTargetSnapshot::Status * status)361 bool PowerTest::GetMergeStatus(DmTargetSnapshot::Status* status) {
362     std::vector<DeviceMapper::TargetInfo> targets;
363     if (!dm_.GetTableStatus(kSnapshotName, &targets)) {
364         std::cerr << "failed to get merge status\n";
365         return false;
366     }
367     if (targets.size() != 1) {
368         std::cerr << "merge device has wrong number of targets\n";
369         return false;
370     }
371     if (!DmTargetSnapshot::ParseStatusText(targets[0].data, status)) {
372         std::cerr << "could not parse merge target status text\n";
373         return false;
374     }
375     return true;
376 }
377 
GetUserdataBlockDeviceName()378 static std::string GetUserdataBlockDeviceName() {
379     Fstab fstab;
380     if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
381         return {};
382     }
383 
384     auto entry = android::fs_mgr::GetEntryForMountPoint(&fstab, "/data");
385     if (!entry) {
386         return {};
387     }
388 
389     auto prefix = "/dev/block/"s;
390     if (!android::base::StartsWith(entry->blk_device, prefix)) {
391         return {};
392     }
393     return entry->blk_device.substr(prefix.size());
394 }
395 
Merge(int argc,char ** argv)396 bool PowerTest::Merge(int argc, char** argv) {
397     // Start an f2fs GC to really stress things. :TODO: figure out data device
398     auto userdata_dev = GetUserdataBlockDeviceName();
399     if (userdata_dev.empty()) {
400         std::cerr << "could not locate userdata block device\n";
401         return false;
402     }
403 
404     auto cmd =
405             android::base::StringPrintf("echo 1 > /sys/fs/f2fs/%s/gc_urgent", userdata_dev.c_str());
406     system(cmd.c_str());
407 
408     if (dm_.GetState(kSnapshotName) == DmDeviceState::INVALID) {
409         if (!MapImages()) {
410             return false;
411         }
412         if (!MapSnapshot(SnapshotStorageMode::Merge)) {
413             return false;
414         }
415     }
416 
417     std::random_device r;
418     std::default_random_engine re(r());
419     std::uniform_real_distribution<double> dist(0.0, 100.0);
420 
421     std::optional<double> failure_rate;
422     if (argc >= 3) {
423         double d;
424         if (!android::base::ParseDouble(argv[2], &d)) {
425             std::cerr << "Could not parse failure rate as double: " << argv[2] << "\n";
426             return false;
427         }
428         failure_rate = d;
429     }
430 
431     while (true) {
432         DmTargetSnapshot::Status status;
433         if (!GetMergeStatus(&status)) {
434             return false;
435         }
436         if (!status.error.empty()) {
437             std::cerr << "merge reported error: " << status.error << "\n";
438             return false;
439         }
440         if (status.sectors_allocated == status.metadata_sectors) {
441             break;
442         }
443 
444         std::cerr << status.sectors_allocated << " / " << status.metadata_sectors << "\n";
445 
446         if (failure_rate && *failure_rate >= dist(re)) {
447             system("echo 1 > /proc/sys/kernel/sysrq");
448             system("echo c > /proc/sysrq-trigger");
449         }
450 
451         std::this_thread::sleep_for(10ms);
452     }
453 
454     std::cout << "Merge completed.\n";
455     return true;
456 }
457 
458 bool PowerTest::Check([[maybe_unused]] int argc, [[maybe_unused]] char** argv) {
459     if (argc < 3) {
460         std::cerr << "Expected argument: <new-image-path>\n";
461         return false;
462     }
463     std::string md_path, image_path;
464     std::string canonical_path = argv[2];
465 
466     if (!dm_.GetDmDevicePathByName(kSnapshotName, &md_path)) {
467         std::cerr << "could not get dm-path for merge device\n";
468         return false;
469     }
470     if (!images_->GetMappedImageDevice(kSnapshotImageName, &image_path)) {
471         std::cerr << "could not get image path\n";
472         return false;
473     }
474 
475     unique_fd md_fd(open(md_path.c_str(), O_RDONLY));
476     if (md_fd < 0) {
477         std::cerr << "open: " << md_path << ": " << strerror(errno) << "\n";
478         return false;
479     }
480     unique_fd image_fd(open(image_path.c_str(), O_RDONLY));
481     if (image_fd < 0) {
482         std::cerr << "open: " << image_path << ": " << strerror(errno) << "\n";
483         return false;
484     }
485     unique_fd canonical_fd(open(canonical_path.c_str(), O_RDONLY));
486     if (canonical_fd < 0) {
487         std::cerr << "open: " << canonical_path << ": " << strerror(errno) << "\n";
488         return false;
489     }
490 
491     struct stat s;
492     if (fstat(canonical_fd, &s)) {
493         std::cerr << "fstat: " << canonical_path << ": " << strerror(errno) << "\n";
494         return false;
495     }
496     uint64_t canonical_size = s.st_size;
497     uint64_t md_size = get_block_device_size(md_fd);
498     uint64_t image_size = get_block_device_size(image_fd);
499     if (image_size != md_size) {
500         std::cerr << "image size does not match merge device size\n";
501         return false;
502     }
503     if (canonical_size > image_size) {
504         std::cerr << "canonical size " << canonical_size << " is greater than image size "
505                   << image_size << "\n";
506         return false;
507     }
508 
509     constexpr size_t kBlockSize = 4096;
510     uint8_t canonical_buffer[kBlockSize];
511     uint8_t image_buffer[kBlockSize];
512     uint8_t md_buffer[kBlockSize];
513 
514     uint64_t remaining = canonical_size;
515     uint64_t blockno = 0;
516     while (remaining) {
517         size_t bytes = (size_t)std::min((uint64_t)kBlockSize, remaining);
518         if (!android::base::ReadFully(canonical_fd, canonical_buffer, bytes)) {
519             std::cerr << "read: " << canonical_buffer << ": " << strerror(errno) << "\n";
520             return false;
521         }
522         if (!android::base::ReadFully(image_fd, image_buffer, bytes)) {
523             std::cerr << "read: " << image_buffer << ": " << strerror(errno) << "\n";
524             return false;
525         }
526         if (!android::base::ReadFully(md_fd, md_buffer, bytes)) {
527             std::cerr << "read: " << md_buffer << ": " << strerror(errno) << "\n";
528             return false;
529         }
530         if (memcmp(canonical_buffer, image_buffer, bytes)) {
531             std::cerr << "canonical and image differ at block " << blockno << "\n";
532             return false;
533         }
534         if (memcmp(canonical_buffer, md_buffer, bytes)) {
535             std::cerr << "canonical and image differ at block " << blockno << "\n";
536             return false;
537         }
538 
539         remaining -= bytes;
540         blockno++;
541     }
542 
543     std::cout << "Images all match.\n";
544     return true;
545 }
546 
547 }  // namespace snapshot
548 }  // namespace android
549 
main(int argc,char ** argv)550 int main(int argc, char** argv) {
551     android::snapshot::PowerTest test;
552 
553     if (!test.Run(argc, argv)) {
554         std::cerr << "Unexpected error running test." << std::endl;
555         return 1;
556     }
557     fflush(stdout);
558     return 0;
559 }
560