blob: 7ff776688d4f749d5a2fcab2f85445cd3d9e7675 [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
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800600std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
601 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800602 if (!validating) {
603 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800604 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
605 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800606 return buffer;
607 }
608
Paul Lawrence27691c22018-11-20 14:07:59 -0800609 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800610 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
611 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800612 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
613 SEEK_SET);
614 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800615 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800616
617 return buffer;
618}
619
Paul Lawrence4f13a902019-01-10 13:06:07 -0800620} // namespace
621
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800622Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800623 bool validating = true;
624 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800625 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700626
Paul Lawrence27691c22018-11-20 14:07:59 -0800627 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800628 Relocations relocations;
629 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800630 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700631
Paul Lawrence27691c22018-11-20 14:07:59 -0800632 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700633 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700634 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800635
Paul Lawrencef5077682019-01-18 10:28:34 -0800636 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800637 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800638 if (original_ls.magic == kPartialRestoreMagic) {
639 validating = false;
640 action = "Restoring";
641 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700642 return error(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700643 }
644
Paul Lawrence4f13a902019-01-10 13:06:07 -0800645 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700646
Paul Lawrence4f13a902019-01-10 13:06:07 -0800647 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800648 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
649 original_ls.block_size, original_ls.block_size);
650 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
651
652 Used_Sectors used_sectors;
653 used_sectors[0] = false;
654
655 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700656 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800657 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700658 }
659
Paul Lawrence4f13a902019-01-10 13:06:07 -0800660 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700661 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800662 break;
663 }
664
Paul Lawrence27691c22018-11-20 14:07:59 -0800665 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700666 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
667 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800668 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700669 }
670
Paul Lawrence27691c22018-11-20 14:07:59 -0800671 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800672 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800673 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
674 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800675 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800676 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
677 << " to " << le->source << " with checksum " << std::hex
678 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800679
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800680 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800681 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800682 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
683 for (size_t i = 0; i < le->size; i += ls.block_size) {
684 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800685 }
686
687 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700688 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800689 break;
690 }
691
Paul Lawrenced41a9392019-01-22 14:31:43 -0800692 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800693 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800694 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800695 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800696 restore_count++;
697 if (restore_limit && restore_count >= restore_limit) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700698 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800699 break;
700 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800701 }
702 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700703 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800704
705 if (!status.isOk()) {
706 if (!validating) {
707 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
708 return status;
709 }
710
711 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800712 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800713 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800714 lseek64(device_fd, 0, SEEK_SET);
715 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800716 return Status::ok();
717 }
718
719 if (!validating) break;
720
721 validating = false;
722 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700723 }
724
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700725 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700726}
727
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700728Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700729 std::string oldContent, newContent;
730 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700731 struct stat st;
732 int result = stat(kMetadataCPFile.c_str(), &st);
733
734 // If the file doesn't exist, we aren't managing a checkpoint retry counter
735 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700736 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
737 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700738 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700739
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700740 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700741 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700742 if (retry > 0) {
743 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700744
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700745 newContent = std::to_string(retry);
746 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700747 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700748 }
749 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700750}
751
Nikita Ioffea5798fc2019-10-11 16:38:21 +0100752void cp_resetCheckpoint() {
753 std::lock_guard<std::mutex> lock(isCheckpointingLock);
754 needsCheckpointWasCalled = false;
755}
756
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700757} // namespace vold
758} // namespace android