blob: a2db4bd9ed80c55710f863a4a6b4089aa05c3bb3 [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() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700266 bool ret;
267 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700268 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700269
Paul Lawrence1d57f682019-08-22 09:51:18 -0700270 std::lock_guard<std::mutex> lock(isCheckpointingLock);
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700271 if (isCheckpointing) return isCheckpointing;
272
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800273 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
274 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700275 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800276 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700277 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800278 if (ret) {
279 ret = content != "0";
280 isCheckpointing = ret;
281 return ret;
282 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700283 return false;
284}
285
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800286namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700287const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
288const uint32_t msleeptime_default = 1000; // 1 s
289const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800290
291const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
292const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
293
294const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
295const bool commit_on_full_default = true;
296
297static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
298 struct statvfs data;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700299 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900300 uint64_t min_free_bytes =
301 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800302 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
303
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700304 struct timespec req;
305 req.tv_sec = msleeptime / 1000;
306 msleeptime %= 1000;
307 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800308 while (isCheckpointing) {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700309 uint64_t free_bytes = 0;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800310 if (is_fs_cp) {
311 statvfs(mnt_pnt.c_str(), &data);
312 free_bytes = data.f_bavail * data.f_frsize;
313 } else {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700314 std::string bow_device = fs_mgr_find_bow_device(blk_device);
315 if (!bow_device.empty()) {
316 std::string content;
317 if (android::base::ReadFileToString(bow_device + "/bow/free", &content)) {
318 free_bytes = std::strtoul(content.c_str(), NULL, 10);
319 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800320 }
321 }
322 if (free_bytes < min_free_bytes) {
323 if (commit_on_full) {
324 LOG(INFO) << "Low space for checkpointing. Commiting changes";
325 cp_commitChanges();
326 break;
327 } else {
328 LOG(INFO) << "Low space for checkpointing. Rebooting";
329 cp_abortChanges("checkpoint,low_space", false);
330 break;
331 }
332 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700333 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800334 }
335}
336
337} // namespace
338
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700339Status cp_prepareCheckpoint() {
Paul Lawrence1d57f682019-08-22 09:51:18 -0700340 std::lock_guard<std::mutex> lock(isCheckpointingLock);
Paul Lawrencedb086942019-02-19 14:18:54 -0800341 if (!isCheckpointing) {
342 return Status::ok();
343 }
344
Tom Cherry4c5bde22019-01-29 14:34:01 -0800345 Fstab mounts;
346 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700347 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800348 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700349
Tom Cherry4c5bde22019-01-29 14:34:01 -0800350 for (const auto& mount_rec : mounts) {
351 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700352 if (!fstab_rec) continue;
353
Tom Cherry4c5bde22019-01-29 14:34:01 -0800354 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700355 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800356 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900357 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800358 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700359 continue;
360 }
361
362 struct fstrim_range range = {};
363 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700364 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700365 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800366 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700367 continue;
368 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700369 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
370 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
371 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700372
Tom Cherry4c5bde22019-01-29 14:34:01 -0800373 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700374 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800375 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
376 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700377 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800378 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
379 .detach();
380 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700381 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700382 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700383}
384
385namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700386const int kSectorSize = 512;
387
388typedef uint64_t sector_t;
389
390struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800391 sector_t source; // in sectors of size kSectorSize
392 sector_t dest; // in sectors of size kSectorSize
393 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700394 uint32_t checksum;
395} __attribute__((packed));
396
Paul Lawrencef5077682019-01-18 10:28:34 -0800397struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700398 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800399 uint16_t header_version;
400 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800401 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700402 uint32_t count;
403 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800404 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700405} __attribute__((packed));
406
407// MAGIC is BOW in ascii
408const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800409// Partially restored MAGIC is WOB in ascii
410const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700411
412void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
413 static uint32_t table[0x100] = {
414 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
415 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
416 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
417 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
418 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
419 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
420 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
421 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
422 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
423 0xB6662D3D,
424
425 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
426 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
427 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
428 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
429 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
430 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
431 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
432 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
433 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
434 0xC0BA6CAD,
435
436 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
437 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
438 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
439 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
440 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
441 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
442 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
443 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
444 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
445 0x5BDEAE1D,
446
447 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
448 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
449 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
450 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
451 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
452 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
453 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
454 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
455 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
456 0x2D02EF8D};
457
458 for (size_t i = 0; i < n_bytes; ++i) {
459 *crc ^= ((uint8_t*)data)[i];
460 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
461 }
462}
463
Paul Lawrenced41a9392019-01-22 14:31:43 -0800464// A map of relocations.
465// The map must be initialized so that relocations[0] = 0
466// During restore, we replay the log records in reverse, copying from dest to
467// source
468// To validate, we must be able to read the 'dest' sectors as though they had
469// been copied but without actually copying. This map represents how the sectors
470// would have been moved. To read a sector s, find the index <= s and read
471// relocations[index] + s - index
472typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800473
Paul Lawrenced41a9392019-01-22 14:31:43 -0800474void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
475 // Find first one we're equal to or greater than
476 auto s = --relocations.upper_bound(source);
477
478 // Take slice
479 Relocations slice;
480 slice[dest] = source - s->first + s->second;
481 ++s;
482
483 // Add rest of elements
484 for (; s != relocations.end() && s->first < source + count; ++s)
485 slice[dest - source + s->first] = s->second;
486
487 // Split range at end of dest
488 auto dest_end = --relocations.upper_bound(dest + count);
489 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
490
491 // Remove all elements in [dest, dest + count)
492 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
493
494 // Add new elements
495 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800496}
497
Daniel Rosenberg52985932019-03-01 22:01:22 -0800498// A map of sectors that have been written to.
499// The final entry must always be False.
500// When we restart the restore after an interruption, we must take care that
501// when we copy from dest to source, that the block we copy to was not
502// previously copied from.
503// i e. A->B C->A; If we replay this sequence, we end up copying C->B
504// We must save our partial result whenever we finish a page, or when we copy
505// to a location that was copied from earlier (our source is an earlier dest)
506typedef std::map<sector_t, bool> Used_Sectors;
507
508bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
509 auto second_overlap = used_sectors.upper_bound(start);
510 auto first_overlap = --second_overlap;
511
512 if (first_overlap->second) {
513 return true;
514 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
515 return true;
516 }
517 return false;
518}
519
520void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
521 auto start_pos = used_sectors.insert_or_assign(start, true).first;
522 auto end_pos = used_sectors.insert_or_assign(end, false).first;
523
524 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
525 start_pos++;
526 }
527 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
528 end_pos++;
529 }
530 if (start_pos->first < end_pos->first) {
531 used_sectors.erase(start_pos, end_pos);
532 }
533}
534
535// Restores the given log_entry's data from dest -> source
536// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
537void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
538 log_entry* le, std::vector<char>& buffer) {
539 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
540 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
541 int count = (le->size - 1) / kSectorSize + 1;
542
543 if (checkCollision(used_sectors, le->source, le->source + count)) {
544 fsync(device_fd);
545 lseek64(device_fd, 0, SEEK_SET);
546 ls.count = index + 1;
547 ls.magic = kPartialRestoreMagic;
548 write(device_fd, &ls_buffer[0], ls.block_size);
549 fsync(device_fd);
550 used_sectors.clear();
551 used_sectors[0] = false;
552 }
553
554 markUsed(used_sectors, le->dest, le->dest + count);
555
556 if (index == 0 && ls.sequence != 0) {
557 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
558 if (next->magic == kMagic) {
559 next->magic = kPartialRestoreMagic;
560 }
561 }
562
563 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
564 write(device_fd, &buffer[0], le->size);
565
566 if (index == 0) {
567 fsync(device_fd);
568 }
569}
570
Paul Lawrenced41a9392019-01-22 14:31:43 -0800571// Read from the device
572// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800573std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
574 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800575 if (!validating) {
576 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800577 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
578 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800579 return buffer;
580 }
581
Paul Lawrence27691c22018-11-20 14:07:59 -0800582 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800583 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
584 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800585 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
586 SEEK_SET);
587 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800588 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800589
590 return buffer;
591}
592
Paul Lawrence4f13a902019-01-10 13:06:07 -0800593} // namespace
594
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800595Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800596 bool validating = true;
597 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800598 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700599
Paul Lawrence27691c22018-11-20 14:07:59 -0800600 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800601 Relocations relocations;
602 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800603 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700604
Paul Lawrence27691c22018-11-20 14:07:59 -0800605 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700606 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700607 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800608
Paul Lawrencef5077682019-01-18 10:28:34 -0800609 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800610 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800611 if (original_ls.magic == kPartialRestoreMagic) {
612 validating = false;
613 action = "Restoring";
614 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700615 return error(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700616 }
617
Paul Lawrence4f13a902019-01-10 13:06:07 -0800618 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700619
Paul Lawrence4f13a902019-01-10 13:06:07 -0800620 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800621 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
622 original_ls.block_size, original_ls.block_size);
623 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
624
625 Used_Sectors used_sectors;
626 used_sectors[0] = false;
627
628 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700629 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800630 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700631 }
632
Paul Lawrence4f13a902019-01-10 13:06:07 -0800633 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700634 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800635 break;
636 }
637
Paul Lawrence27691c22018-11-20 14:07:59 -0800638 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700639 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
640 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800641 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700642 }
643
Paul Lawrence27691c22018-11-20 14:07:59 -0800644 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800645 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800646 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
647 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800648 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800649 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
650 << " to " << le->source << " with checksum " << std::hex
651 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800652
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800653 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800654 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800655 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
656 for (size_t i = 0; i < le->size; i += ls.block_size) {
657 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800658 }
659
660 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700661 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800662 break;
663 }
664
Paul Lawrenced41a9392019-01-22 14:31:43 -0800665 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800666 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800667 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800668 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800669 restore_count++;
670 if (restore_limit && restore_count >= restore_limit) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700671 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800672 break;
673 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800674 }
675 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700676 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800677
678 if (!status.isOk()) {
679 if (!validating) {
680 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
681 return status;
682 }
683
684 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800685 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800686 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800687 lseek64(device_fd, 0, SEEK_SET);
688 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800689 return Status::ok();
690 }
691
692 if (!validating) break;
693
694 validating = false;
695 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700696 }
697
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700698 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700699}
700
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700701Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700702 std::string oldContent, newContent;
703 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700704 struct stat st;
705 int result = stat(kMetadataCPFile.c_str(), &st);
706
707 // If the file doesn't exist, we aren't managing a checkpoint retry counter
708 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700709 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
710 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700711 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700712
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700713 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700714 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700715 if (retry > 0) {
716 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700717
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700718 newContent = std::to_string(retry);
719 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700720 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700721 }
722 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700723}
724
725} // namespace vold
726} // namespace android