blob: a3d78e71b67777fe89fcf02db998d82776d106a7 [file] [log] [blame]
Daniel Rosenberg65f99c92018-08-28 01:58:49 -07001/*
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"
Daniel Rosenberg253b44e2019-02-01 19:25:47 -080019#include "VoldUtil.h"
Sandeep Patile802d472019-04-15 08:45:27 -070020#include "VolumeManager.h"
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070021
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070022#include <fstream>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070023#include <list>
Paul Lawrence20400892018-10-03 14:14:52 -070024#include <memory>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070025#include <string>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080026#include <thread>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070027#include <vector>
28
29#include <android-base/file.h>
30#include <android-base/logging.h>
31#include <android-base/parseint.h>
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080032#include <android-base/properties.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070033#include <android-base/unique_fd.h>
Daniel Rosenbergd3992492018-10-02 17:40:44 -070034#include <android/hardware/boot/1.0/IBootControl.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070035#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>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080042#include <sys/statvfs.h>
43#include <unistd.h>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070044
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080045using android::base::GetBoolProperty;
46using android::base::GetUintProperty;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080047using android::base::SetProperty;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070048using android::binder::Status;
Tom Cherry4c5bde22019-01-29 14:34:01 -080049using android::fs_mgr::Fstab;
50using android::fs_mgr::ReadDefaultFstab;
51using android::fs_mgr::ReadFstabFromFile;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070052using android::hardware::hidl_string;
53using android::hardware::boot::V1_0::BoolResult;
Daniel Rosenberg886915b2019-01-23 15:16:04 -080054using android::hardware::boot::V1_0::CommandResult;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070055using android::hardware::boot::V1_0::IBootControl;
56using android::hardware::boot::V1_0::Slot;
57
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070058namespace android {
59namespace vold {
60
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070061namespace {
62const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
63
64bool setBowState(std::string const& block_device, std::string const& state) {
65 if (block_device.substr(0, 5) != "/dev/") {
66 LOG(ERROR) << "Expected block device, got " << block_device;
67 return false;
68 }
69
70 std::string state_filename = std::string("/sys/") + block_device.substr(5) + "/bow/state";
71 if (!android::base::WriteStringToFile(state, state_filename)) {
72 PLOG(ERROR) << "Failed to write to file " << state_filename;
73 return false;
74 }
75
76 return true;
77}
78
79} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070080
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080081Status cp_supportsCheckpoint(bool& result) {
82 result = false;
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080083
Tom Cherry4c5bde22019-01-29 14:34:01 -080084 for (const auto& entry : fstab_default) {
85 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080086 result = true;
87 return Status::ok();
88 }
89 }
90 return Status::ok();
91}
92
Paul Lawrencec5c79c52019-03-18 13:36:40 -070093Status cp_supportsBlockCheckpoint(bool& result) {
94 result = false;
95
96 for (const auto& entry : fstab_default) {
97 if (entry.fs_mgr_flags.checkpoint_blk) {
98 result = true;
99 return Status::ok();
100 }
101 }
102 return Status::ok();
103}
104
105Status cp_supportsFileCheckpoint(bool& result) {
106 result = false;
107
108 for (const auto& entry : fstab_default) {
109 if (entry.fs_mgr_flags.checkpoint_fs) {
110 result = true;
111 return Status::ok();
112 }
113 }
114 return Status::ok();
115}
116
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700117Status cp_startCheckpoint(int retry) {
118 if (retry < -1) return Status::fromExceptionCode(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700119 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700120 if (retry == -1) {
121 sp<IBootControl> module = IBootControl::getService();
122 if (module) {
123 std::string suffix;
124 auto cb = [&suffix](hidl_string s) { suffix = s; };
125 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
126 }
127 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700128 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
129 return Status::fromExceptionCode(errno, "Failed to write checkpoint file");
130 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700131}
132
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800133namespace {
134
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800135volatile bool isCheckpointing = false;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800136}
137
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700138Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800139 if (!isCheckpointing) {
140 return Status::ok();
141 }
Paul Lawrence3f1ce062019-06-12 12:03:01 -0700142 if (android::base::GetProperty("persist.vold.dont_commit_checkpoint", "0") == "1") {
143 LOG(WARNING)
144 << "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
145 return Status::ok();
146 }
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800147 sp<IBootControl> module = IBootControl::getService();
148 if (module) {
149 CommandResult cr;
150 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
151 if (!cr.success) {
152 std::string msg = "Error marking booted successfully: " + std::string(cr.errMsg);
153 return Status::fromExceptionCode(EINVAL, String8(msg.c_str()));
154 }
155 LOG(INFO) << "Marked slot as booted successfully.";
156 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700157 // Must take action for list of mounted checkpointed things here
158 // To do this, we walk the list of mounted file systems.
159 // But we also need to get the matching fstab entries to see
160 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700161 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700162
Tom Cherry4c5bde22019-01-29 14:34:01 -0800163 Fstab mounts;
164 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
165 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
166 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700167
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700168 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800169 for (const auto& mount_rec : mounts) {
170 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700171 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700172
Tom Cherry4c5bde22019-01-29 14:34:01 -0800173 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
174 if (fstab_rec->fs_type == "f2fs") {
175 std::string options = mount_rec.fs_options + ",checkpoint=enable";
176 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800177 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800178 return Status::fromExceptionCode(EINVAL, "Failed to remount");
179 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700180 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800181 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
182 if (!setBowState(mount_rec.blk_device, "2"))
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800183 return Status::fromExceptionCode(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700184 }
185 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800186 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800187 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800188 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800189 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700190 return Status::fromExceptionCode(errno, err_str.c_str());
191 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700192}
193
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700194namespace {
195void abort_metadata_file() {
196 std::string oldContent, newContent;
197 int retry = 0;
198 struct stat st;
199 int result = stat(kMetadataCPFile.c_str(), &st);
200
201 // If the file doesn't exist, we aren't managing a checkpoint retry counter
202 if (result != 0) return;
203 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
204 PLOG(ERROR) << "Failed to read checkpoint file";
205 return;
206 }
207 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
208
209 if (!android::base::ParseInt(retryContent, &retry)) {
210 PLOG(ERROR) << "Could not parse retry count";
211 return;
212 }
213 if (retry > 0) {
214 newContent = "0";
215 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
216 PLOG(ERROR) << "Could not write checkpoint file";
217 }
218}
219} // namespace
220
221void cp_abortChanges(const std::string& message, bool retry) {
222 if (!cp_needsCheckpoint()) return;
223 if (!retry) abort_metadata_file();
224 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700225}
226
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700227bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700228 std::string content;
229 bool ret;
230
231 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700232 if (ret) {
233 if (content == "0") return true;
234 if (content.substr(0, 3) == "-1 ") {
235 std::string oldSuffix = content.substr(3);
236 sp<IBootControl> module = IBootControl::getService();
237 std::string newSuffix;
238
239 if (module) {
240 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
241 module->getSuffix(module->getCurrentSlot(), cb);
242 if (oldSuffix == newSuffix) return true;
243 }
244 }
245 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700246 return false;
247}
248
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700249bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700250 bool ret;
251 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700252 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700253
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700254 if (isCheckpointing) return isCheckpointing;
255
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800256 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
257 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700258 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800259 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700260 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800261 if (ret) {
262 ret = content != "0";
263 isCheckpointing = ret;
264 return ret;
265 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700266 return false;
267}
268
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800269namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700270const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
271const uint32_t msleeptime_default = 1000; // 1 s
272const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800273
274const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
275const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
276
277const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
278const bool commit_on_full_default = true;
279
280static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
281 struct statvfs data;
282 uint64_t free_bytes = 0;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700283 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900284 uint64_t min_free_bytes =
285 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800286 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
287
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700288 struct timespec req;
289 req.tv_sec = msleeptime / 1000;
290 msleeptime %= 1000;
291 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800292 while (isCheckpointing) {
293 if (is_fs_cp) {
294 statvfs(mnt_pnt.c_str(), &data);
295 free_bytes = data.f_bavail * data.f_frsize;
296 } else {
297 int ret;
298 std::string size_filename = std::string("/sys/") + blk_device.substr(5) + "/bow/free";
299 std::string content;
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700300 ret = android::base::ReadFileToString(size_filename, &content);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800301 if (ret) {
302 free_bytes = std::strtoul(content.c_str(), NULL, 10);
303 }
304 }
305 if (free_bytes < min_free_bytes) {
306 if (commit_on_full) {
307 LOG(INFO) << "Low space for checkpointing. Commiting changes";
308 cp_commitChanges();
309 break;
310 } else {
311 LOG(INFO) << "Low space for checkpointing. Rebooting";
312 cp_abortChanges("checkpoint,low_space", false);
313 break;
314 }
315 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700316 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800317 }
318}
319
320} // namespace
321
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700322Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800323 if (!isCheckpointing) {
324 return Status::ok();
325 }
326
Tom Cherry4c5bde22019-01-29 14:34:01 -0800327 Fstab mounts;
328 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
329 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
330 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700331
Tom Cherry4c5bde22019-01-29 14:34:01 -0800332 for (const auto& mount_rec : mounts) {
333 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700334 if (!fstab_rec) continue;
335
Tom Cherry4c5bde22019-01-29 14:34:01 -0800336 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700337 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800338 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900339 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800340 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700341 continue;
342 }
343
344 struct fstrim_range range = {};
345 range.len = ULLONG_MAX;
Sandeep Patile802d472019-04-15 08:45:27 -0700346 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700347 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800348 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700349 continue;
350 }
Sandeep Patile802d472019-04-15 08:45:27 -0700351 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
352 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
353 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700354
Tom Cherry4c5bde22019-01-29 14:34:01 -0800355 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700356 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800357 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
358 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700359 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800360 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
361 .detach();
362 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700363 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700364 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700365}
366
367namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700368const int kSectorSize = 512;
369
370typedef uint64_t sector_t;
371
372struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800373 sector_t source; // in sectors of size kSectorSize
374 sector_t dest; // in sectors of size kSectorSize
375 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700376 uint32_t checksum;
377} __attribute__((packed));
378
Paul Lawrencef5077682019-01-18 10:28:34 -0800379struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700380 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800381 uint16_t header_version;
382 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800383 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700384 uint32_t count;
385 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800386 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700387} __attribute__((packed));
388
389// MAGIC is BOW in ascii
390const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800391// Partially restored MAGIC is WOB in ascii
392const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700393
394void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
395 static uint32_t table[0x100] = {
396 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
397 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
398 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
399 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
400 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
401 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
402 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
403 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
404 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
405 0xB6662D3D,
406
407 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
408 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
409 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
410 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
411 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
412 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
413 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
414 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
415 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
416 0xC0BA6CAD,
417
418 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
419 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
420 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
421 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
422 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
423 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
424 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
425 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
426 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
427 0x5BDEAE1D,
428
429 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
430 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
431 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
432 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
433 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
434 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
435 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
436 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
437 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
438 0x2D02EF8D};
439
440 for (size_t i = 0; i < n_bytes; ++i) {
441 *crc ^= ((uint8_t*)data)[i];
442 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
443 }
444}
445
Paul Lawrenced41a9392019-01-22 14:31:43 -0800446// A map of relocations.
447// The map must be initialized so that relocations[0] = 0
448// During restore, we replay the log records in reverse, copying from dest to
449// source
450// To validate, we must be able to read the 'dest' sectors as though they had
451// been copied but without actually copying. This map represents how the sectors
452// would have been moved. To read a sector s, find the index <= s and read
453// relocations[index] + s - index
454typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800455
Paul Lawrenced41a9392019-01-22 14:31:43 -0800456void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
457 // Find first one we're equal to or greater than
458 auto s = --relocations.upper_bound(source);
459
460 // Take slice
461 Relocations slice;
462 slice[dest] = source - s->first + s->second;
463 ++s;
464
465 // Add rest of elements
466 for (; s != relocations.end() && s->first < source + count; ++s)
467 slice[dest - source + s->first] = s->second;
468
469 // Split range at end of dest
470 auto dest_end = --relocations.upper_bound(dest + count);
471 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
472
473 // Remove all elements in [dest, dest + count)
474 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
475
476 // Add new elements
477 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800478}
479
Daniel Rosenberg52985932019-03-01 22:01:22 -0800480// A map of sectors that have been written to.
481// The final entry must always be False.
482// When we restart the restore after an interruption, we must take care that
483// when we copy from dest to source, that the block we copy to was not
484// previously copied from.
485// i e. A->B C->A; If we replay this sequence, we end up copying C->B
486// We must save our partial result whenever we finish a page, or when we copy
487// to a location that was copied from earlier (our source is an earlier dest)
488typedef std::map<sector_t, bool> Used_Sectors;
489
490bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
491 auto second_overlap = used_sectors.upper_bound(start);
492 auto first_overlap = --second_overlap;
493
494 if (first_overlap->second) {
495 return true;
496 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
497 return true;
498 }
499 return false;
500}
501
502void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
503 auto start_pos = used_sectors.insert_or_assign(start, true).first;
504 auto end_pos = used_sectors.insert_or_assign(end, false).first;
505
506 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
507 start_pos++;
508 }
509 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
510 end_pos++;
511 }
512 if (start_pos->first < end_pos->first) {
513 used_sectors.erase(start_pos, end_pos);
514 }
515}
516
517// Restores the given log_entry's data from dest -> source
518// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
519void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
520 log_entry* le, std::vector<char>& buffer) {
521 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
522 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
523 int count = (le->size - 1) / kSectorSize + 1;
524
525 if (checkCollision(used_sectors, le->source, le->source + count)) {
526 fsync(device_fd);
527 lseek64(device_fd, 0, SEEK_SET);
528 ls.count = index + 1;
529 ls.magic = kPartialRestoreMagic;
530 write(device_fd, &ls_buffer[0], ls.block_size);
531 fsync(device_fd);
532 used_sectors.clear();
533 used_sectors[0] = false;
534 }
535
536 markUsed(used_sectors, le->dest, le->dest + count);
537
538 if (index == 0 && ls.sequence != 0) {
539 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
540 if (next->magic == kMagic) {
541 next->magic = kPartialRestoreMagic;
542 }
543 }
544
545 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
546 write(device_fd, &buffer[0], le->size);
547
548 if (index == 0) {
549 fsync(device_fd);
550 }
551}
552
Paul Lawrenced41a9392019-01-22 14:31:43 -0800553// Read from the device
554// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800555std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
556 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800557 if (!validating) {
558 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800559 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
560 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800561 return buffer;
562 }
563
Paul Lawrence27691c22018-11-20 14:07:59 -0800564 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800565 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
566 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800567 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
568 SEEK_SET);
569 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800570 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800571
572 return buffer;
573}
574
Paul Lawrence4f13a902019-01-10 13:06:07 -0800575} // namespace
576
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800577Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800578 bool validating = true;
579 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800580 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700581
Paul Lawrence27691c22018-11-20 14:07:59 -0800582 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800583 Relocations relocations;
584 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800585 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700586
Paul Lawrence27691c22018-11-20 14:07:59 -0800587 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700588 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800589 if (device_fd < 0) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800590 PLOG(ERROR) << "Cannot open " << blockDevice;
591 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
592 }
Paul Lawrence4f13a902019-01-10 13:06:07 -0800593
Paul Lawrencef5077682019-01-18 10:28:34 -0800594 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800595 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800596 if (original_ls.magic == kPartialRestoreMagic) {
597 validating = false;
598 action = "Restoring";
599 } else if (original_ls.magic != kMagic) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800600 LOG(ERROR) << "No magic";
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700601 return Status::fromExceptionCode(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700602 }
603
Paul Lawrence4f13a902019-01-10 13:06:07 -0800604 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700605
Paul Lawrence4f13a902019-01-10 13:06:07 -0800606 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800607 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
608 original_ls.block_size, original_ls.block_size);
609 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
610
611 Used_Sectors used_sectors;
612 used_sectors[0] = false;
613
614 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800615 LOG(ERROR) << "No magic!";
616 status = Status::fromExceptionCode(EINVAL, "No magic");
617 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700618 }
619
Paul Lawrence4f13a902019-01-10 13:06:07 -0800620 if (ls.block_size != original_ls.block_size) {
621 LOG(ERROR) << "Block size mismatch!";
622 status = Status::fromExceptionCode(EINVAL, "Block size mismatch");
623 break;
624 }
625
Paul Lawrence27691c22018-11-20 14:07:59 -0800626 if ((int)ls.sequence != sequence) {
627 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
628 status = Status::fromExceptionCode(
629 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
630 std::to_string(ls.sequence))
631 .c_str());
632 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700633 }
634
Paul Lawrence27691c22018-11-20 14:07:59 -0800635 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800636 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800637 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
638 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800639 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800640 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
641 << " to " << le->source << " with checksum " << std::hex
642 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800643
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800644 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800645 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800646 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
647 for (size_t i = 0; i < le->size; i += ls.block_size) {
648 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800649 }
650
651 if (le->checksum && checksum != le->checksum) {
652 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
653 status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
654 break;
655 }
656
Paul Lawrenced41a9392019-01-22 14:31:43 -0800657 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800658 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800659 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800660 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800661 restore_count++;
662 if (restore_limit && restore_count >= restore_limit) {
663 LOG(WARNING) << "Hit the test limit";
664 status = Status::fromExceptionCode(EAGAIN, "Hit the test limit");
665 break;
666 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800667 }
668 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700669 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800670
671 if (!status.isOk()) {
672 if (!validating) {
673 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
674 return status;
675 }
676
677 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800678 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800679 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800680 lseek64(device_fd, 0, SEEK_SET);
681 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800682 return Status::ok();
683 }
684
685 if (!validating) break;
686
687 validating = false;
688 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700689 }
690
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700691 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700692}
693
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700694Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700695 std::string oldContent, newContent;
696 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700697 struct stat st;
698 int result = stat(kMetadataCPFile.c_str(), &st);
699
700 // If the file doesn't exist, we aren't managing a checkpoint retry counter
701 if (result != 0) return Status::ok();
702 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
703 PLOG(ERROR) << "Failed to read checkpoint file";
704 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
705 }
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700706 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700707
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700708 if (!android::base::ParseInt(retryContent, &retry))
709 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
710 if (retry > 0) {
711 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700712
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700713 newContent = std::to_string(retry);
714 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
715 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
716 }
717 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700718}
719
720} // namespace vold
721} // namespace android