blob: eca49ef59059580ce6f74897d549c31ddc7a4c41 [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) {
201 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700202 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700203
Tom Cherry4c5bde22019-01-29 14:34:01 -0800204 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
205 if (fstab_rec->fs_type == "f2fs") {
206 std::string options = mount_rec.fs_options + ",checkpoint=enable";
207 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800208 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700209 return error(EINVAL, "Failed to remount");
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800210 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700211 }
faqiang.zhudd20dc32021-07-19 12:27:37 +0800212 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk && isBow) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800213 if (!setBowState(mount_rec.blk_device, "2"))
Paul Lawrence82b35052019-04-19 14:26:39 -0700214 return error(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700215 }
216 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800217 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800218 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800219 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800220 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Paul Lawrence82b35052019-04-19 14:26:39 -0700221 return error(err_str.c_str());
222
Eric Biggersb615f3b2022-11-09 05:48:45 +0000223 std::thread(DoCheckpointCommittedWork).detach();
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700224 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700225}
226
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700227namespace {
228void abort_metadata_file() {
229 std::string oldContent, newContent;
230 int retry = 0;
231 struct stat st;
232 int result = stat(kMetadataCPFile.c_str(), &st);
233
234 // If the file doesn't exist, we aren't managing a checkpoint retry counter
235 if (result != 0) return;
236 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
237 PLOG(ERROR) << "Failed to read checkpoint file";
238 return;
239 }
240 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
241
242 if (!android::base::ParseInt(retryContent, &retry)) {
243 PLOG(ERROR) << "Could not parse retry count";
244 return;
245 }
246 if (retry > 0) {
247 newContent = "0";
248 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
249 PLOG(ERROR) << "Could not write checkpoint file";
250 }
251}
252} // namespace
253
254void cp_abortChanges(const std::string& message, bool retry) {
255 if (!cp_needsCheckpoint()) return;
256 if (!retry) abort_metadata_file();
257 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700258}
259
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700260bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700261 std::string content;
262 bool ret;
263
264 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700265 if (ret) {
266 if (content == "0") return true;
267 if (content.substr(0, 3) == "-1 ") {
268 std::string oldSuffix = content.substr(3);
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700269 auto module = BootControlClient::WaitForService();
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700270 std::string newSuffix;
271
272 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700273 newSuffix = module->GetSuffix(module->GetCurrentSlot());
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700274 if (oldSuffix == newSuffix) return true;
275 }
276 }
277 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700278 return false;
279}
280
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700281bool cp_needsCheckpoint() {
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100282 std::lock_guard<std::mutex> lock(isCheckpointingLock);
283
Paul Lawrence9a6d1f72019-08-26 15:09:41 -0700284 // Make sure we only return true during boot. See b/138952436 for discussion
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100285 if (needsCheckpointWasCalled) return isCheckpointing;
286 needsCheckpointWasCalled = true;
Paul Lawrence9a6d1f72019-08-26 15:09:41 -0700287
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700288 bool ret;
289 std::string content;
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700290 auto module = BootControlClient::WaitForService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700291
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700292 if (isCheckpointing) return isCheckpointing;
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700293 // In case of INVALID slot or other failures, we do not perform checkpoint.
294 if (module && !module->IsSlotMarkedSuccessful(module->GetCurrentSlot()).value_or(true)) {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800295 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700296 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800297 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700298 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800299 if (ret) {
300 ret = content != "0";
301 isCheckpointing = ret;
302 return ret;
303 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700304 return false;
305}
306
David Anderson23850d32020-06-10 23:51:17 -0700307bool cp_isCheckpointing() {
308 return isCheckpointing;
309}
310
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800311namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700312const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
313const uint32_t msleeptime_default = 1000; // 1 s
314const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800315
316const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
317const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
318
319const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
320const bool commit_on_full_default = true;
321
322static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
323 struct statvfs data;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700324 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900325 uint64_t min_free_bytes =
326 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800327 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
328
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700329 struct timespec req;
330 req.tv_sec = msleeptime / 1000;
331 msleeptime %= 1000;
332 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800333 while (isCheckpointing) {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700334 uint64_t free_bytes = 0;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800335 if (is_fs_cp) {
336 statvfs(mnt_pnt.c_str(), &data);
Qilin Tan5d0aaaf2020-01-02 19:07:47 +0800337 free_bytes = ((uint64_t) data.f_bavail) * data.f_frsize;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800338 } else {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700339 std::string bow_device = fs_mgr_find_bow_device(blk_device);
340 if (!bow_device.empty()) {
341 std::string content;
342 if (android::base::ReadFileToString(bow_device + "/bow/free", &content)) {
Qilin Tan5d0aaaf2020-01-02 19:07:47 +0800343 free_bytes = std::strtoull(content.c_str(), NULL, 10);
Paul Lawrence236e5e82019-06-25 14:44:33 -0700344 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800345 }
346 }
347 if (free_bytes < min_free_bytes) {
348 if (commit_on_full) {
349 LOG(INFO) << "Low space for checkpointing. Commiting changes";
350 cp_commitChanges();
351 break;
352 } else {
353 LOG(INFO) << "Low space for checkpointing. Rebooting";
354 cp_abortChanges("checkpoint,low_space", false);
355 break;
356 }
357 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700358 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800359 }
360}
361
362} // namespace
363
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700364Status cp_prepareCheckpoint() {
Paul Lawrence4c757fb2019-10-23 09:36:18 -0700365 // Log to notify CTS - see b/137924328 for context
366 LOG(INFO) << "cp_prepareCheckpoint called";
Paul Lawrence1d57f682019-08-22 09:51:18 -0700367 std::lock_guard<std::mutex> lock(isCheckpointingLock);
Paul Lawrencedb086942019-02-19 14:18:54 -0800368 if (!isCheckpointing) {
369 return Status::ok();
370 }
371
Tom Cherry4c5bde22019-01-29 14:34:01 -0800372 Fstab mounts;
373 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700374 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800375 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700376
Tom Cherry4c5bde22019-01-29 14:34:01 -0800377 for (const auto& mount_rec : mounts) {
378 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700379 if (!fstab_rec) continue;
380
Tom Cherry4c5bde22019-01-29 14:34:01 -0800381 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700382 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800383 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900384 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800385 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700386 continue;
387 }
388
389 struct fstrim_range range = {};
390 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700391 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700392 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800393 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700394 continue;
395 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700396 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
397 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
398 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700399
faqiang.zhudd20dc32021-07-19 12:27:37 +0800400 isBow &= setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700401 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800402 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
403 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700404 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800405 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
406 .detach();
407 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700408 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700409 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700410}
411
412namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700413const int kSectorSize = 512;
414
415typedef uint64_t sector_t;
416
417struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800418 sector_t source; // in sectors of size kSectorSize
419 sector_t dest; // in sectors of size kSectorSize
420 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700421 uint32_t checksum;
422} __attribute__((packed));
423
Paul Lawrencef5077682019-01-18 10:28:34 -0800424struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700425 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800426 uint16_t header_version;
427 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800428 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700429 uint32_t count;
430 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800431 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700432} __attribute__((packed));
433
434// MAGIC is BOW in ascii
435const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800436// Partially restored MAGIC is WOB in ascii
437const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700438
439void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
440 static uint32_t table[0x100] = {
441 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
442 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
443 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
444 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
445 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
446 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
447 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
448 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
449 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
450 0xB6662D3D,
451
452 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
453 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
454 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
455 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
456 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
457 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
458 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
459 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
460 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
461 0xC0BA6CAD,
462
463 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
464 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
465 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
466 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
467 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
468 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
469 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
470 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
471 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
472 0x5BDEAE1D,
473
474 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
475 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
476 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
477 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
478 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
479 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
480 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
481 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
482 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
483 0x2D02EF8D};
484
485 for (size_t i = 0; i < n_bytes; ++i) {
486 *crc ^= ((uint8_t*)data)[i];
487 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
488 }
489}
490
Paul Lawrenced41a9392019-01-22 14:31:43 -0800491// A map of relocations.
492// The map must be initialized so that relocations[0] = 0
493// During restore, we replay the log records in reverse, copying from dest to
494// source
495// To validate, we must be able to read the 'dest' sectors as though they had
496// been copied but without actually copying. This map represents how the sectors
497// would have been moved. To read a sector s, find the index <= s and read
498// relocations[index] + s - index
499typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800500
Paul Lawrenced41a9392019-01-22 14:31:43 -0800501void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
502 // Find first one we're equal to or greater than
503 auto s = --relocations.upper_bound(source);
504
505 // Take slice
506 Relocations slice;
507 slice[dest] = source - s->first + s->second;
508 ++s;
509
510 // Add rest of elements
511 for (; s != relocations.end() && s->first < source + count; ++s)
512 slice[dest - source + s->first] = s->second;
513
514 // Split range at end of dest
515 auto dest_end = --relocations.upper_bound(dest + count);
516 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
517
518 // Remove all elements in [dest, dest + count)
519 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
520
521 // Add new elements
522 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800523}
524
Daniel Rosenberg52985932019-03-01 22:01:22 -0800525// A map of sectors that have been written to.
526// The final entry must always be False.
527// When we restart the restore after an interruption, we must take care that
528// when we copy from dest to source, that the block we copy to was not
529// previously copied from.
530// i e. A->B C->A; If we replay this sequence, we end up copying C->B
531// We must save our partial result whenever we finish a page, or when we copy
532// to a location that was copied from earlier (our source is an earlier dest)
533typedef std::map<sector_t, bool> Used_Sectors;
534
535bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
536 auto second_overlap = used_sectors.upper_bound(start);
537 auto first_overlap = --second_overlap;
538
539 if (first_overlap->second) {
540 return true;
541 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
542 return true;
543 }
544 return false;
545}
546
547void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
548 auto start_pos = used_sectors.insert_or_assign(start, true).first;
549 auto end_pos = used_sectors.insert_or_assign(end, false).first;
550
551 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
552 start_pos++;
553 }
554 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
555 end_pos++;
556 }
557 if (start_pos->first < end_pos->first) {
558 used_sectors.erase(start_pos, end_pos);
559 }
560}
561
562// Restores the given log_entry's data from dest -> source
563// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
564void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
565 log_entry* le, std::vector<char>& buffer) {
566 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
567 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
568 int count = (le->size - 1) / kSectorSize + 1;
569
570 if (checkCollision(used_sectors, le->source, le->source + count)) {
571 fsync(device_fd);
572 lseek64(device_fd, 0, SEEK_SET);
573 ls.count = index + 1;
574 ls.magic = kPartialRestoreMagic;
575 write(device_fd, &ls_buffer[0], ls.block_size);
576 fsync(device_fd);
577 used_sectors.clear();
578 used_sectors[0] = false;
579 }
580
581 markUsed(used_sectors, le->dest, le->dest + count);
582
583 if (index == 0 && ls.sequence != 0) {
584 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
585 if (next->magic == kMagic) {
586 next->magic = kPartialRestoreMagic;
587 }
588 }
589
590 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
591 write(device_fd, &buffer[0], le->size);
592
593 if (index == 0) {
594 fsync(device_fd);
595 }
596}
597
Paul Lawrenced41a9392019-01-22 14:31:43 -0800598// Read from the device
599// If we are validating, the read occurs as though the relocations had happened
Paul Lawrencea3594a62023-01-31 13:42:09 -0800600// returns the amount asked for or an empty buffer on error. Partial reads are considered a failure
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800601std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
602 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800603 if (!validating) {
604 std::vector<char> buffer(size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800605 off64_t offset = sector * kSectorSize;
606 if (lseek64(device_fd, offset, SEEK_SET) != offset) {
607 return std::vector<char>();
608 }
609 if (read(device_fd, &buffer[0], size) != static_cast<ssize_t>(size)) {
610 return std::vector<char>();
611 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800612 return buffer;
613 }
614
Paul Lawrence27691c22018-11-20 14:07:59 -0800615 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800616 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
617 auto relocation = --relocations.upper_bound(sector);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800618 off64_t offset = (sector + relocation->second - relocation->first) * kSectorSize;
619 if (lseek64(device_fd, offset, SEEK_SET) != offset) {
620 return std::vector<char>();
621 }
622 if (read(device_fd, &buffer[i], block_size) != static_cast<ssize_t>(block_size)) {
623 return std::vector<char>();
624 }
Paul Lawrenced41a9392019-01-22 14:31:43 -0800625 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800626
627 return buffer;
628}
629
Paul Lawrence4f13a902019-01-10 13:06:07 -0800630} // namespace
631
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800632Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800633 bool validating = true;
634 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800635 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700636
Paul Lawrence27691c22018-11-20 14:07:59 -0800637 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800638 Relocations relocations;
639 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800640 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700641
Paul Lawrence27691c22018-11-20 14:07:59 -0800642 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700643 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700644 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800645
Paul Lawrencef5077682019-01-18 10:28:34 -0800646 log_sector_v1_0 original_ls;
Paul Lawrencea3594a62023-01-31 13:42:09 -0800647 if (read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls)) !=
648 sizeof(original_ls)) {
649 return error(EINVAL, "Cannot read sector");
650 }
Daniel Rosenberg52985932019-03-01 22:01:22 -0800651 if (original_ls.magic == kPartialRestoreMagic) {
652 validating = false;
653 action = "Restoring";
654 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700655 return error(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700656 }
657
Paul Lawrencea3594a62023-01-31 13:42:09 -0800658 if (original_ls.block_size < sizeof(log_sector_v1_0)) {
659 return error(EINVAL, "Block size is invalid");
660 }
661
Paul Lawrence4f13a902019-01-10 13:06:07 -0800662 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700663
Paul Lawrence4f13a902019-01-10 13:06:07 -0800664 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800665 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
666 original_ls.block_size, original_ls.block_size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800667 if (ls_buffer.size() != original_ls.block_size) {
668 status = error(EINVAL, "Failed to read log sector");
669 break;
670 }
Daniel Rosenberg52985932019-03-01 22:01:22 -0800671 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
672
673 Used_Sectors used_sectors;
674 used_sectors[0] = false;
675
676 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700677 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800678 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700679 }
680
Paul Lawrence4f13a902019-01-10 13:06:07 -0800681 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700682 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800683 break;
684 }
685
Paul Lawrence27691c22018-11-20 14:07:59 -0800686 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700687 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
688 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800689 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700690 }
691
Paul Lawrencea3594a62023-01-31 13:42:09 -0800692 if (ls.header_size < sizeof(log_sector_v1_0) || ls.header_size > ls.block_size) {
693 status = error(EINVAL, "Log sector header size is invalid");
694 break;
695 }
696 if (ls.count < 1 || ls.count > (ls.block_size - ls.header_size) / sizeof(log_entry)) {
697 status = error(EINVAL, "Log sector count is invalid");
698 break;
699 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800700 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800701 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800702 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
703 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800704 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800705 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
706 << " to " << le->source << " with checksum " << std::hex
707 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800708
Paul Lawrencea3594a62023-01-31 13:42:09 -0800709 if (ls.block_size > UINT_MAX - le->size || le->size < ls.block_size) {
710 status = error(EINVAL, "log entry is invalid");
711 break;
712 }
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800713 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800714 ls.block_size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800715 if (buffer.size() != le->size) {
716 status = error(EINVAL, "Failed to read sector");
717 break;
718 }
Paul Lawrence4f13a902019-01-10 13:06:07 -0800719 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
720 for (size_t i = 0; i < le->size; i += ls.block_size) {
721 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800722 }
723
724 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700725 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800726 break;
727 }
728
Paul Lawrenced41a9392019-01-22 14:31:43 -0800729 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800730 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800731 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800732 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800733 restore_count++;
734 if (restore_limit && restore_count >= restore_limit) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700735 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800736 break;
737 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800738 }
739 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700740 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800741
742 if (!status.isOk()) {
743 if (!validating) {
744 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
745 return status;
746 }
747
748 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800749 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800750 original_ls.block_size, original_ls.block_size);
Paul Lawrencea3594a62023-01-31 13:42:09 -0800751 if (buffer.size() != original_ls.block_size) {
752 return error(EINVAL, "Failed to read original sector");
753 }
754
755 if (lseek64(device_fd, 0, SEEK_SET) != 0) {
756 return error(EINVAL, "Failed to seek to sector 0");
757 }
758 if (write(device_fd, &buffer[0], original_ls.block_size) !=
759 static_cast<ssize_t>(original_ls.block_size)) {
760 return error(EINVAL, "Failed to write original sector");
761 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800762 return Status::ok();
763 }
764
765 if (!validating) break;
766
767 validating = false;
768 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700769 }
770
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700771 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700772}
773
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700774Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700775 std::string oldContent, newContent;
776 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700777 struct stat st;
778 int result = stat(kMetadataCPFile.c_str(), &st);
779
780 // If the file doesn't exist, we aren't managing a checkpoint retry counter
781 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700782 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
783 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700784 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700785
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700786 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700787 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700788 if (retry > 0) {
789 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700790
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700791 newContent = std::to_string(retry);
792 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700793 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700794 }
795 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700796}
797
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100798void cp_resetCheckpoint() {
799 std::lock_guard<std::mutex> lock(isCheckpointingLock);
800 needsCheckpointWasCalled = false;
801}
802
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700803} // namespace vold
804} // namespace android