blob: ba9af110d7ec2cba7f24de877e246604ee8d8313 [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 Lawrence82b35052019-04-19 14:26:39 -0700128 if (retry < -1) return error(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700129 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700130 if (retry == -1) {
131 sp<IBootControl> module = IBootControl::getService();
132 if (module) {
133 std::string suffix;
134 auto cb = [&suffix](hidl_string s) { suffix = s; };
135 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
136 }
137 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700138 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700139 return error("Failed to write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700140 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700141}
142
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800143namespace {
144
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800145volatile bool isCheckpointing = false;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800146}
147
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700148Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800149 if (!isCheckpointing) {
150 return Status::ok();
151 }
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800152 sp<IBootControl> module = IBootControl::getService();
153 if (module) {
154 CommandResult cr;
155 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
Paul Lawrence82b35052019-04-19 14:26:39 -0700156 if (!cr.success)
157 return error(EINVAL, "Error marking booted successfully: " + std::string(cr.errMsg));
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800158 LOG(INFO) << "Marked slot as booted successfully.";
159 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700160 // Must take action for list of mounted checkpointed things here
161 // To do this, we walk the list of mounted file systems.
162 // But we also need to get the matching fstab entries to see
163 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700164 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700165
Tom Cherry4c5bde22019-01-29 14:34:01 -0800166 Fstab mounts;
167 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700168 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800169 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700170
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700171 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800172 for (const auto& mount_rec : mounts) {
173 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700174 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700175
Tom Cherry4c5bde22019-01-29 14:34:01 -0800176 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
177 if (fstab_rec->fs_type == "f2fs") {
178 std::string options = mount_rec.fs_options + ",checkpoint=enable";
179 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800180 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700181 return error(EINVAL, "Failed to remount");
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800182 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700183 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800184 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
185 if (!setBowState(mount_rec.blk_device, "2"))
Paul Lawrence82b35052019-04-19 14:26:39 -0700186 return error(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700187 }
188 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800189 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800190 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800191 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800192 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Paul Lawrence82b35052019-04-19 14:26:39 -0700193 return error(err_str.c_str());
194
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700195 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700196}
197
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700198namespace {
199void abort_metadata_file() {
200 std::string oldContent, newContent;
201 int retry = 0;
202 struct stat st;
203 int result = stat(kMetadataCPFile.c_str(), &st);
204
205 // If the file doesn't exist, we aren't managing a checkpoint retry counter
206 if (result != 0) return;
207 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
208 PLOG(ERROR) << "Failed to read checkpoint file";
209 return;
210 }
211 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
212
213 if (!android::base::ParseInt(retryContent, &retry)) {
214 PLOG(ERROR) << "Could not parse retry count";
215 return;
216 }
217 if (retry > 0) {
218 newContent = "0";
219 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
220 PLOG(ERROR) << "Could not write checkpoint file";
221 }
222}
223} // namespace
224
225void cp_abortChanges(const std::string& message, bool retry) {
226 if (!cp_needsCheckpoint()) return;
227 if (!retry) abort_metadata_file();
228 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700229}
230
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700231bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700232 std::string content;
233 bool ret;
234
235 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700236 if (ret) {
237 if (content == "0") return true;
238 if (content.substr(0, 3) == "-1 ") {
239 std::string oldSuffix = content.substr(3);
240 sp<IBootControl> module = IBootControl::getService();
241 std::string newSuffix;
242
243 if (module) {
244 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
245 module->getSuffix(module->getCurrentSlot(), cb);
246 if (oldSuffix == newSuffix) return true;
247 }
248 }
249 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700250 return false;
251}
252
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700253bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700254 bool ret;
255 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700256 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700257
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700258 if (isCheckpointing) return isCheckpointing;
259
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800260 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
261 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700262 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800263 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700264 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800265 if (ret) {
266 ret = content != "0";
267 isCheckpointing = ret;
268 return ret;
269 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700270 return false;
271}
272
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800273namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700274const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
275const uint32_t msleeptime_default = 1000; // 1 s
276const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800277
278const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
279const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
280
281const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
282const bool commit_on_full_default = true;
283
284static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
285 struct statvfs data;
286 uint64_t free_bytes = 0;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700287 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900288 uint64_t min_free_bytes =
289 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800290 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
291
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700292 struct timespec req;
293 req.tv_sec = msleeptime / 1000;
294 msleeptime %= 1000;
295 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800296 while (isCheckpointing) {
297 if (is_fs_cp) {
298 statvfs(mnt_pnt.c_str(), &data);
299 free_bytes = data.f_bavail * data.f_frsize;
300 } else {
301 int ret;
302 std::string size_filename = std::string("/sys/") + blk_device.substr(5) + "/bow/free";
303 std::string content;
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700304 ret = android::base::ReadFileToString(size_filename, &content);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800305 if (ret) {
306 free_bytes = std::strtoul(content.c_str(), NULL, 10);
307 }
308 }
309 if (free_bytes < min_free_bytes) {
310 if (commit_on_full) {
311 LOG(INFO) << "Low space for checkpointing. Commiting changes";
312 cp_commitChanges();
313 break;
314 } else {
315 LOG(INFO) << "Low space for checkpointing. Rebooting";
316 cp_abortChanges("checkpoint,low_space", false);
317 break;
318 }
319 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700320 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800321 }
322}
323
324} // namespace
325
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700326Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800327 if (!isCheckpointing) {
328 return Status::ok();
329 }
330
Tom Cherry4c5bde22019-01-29 14:34:01 -0800331 Fstab mounts;
332 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700333 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800334 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700335
Tom Cherry4c5bde22019-01-29 14:34:01 -0800336 for (const auto& mount_rec : mounts) {
337 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700338 if (!fstab_rec) continue;
339
Tom Cherry4c5bde22019-01-29 14:34:01 -0800340 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700341 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800342 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900343 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800344 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700345 continue;
346 }
347
348 struct fstrim_range range = {};
349 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700350 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700351 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800352 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700353 continue;
354 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700355 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
356 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
357 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700358
Tom Cherry4c5bde22019-01-29 14:34:01 -0800359 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700360 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800361 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
362 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700363 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800364 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
365 .detach();
366 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700367 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700368 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700369}
370
371namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700372const int kSectorSize = 512;
373
374typedef uint64_t sector_t;
375
376struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800377 sector_t source; // in sectors of size kSectorSize
378 sector_t dest; // in sectors of size kSectorSize
379 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700380 uint32_t checksum;
381} __attribute__((packed));
382
Paul Lawrencef5077682019-01-18 10:28:34 -0800383struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700384 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800385 uint16_t header_version;
386 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800387 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700388 uint32_t count;
389 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800390 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700391} __attribute__((packed));
392
393// MAGIC is BOW in ascii
394const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800395// Partially restored MAGIC is WOB in ascii
396const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700397
398void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
399 static uint32_t table[0x100] = {
400 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
401 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
402 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
403 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
404 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
405 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
406 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
407 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
408 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
409 0xB6662D3D,
410
411 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
412 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
413 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
414 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
415 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
416 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
417 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
418 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
419 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
420 0xC0BA6CAD,
421
422 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
423 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
424 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
425 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
426 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
427 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
428 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
429 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
430 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
431 0x5BDEAE1D,
432
433 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
434 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
435 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
436 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
437 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
438 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
439 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
440 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
441 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
442 0x2D02EF8D};
443
444 for (size_t i = 0; i < n_bytes; ++i) {
445 *crc ^= ((uint8_t*)data)[i];
446 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
447 }
448}
449
Paul Lawrenced41a9392019-01-22 14:31:43 -0800450// A map of relocations.
451// The map must be initialized so that relocations[0] = 0
452// During restore, we replay the log records in reverse, copying from dest to
453// source
454// To validate, we must be able to read the 'dest' sectors as though they had
455// been copied but without actually copying. This map represents how the sectors
456// would have been moved. To read a sector s, find the index <= s and read
457// relocations[index] + s - index
458typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800459
Paul Lawrenced41a9392019-01-22 14:31:43 -0800460void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
461 // Find first one we're equal to or greater than
462 auto s = --relocations.upper_bound(source);
463
464 // Take slice
465 Relocations slice;
466 slice[dest] = source - s->first + s->second;
467 ++s;
468
469 // Add rest of elements
470 for (; s != relocations.end() && s->first < source + count; ++s)
471 slice[dest - source + s->first] = s->second;
472
473 // Split range at end of dest
474 auto dest_end = --relocations.upper_bound(dest + count);
475 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
476
477 // Remove all elements in [dest, dest + count)
478 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
479
480 // Add new elements
481 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800482}
483
Daniel Rosenberg52985932019-03-01 22:01:22 -0800484// A map of sectors that have been written to.
485// The final entry must always be False.
486// When we restart the restore after an interruption, we must take care that
487// when we copy from dest to source, that the block we copy to was not
488// previously copied from.
489// i e. A->B C->A; If we replay this sequence, we end up copying C->B
490// We must save our partial result whenever we finish a page, or when we copy
491// to a location that was copied from earlier (our source is an earlier dest)
492typedef std::map<sector_t, bool> Used_Sectors;
493
494bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
495 auto second_overlap = used_sectors.upper_bound(start);
496 auto first_overlap = --second_overlap;
497
498 if (first_overlap->second) {
499 return true;
500 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
501 return true;
502 }
503 return false;
504}
505
506void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
507 auto start_pos = used_sectors.insert_or_assign(start, true).first;
508 auto end_pos = used_sectors.insert_or_assign(end, false).first;
509
510 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
511 start_pos++;
512 }
513 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
514 end_pos++;
515 }
516 if (start_pos->first < end_pos->first) {
517 used_sectors.erase(start_pos, end_pos);
518 }
519}
520
521// Restores the given log_entry's data from dest -> source
522// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
523void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
524 log_entry* le, std::vector<char>& buffer) {
525 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
526 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
527 int count = (le->size - 1) / kSectorSize + 1;
528
529 if (checkCollision(used_sectors, le->source, le->source + count)) {
530 fsync(device_fd);
531 lseek64(device_fd, 0, SEEK_SET);
532 ls.count = index + 1;
533 ls.magic = kPartialRestoreMagic;
534 write(device_fd, &ls_buffer[0], ls.block_size);
535 fsync(device_fd);
536 used_sectors.clear();
537 used_sectors[0] = false;
538 }
539
540 markUsed(used_sectors, le->dest, le->dest + count);
541
542 if (index == 0 && ls.sequence != 0) {
543 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
544 if (next->magic == kMagic) {
545 next->magic = kPartialRestoreMagic;
546 }
547 }
548
549 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
550 write(device_fd, &buffer[0], le->size);
551
552 if (index == 0) {
553 fsync(device_fd);
554 }
555}
556
Paul Lawrenced41a9392019-01-22 14:31:43 -0800557// Read from the device
558// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800559std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
560 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800561 if (!validating) {
562 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800563 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
564 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800565 return buffer;
566 }
567
Paul Lawrence27691c22018-11-20 14:07:59 -0800568 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800569 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
570 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800571 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
572 SEEK_SET);
573 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800574 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800575
576 return buffer;
577}
578
Paul Lawrence4f13a902019-01-10 13:06:07 -0800579} // namespace
580
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800581Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800582 bool validating = true;
583 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800584 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700585
Paul Lawrence27691c22018-11-20 14:07:59 -0800586 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800587 Relocations relocations;
588 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800589 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700590
Paul Lawrence27691c22018-11-20 14:07:59 -0800591 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700592 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700593 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800594
Paul Lawrencef5077682019-01-18 10:28:34 -0800595 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800596 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800597 if (original_ls.magic == kPartialRestoreMagic) {
598 validating = false;
599 action = "Restoring";
600 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700601 return error(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 Lawrence82b35052019-04-19 14:26:39 -0700615 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800616 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700617 }
618
Paul Lawrence4f13a902019-01-10 13:06:07 -0800619 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700620 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800621 break;
622 }
623
Paul Lawrence27691c22018-11-20 14:07:59 -0800624 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700625 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
626 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800627 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700628 }
629
Paul Lawrence27691c22018-11-20 14:07:59 -0800630 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800631 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800632 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
633 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800634 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800635 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
636 << " to " << le->source << " with checksum " << std::hex
637 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800638
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800639 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800640 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800641 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
642 for (size_t i = 0; i < le->size; i += ls.block_size) {
643 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800644 }
645
646 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700647 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800648 break;
649 }
650
Paul Lawrenced41a9392019-01-22 14:31:43 -0800651 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800652 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800653 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800654 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800655 restore_count++;
656 if (restore_limit && restore_count >= restore_limit) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700657 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800658 break;
659 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800660 }
661 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700662 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800663
664 if (!status.isOk()) {
665 if (!validating) {
666 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
667 return status;
668 }
669
670 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800671 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800672 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800673 lseek64(device_fd, 0, SEEK_SET);
674 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800675 return Status::ok();
676 }
677
678 if (!validating) break;
679
680 validating = false;
681 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700682 }
683
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700684 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700685}
686
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700687Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700688 std::string oldContent, newContent;
689 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700690 struct stat st;
691 int result = stat(kMetadataCPFile.c_str(), &st);
692
693 // If the file doesn't exist, we aren't managing a checkpoint retry counter
694 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700695 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
696 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700697 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700698
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700699 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700700 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700701 if (retry > 0) {
702 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700703
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700704 newContent = std::to_string(retry);
705 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700706 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700707 }
708 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700709}
710
711} // namespace vold
712} // namespace android