blob: 598a87bc55a426ef9e9987fc7a192304678ecee4 [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"
Eric Biggersb615f3b2022-11-09 05:48:45 +000019#include "FsCrypt.h"
20#include "KeyStorage.h"
Daniel Rosenberg253b44e2019-02-01 19:25:47 -080021#include "VoldUtil.h"
Sandeep Patilf8da61f2019-04-15 08:45:27 -070022#include "VolumeManager.h"
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070023
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070024#include <fstream>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070025#include <list>
Paul Lawrence20400892018-10-03 14:14:52 -070026#include <memory>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070027#include <string>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080028#include <thread>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070029#include <vector>
30
Kelvin Zhangdec03ab2022-06-21 14:31:01 -070031#include <BootControlClient.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070032#include <android-base/file.h>
33#include <android-base/logging.h>
34#include <android-base/parseint.h>
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080035#include <android-base/properties.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070036#include <android-base/unique_fd.h>
37#include <cutils/android_reboot.h>
38#include <fcntl.h>
39#include <fs_mgr.h>
40#include <linux/fs.h>
41#include <mntent.h>
42#include <sys/mount.h>
43#include <sys/stat.h>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080044#include <sys/statvfs.h>
45#include <unistd.h>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070046
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080047using android::base::GetBoolProperty;
48using android::base::GetUintProperty;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080049using android::base::SetProperty;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070050using android::binder::Status;
Tom Cherry4c5bde22019-01-29 14:34:01 -080051using android::fs_mgr::Fstab;
Tom Cherry4c5bde22019-01-29 14:34:01 -080052using android::fs_mgr::ReadFstabFromFile;
Kelvin Zhangdec03ab2022-06-21 14:31:01 -070053using android::hal::BootControlClient;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070054
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070055namespace android {
56namespace vold {
57
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070058namespace {
59const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
60
Paul Lawrence82b35052019-04-19 14:26:39 -070061binder::Status error(const std::string& msg) {
62 PLOG(ERROR) << msg;
63 return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str()));
64}
65
66binder::Status error(int error, const std::string& msg) {
67 LOG(ERROR) << msg;
68 return binder::Status::fromServiceSpecificError(error, String8(msg.c_str()));
69}
70
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070071bool setBowState(std::string const& block_device, std::string const& state) {
Paul Lawrence236e5e82019-06-25 14:44:33 -070072 std::string bow_device = fs_mgr_find_bow_device(block_device);
73 if (bow_device.empty()) return false;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070074
Paul Lawrence236e5e82019-06-25 14:44:33 -070075 if (!android::base::WriteStringToFile(state, bow_device + "/bow/state")) {
76 PLOG(ERROR) << "Failed to write to file " << bow_device + "/bow/state";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070077 return false;
78 }
79
80 return true;
81}
82
Eric Biggersb615f3b2022-11-09 05:48:45 +000083// Do any work that was deferred until the userdata filesystem checkpoint was
84// committed. This work involves the deletion of resources that aren't covered
85// by the userdata filesystem checkpoint, e.g. Keystore keys.
86void DoCheckpointCommittedWork() {
87 // Take the crypt lock to provide synchronization with the Binder calls that
88 // operate on key directories.
89 std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getCryptLock());
90
91 DeferredCommitKeystoreKeys();
92 fscrypt_deferred_fixate_ce_keys();
93}
94
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070095} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070096
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080097Status cp_supportsCheckpoint(bool& result) {
98 result = false;
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080099
Tom Cherry4c5bde22019-01-29 14:34:01 -0800100 for (const auto& entry : fstab_default) {
101 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -0800102 result = true;
103 return Status::ok();
104 }
105 }
106 return Status::ok();
107}
108
Paul Lawrencec5c79c52019-03-18 13:36:40 -0700109Status cp_supportsBlockCheckpoint(bool& result) {
110 result = false;
111
112 for (const auto& entry : fstab_default) {
113 if (entry.fs_mgr_flags.checkpoint_blk) {
114 result = true;
115 return Status::ok();
116 }
117 }
118 return Status::ok();
119}
120
121Status cp_supportsFileCheckpoint(bool& result) {
122 result = false;
123
124 for (const auto& entry : fstab_default) {
125 if (entry.fs_mgr_flags.checkpoint_fs) {
126 result = true;
127 return Status::ok();
128 }
129 }
130 return Status::ok();
131}
132
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700133Status cp_startCheckpoint(int retry) {
Paul Lawrencec2a145f2019-05-15 09:42:04 -0700134 bool result;
135 if (!cp_supportsCheckpoint(result).isOk() || !result)
136 return error(ENOTSUP, "Checkpoints not supported");
137
Paul Lawrence82b35052019-04-19 14:26:39 -0700138 if (retry < -1) return error(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700139 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700140 if (retry == -1) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700141 auto module = BootControlClient::WaitForService();
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700142 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700143 std::string suffix = module->GetSuffix(module->GetCurrentSlot());
144 if (!suffix.empty()) content += " " + suffix;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700145 }
146 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700147 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700148 return error("Failed to write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700149 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700150}
151
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800152namespace {
153
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800154volatile bool isCheckpointing = false;
faqiang.zhudd20dc32021-07-19 12:27:37 +0800155volatile bool isBow = true;
Paul Lawrence1d57f682019-08-22 09:51:18 -0700156
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100157volatile bool needsCheckpointWasCalled = false;
158
159// Protects isCheckpointing, needsCheckpointWasCalled and code that makes decisions based on status
160// of isCheckpointing
Paul Lawrence1d57f682019-08-22 09:51:18 -0700161std::mutex isCheckpointingLock;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800162}
163
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700164Status cp_commitChanges() {
Paul Lawrence1d57f682019-08-22 09:51:18 -0700165 std::lock_guard<std::mutex> lock(isCheckpointingLock);
166
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800167 if (!isCheckpointing) {
168 return Status::ok();
169 }
Paul Lawrencea7972dc2019-06-12 12:03:01 -0700170 if (android::base::GetProperty("persist.vold.dont_commit_checkpoint", "0") == "1") {
171 LOG(WARNING)
172 << "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
173 return Status::ok();
174 }
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700175 auto module = BootControlClient::WaitForService();
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800176 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700177 auto cr = module->MarkBootSuccessful();
Paul Lawrence82b35052019-04-19 14:26:39 -0700178 if (!cr.success)
179 return error(EINVAL, "Error marking booted successfully: " + std::string(cr.errMsg));
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800180 LOG(INFO) << "Marked slot as booted successfully.";
Tianjie Xu09de0ff2019-11-15 14:05:29 -0800181 // Clears the warm reset flag for next reboot.
182 if (!SetProperty("ota.warm_reset", "0")) {
183 LOG(WARNING) << "Failed to reset the warm reset flag";
184 }
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700185 } else {
186 LOG(ERROR) << "Failed to get BootControl HAL, not marking slot as successful.";
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800187 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700188 // Must take action for list of mounted checkpointed things here
189 // To do this, we walk the list of mounted file systems.
190 // But we also need to get the matching fstab entries to see
191 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700192 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700193
Tom Cherry4c5bde22019-01-29 14:34:01 -0800194 Fstab mounts;
195 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700196 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800197 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700198
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700199 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800200 for (const auto& mount_rec : mounts) {
Kelvin Zhangfd5eb262024-04-24 14:15:06 -0700201 const auto fstab_rec =
202 GetEntryForMountPoint(&fstab_default, mount_rec.mount_point, mount_rec.fs_type);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700203 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700204
Tom Cherry4c5bde22019-01-29 14:34:01 -0800205 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
206 if (fstab_rec->fs_type == "f2fs") {
207 std::string options = mount_rec.fs_options + ",checkpoint=enable";
208 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800209 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700210 return error(EINVAL, "Failed to remount");
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800211 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700212 }
faqiang.zhudd20dc32021-07-19 12:27:37 +0800213 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk && isBow) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800214 if (!setBowState(mount_rec.blk_device, "2"))
Paul Lawrence82b35052019-04-19 14:26:39 -0700215 return error(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700216 }
217 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800218 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800219 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800220 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800221 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Paul Lawrence82b35052019-04-19 14:26:39 -0700222 return error(err_str.c_str());
223
Eric Biggersb615f3b2022-11-09 05:48:45 +0000224 std::thread(DoCheckpointCommittedWork).detach();
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700225 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700226}
227
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700228namespace {
229void abort_metadata_file() {
230 std::string oldContent, newContent;
231 int retry = 0;
232 struct stat st;
233 int result = stat(kMetadataCPFile.c_str(), &st);
234
235 // If the file doesn't exist, we aren't managing a checkpoint retry counter
236 if (result != 0) return;
237 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
238 PLOG(ERROR) << "Failed to read checkpoint file";
239 return;
240 }
241 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
242
243 if (!android::base::ParseInt(retryContent, &retry)) {
244 PLOG(ERROR) << "Could not parse retry count";
245 return;
246 }
247 if (retry > 0) {
248 newContent = "0";
249 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
250 PLOG(ERROR) << "Could not write checkpoint file";
251 }
252}
253} // namespace
254
255void cp_abortChanges(const std::string& message, bool retry) {
256 if (!cp_needsCheckpoint()) return;
257 if (!retry) abort_metadata_file();
258 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700259}
260
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700261bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700262 std::string content;
263 bool ret;
264
265 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700266 if (ret) {
267 if (content == "0") return true;
268 if (content.substr(0, 3) == "-1 ") {
269 std::string oldSuffix = content.substr(3);
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700270 auto module = BootControlClient::WaitForService();
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700271 std::string newSuffix;
272
273 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700274 newSuffix = module->GetSuffix(module->GetCurrentSlot());
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700275 if (oldSuffix == newSuffix) return true;
276 }
277 }
278 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700279 return false;
280}
281
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700282bool cp_needsCheckpoint() {
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100283 std::lock_guard<std::mutex> lock(isCheckpointingLock);
284
Paul Lawrence9a6d1f72019-08-26 15:09:41 -0700285 // Make sure we only return true during boot. See b/138952436 for discussion
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100286 if (needsCheckpointWasCalled) return isCheckpointing;
287 needsCheckpointWasCalled = true;
Paul Lawrence9a6d1f72019-08-26 15:09:41 -0700288
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700289 bool ret;
290 std::string content;
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700291 auto module = BootControlClient::WaitForService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700292
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700293 if (isCheckpointing) return isCheckpointing;
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700294 // In case of INVALID slot or other failures, we do not perform checkpoint.
295 if (module && !module->IsSlotMarkedSuccessful(module->GetCurrentSlot()).value_or(true)) {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800296 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700297 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800298 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700299 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800300 if (ret) {
301 ret = content != "0";
302 isCheckpointing = ret;
303 return ret;
304 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700305 return false;
306}
307
David Anderson23850d32020-06-10 23:51:17 -0700308bool cp_isCheckpointing() {
309 return isCheckpointing;
310}
311
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800312namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700313const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
314const uint32_t msleeptime_default = 1000; // 1 s
315const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800316
317const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
318const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
319
320const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
321const bool commit_on_full_default = true;
322
323static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
324 struct statvfs data;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700325 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900326 uint64_t min_free_bytes =
327 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800328 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
329
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700330 struct timespec req;
331 req.tv_sec = msleeptime / 1000;
332 msleeptime %= 1000;
333 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800334 while (isCheckpointing) {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700335 uint64_t free_bytes = 0;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800336 if (is_fs_cp) {
337 statvfs(mnt_pnt.c_str(), &data);
Qilin Tan5d0aaaf2020-01-02 19:07:47 +0800338 free_bytes = ((uint64_t) data.f_bavail) * data.f_frsize;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800339 } else {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700340 std::string bow_device = fs_mgr_find_bow_device(blk_device);
341 if (!bow_device.empty()) {
342 std::string content;
343 if (android::base::ReadFileToString(bow_device + "/bow/free", &content)) {
Qilin Tan5d0aaaf2020-01-02 19:07:47 +0800344 free_bytes = std::strtoull(content.c_str(), NULL, 10);
Paul Lawrence236e5e82019-06-25 14:44:33 -0700345 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800346 }
347 }
348 if (free_bytes < min_free_bytes) {
349 if (commit_on_full) {
350 LOG(INFO) << "Low space for checkpointing. Commiting changes";
351 cp_commitChanges();
352 break;
353 } else {
354 LOG(INFO) << "Low space for checkpointing. Rebooting";
355 cp_abortChanges("checkpoint,low_space", false);
356 break;
357 }
358 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700359 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800360 }
361}
362
363} // namespace
364
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700365Status cp_prepareCheckpoint() {
Paul Lawrence4c757fb2019-10-23 09:36:18 -0700366 // Log to notify CTS - see b/137924328 for context
367 LOG(INFO) << "cp_prepareCheckpoint called";
Paul Lawrence1d57f682019-08-22 09:51:18 -0700368 std::lock_guard<std::mutex> lock(isCheckpointingLock);
Paul Lawrencedb086942019-02-19 14:18:54 -0800369 if (!isCheckpointing) {
370 return Status::ok();
371 }
372
Tom Cherry4c5bde22019-01-29 14:34:01 -0800373 Fstab mounts;
374 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700375 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800376 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700377
Tom Cherry4c5bde22019-01-29 14:34:01 -0800378 for (const auto& mount_rec : mounts) {
379 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700380 if (!fstab_rec) continue;
381
Tom Cherry4c5bde22019-01-29 14:34:01 -0800382 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700383 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800384 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900385 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800386 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700387 continue;
388 }
389
390 struct fstrim_range range = {};
391 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700392 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700393 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800394 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700395 continue;
396 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700397 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
398 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
399 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700400
faqiang.zhudd20dc32021-07-19 12:27:37 +0800401 isBow &= setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700402 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800403 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
404 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700405 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800406 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
407 .detach();
408 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700409 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700410 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700411}
412
413namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700414const int kSectorSize = 512;
415
416typedef uint64_t sector_t;
417
418struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800419 sector_t source; // in sectors of size kSectorSize
420 sector_t dest; // in sectors of size kSectorSize
421 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700422 uint32_t checksum;
423} __attribute__((packed));
424
Paul Lawrencef5077682019-01-18 10:28:34 -0800425struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700426 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800427 uint16_t header_version;
428 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800429 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700430 uint32_t count;
431 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800432 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700433} __attribute__((packed));
434
435// MAGIC is BOW in ascii
436const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800437// Partially restored MAGIC is WOB in ascii
438const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700439
440void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
441 static uint32_t table[0x100] = {
442 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
443 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
444 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
445 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
446 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
447 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
448 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
449 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
450 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
451 0xB6662D3D,
452
453 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
454 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
455 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
456 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
457 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
458 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
459 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
460 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
461 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
462 0xC0BA6CAD,
463
464 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
465 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
466 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
467 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
468 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
469 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
470 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
471 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
472 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
473 0x5BDEAE1D,
474
475 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
476 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
477 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
478 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
479 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
480 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
481 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
482 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
483 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
484 0x2D02EF8D};
485
486 for (size_t i = 0; i < n_bytes; ++i) {
487 *crc ^= ((uint8_t*)data)[i];
488 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
489 }
490}
491
Paul Lawrenced41a9392019-01-22 14:31:43 -0800492// A map of relocations.
493// The map must be initialized so that relocations[0] = 0
494// During restore, we replay the log records in reverse, copying from dest to
495// source
496// To validate, we must be able to read the 'dest' sectors as though they had
497// been copied but without actually copying. This map represents how the sectors
498// would have been moved. To read a sector s, find the index <= s and read
499// relocations[index] + s - index
500typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800501
Paul Lawrenced41a9392019-01-22 14:31:43 -0800502void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
503 // Find first one we're equal to or greater than
504 auto s = --relocations.upper_bound(source);
505
506 // Take slice
507 Relocations slice;
508 slice[dest] = source - s->first + s->second;
509 ++s;
510
511 // Add rest of elements
512 for (; s != relocations.end() && s->first < source + count; ++s)
513 slice[dest - source + s->first] = s->second;
514
515 // Split range at end of dest
516 auto dest_end = --relocations.upper_bound(dest + count);
517 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
518
519 // Remove all elements in [dest, dest + count)
520 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
521
522 // Add new elements
523 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800524}
525
Daniel Rosenberg52985932019-03-01 22:01:22 -0800526// A map of sectors that have been written to.
527// The final entry must always be False.
528// When we restart the restore after an interruption, we must take care that
529// when we copy from dest to source, that the block we copy to was not
530// previously copied from.
531// i e. A->B C->A; If we replay this sequence, we end up copying C->B
532// We must save our partial result whenever we finish a page, or when we copy
533// to a location that was copied from earlier (our source is an earlier dest)
534typedef std::map<sector_t, bool> Used_Sectors;
535
536bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
537 auto second_overlap = used_sectors.upper_bound(start);
538 auto first_overlap = --second_overlap;
539
540 if (first_overlap->second) {
541 return true;
542 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
543 return true;
544 }
545 return false;
546}
547
548void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
549 auto start_pos = used_sectors.insert_or_assign(start, true).first;
550 auto end_pos = used_sectors.insert_or_assign(end, false).first;
551
552 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
553 start_pos++;
554 }
555 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
556 end_pos++;
557 }
558 if (start_pos->first < end_pos->first) {
559 used_sectors.erase(start_pos, end_pos);
560 }
561}
562
563// Restores the given log_entry's data from dest -> source
564// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
565void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
566 log_entry* le, std::vector<char>& buffer) {
567 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
568 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
569 int count = (le->size - 1) / kSectorSize + 1;
570
571 if (checkCollision(used_sectors, le->source, le->source + count)) {
572 fsync(device_fd);
573 lseek64(device_fd, 0, SEEK_SET);
574 ls.count = index + 1;
575 ls.magic = kPartialRestoreMagic;
576 write(device_fd, &ls_buffer[0], ls.block_size);
577 fsync(device_fd);
578 used_sectors.clear();
579 used_sectors[0] = false;
580 }
581
582 markUsed(used_sectors, le->dest, le->dest + count);
583
584 if (index == 0 && ls.sequence != 0) {
585 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
586 if (next->magic == kMagic) {
587 next->magic = kPartialRestoreMagic;
588 }
589 }
590
591 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
592 write(device_fd, &buffer[0], le->size);
593
594 if (index == 0) {
595 fsync(device_fd);
596 }
597}
598
Paul Lawrenced41a9392019-01-22 14:31:43 -0800599// Read from the device
600// If we are validating, the read occurs as though the relocations had happened
Paul Lawrencea3594a62023-01-31 13:42:09 -0800601// returns the amount asked for or an empty buffer on error. Partial reads are considered a failure
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800602std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
603 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800604 if (!validating) {
605 std::vector<char> buffer(size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800606 off64_t offset = sector * kSectorSize;
607 if (lseek64(device_fd, offset, SEEK_SET) != offset) {
608 return std::vector<char>();
609 }
610 if (read(device_fd, &buffer[0], size) != static_cast<ssize_t>(size)) {
611 return std::vector<char>();
612 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800613 return buffer;
614 }
615
Paul Lawrence27691c22018-11-20 14:07:59 -0800616 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800617 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
618 auto relocation = --relocations.upper_bound(sector);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800619 off64_t offset = (sector + relocation->second - relocation->first) * kSectorSize;
620 if (lseek64(device_fd, offset, SEEK_SET) != offset) {
621 return std::vector<char>();
622 }
623 if (read(device_fd, &buffer[i], block_size) != static_cast<ssize_t>(block_size)) {
624 return std::vector<char>();
625 }
Paul Lawrenced41a9392019-01-22 14:31:43 -0800626 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800627
628 return buffer;
629}
630
Paul Lawrence4f13a902019-01-10 13:06:07 -0800631} // namespace
632
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800633Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800634 bool validating = true;
635 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800636 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700637
Paul Lawrence27691c22018-11-20 14:07:59 -0800638 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800639 Relocations relocations;
640 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800641 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700642
Paul Lawrence27691c22018-11-20 14:07:59 -0800643 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700644 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700645 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800646
Paul Lawrencef5077682019-01-18 10:28:34 -0800647 log_sector_v1_0 original_ls;
Paul Lawrencea3594a62023-01-31 13:42:09 -0800648 if (read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls)) !=
649 sizeof(original_ls)) {
650 return error(EINVAL, "Cannot read sector");
651 }
Daniel Rosenberg52985932019-03-01 22:01:22 -0800652 if (original_ls.magic == kPartialRestoreMagic) {
653 validating = false;
654 action = "Restoring";
655 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700656 return error(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700657 }
658
Paul Lawrencea3594a62023-01-31 13:42:09 -0800659 if (original_ls.block_size < sizeof(log_sector_v1_0)) {
660 return error(EINVAL, "Block size is invalid");
661 }
662
Paul Lawrence4f13a902019-01-10 13:06:07 -0800663 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700664
Paul Lawrence4f13a902019-01-10 13:06:07 -0800665 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800666 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
667 original_ls.block_size, original_ls.block_size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800668 if (ls_buffer.size() != original_ls.block_size) {
669 status = error(EINVAL, "Failed to read log sector");
670 break;
671 }
Daniel Rosenberg52985932019-03-01 22:01:22 -0800672 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
673
674 Used_Sectors used_sectors;
675 used_sectors[0] = false;
676
677 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700678 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800679 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700680 }
681
Paul Lawrence4f13a902019-01-10 13:06:07 -0800682 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700683 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800684 break;
685 }
686
Paul Lawrence27691c22018-11-20 14:07:59 -0800687 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700688 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
689 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800690 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700691 }
692
Paul Lawrencea3594a62023-01-31 13:42:09 -0800693 if (ls.header_size < sizeof(log_sector_v1_0) || ls.header_size > ls.block_size) {
694 status = error(EINVAL, "Log sector header size is invalid");
695 break;
696 }
697 if (ls.count < 1 || ls.count > (ls.block_size - ls.header_size) / sizeof(log_entry)) {
698 status = error(EINVAL, "Log sector count is invalid");
699 break;
700 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800701 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800702 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800703 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
704 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800705 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800706 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
707 << " to " << le->source << " with checksum " << std::hex
708 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800709
Paul Lawrencea3594a62023-01-31 13:42:09 -0800710 if (ls.block_size > UINT_MAX - le->size || le->size < ls.block_size) {
711 status = error(EINVAL, "log entry is invalid");
712 break;
713 }
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800714 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800715 ls.block_size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800716 if (buffer.size() != le->size) {
717 status = error(EINVAL, "Failed to read sector");
718 break;
719 }
Paul Lawrence4f13a902019-01-10 13:06:07 -0800720 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
721 for (size_t i = 0; i < le->size; i += ls.block_size) {
722 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800723 }
724
725 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700726 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800727 break;
728 }
729
Paul Lawrenced41a9392019-01-22 14:31:43 -0800730 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800731 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800732 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800733 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800734 restore_count++;
735 if (restore_limit && restore_count >= restore_limit) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700736 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800737 break;
738 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800739 }
740 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700741 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800742
743 if (!status.isOk()) {
744 if (!validating) {
745 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
746 return status;
747 }
748
749 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800750 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800751 original_ls.block_size, original_ls.block_size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800752 if (buffer.size() != original_ls.block_size) {
753 return error(EINVAL, "Failed to read original sector");
754 }
755
756 if (lseek64(device_fd, 0, SEEK_SET) != 0) {
757 return error(EINVAL, "Failed to seek to sector 0");
758 }
759 if (write(device_fd, &buffer[0], original_ls.block_size) !=
760 static_cast<ssize_t>(original_ls.block_size)) {
761 return error(EINVAL, "Failed to write original sector");
762 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800763 return Status::ok();
764 }
765
766 if (!validating) break;
767
768 validating = false;
769 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700770 }
771
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700772 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700773}
774
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700775Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700776 std::string oldContent, newContent;
777 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700778 struct stat st;
779 int result = stat(kMetadataCPFile.c_str(), &st);
780
781 // If the file doesn't exist, we aren't managing a checkpoint retry counter
782 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700783 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
784 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700785 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700786
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700787 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700788 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700789 if (retry > 0) {
790 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700791
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700792 newContent = std::to_string(retry);
793 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700794 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700795 }
796 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700797}
798
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100799void cp_resetCheckpoint() {
800 std::lock_guard<std::mutex> lock(isCheckpointingLock);
801 needsCheckpointWasCalled = false;
802}
803
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700804} // namespace vold
805} // namespace android