blob: 4766d794177e22996de503b084c96327091c44ea [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
Kelvin Zhangdec03ab2022-06-21 14:31:01 -070029#include <BootControlClient.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070030#include <android-base/file.h>
31#include <android-base/logging.h>
32#include <android-base/parseint.h>
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080033#include <android-base/properties.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070034#include <android-base/unique_fd.h>
35#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;
Tom Cherry4c5bde22019-01-29 14:34:01 -080050using android::fs_mgr::ReadFstabFromFile;
Kelvin Zhangdec03ab2022-06-21 14:31:01 -070051using android::hal::BootControlClient;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070052
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070053namespace android {
54namespace vold {
55
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070056namespace {
57const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
58
Paul Lawrence82b35052019-04-19 14:26:39 -070059binder::Status error(const std::string& msg) {
60 PLOG(ERROR) << msg;
61 return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str()));
62}
63
64binder::Status error(int error, const std::string& msg) {
65 LOG(ERROR) << msg;
66 return binder::Status::fromServiceSpecificError(error, String8(msg.c_str()));
67}
68
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070069bool setBowState(std::string const& block_device, std::string const& state) {
Paul Lawrence236e5e82019-06-25 14:44:33 -070070 std::string bow_device = fs_mgr_find_bow_device(block_device);
71 if (bow_device.empty()) return false;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070072
Paul Lawrence236e5e82019-06-25 14:44:33 -070073 if (!android::base::WriteStringToFile(state, bow_device + "/bow/state")) {
74 PLOG(ERROR) << "Failed to write to file " << bow_device + "/bow/state";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070075 return false;
76 }
77
78 return true;
79}
80
81} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070082
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080083Status cp_supportsCheckpoint(bool& result) {
84 result = false;
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080085
Tom Cherry4c5bde22019-01-29 14:34:01 -080086 for (const auto& entry : fstab_default) {
87 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080088 result = true;
89 return Status::ok();
90 }
91 }
92 return Status::ok();
93}
94
Paul Lawrencec5c79c52019-03-18 13:36:40 -070095Status cp_supportsBlockCheckpoint(bool& result) {
96 result = false;
97
98 for (const auto& entry : fstab_default) {
99 if (entry.fs_mgr_flags.checkpoint_blk) {
100 result = true;
101 return Status::ok();
102 }
103 }
104 return Status::ok();
105}
106
107Status cp_supportsFileCheckpoint(bool& result) {
108 result = false;
109
110 for (const auto& entry : fstab_default) {
111 if (entry.fs_mgr_flags.checkpoint_fs) {
112 result = true;
113 return Status::ok();
114 }
115 }
116 return Status::ok();
117}
118
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700119Status cp_startCheckpoint(int retry) {
Paul Lawrencec2a145f2019-05-15 09:42:04 -0700120 bool result;
121 if (!cp_supportsCheckpoint(result).isOk() || !result)
122 return error(ENOTSUP, "Checkpoints not supported");
123
Paul Lawrence82b35052019-04-19 14:26:39 -0700124 if (retry < -1) return error(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700125 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700126 if (retry == -1) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700127 auto module = BootControlClient::WaitForService();
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700128 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700129 std::string suffix = module->GetSuffix(module->GetCurrentSlot());
130 if (!suffix.empty()) content += " " + suffix;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700131 }
132 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700133 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700134 return error("Failed to write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700135 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700136}
137
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800138namespace {
139
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800140volatile bool isCheckpointing = false;
faqiang.zhudd20dc32021-07-19 12:27:37 +0800141volatile bool isBow = true;
Paul Lawrence1d57f682019-08-22 09:51:18 -0700142
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100143volatile bool needsCheckpointWasCalled = false;
144
145// Protects isCheckpointing, needsCheckpointWasCalled and code that makes decisions based on status
146// of isCheckpointing
Paul Lawrence1d57f682019-08-22 09:51:18 -0700147std::mutex isCheckpointingLock;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800148}
149
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700150Status cp_commitChanges() {
Paul Lawrence1d57f682019-08-22 09:51:18 -0700151 std::lock_guard<std::mutex> lock(isCheckpointingLock);
152
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800153 if (!isCheckpointing) {
154 return Status::ok();
155 }
Paul Lawrencea7972dc2019-06-12 12:03:01 -0700156 if (android::base::GetProperty("persist.vold.dont_commit_checkpoint", "0") == "1") {
157 LOG(WARNING)
158 << "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
159 return Status::ok();
160 }
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700161 auto module = BootControlClient::WaitForService();
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800162 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700163 auto cr = module->MarkBootSuccessful();
Paul Lawrence82b35052019-04-19 14:26:39 -0700164 if (!cr.success)
165 return error(EINVAL, "Error marking booted successfully: " + std::string(cr.errMsg));
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800166 LOG(INFO) << "Marked slot as booted successfully.";
Tianjie Xu09de0ff2019-11-15 14:05:29 -0800167 // Clears the warm reset flag for next reboot.
168 if (!SetProperty("ota.warm_reset", "0")) {
169 LOG(WARNING) << "Failed to reset the warm reset flag";
170 }
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700171 } else {
172 LOG(ERROR) << "Failed to get BootControl HAL, not marking slot as successful.";
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800173 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700174 // Must take action for list of mounted checkpointed things here
175 // To do this, we walk the list of mounted file systems.
176 // But we also need to get the matching fstab entries to see
177 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700178 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700179
Tom Cherry4c5bde22019-01-29 14:34:01 -0800180 Fstab mounts;
181 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700182 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800183 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700184
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700185 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800186 for (const auto& mount_rec : mounts) {
187 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700188 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700189
Tom Cherry4c5bde22019-01-29 14:34:01 -0800190 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
191 if (fstab_rec->fs_type == "f2fs") {
192 std::string options = mount_rec.fs_options + ",checkpoint=enable";
193 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800194 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700195 return error(EINVAL, "Failed to remount");
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800196 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700197 }
faqiang.zhudd20dc32021-07-19 12:27:37 +0800198 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk && isBow) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800199 if (!setBowState(mount_rec.blk_device, "2"))
Paul Lawrence82b35052019-04-19 14:26:39 -0700200 return error(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700201 }
202 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800203 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800204 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800205 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800206 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Paul Lawrence82b35052019-04-19 14:26:39 -0700207 return error(err_str.c_str());
208
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700209 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700210}
211
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700212namespace {
213void abort_metadata_file() {
214 std::string oldContent, newContent;
215 int retry = 0;
216 struct stat st;
217 int result = stat(kMetadataCPFile.c_str(), &st);
218
219 // If the file doesn't exist, we aren't managing a checkpoint retry counter
220 if (result != 0) return;
221 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
222 PLOG(ERROR) << "Failed to read checkpoint file";
223 return;
224 }
225 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
226
227 if (!android::base::ParseInt(retryContent, &retry)) {
228 PLOG(ERROR) << "Could not parse retry count";
229 return;
230 }
231 if (retry > 0) {
232 newContent = "0";
233 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
234 PLOG(ERROR) << "Could not write checkpoint file";
235 }
236}
237} // namespace
238
239void cp_abortChanges(const std::string& message, bool retry) {
240 if (!cp_needsCheckpoint()) return;
241 if (!retry) abort_metadata_file();
242 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700243}
244
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700245bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700246 std::string content;
247 bool ret;
248
249 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700250 if (ret) {
251 if (content == "0") return true;
252 if (content.substr(0, 3) == "-1 ") {
253 std::string oldSuffix = content.substr(3);
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700254 auto module = BootControlClient::WaitForService();
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700255 std::string newSuffix;
256
257 if (module) {
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700258 newSuffix = module->GetSuffix(module->GetCurrentSlot());
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700259 if (oldSuffix == newSuffix) return true;
260 }
261 }
262 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700263 return false;
264}
265
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700266bool cp_needsCheckpoint() {
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100267 std::lock_guard<std::mutex> lock(isCheckpointingLock);
268
Paul Lawrence9a6d1f72019-08-26 15:09:41 -0700269 // Make sure we only return true during boot. See b/138952436 for discussion
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100270 if (needsCheckpointWasCalled) return isCheckpointing;
271 needsCheckpointWasCalled = true;
Paul Lawrence9a6d1f72019-08-26 15:09:41 -0700272
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700273 bool ret;
274 std::string content;
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700275 auto module = BootControlClient::WaitForService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700276
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700277 if (isCheckpointing) return isCheckpointing;
Kelvin Zhangdec03ab2022-06-21 14:31:01 -0700278 // In case of INVALID slot or other failures, we do not perform checkpoint.
279 if (module && !module->IsSlotMarkedSuccessful(module->GetCurrentSlot()).value_or(true)) {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800280 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700281 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800282 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700283 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800284 if (ret) {
285 ret = content != "0";
286 isCheckpointing = ret;
287 return ret;
288 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700289 return false;
290}
291
David Anderson23850d32020-06-10 23:51:17 -0700292bool cp_isCheckpointing() {
293 return isCheckpointing;
294}
295
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800296namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700297const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
298const uint32_t msleeptime_default = 1000; // 1 s
299const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800300
301const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
302const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
303
304const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
305const bool commit_on_full_default = true;
306
307static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
308 struct statvfs data;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700309 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900310 uint64_t min_free_bytes =
311 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800312 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
313
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700314 struct timespec req;
315 req.tv_sec = msleeptime / 1000;
316 msleeptime %= 1000;
317 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800318 while (isCheckpointing) {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700319 uint64_t free_bytes = 0;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800320 if (is_fs_cp) {
321 statvfs(mnt_pnt.c_str(), &data);
Qilin Tan5d0aaaf2020-01-02 19:07:47 +0800322 free_bytes = ((uint64_t) data.f_bavail) * data.f_frsize;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800323 } else {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700324 std::string bow_device = fs_mgr_find_bow_device(blk_device);
325 if (!bow_device.empty()) {
326 std::string content;
327 if (android::base::ReadFileToString(bow_device + "/bow/free", &content)) {
Qilin Tan5d0aaaf2020-01-02 19:07:47 +0800328 free_bytes = std::strtoull(content.c_str(), NULL, 10);
Paul Lawrence236e5e82019-06-25 14:44:33 -0700329 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800330 }
331 }
332 if (free_bytes < min_free_bytes) {
333 if (commit_on_full) {
334 LOG(INFO) << "Low space for checkpointing. Commiting changes";
335 cp_commitChanges();
336 break;
337 } else {
338 LOG(INFO) << "Low space for checkpointing. Rebooting";
339 cp_abortChanges("checkpoint,low_space", false);
340 break;
341 }
342 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700343 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800344 }
345}
346
347} // namespace
348
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700349Status cp_prepareCheckpoint() {
Paul Lawrence4c757fb2019-10-23 09:36:18 -0700350 // Log to notify CTS - see b/137924328 for context
351 LOG(INFO) << "cp_prepareCheckpoint called";
Paul Lawrence1d57f682019-08-22 09:51:18 -0700352 std::lock_guard<std::mutex> lock(isCheckpointingLock);
Paul Lawrencedb086942019-02-19 14:18:54 -0800353 if (!isCheckpointing) {
354 return Status::ok();
355 }
356
Tom Cherry4c5bde22019-01-29 14:34:01 -0800357 Fstab mounts;
358 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700359 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800360 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700361
Tom Cherry4c5bde22019-01-29 14:34:01 -0800362 for (const auto& mount_rec : mounts) {
363 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700364 if (!fstab_rec) continue;
365
Tom Cherry4c5bde22019-01-29 14:34:01 -0800366 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700367 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800368 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900369 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800370 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700371 continue;
372 }
373
374 struct fstrim_range range = {};
375 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700376 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700377 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800378 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700379 continue;
380 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700381 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
382 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
383 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700384
faqiang.zhudd20dc32021-07-19 12:27:37 +0800385 isBow &= setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700386 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800387 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
388 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700389 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800390 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
391 .detach();
392 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700393 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700394 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700395}
396
397namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700398const int kSectorSize = 512;
399
400typedef uint64_t sector_t;
401
402struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800403 sector_t source; // in sectors of size kSectorSize
404 sector_t dest; // in sectors of size kSectorSize
405 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700406 uint32_t checksum;
407} __attribute__((packed));
408
Paul Lawrencef5077682019-01-18 10:28:34 -0800409struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700410 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800411 uint16_t header_version;
412 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800413 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700414 uint32_t count;
415 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800416 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700417} __attribute__((packed));
418
419// MAGIC is BOW in ascii
420const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800421// Partially restored MAGIC is WOB in ascii
422const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700423
424void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
425 static uint32_t table[0x100] = {
426 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
427 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
428 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
429 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
430 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
431 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
432 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
433 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
434 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
435 0xB6662D3D,
436
437 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
438 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
439 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
440 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
441 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
442 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
443 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
444 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
445 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
446 0xC0BA6CAD,
447
448 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
449 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
450 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
451 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
452 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
453 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
454 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
455 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
456 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
457 0x5BDEAE1D,
458
459 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
460 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
461 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
462 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
463 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
464 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
465 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
466 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
467 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
468 0x2D02EF8D};
469
470 for (size_t i = 0; i < n_bytes; ++i) {
471 *crc ^= ((uint8_t*)data)[i];
472 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
473 }
474}
475
Paul Lawrenced41a9392019-01-22 14:31:43 -0800476// A map of relocations.
477// The map must be initialized so that relocations[0] = 0
478// During restore, we replay the log records in reverse, copying from dest to
479// source
480// To validate, we must be able to read the 'dest' sectors as though they had
481// been copied but without actually copying. This map represents how the sectors
482// would have been moved. To read a sector s, find the index <= s and read
483// relocations[index] + s - index
484typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800485
Paul Lawrenced41a9392019-01-22 14:31:43 -0800486void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
487 // Find first one we're equal to or greater than
488 auto s = --relocations.upper_bound(source);
489
490 // Take slice
491 Relocations slice;
492 slice[dest] = source - s->first + s->second;
493 ++s;
494
495 // Add rest of elements
496 for (; s != relocations.end() && s->first < source + count; ++s)
497 slice[dest - source + s->first] = s->second;
498
499 // Split range at end of dest
500 auto dest_end = --relocations.upper_bound(dest + count);
501 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
502
503 // Remove all elements in [dest, dest + count)
504 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
505
506 // Add new elements
507 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800508}
509
Daniel Rosenberg52985932019-03-01 22:01:22 -0800510// A map of sectors that have been written to.
511// The final entry must always be False.
512// When we restart the restore after an interruption, we must take care that
513// when we copy from dest to source, that the block we copy to was not
514// previously copied from.
515// i e. A->B C->A; If we replay this sequence, we end up copying C->B
516// We must save our partial result whenever we finish a page, or when we copy
517// to a location that was copied from earlier (our source is an earlier dest)
518typedef std::map<sector_t, bool> Used_Sectors;
519
520bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
521 auto second_overlap = used_sectors.upper_bound(start);
522 auto first_overlap = --second_overlap;
523
524 if (first_overlap->second) {
525 return true;
526 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
527 return true;
528 }
529 return false;
530}
531
532void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
533 auto start_pos = used_sectors.insert_or_assign(start, true).first;
534 auto end_pos = used_sectors.insert_or_assign(end, false).first;
535
536 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
537 start_pos++;
538 }
539 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
540 end_pos++;
541 }
542 if (start_pos->first < end_pos->first) {
543 used_sectors.erase(start_pos, end_pos);
544 }
545}
546
547// Restores the given log_entry's data from dest -> source
548// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
549void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
550 log_entry* le, std::vector<char>& buffer) {
551 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
552 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
553 int count = (le->size - 1) / kSectorSize + 1;
554
555 if (checkCollision(used_sectors, le->source, le->source + count)) {
556 fsync(device_fd);
557 lseek64(device_fd, 0, SEEK_SET);
558 ls.count = index + 1;
559 ls.magic = kPartialRestoreMagic;
560 write(device_fd, &ls_buffer[0], ls.block_size);
561 fsync(device_fd);
562 used_sectors.clear();
563 used_sectors[0] = false;
564 }
565
566 markUsed(used_sectors, le->dest, le->dest + count);
567
568 if (index == 0 && ls.sequence != 0) {
569 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
570 if (next->magic == kMagic) {
571 next->magic = kPartialRestoreMagic;
572 }
573 }
574
575 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
576 write(device_fd, &buffer[0], le->size);
577
578 if (index == 0) {
579 fsync(device_fd);
580 }
581}
582
Paul Lawrenced41a9392019-01-22 14:31:43 -0800583// Read from the device
584// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800585std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
586 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800587 if (!validating) {
588 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800589 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
590 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800591 return buffer;
592 }
593
Paul Lawrence27691c22018-11-20 14:07:59 -0800594 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800595 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
596 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800597 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
598 SEEK_SET);
599 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800600 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800601
602 return buffer;
603}
604
Paul Lawrence4f13a902019-01-10 13:06:07 -0800605} // namespace
606
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800607Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800608 bool validating = true;
609 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800610 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700611
Paul Lawrence27691c22018-11-20 14:07:59 -0800612 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800613 Relocations relocations;
614 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800615 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700616
Paul Lawrence27691c22018-11-20 14:07:59 -0800617 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700618 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700619 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800620
Paul Lawrencef5077682019-01-18 10:28:34 -0800621 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800622 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800623 if (original_ls.magic == kPartialRestoreMagic) {
624 validating = false;
625 action = "Restoring";
626 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700627 return error(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700628 }
629
Paul Lawrence4f13a902019-01-10 13:06:07 -0800630 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700631
Paul Lawrence4f13a902019-01-10 13:06:07 -0800632 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800633 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
634 original_ls.block_size, original_ls.block_size);
635 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
636
637 Used_Sectors used_sectors;
638 used_sectors[0] = false;
639
640 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700641 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800642 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700643 }
644
Paul Lawrence4f13a902019-01-10 13:06:07 -0800645 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700646 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800647 break;
648 }
649
Paul Lawrence27691c22018-11-20 14:07:59 -0800650 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700651 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
652 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800653 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700654 }
655
Paul Lawrence27691c22018-11-20 14:07:59 -0800656 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800657 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800658 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
659 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800660 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800661 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
662 << " to " << le->source << " with checksum " << std::hex
663 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800664
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800665 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800666 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800667 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
668 for (size_t i = 0; i < le->size; i += ls.block_size) {
669 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800670 }
671
672 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700673 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800674 break;
675 }
676
Paul Lawrenced41a9392019-01-22 14:31:43 -0800677 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800678 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800679 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800680 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800681 restore_count++;
682 if (restore_limit && restore_count >= restore_limit) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700683 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800684 break;
685 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800686 }
687 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700688 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800689
690 if (!status.isOk()) {
691 if (!validating) {
692 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
693 return status;
694 }
695
696 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800697 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800698 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800699 lseek64(device_fd, 0, SEEK_SET);
700 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800701 return Status::ok();
702 }
703
704 if (!validating) break;
705
706 validating = false;
707 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700708 }
709
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700710 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700711}
712
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700713Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700714 std::string oldContent, newContent;
715 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700716 struct stat st;
717 int result = stat(kMetadataCPFile.c_str(), &st);
718
719 // If the file doesn't exist, we aren't managing a checkpoint retry counter
720 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700721 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
722 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700723 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700724
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700725 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700726 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700727 if (retry > 0) {
728 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700729
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700730 newContent = std::to_string(retry);
731 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700732 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700733 }
734 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700735}
736
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100737void cp_resetCheckpoint() {
738 std::lock_guard<std::mutex> lock(isCheckpointingLock);
739 needsCheckpointWasCalled = false;
740}
741
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700742} // namespace vold
743} // namespace android