blob: 56ec7824250360db3b1f10d6fb10a10aa6d67a3a [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 Patilf8da61f2019-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
Paul Lawrence82b35052019-04-19 14:26:39 -070064binder::Status error(const std::string& msg) {
65 PLOG(ERROR) << msg;
66 return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str()));
67}
68
69binder::Status error(int error, const std::string& msg) {
70 LOG(ERROR) << msg;
71 return binder::Status::fromServiceSpecificError(error, String8(msg.c_str()));
72}
73
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070074bool setBowState(std::string const& block_device, std::string const& state) {
75 if (block_device.substr(0, 5) != "/dev/") {
76 LOG(ERROR) << "Expected block device, got " << block_device;
77 return false;
78 }
79
80 std::string state_filename = std::string("/sys/") + block_device.substr(5) + "/bow/state";
81 if (!android::base::WriteStringToFile(state, state_filename)) {
82 PLOG(ERROR) << "Failed to write to file " << state_filename;
83 return false;
84 }
85
86 return true;
87}
88
89} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070090
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080091Status cp_supportsCheckpoint(bool& result) {
92 result = false;
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080093
Tom Cherry4c5bde22019-01-29 14:34:01 -080094 for (const auto& entry : fstab_default) {
95 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080096 result = true;
97 return Status::ok();
98 }
99 }
100 return Status::ok();
101}
102
Paul Lawrencec5c79c52019-03-18 13:36:40 -0700103Status cp_supportsBlockCheckpoint(bool& result) {
104 result = false;
105
106 for (const auto& entry : fstab_default) {
107 if (entry.fs_mgr_flags.checkpoint_blk) {
108 result = true;
109 return Status::ok();
110 }
111 }
112 return Status::ok();
113}
114
115Status cp_supportsFileCheckpoint(bool& result) {
116 result = false;
117
118 for (const auto& entry : fstab_default) {
119 if (entry.fs_mgr_flags.checkpoint_fs) {
120 result = true;
121 return Status::ok();
122 }
123 }
124 return Status::ok();
125}
126
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700127Status cp_startCheckpoint(int retry) {
Paul Lawrencec2a145f2019-05-15 09:42:04 -0700128 bool result;
129 if (!cp_supportsCheckpoint(result).isOk() || !result)
130 return error(ENOTSUP, "Checkpoints not supported");
131
Paul Lawrence82b35052019-04-19 14:26:39 -0700132 if (retry < -1) return error(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700133 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700134 if (retry == -1) {
135 sp<IBootControl> module = IBootControl::getService();
136 if (module) {
137 std::string suffix;
138 auto cb = [&suffix](hidl_string s) { suffix = s; };
139 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
140 }
141 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700142 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700143 return error("Failed to write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700144 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700145}
146
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800147namespace {
148
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800149volatile bool isCheckpointing = false;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800150}
151
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700152Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800153 if (!isCheckpointing) {
154 return Status::ok();
155 }
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800156 sp<IBootControl> module = IBootControl::getService();
157 if (module) {
158 CommandResult cr;
159 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
Paul Lawrence82b35052019-04-19 14:26:39 -0700160 if (!cr.success)
161 return error(EINVAL, "Error marking booted successfully: " + std::string(cr.errMsg));
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800162 LOG(INFO) << "Marked slot as booted successfully.";
163 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700164 // Must take action for list of mounted checkpointed things here
165 // To do this, we walk the list of mounted file systems.
166 // But we also need to get the matching fstab entries to see
167 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700168 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700169
Tom Cherry4c5bde22019-01-29 14:34:01 -0800170 Fstab mounts;
171 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700172 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800173 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700174
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700175 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800176 for (const auto& mount_rec : mounts) {
177 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700178 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700179
Tom Cherry4c5bde22019-01-29 14:34:01 -0800180 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
181 if (fstab_rec->fs_type == "f2fs") {
182 std::string options = mount_rec.fs_options + ",checkpoint=enable";
183 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800184 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700185 return error(EINVAL, "Failed to remount");
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800186 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700187 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800188 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
189 if (!setBowState(mount_rec.blk_device, "2"))
Paul Lawrence82b35052019-04-19 14:26:39 -0700190 return error(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700191 }
192 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800193 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800194 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800195 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800196 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Paul Lawrence82b35052019-04-19 14:26:39 -0700197 return error(err_str.c_str());
198
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700199 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700200}
201
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700202namespace {
203void abort_metadata_file() {
204 std::string oldContent, newContent;
205 int retry = 0;
206 struct stat st;
207 int result = stat(kMetadataCPFile.c_str(), &st);
208
209 // If the file doesn't exist, we aren't managing a checkpoint retry counter
210 if (result != 0) return;
211 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
212 PLOG(ERROR) << "Failed to read checkpoint file";
213 return;
214 }
215 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
216
217 if (!android::base::ParseInt(retryContent, &retry)) {
218 PLOG(ERROR) << "Could not parse retry count";
219 return;
220 }
221 if (retry > 0) {
222 newContent = "0";
223 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
224 PLOG(ERROR) << "Could not write checkpoint file";
225 }
226}
227} // namespace
228
229void cp_abortChanges(const std::string& message, bool retry) {
230 if (!cp_needsCheckpoint()) return;
231 if (!retry) abort_metadata_file();
232 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700233}
234
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700235bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700236 std::string content;
237 bool ret;
238
239 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700240 if (ret) {
241 if (content == "0") return true;
242 if (content.substr(0, 3) == "-1 ") {
243 std::string oldSuffix = content.substr(3);
244 sp<IBootControl> module = IBootControl::getService();
245 std::string newSuffix;
246
247 if (module) {
248 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
249 module->getSuffix(module->getCurrentSlot(), cb);
250 if (oldSuffix == newSuffix) return true;
251 }
252 }
253 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700254 return false;
255}
256
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700257bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700258 bool ret;
259 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700260 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700261
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700262 if (isCheckpointing) return isCheckpointing;
263
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800264 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
265 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700266 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800267 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700268 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800269 if (ret) {
270 ret = content != "0";
271 isCheckpointing = ret;
272 return ret;
273 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700274 return false;
275}
276
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800277namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700278const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
279const uint32_t msleeptime_default = 1000; // 1 s
280const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800281
282const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
283const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
284
285const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
286const bool commit_on_full_default = true;
287
288static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
289 struct statvfs data;
290 uint64_t free_bytes = 0;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700291 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900292 uint64_t min_free_bytes =
293 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800294 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
295
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700296 struct timespec req;
297 req.tv_sec = msleeptime / 1000;
298 msleeptime %= 1000;
299 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800300 while (isCheckpointing) {
301 if (is_fs_cp) {
302 statvfs(mnt_pnt.c_str(), &data);
303 free_bytes = data.f_bavail * data.f_frsize;
304 } else {
305 int ret;
306 std::string size_filename = std::string("/sys/") + blk_device.substr(5) + "/bow/free";
307 std::string content;
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700308 ret = android::base::ReadFileToString(size_filename, &content);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800309 if (ret) {
310 free_bytes = std::strtoul(content.c_str(), NULL, 10);
311 }
312 }
313 if (free_bytes < min_free_bytes) {
314 if (commit_on_full) {
315 LOG(INFO) << "Low space for checkpointing. Commiting changes";
316 cp_commitChanges();
317 break;
318 } else {
319 LOG(INFO) << "Low space for checkpointing. Rebooting";
320 cp_abortChanges("checkpoint,low_space", false);
321 break;
322 }
323 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700324 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800325 }
326}
327
328} // namespace
329
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700330Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800331 if (!isCheckpointing) {
332 return Status::ok();
333 }
334
Tom Cherry4c5bde22019-01-29 14:34:01 -0800335 Fstab mounts;
336 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700337 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800338 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700339
Tom Cherry4c5bde22019-01-29 14:34:01 -0800340 for (const auto& mount_rec : mounts) {
341 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700342 if (!fstab_rec) continue;
343
Tom Cherry4c5bde22019-01-29 14:34:01 -0800344 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700345 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800346 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900347 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800348 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700349 continue;
350 }
351
352 struct fstrim_range range = {};
353 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700354 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700355 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800356 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700357 continue;
358 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700359 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
360 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
361 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700362
Tom Cherry4c5bde22019-01-29 14:34:01 -0800363 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700364 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800365 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
366 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700367 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800368 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
369 .detach();
370 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700371 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700372 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700373}
374
375namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700376const int kSectorSize = 512;
377
378typedef uint64_t sector_t;
379
380struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800381 sector_t source; // in sectors of size kSectorSize
382 sector_t dest; // in sectors of size kSectorSize
383 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700384 uint32_t checksum;
385} __attribute__((packed));
386
Paul Lawrencef5077682019-01-18 10:28:34 -0800387struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700388 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800389 uint16_t header_version;
390 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800391 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700392 uint32_t count;
393 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800394 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700395} __attribute__((packed));
396
397// MAGIC is BOW in ascii
398const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800399// Partially restored MAGIC is WOB in ascii
400const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700401
402void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
403 static uint32_t table[0x100] = {
404 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
405 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
406 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
407 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
408 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
409 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
410 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
411 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
412 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
413 0xB6662D3D,
414
415 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
416 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
417 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
418 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
419 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
420 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
421 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
422 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
423 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
424 0xC0BA6CAD,
425
426 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
427 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
428 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
429 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
430 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
431 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
432 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
433 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
434 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
435 0x5BDEAE1D,
436
437 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
438 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
439 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
440 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
441 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
442 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
443 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
444 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
445 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
446 0x2D02EF8D};
447
448 for (size_t i = 0; i < n_bytes; ++i) {
449 *crc ^= ((uint8_t*)data)[i];
450 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
451 }
452}
453
Paul Lawrenced41a9392019-01-22 14:31:43 -0800454// A map of relocations.
455// The map must be initialized so that relocations[0] = 0
456// During restore, we replay the log records in reverse, copying from dest to
457// source
458// To validate, we must be able to read the 'dest' sectors as though they had
459// been copied but without actually copying. This map represents how the sectors
460// would have been moved. To read a sector s, find the index <= s and read
461// relocations[index] + s - index
462typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800463
Paul Lawrenced41a9392019-01-22 14:31:43 -0800464void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
465 // Find first one we're equal to or greater than
466 auto s = --relocations.upper_bound(source);
467
468 // Take slice
469 Relocations slice;
470 slice[dest] = source - s->first + s->second;
471 ++s;
472
473 // Add rest of elements
474 for (; s != relocations.end() && s->first < source + count; ++s)
475 slice[dest - source + s->first] = s->second;
476
477 // Split range at end of dest
478 auto dest_end = --relocations.upper_bound(dest + count);
479 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
480
481 // Remove all elements in [dest, dest + count)
482 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
483
484 // Add new elements
485 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800486}
487
Daniel Rosenberg52985932019-03-01 22:01:22 -0800488// A map of sectors that have been written to.
489// The final entry must always be False.
490// When we restart the restore after an interruption, we must take care that
491// when we copy from dest to source, that the block we copy to was not
492// previously copied from.
493// i e. A->B C->A; If we replay this sequence, we end up copying C->B
494// We must save our partial result whenever we finish a page, or when we copy
495// to a location that was copied from earlier (our source is an earlier dest)
496typedef std::map<sector_t, bool> Used_Sectors;
497
498bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
499 auto second_overlap = used_sectors.upper_bound(start);
500 auto first_overlap = --second_overlap;
501
502 if (first_overlap->second) {
503 return true;
504 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
505 return true;
506 }
507 return false;
508}
509
510void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
511 auto start_pos = used_sectors.insert_or_assign(start, true).first;
512 auto end_pos = used_sectors.insert_or_assign(end, false).first;
513
514 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
515 start_pos++;
516 }
517 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
518 end_pos++;
519 }
520 if (start_pos->first < end_pos->first) {
521 used_sectors.erase(start_pos, end_pos);
522 }
523}
524
525// Restores the given log_entry's data from dest -> source
526// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
527void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
528 log_entry* le, std::vector<char>& buffer) {
529 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
530 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
531 int count = (le->size - 1) / kSectorSize + 1;
532
533 if (checkCollision(used_sectors, le->source, le->source + count)) {
534 fsync(device_fd);
535 lseek64(device_fd, 0, SEEK_SET);
536 ls.count = index + 1;
537 ls.magic = kPartialRestoreMagic;
538 write(device_fd, &ls_buffer[0], ls.block_size);
539 fsync(device_fd);
540 used_sectors.clear();
541 used_sectors[0] = false;
542 }
543
544 markUsed(used_sectors, le->dest, le->dest + count);
545
546 if (index == 0 && ls.sequence != 0) {
547 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
548 if (next->magic == kMagic) {
549 next->magic = kPartialRestoreMagic;
550 }
551 }
552
553 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
554 write(device_fd, &buffer[0], le->size);
555
556 if (index == 0) {
557 fsync(device_fd);
558 }
559}
560
Paul Lawrenced41a9392019-01-22 14:31:43 -0800561// Read from the device
562// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800563std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
564 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800565 if (!validating) {
566 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800567 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
568 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800569 return buffer;
570 }
571
Paul Lawrence27691c22018-11-20 14:07:59 -0800572 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800573 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
574 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800575 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
576 SEEK_SET);
577 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800578 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800579
580 return buffer;
581}
582
Paul Lawrence4f13a902019-01-10 13:06:07 -0800583} // namespace
584
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800585Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800586 bool validating = true;
587 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800588 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700589
Paul Lawrence27691c22018-11-20 14:07:59 -0800590 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800591 Relocations relocations;
592 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800593 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700594
Paul Lawrence27691c22018-11-20 14:07:59 -0800595 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700596 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700597 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800598
Paul Lawrencef5077682019-01-18 10:28:34 -0800599 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800600 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800601 if (original_ls.magic == kPartialRestoreMagic) {
602 validating = false;
603 action = "Restoring";
604 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700605 return error(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700606 }
607
Paul Lawrence4f13a902019-01-10 13:06:07 -0800608 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700609
Paul Lawrence4f13a902019-01-10 13:06:07 -0800610 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800611 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
612 original_ls.block_size, original_ls.block_size);
613 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
614
615 Used_Sectors used_sectors;
616 used_sectors[0] = false;
617
618 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700619 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800620 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700621 }
622
Paul Lawrence4f13a902019-01-10 13:06:07 -0800623 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700624 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800625 break;
626 }
627
Paul Lawrence27691c22018-11-20 14:07:59 -0800628 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700629 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
630 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800631 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700632 }
633
Paul Lawrence27691c22018-11-20 14:07:59 -0800634 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800635 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800636 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
637 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800638 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800639 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
640 << " to " << le->source << " with checksum " << std::hex
641 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800642
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800643 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800644 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800645 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
646 for (size_t i = 0; i < le->size; i += ls.block_size) {
647 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800648 }
649
650 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700651 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800652 break;
653 }
654
Paul Lawrenced41a9392019-01-22 14:31:43 -0800655 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800656 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800657 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800658 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800659 restore_count++;
660 if (restore_limit && restore_count >= restore_limit) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700661 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800662 break;
663 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800664 }
665 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700666 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800667
668 if (!status.isOk()) {
669 if (!validating) {
670 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
671 return status;
672 }
673
674 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800675 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800676 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800677 lseek64(device_fd, 0, SEEK_SET);
678 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800679 return Status::ok();
680 }
681
682 if (!validating) break;
683
684 validating = false;
685 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700686 }
687
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700688 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700689}
690
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700691Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700692 std::string oldContent, newContent;
693 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700694 struct stat st;
695 int result = stat(kMetadataCPFile.c_str(), &st);
696
697 // If the file doesn't exist, we aren't managing a checkpoint retry counter
698 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700699 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
700 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700701 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700702
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700703 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700704 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700705 if (retry > 0) {
706 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700707
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700708 newContent = std::to_string(retry);
709 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700710 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700711 }
712 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700713}
714
715} // namespace vold
716} // namespace android