blob: e5ef4a2110902dbac5662044a29d62ad47c94a6e [file] [log] [blame]
Daniel Rosenberg65f99c92018-08-28 01:58:49 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "Checkpoint"
18#include "Checkpoint.h"
Daniel Rosenberg253b44e2019-02-01 19:25:47 -080019#include "VoldUtil.h"
Sandeep Patilf8da61f2019-04-15 08:45:27 -070020#include "VolumeManager.h"
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070021
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070022#include <fstream>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070023#include <list>
Paul Lawrence20400892018-10-03 14:14:52 -070024#include <memory>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070025#include <string>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080026#include <thread>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070027#include <vector>
28
29#include <android-base/file.h>
30#include <android-base/logging.h>
31#include <android-base/parseint.h>
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080032#include <android-base/properties.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070033#include <android-base/unique_fd.h>
Daniel Rosenbergd3992492018-10-02 17:40:44 -070034#include <android/hardware/boot/1.0/IBootControl.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070035#include <cutils/android_reboot.h>
36#include <fcntl.h>
37#include <fs_mgr.h>
38#include <linux/fs.h>
39#include <mntent.h>
40#include <sys/mount.h>
41#include <sys/stat.h>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080042#include <sys/statvfs.h>
43#include <unistd.h>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070044
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080045using android::base::GetBoolProperty;
46using android::base::GetUintProperty;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080047using android::base::SetProperty;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070048using android::binder::Status;
Tom Cherry4c5bde22019-01-29 14:34:01 -080049using android::fs_mgr::Fstab;
50using android::fs_mgr::ReadDefaultFstab;
51using android::fs_mgr::ReadFstabFromFile;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070052using android::hardware::hidl_string;
53using android::hardware::boot::V1_0::BoolResult;
Daniel Rosenberg886915b2019-01-23 15:16:04 -080054using android::hardware::boot::V1_0::CommandResult;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070055using android::hardware::boot::V1_0::IBootControl;
56using android::hardware::boot::V1_0::Slot;
57
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070058namespace android {
59namespace vold {
60
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070061namespace {
62const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
63
Paul Lawrence82b35052019-04-19 14:26:39 -070064binder::Status error(const std::string& msg) {
65 PLOG(ERROR) << msg;
66 return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str()));
67}
68
69binder::Status error(int error, const std::string& msg) {
70 LOG(ERROR) << msg;
71 return binder::Status::fromServiceSpecificError(error, String8(msg.c_str()));
72}
73
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070074bool setBowState(std::string const& block_device, std::string const& state) {
Paul Lawrence236e5e82019-06-25 14:44:33 -070075 std::string bow_device = fs_mgr_find_bow_device(block_device);
76 if (bow_device.empty()) return false;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070077
Paul Lawrence236e5e82019-06-25 14:44:33 -070078 if (!android::base::WriteStringToFile(state, bow_device + "/bow/state")) {
79 PLOG(ERROR) << "Failed to write to file " << bow_device + "/bow/state";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070080 return false;
81 }
82
83 return true;
84}
85
86} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070087
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080088Status cp_supportsCheckpoint(bool& result) {
89 result = false;
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080090
Tom Cherry4c5bde22019-01-29 14:34:01 -080091 for (const auto& entry : fstab_default) {
92 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080093 result = true;
94 return Status::ok();
95 }
96 }
97 return Status::ok();
98}
99
Paul Lawrencec5c79c52019-03-18 13:36:40 -0700100Status cp_supportsBlockCheckpoint(bool& result) {
101 result = false;
102
103 for (const auto& entry : fstab_default) {
104 if (entry.fs_mgr_flags.checkpoint_blk) {
105 result = true;
106 return Status::ok();
107 }
108 }
109 return Status::ok();
110}
111
112Status cp_supportsFileCheckpoint(bool& result) {
113 result = false;
114
115 for (const auto& entry : fstab_default) {
116 if (entry.fs_mgr_flags.checkpoint_fs) {
117 result = true;
118 return Status::ok();
119 }
120 }
121 return Status::ok();
122}
123
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700124Status cp_startCheckpoint(int retry) {
Paul Lawrencec2a145f2019-05-15 09:42:04 -0700125 bool result;
126 if (!cp_supportsCheckpoint(result).isOk() || !result)
127 return error(ENOTSUP, "Checkpoints not supported");
128
Paul Lawrence82b35052019-04-19 14:26:39 -0700129 if (retry < -1) return error(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700130 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700131 if (retry == -1) {
132 sp<IBootControl> module = IBootControl::getService();
133 if (module) {
134 std::string suffix;
135 auto cb = [&suffix](hidl_string s) { suffix = s; };
136 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
137 }
138 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700139 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700140 return error("Failed to write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700141 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700142}
143
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800144namespace {
145
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800146volatile bool isCheckpointing = false;
Paul Lawrence1d57f682019-08-22 09:51:18 -0700147
148// Protects isCheckpointing and code that makes decisions based on status of
149// isCheckpointing
150std::mutex isCheckpointingLock;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800151}
152
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700153Status cp_commitChanges() {
Paul Lawrence1d57f682019-08-22 09:51:18 -0700154 std::lock_guard<std::mutex> lock(isCheckpointingLock);
155
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800156 if (!isCheckpointing) {
157 return Status::ok();
158 }
Paul Lawrencea7972dc2019-06-12 12:03:01 -0700159 if (android::base::GetProperty("persist.vold.dont_commit_checkpoint", "0") == "1") {
160 LOG(WARNING)
161 << "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
162 return Status::ok();
163 }
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800164 sp<IBootControl> module = IBootControl::getService();
165 if (module) {
166 CommandResult cr;
167 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
Paul Lawrence82b35052019-04-19 14:26:39 -0700168 if (!cr.success)
169 return error(EINVAL, "Error marking booted successfully: " + std::string(cr.errMsg));
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800170 LOG(INFO) << "Marked slot as booted successfully.";
171 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700172 // Must take action for list of mounted checkpointed things here
173 // To do this, we walk the list of mounted file systems.
174 // But we also need to get the matching fstab entries to see
175 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700176 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700177
Tom Cherry4c5bde22019-01-29 14:34:01 -0800178 Fstab mounts;
179 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700180 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800181 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700182
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700183 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800184 for (const auto& mount_rec : mounts) {
185 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700186 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700187
Tom Cherry4c5bde22019-01-29 14:34:01 -0800188 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
189 if (fstab_rec->fs_type == "f2fs") {
190 std::string options = mount_rec.fs_options + ",checkpoint=enable";
191 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800192 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700193 return error(EINVAL, "Failed to remount");
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800194 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700195 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800196 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
197 if (!setBowState(mount_rec.blk_device, "2"))
Paul Lawrence82b35052019-04-19 14:26:39 -0700198 return error(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700199 }
200 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800201 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800202 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800203 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800204 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Paul Lawrence82b35052019-04-19 14:26:39 -0700205 return error(err_str.c_str());
206
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700207 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700208}
209
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700210namespace {
211void abort_metadata_file() {
212 std::string oldContent, newContent;
213 int retry = 0;
214 struct stat st;
215 int result = stat(kMetadataCPFile.c_str(), &st);
216
217 // If the file doesn't exist, we aren't managing a checkpoint retry counter
218 if (result != 0) return;
219 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
220 PLOG(ERROR) << "Failed to read checkpoint file";
221 return;
222 }
223 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
224
225 if (!android::base::ParseInt(retryContent, &retry)) {
226 PLOG(ERROR) << "Could not parse retry count";
227 return;
228 }
229 if (retry > 0) {
230 newContent = "0";
231 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
232 PLOG(ERROR) << "Could not write checkpoint file";
233 }
234}
235} // namespace
236
237void cp_abortChanges(const std::string& message, bool retry) {
238 if (!cp_needsCheckpoint()) return;
239 if (!retry) abort_metadata_file();
240 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700241}
242
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700243bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700244 std::string content;
245 bool ret;
246
247 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700248 if (ret) {
249 if (content == "0") return true;
250 if (content.substr(0, 3) == "-1 ") {
251 std::string oldSuffix = content.substr(3);
252 sp<IBootControl> module = IBootControl::getService();
253 std::string newSuffix;
254
255 if (module) {
256 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
257 module->getSuffix(module->getCurrentSlot(), cb);
258 if (oldSuffix == newSuffix) return true;
259 }
260 }
261 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700262 return false;
263}
264
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700265bool cp_needsCheckpoint() {
Paul Lawrence9a6d1f72019-08-26 15:09:41 -0700266 // Make sure we only return true during boot. See b/138952436 for discussion
267 static bool called_once = false;
268 if (called_once) return isCheckpointing;
269 called_once = true;
270
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700271 bool ret;
272 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700273 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700274
Paul Lawrence1d57f682019-08-22 09:51:18 -0700275 std::lock_guard<std::mutex> lock(isCheckpointingLock);
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700276 if (isCheckpointing) return isCheckpointing;
277
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800278 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
279 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700280 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800281 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700282 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800283 if (ret) {
284 ret = content != "0";
285 isCheckpointing = ret;
286 return ret;
287 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700288 return false;
289}
290
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800291namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700292const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
293const uint32_t msleeptime_default = 1000; // 1 s
294const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800295
296const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
297const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
298
299const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
300const bool commit_on_full_default = true;
301
302static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
303 struct statvfs data;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700304 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900305 uint64_t min_free_bytes =
306 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800307 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
308
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700309 struct timespec req;
310 req.tv_sec = msleeptime / 1000;
311 msleeptime %= 1000;
312 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800313 while (isCheckpointing) {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700314 uint64_t free_bytes = 0;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800315 if (is_fs_cp) {
316 statvfs(mnt_pnt.c_str(), &data);
317 free_bytes = data.f_bavail * data.f_frsize;
318 } else {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700319 std::string bow_device = fs_mgr_find_bow_device(blk_device);
320 if (!bow_device.empty()) {
321 std::string content;
322 if (android::base::ReadFileToString(bow_device + "/bow/free", &content)) {
323 free_bytes = std::strtoul(content.c_str(), NULL, 10);
324 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800325 }
326 }
327 if (free_bytes < min_free_bytes) {
328 if (commit_on_full) {
329 LOG(INFO) << "Low space for checkpointing. Commiting changes";
330 cp_commitChanges();
331 break;
332 } else {
333 LOG(INFO) << "Low space for checkpointing. Rebooting";
334 cp_abortChanges("checkpoint,low_space", false);
335 break;
336 }
337 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700338 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800339 }
340}
341
342} // namespace
343
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700344Status cp_prepareCheckpoint() {
Paul Lawrence1d57f682019-08-22 09:51:18 -0700345 std::lock_guard<std::mutex> lock(isCheckpointingLock);
Paul Lawrencedb086942019-02-19 14:18:54 -0800346 if (!isCheckpointing) {
347 return Status::ok();
348 }
349
Tom Cherry4c5bde22019-01-29 14:34:01 -0800350 Fstab mounts;
351 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700352 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800353 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700354
Tom Cherry4c5bde22019-01-29 14:34:01 -0800355 for (const auto& mount_rec : mounts) {
356 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700357 if (!fstab_rec) continue;
358
Tom Cherry4c5bde22019-01-29 14:34:01 -0800359 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700360 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800361 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900362 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800363 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700364 continue;
365 }
366
367 struct fstrim_range range = {};
368 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700369 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700370 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800371 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700372 continue;
373 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700374 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
375 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
376 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700377
Tom Cherry4c5bde22019-01-29 14:34:01 -0800378 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700379 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800380 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
381 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700382 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800383 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
384 .detach();
385 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700386 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700387 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700388}
389
390namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700391const int kSectorSize = 512;
392
393typedef uint64_t sector_t;
394
395struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800396 sector_t source; // in sectors of size kSectorSize
397 sector_t dest; // in sectors of size kSectorSize
398 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700399 uint32_t checksum;
400} __attribute__((packed));
401
Paul Lawrencef5077682019-01-18 10:28:34 -0800402struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700403 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800404 uint16_t header_version;
405 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800406 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700407 uint32_t count;
408 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800409 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700410} __attribute__((packed));
411
412// MAGIC is BOW in ascii
413const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800414// Partially restored MAGIC is WOB in ascii
415const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700416
417void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
418 static uint32_t table[0x100] = {
419 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
420 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
421 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
422 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
423 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
424 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
425 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
426 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
427 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
428 0xB6662D3D,
429
430 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
431 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
432 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
433 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
434 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
435 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
436 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
437 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
438 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
439 0xC0BA6CAD,
440
441 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
442 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
443 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
444 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
445 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
446 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
447 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
448 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
449 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
450 0x5BDEAE1D,
451
452 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
453 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
454 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
455 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
456 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
457 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
458 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
459 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
460 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
461 0x2D02EF8D};
462
463 for (size_t i = 0; i < n_bytes; ++i) {
464 *crc ^= ((uint8_t*)data)[i];
465 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
466 }
467}
468
Paul Lawrenced41a9392019-01-22 14:31:43 -0800469// A map of relocations.
470// The map must be initialized so that relocations[0] = 0
471// During restore, we replay the log records in reverse, copying from dest to
472// source
473// To validate, we must be able to read the 'dest' sectors as though they had
474// been copied but without actually copying. This map represents how the sectors
475// would have been moved. To read a sector s, find the index <= s and read
476// relocations[index] + s - index
477typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800478
Paul Lawrenced41a9392019-01-22 14:31:43 -0800479void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
480 // Find first one we're equal to or greater than
481 auto s = --relocations.upper_bound(source);
482
483 // Take slice
484 Relocations slice;
485 slice[dest] = source - s->first + s->second;
486 ++s;
487
488 // Add rest of elements
489 for (; s != relocations.end() && s->first < source + count; ++s)
490 slice[dest - source + s->first] = s->second;
491
492 // Split range at end of dest
493 auto dest_end = --relocations.upper_bound(dest + count);
494 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
495
496 // Remove all elements in [dest, dest + count)
497 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
498
499 // Add new elements
500 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800501}
502
Daniel Rosenberg52985932019-03-01 22:01:22 -0800503// A map of sectors that have been written to.
504// The final entry must always be False.
505// When we restart the restore after an interruption, we must take care that
506// when we copy from dest to source, that the block we copy to was not
507// previously copied from.
508// i e. A->B C->A; If we replay this sequence, we end up copying C->B
509// We must save our partial result whenever we finish a page, or when we copy
510// to a location that was copied from earlier (our source is an earlier dest)
511typedef std::map<sector_t, bool> Used_Sectors;
512
513bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
514 auto second_overlap = used_sectors.upper_bound(start);
515 auto first_overlap = --second_overlap;
516
517 if (first_overlap->second) {
518 return true;
519 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
520 return true;
521 }
522 return false;
523}
524
525void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
526 auto start_pos = used_sectors.insert_or_assign(start, true).first;
527 auto end_pos = used_sectors.insert_or_assign(end, false).first;
528
529 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
530 start_pos++;
531 }
532 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
533 end_pos++;
534 }
535 if (start_pos->first < end_pos->first) {
536 used_sectors.erase(start_pos, end_pos);
537 }
538}
539
540// Restores the given log_entry's data from dest -> source
541// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
542void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
543 log_entry* le, std::vector<char>& buffer) {
544 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
545 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
546 int count = (le->size - 1) / kSectorSize + 1;
547
548 if (checkCollision(used_sectors, le->source, le->source + count)) {
549 fsync(device_fd);
550 lseek64(device_fd, 0, SEEK_SET);
551 ls.count = index + 1;
552 ls.magic = kPartialRestoreMagic;
553 write(device_fd, &ls_buffer[0], ls.block_size);
554 fsync(device_fd);
555 used_sectors.clear();
556 used_sectors[0] = false;
557 }
558
559 markUsed(used_sectors, le->dest, le->dest + count);
560
561 if (index == 0 && ls.sequence != 0) {
562 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
563 if (next->magic == kMagic) {
564 next->magic = kPartialRestoreMagic;
565 }
566 }
567
568 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
569 write(device_fd, &buffer[0], le->size);
570
571 if (index == 0) {
572 fsync(device_fd);
573 }
574}
575
Paul Lawrenced41a9392019-01-22 14:31:43 -0800576// Read from the device
577// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800578std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
579 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800580 if (!validating) {
581 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800582 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
583 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800584 return buffer;
585 }
586
Paul Lawrence27691c22018-11-20 14:07:59 -0800587 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800588 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
589 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800590 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
591 SEEK_SET);
592 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800593 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800594
595 return buffer;
596}
597
Paul Lawrence4f13a902019-01-10 13:06:07 -0800598} // namespace
599
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800600Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800601 bool validating = true;
602 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800603 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700604
Paul Lawrence27691c22018-11-20 14:07:59 -0800605 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800606 Relocations relocations;
607 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800608 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700609
Paul Lawrence27691c22018-11-20 14:07:59 -0800610 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700611 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700612 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800613
Paul Lawrencef5077682019-01-18 10:28:34 -0800614 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800615 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800616 if (original_ls.magic == kPartialRestoreMagic) {
617 validating = false;
618 action = "Restoring";
619 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700620 return error(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700621 }
622
Paul Lawrence4f13a902019-01-10 13:06:07 -0800623 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700624
Paul Lawrence4f13a902019-01-10 13:06:07 -0800625 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800626 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
627 original_ls.block_size, original_ls.block_size);
628 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
629
630 Used_Sectors used_sectors;
631 used_sectors[0] = false;
632
633 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700634 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800635 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700636 }
637
Paul Lawrence4f13a902019-01-10 13:06:07 -0800638 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700639 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800640 break;
641 }
642
Paul Lawrence27691c22018-11-20 14:07:59 -0800643 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700644 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
645 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800646 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700647 }
648
Paul Lawrence27691c22018-11-20 14:07:59 -0800649 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800650 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800651 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
652 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800653 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800654 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
655 << " to " << le->source << " with checksum " << std::hex
656 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800657
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800658 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800659 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800660 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
661 for (size_t i = 0; i < le->size; i += ls.block_size) {
662 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800663 }
664
665 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700666 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800667 break;
668 }
669
Paul Lawrenced41a9392019-01-22 14:31:43 -0800670 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800671 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800672 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800673 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800674 restore_count++;
675 if (restore_limit && restore_count >= restore_limit) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700676 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800677 break;
678 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800679 }
680 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700681 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800682
683 if (!status.isOk()) {
684 if (!validating) {
685 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
686 return status;
687 }
688
689 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800690 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800691 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800692 lseek64(device_fd, 0, SEEK_SET);
693 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800694 return Status::ok();
695 }
696
697 if (!validating) break;
698
699 validating = false;
700 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700701 }
702
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700703 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700704}
705
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700706Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700707 std::string oldContent, newContent;
708 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700709 struct stat st;
710 int result = stat(kMetadataCPFile.c_str(), &st);
711
712 // If the file doesn't exist, we aren't managing a checkpoint retry counter
713 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700714 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
715 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700716 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700717
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700718 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700719 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700720 if (retry > 0) {
721 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700722
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700723 newContent = std::to_string(retry);
724 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700725 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700726 }
727 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700728}
729
730} // namespace vold
731} // namespace android