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