• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 #define LOG_TAG "Checkpoint"
18 #include "Checkpoint.h"
19 #include "VoldUtil.h"
20 #include "VolumeManager.h"
21 
22 #include <fstream>
23 #include <list>
24 #include <memory>
25 #include <string>
26 #include <thread>
27 #include <vector>
28 
29 #include <android-base/file.h>
30 #include <android-base/logging.h>
31 #include <android-base/parseint.h>
32 #include <android-base/properties.h>
33 #include <android-base/unique_fd.h>
34 #include <android/hardware/boot/1.0/IBootControl.h>
35 #include <cutils/android_reboot.h>
36 #include <fcntl.h>
37 #include <fs_mgr.h>
38 #include <linux/fs.h>
39 #include <mntent.h>
40 #include <sys/mount.h>
41 #include <sys/stat.h>
42 #include <sys/statvfs.h>
43 #include <unistd.h>
44 
45 using android::base::GetBoolProperty;
46 using android::base::GetUintProperty;
47 using android::base::SetProperty;
48 using android::binder::Status;
49 using android::fs_mgr::Fstab;
50 using android::fs_mgr::ReadDefaultFstab;
51 using android::fs_mgr::ReadFstabFromFile;
52 using android::hardware::hidl_string;
53 using android::hardware::boot::V1_0::BoolResult;
54 using android::hardware::boot::V1_0::CommandResult;
55 using android::hardware::boot::V1_0::IBootControl;
56 using android::hardware::boot::V1_0::Slot;
57 
58 namespace android {
59 namespace vold {
60 
61 namespace {
62 const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
63 
setBowState(std::string const & block_device,std::string const & state)64 bool setBowState(std::string const& block_device, std::string const& state) {
65     std::string bow_device = fs_mgr_find_bow_device(block_device);
66     if (bow_device.empty()) return false;
67 
68     if (!android::base::WriteStringToFile(state, bow_device + "/bow/state")) {
69         PLOG(ERROR) << "Failed to write to file " << bow_device + "/bow/state";
70         return false;
71     }
72 
73     return true;
74 }
75 
76 }  // namespace
77 
cp_supportsCheckpoint(bool & result)78 Status cp_supportsCheckpoint(bool& result) {
79     result = false;
80 
81     for (const auto& entry : fstab_default) {
82         if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
83             result = true;
84             return Status::ok();
85         }
86     }
87     return Status::ok();
88 }
89 
cp_supportsBlockCheckpoint(bool & result)90 Status cp_supportsBlockCheckpoint(bool& result) {
91     result = false;
92 
93     for (const auto& entry : fstab_default) {
94         if (entry.fs_mgr_flags.checkpoint_blk) {
95             result = true;
96             return Status::ok();
97         }
98     }
99     return Status::ok();
100 }
101 
cp_supportsFileCheckpoint(bool & result)102 Status cp_supportsFileCheckpoint(bool& result) {
103     result = false;
104 
105     for (const auto& entry : fstab_default) {
106         if (entry.fs_mgr_flags.checkpoint_fs) {
107             result = true;
108             return Status::ok();
109         }
110     }
111     return Status::ok();
112 }
113 
cp_startCheckpoint(int retry)114 Status cp_startCheckpoint(int retry) {
115     if (retry < -1) return Status::fromExceptionCode(EINVAL, "Retry count must be more than -1");
116     std::string content = std::to_string(retry + 1);
117     if (retry == -1) {
118         sp<IBootControl> module = IBootControl::getService();
119         if (module) {
120             std::string suffix;
121             auto cb = [&suffix](hidl_string s) { suffix = s; };
122             if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
123         }
124     }
125     if (!android::base::WriteStringToFile(content, kMetadataCPFile))
126         return Status::fromExceptionCode(errno, "Failed to write checkpoint file");
127     return Status::ok();
128 }
129 
130 namespace {
131 
132 volatile bool isCheckpointing = false;
133 }
134 
cp_commitChanges()135 Status cp_commitChanges() {
136     if (!isCheckpointing) {
137         return Status::ok();
138     }
139     if (android::base::GetProperty("persist.vold.dont_commit_checkpoint", "0") == "1") {
140         LOG(WARNING)
141             << "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
142         return Status::ok();
143     }
144     sp<IBootControl> module = IBootControl::getService();
145     if (module) {
146         CommandResult cr;
147         module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
148         if (!cr.success) {
149             std::string msg = "Error marking booted successfully: " + std::string(cr.errMsg);
150             return Status::fromExceptionCode(EINVAL, String8(msg.c_str()));
151         }
152         LOG(INFO) << "Marked slot as booted successfully.";
153     }
154     // Must take action for list of mounted checkpointed things here
155     // To do this, we walk the list of mounted file systems.
156     // But we also need to get the matching fstab entries to see
157     // the original flags
158     std::string err_str;
159 
160     Fstab mounts;
161     if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
162         return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
163     }
164 
165     // Walk mounted file systems
166     for (const auto& mount_rec : mounts) {
167         const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
168         if (!fstab_rec) continue;
169 
170         if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
171             if (fstab_rec->fs_type == "f2fs") {
172                 std::string options = mount_rec.fs_options + ",checkpoint=enable";
173                 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
174                           MS_REMOUNT | fstab_rec->flags, options.c_str())) {
175                     return Status::fromExceptionCode(EINVAL, "Failed to remount");
176                 }
177             }
178         } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
179             if (!setBowState(mount_rec.blk_device, "2"))
180                 return Status::fromExceptionCode(EINVAL, "Failed to set bow state");
181         }
182     }
183     SetProperty("vold.checkpoint_committed", "1");
184     LOG(INFO) << "Checkpoint has been committed.";
185     isCheckpointing = false;
186     if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
187         return Status::fromExceptionCode(errno, err_str.c_str());
188     return Status::ok();
189 }
190 
191 namespace {
abort_metadata_file()192 void abort_metadata_file() {
193     std::string oldContent, newContent;
194     int retry = 0;
195     struct stat st;
196     int result = stat(kMetadataCPFile.c_str(), &st);
197 
198     // If the file doesn't exist, we aren't managing a checkpoint retry counter
199     if (result != 0) return;
200     if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
201         PLOG(ERROR) << "Failed to read checkpoint file";
202         return;
203     }
204     std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
205 
206     if (!android::base::ParseInt(retryContent, &retry)) {
207         PLOG(ERROR) << "Could not parse retry count";
208         return;
209     }
210     if (retry > 0) {
211         newContent = "0";
212         if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
213             PLOG(ERROR) << "Could not write checkpoint file";
214     }
215 }
216 }  // namespace
217 
cp_abortChanges(const std::string & message,bool retry)218 void cp_abortChanges(const std::string& message, bool retry) {
219     if (!cp_needsCheckpoint()) return;
220     if (!retry) abort_metadata_file();
221     android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
222 }
223 
cp_needsRollback()224 bool cp_needsRollback() {
225     std::string content;
226     bool ret;
227 
228     ret = android::base::ReadFileToString(kMetadataCPFile, &content);
229     if (ret) {
230         if (content == "0") return true;
231         if (content.substr(0, 3) == "-1 ") {
232             std::string oldSuffix = content.substr(3);
233             sp<IBootControl> module = IBootControl::getService();
234             std::string newSuffix;
235 
236             if (module) {
237                 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
238                 module->getSuffix(module->getCurrentSlot(), cb);
239                 if (oldSuffix == newSuffix) return true;
240             }
241         }
242     }
243     return false;
244 }
245 
cp_needsCheckpoint()246 bool cp_needsCheckpoint() {
247     bool ret;
248     std::string content;
249     sp<IBootControl> module = IBootControl::getService();
250 
251     if (isCheckpointing) return isCheckpointing;
252 
253     if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
254         isCheckpointing = true;
255         return true;
256     }
257     ret = android::base::ReadFileToString(kMetadataCPFile, &content);
258     if (ret) {
259         ret = content != "0";
260         isCheckpointing = ret;
261         return ret;
262     }
263     return false;
264 }
265 
266 namespace {
267 const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
268 const uint32_t msleeptime_default = 1000;  // 1 s
269 const uint32_t max_msleeptime = 3600000;   // 1 h
270 
271 const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
272 const uint64_t min_free_bytes_default = 100 * (1 << 20);  // 100 MiB
273 
274 const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
275 const bool commit_on_full_default = true;
276 
cp_healthDaemon(std::string mnt_pnt,std::string blk_device,bool is_fs_cp)277 static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
278     struct statvfs data;
279     uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
280     uint64_t min_free_bytes =
281         GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
282     bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
283 
284     struct timespec req;
285     req.tv_sec = msleeptime / 1000;
286     msleeptime %= 1000;
287     req.tv_nsec = msleeptime * 1000000;
288     while (isCheckpointing) {
289         uint64_t free_bytes = 0;
290         if (is_fs_cp) {
291             statvfs(mnt_pnt.c_str(), &data);
292             free_bytes = data.f_bavail * data.f_frsize;
293         } else {
294             std::string bow_device = fs_mgr_find_bow_device(blk_device);
295             if (!bow_device.empty()) {
296                 std::string content;
297                 if (android::base::ReadFileToString(bow_device + "/bow/free", &content)) {
298                     free_bytes = std::strtoul(content.c_str(), NULL, 10);
299                 }
300             }
301         }
302         if (free_bytes < min_free_bytes) {
303             if (commit_on_full) {
304                 LOG(INFO) << "Low space for checkpointing. Commiting changes";
305                 cp_commitChanges();
306                 break;
307             } else {
308                 LOG(INFO) << "Low space for checkpointing. Rebooting";
309                 cp_abortChanges("checkpoint,low_space", false);
310                 break;
311             }
312         }
313         nanosleep(&req, NULL);
314     }
315 }
316 
317 }  // namespace
318 
cp_prepareCheckpoint()319 Status cp_prepareCheckpoint() {
320     if (!isCheckpointing) {
321         return Status::ok();
322     }
323 
324     Fstab mounts;
325     if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
326         return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
327     }
328 
329     for (const auto& mount_rec : mounts) {
330         const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
331         if (!fstab_rec) continue;
332 
333         if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
334             android::base::unique_fd fd(
335                 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
336             if (fd == -1) {
337                 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
338                 continue;
339             }
340 
341             struct fstrim_range range = {};
342             range.len = ULLONG_MAX;
343             nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
344             if (ioctl(fd, FITRIM, &range)) {
345                 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
346                 continue;
347             }
348             nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
349             LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
350                       << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
351 
352             setBowState(mount_rec.blk_device, "1");
353         }
354         if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
355             std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
356                         std::string(mount_rec.blk_device),
357                         fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
358                 .detach();
359         }
360     }
361     return Status::ok();
362 }
363 
364 namespace {
365 const int kSectorSize = 512;
366 
367 typedef uint64_t sector_t;
368 
369 struct log_entry {
370     sector_t source;  // in sectors of size kSectorSize
371     sector_t dest;    // in sectors of size kSectorSize
372     uint32_t size;    // in bytes
373     uint32_t checksum;
374 } __attribute__((packed));
375 
376 struct log_sector_v1_0 {
377     uint32_t magic;
378     uint16_t header_version;
379     uint16_t header_size;
380     uint32_t block_size;
381     uint32_t count;
382     uint32_t sequence;
383     uint64_t sector0;
384 } __attribute__((packed));
385 
386 // MAGIC is BOW in ascii
387 const int kMagic = 0x00574f42;
388 // Partially restored MAGIC is WOB in ascii
389 const int kPartialRestoreMagic = 0x00424f57;
390 
crc32(const void * data,size_t n_bytes,uint32_t * crc)391 void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
392     static uint32_t table[0x100] = {
393         0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
394         0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
395         0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
396         0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
397         0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
398         0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
399         0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
400         0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
401         0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
402         0xB6662D3D,
403 
404         0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
405         0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
406         0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
407         0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
408         0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
409         0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
410         0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
411         0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
412         0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
413         0xC0BA6CAD,
414 
415         0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
416         0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
417         0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
418         0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
419         0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
420         0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
421         0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
422         0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
423         0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
424         0x5BDEAE1D,
425 
426         0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
427         0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
428         0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
429         0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
430         0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
431         0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
432         0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
433         0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
434         0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
435         0x2D02EF8D};
436 
437     for (size_t i = 0; i < n_bytes; ++i) {
438         *crc ^= ((uint8_t*)data)[i];
439         *crc = table[(uint8_t)*crc] ^ *crc >> 8;
440     }
441 }
442 
443 // A map of relocations.
444 // The map must be initialized so that relocations[0] = 0
445 // During restore, we replay the log records in reverse, copying from dest to
446 // source
447 // To validate, we must be able to read the 'dest' sectors as though they had
448 // been copied but without actually copying. This map represents how the sectors
449 // would have been moved. To read a sector s, find the index <= s and read
450 // relocations[index] + s - index
451 typedef std::map<sector_t, sector_t> Relocations;
452 
relocate(Relocations & relocations,sector_t dest,sector_t source,int count)453 void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
454     // Find first one we're equal to or greater than
455     auto s = --relocations.upper_bound(source);
456 
457     // Take slice
458     Relocations slice;
459     slice[dest] = source - s->first + s->second;
460     ++s;
461 
462     // Add rest of elements
463     for (; s != relocations.end() && s->first < source + count; ++s)
464         slice[dest - source + s->first] = s->second;
465 
466     // Split range at end of dest
467     auto dest_end = --relocations.upper_bound(dest + count);
468     relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
469 
470     // Remove all elements in [dest, dest + count)
471     relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
472 
473     // Add new elements
474     relocations.insert(slice.begin(), slice.end());
475 }
476 
477 // A map of sectors that have been written to.
478 // The final entry must always be False.
479 // When we restart the restore after an interruption, we must take care that
480 // when we copy from dest to source, that the block we copy to was not
481 // previously copied from.
482 // i e. A->B C->A; If we replay this sequence, we end up copying C->B
483 // We must save our partial result whenever we finish a page, or when we copy
484 // to a location that was copied from earlier (our source is an earlier dest)
485 typedef std::map<sector_t, bool> Used_Sectors;
486 
checkCollision(Used_Sectors & used_sectors,sector_t start,sector_t end)487 bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
488     auto second_overlap = used_sectors.upper_bound(start);
489     auto first_overlap = --second_overlap;
490 
491     if (first_overlap->second) {
492         return true;
493     } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
494         return true;
495     }
496     return false;
497 }
498 
markUsed(Used_Sectors & used_sectors,sector_t start,sector_t end)499 void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
500     auto start_pos = used_sectors.insert_or_assign(start, true).first;
501     auto end_pos = used_sectors.insert_or_assign(end, false).first;
502 
503     if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
504         start_pos++;
505     }
506     if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
507         end_pos++;
508     }
509     if (start_pos->first < end_pos->first) {
510         used_sectors.erase(start_pos, end_pos);
511     }
512 }
513 
514 // Restores the given log_entry's data from dest -> source
515 // If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
restoreSector(int device_fd,Used_Sectors & used_sectors,std::vector<char> & ls_buffer,log_entry * le,std::vector<char> & buffer)516 void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
517                    log_entry* le, std::vector<char>& buffer) {
518     log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
519     uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
520     int count = (le->size - 1) / kSectorSize + 1;
521 
522     if (checkCollision(used_sectors, le->source, le->source + count)) {
523         fsync(device_fd);
524         lseek64(device_fd, 0, SEEK_SET);
525         ls.count = index + 1;
526         ls.magic = kPartialRestoreMagic;
527         write(device_fd, &ls_buffer[0], ls.block_size);
528         fsync(device_fd);
529         used_sectors.clear();
530         used_sectors[0] = false;
531     }
532 
533     markUsed(used_sectors, le->dest, le->dest + count);
534 
535     if (index == 0 && ls.sequence != 0) {
536         log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
537         if (next->magic == kMagic) {
538             next->magic = kPartialRestoreMagic;
539         }
540     }
541 
542     lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
543     write(device_fd, &buffer[0], le->size);
544 
545     if (index == 0) {
546         fsync(device_fd);
547     }
548 }
549 
550 // Read from the device
551 // If we are validating, the read occurs as though the relocations had happened
relocatedRead(int device_fd,Relocations const & relocations,bool validating,sector_t sector,uint32_t size,uint32_t block_size)552 std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
553                                 sector_t sector, uint32_t size, uint32_t block_size) {
554     if (!validating) {
555         std::vector<char> buffer(size);
556         lseek64(device_fd, sector * kSectorSize, SEEK_SET);
557         read(device_fd, &buffer[0], size);
558         return buffer;
559     }
560 
561     std::vector<char> buffer(size);
562     for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
563         auto relocation = --relocations.upper_bound(sector);
564         lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
565                 SEEK_SET);
566         read(device_fd, &buffer[i], block_size);
567     }
568 
569     return buffer;
570 }
571 
572 }  // namespace
573 
cp_restoreCheckpoint(const std::string & blockDevice,int restore_limit)574 Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
575     bool validating = true;
576     std::string action = "Validating";
577     int restore_count = 0;
578 
579     for (;;) {
580         Relocations relocations;
581         relocations[0] = 0;
582         Status status = Status::ok();
583 
584         LOG(INFO) << action << " checkpoint on " << blockDevice;
585         base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
586         if (device_fd < 0) {
587             PLOG(ERROR) << "Cannot open " << blockDevice;
588             return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
589         }
590 
591         log_sector_v1_0 original_ls;
592         read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
593         if (original_ls.magic == kPartialRestoreMagic) {
594             validating = false;
595             action = "Restoring";
596         } else if (original_ls.magic != kMagic) {
597             LOG(ERROR) << "No magic";
598             return Status::fromExceptionCode(EINVAL, "No magic");
599         }
600 
601         LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
602 
603         for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
604             auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
605                                            original_ls.block_size, original_ls.block_size);
606             log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
607 
608             Used_Sectors used_sectors;
609             used_sectors[0] = false;
610 
611             if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
612                 LOG(ERROR) << "No magic!";
613                 status = Status::fromExceptionCode(EINVAL, "No magic");
614                 break;
615             }
616 
617             if (ls.block_size != original_ls.block_size) {
618                 LOG(ERROR) << "Block size mismatch!";
619                 status = Status::fromExceptionCode(EINVAL, "Block size mismatch");
620                 break;
621             }
622 
623             if ((int)ls.sequence != sequence) {
624                 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
625                 status = Status::fromExceptionCode(
626                     EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
627                              std::to_string(ls.sequence))
628                                 .c_str());
629                 break;
630             }
631 
632             LOG(INFO) << action << " from log sector " << ls.sequence;
633             for (log_entry* le =
634                      reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
635                  le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
636                 // This is very noisy - limit to DEBUG only
637                 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
638                              << " to " << le->source << " with checksum " << std::hex
639                              << le->checksum;
640 
641                 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
642                                             ls.block_size);
643                 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
644                 for (size_t i = 0; i < le->size; i += ls.block_size) {
645                     crc32(&buffer[i], ls.block_size, &checksum);
646                 }
647 
648                 if (le->checksum && checksum != le->checksum) {
649                     LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
650                     status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
651                     break;
652                 }
653 
654                 if (validating) {
655                     relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
656                 } else {
657                     restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
658                     restore_count++;
659                     if (restore_limit && restore_count >= restore_limit) {
660                         LOG(WARNING) << "Hit the test limit";
661                         status = Status::fromExceptionCode(EAGAIN, "Hit the test limit");
662                         break;
663                     }
664                 }
665             }
666         }
667 
668         if (!status.isOk()) {
669             if (!validating) {
670                 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
671                 return status;
672             }
673 
674             LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
675             auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
676                                         original_ls.block_size, original_ls.block_size);
677             lseek64(device_fd, 0, SEEK_SET);
678             write(device_fd, &buffer[0], original_ls.block_size);
679             return Status::ok();
680         }
681 
682         if (!validating) break;
683 
684         validating = false;
685         action = "Restoring";
686     }
687 
688     return Status::ok();
689 }
690 
cp_markBootAttempt()691 Status cp_markBootAttempt() {
692     std::string oldContent, newContent;
693     int retry = 0;
694     struct stat st;
695     int result = stat(kMetadataCPFile.c_str(), &st);
696 
697     // If the file doesn't exist, we aren't managing a checkpoint retry counter
698     if (result != 0) return Status::ok();
699     if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
700         PLOG(ERROR) << "Failed to read checkpoint file";
701         return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
702     }
703     std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
704 
705     if (!android::base::ParseInt(retryContent, &retry))
706         return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
707     if (retry > 0) {
708         retry--;
709 
710         newContent = std::to_string(retry);
711         if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
712             return Status::fromExceptionCode(errno, "Could not write checkpoint file");
713     }
714     return Status::ok();
715 }
716 
717 }  // namespace vold
718 }  // namespace android
719