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