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