blob: 362c8236ddfaca43485c612d24bbcd1fb7a1432a [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;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800147}
148
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700149Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800150 if (!isCheckpointing) {
151 return Status::ok();
152 }
Paul Lawrencea7972dc2019-06-12 12:03:01 -0700153 if (android::base::GetProperty("persist.vold.dont_commit_checkpoint", "0") == "1") {
154 LOG(WARNING)
155 << "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
156 return Status::ok();
157 }
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800158 sp<IBootControl> module = IBootControl::getService();
159 if (module) {
160 CommandResult cr;
161 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
Paul Lawrence82b35052019-04-19 14:26:39 -0700162 if (!cr.success)
163 return error(EINVAL, "Error marking booted successfully: " + std::string(cr.errMsg));
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800164 LOG(INFO) << "Marked slot as booted successfully.";
165 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700166 // Must take action for list of mounted checkpointed things here
167 // To do this, we walk the list of mounted file systems.
168 // But we also need to get the matching fstab entries to see
169 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700170 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700171
Tom Cherry4c5bde22019-01-29 14:34:01 -0800172 Fstab mounts;
173 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700174 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800175 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700176
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700177 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800178 for (const auto& mount_rec : mounts) {
179 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700180 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700181
Tom Cherry4c5bde22019-01-29 14:34:01 -0800182 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
183 if (fstab_rec->fs_type == "f2fs") {
184 std::string options = mount_rec.fs_options + ",checkpoint=enable";
185 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800186 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700187 return error(EINVAL, "Failed to remount");
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800188 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700189 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800190 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
191 if (!setBowState(mount_rec.blk_device, "2"))
Paul Lawrence82b35052019-04-19 14:26:39 -0700192 return error(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700193 }
194 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800195 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800196 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800197 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800198 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Paul Lawrence82b35052019-04-19 14:26:39 -0700199 return error(err_str.c_str());
200
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700201 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700202}
203
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700204namespace {
205void abort_metadata_file() {
206 std::string oldContent, newContent;
207 int retry = 0;
208 struct stat st;
209 int result = stat(kMetadataCPFile.c_str(), &st);
210
211 // If the file doesn't exist, we aren't managing a checkpoint retry counter
212 if (result != 0) return;
213 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
214 PLOG(ERROR) << "Failed to read checkpoint file";
215 return;
216 }
217 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
218
219 if (!android::base::ParseInt(retryContent, &retry)) {
220 PLOG(ERROR) << "Could not parse retry count";
221 return;
222 }
223 if (retry > 0) {
224 newContent = "0";
225 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
226 PLOG(ERROR) << "Could not write checkpoint file";
227 }
228}
229} // namespace
230
231void cp_abortChanges(const std::string& message, bool retry) {
232 if (!cp_needsCheckpoint()) return;
233 if (!retry) abort_metadata_file();
234 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700235}
236
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700237bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700238 std::string content;
239 bool ret;
240
241 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700242 if (ret) {
243 if (content == "0") return true;
244 if (content.substr(0, 3) == "-1 ") {
245 std::string oldSuffix = content.substr(3);
246 sp<IBootControl> module = IBootControl::getService();
247 std::string newSuffix;
248
249 if (module) {
250 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
251 module->getSuffix(module->getCurrentSlot(), cb);
252 if (oldSuffix == newSuffix) return true;
253 }
254 }
255 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700256 return false;
257}
258
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700259bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700260 bool ret;
261 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700262 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700263
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700264 if (isCheckpointing) return isCheckpointing;
265
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800266 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
267 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700268 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800269 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700270 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800271 if (ret) {
272 ret = content != "0";
273 isCheckpointing = ret;
274 return ret;
275 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700276 return false;
277}
278
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800279namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700280const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
281const uint32_t msleeptime_default = 1000; // 1 s
282const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800283
284const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
285const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
286
287const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
288const bool commit_on_full_default = true;
289
290static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
291 struct statvfs data;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700292 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900293 uint64_t min_free_bytes =
294 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800295 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
296
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700297 struct timespec req;
298 req.tv_sec = msleeptime / 1000;
299 msleeptime %= 1000;
300 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800301 while (isCheckpointing) {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700302 uint64_t free_bytes = 0;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800303 if (is_fs_cp) {
304 statvfs(mnt_pnt.c_str(), &data);
305 free_bytes = data.f_bavail * data.f_frsize;
306 } else {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700307 std::string bow_device = fs_mgr_find_bow_device(blk_device);
308 if (!bow_device.empty()) {
309 std::string content;
310 if (android::base::ReadFileToString(bow_device + "/bow/free", &content)) {
311 free_bytes = std::strtoul(content.c_str(), NULL, 10);
312 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800313 }
314 }
315 if (free_bytes < min_free_bytes) {
316 if (commit_on_full) {
317 LOG(INFO) << "Low space for checkpointing. Commiting changes";
318 cp_commitChanges();
319 break;
320 } else {
321 LOG(INFO) << "Low space for checkpointing. Rebooting";
322 cp_abortChanges("checkpoint,low_space", false);
323 break;
324 }
325 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700326 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800327 }
328}
329
330} // namespace
331
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700332Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800333 if (!isCheckpointing) {
334 return Status::ok();
335 }
336
Tom Cherry4c5bde22019-01-29 14:34:01 -0800337 Fstab mounts;
338 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700339 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800340 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700341
Tom Cherry4c5bde22019-01-29 14:34:01 -0800342 for (const auto& mount_rec : mounts) {
343 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700344 if (!fstab_rec) continue;
345
Tom Cherry4c5bde22019-01-29 14:34:01 -0800346 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700347 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800348 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900349 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800350 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700351 continue;
352 }
353
354 struct fstrim_range range = {};
355 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700356 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700357 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800358 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700359 continue;
360 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700361 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
362 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
363 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700364
Tom Cherry4c5bde22019-01-29 14:34:01 -0800365 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700366 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800367 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
368 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700369 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800370 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
371 .detach();
372 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700373 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700374 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700375}
376
377namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700378const int kSectorSize = 512;
379
380typedef uint64_t sector_t;
381
382struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800383 sector_t source; // in sectors of size kSectorSize
384 sector_t dest; // in sectors of size kSectorSize
385 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700386 uint32_t checksum;
387} __attribute__((packed));
388
Paul Lawrencef5077682019-01-18 10:28:34 -0800389struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700390 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800391 uint16_t header_version;
392 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800393 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700394 uint32_t count;
395 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800396 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700397} __attribute__((packed));
398
399// MAGIC is BOW in ascii
400const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800401// Partially restored MAGIC is WOB in ascii
402const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700403
404void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
405 static uint32_t table[0x100] = {
406 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
407 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
408 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
409 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
410 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
411 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
412 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
413 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
414 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
415 0xB6662D3D,
416
417 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
418 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
419 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
420 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
421 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
422 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
423 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
424 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
425 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
426 0xC0BA6CAD,
427
428 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
429 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
430 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
431 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
432 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
433 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
434 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
435 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
436 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
437 0x5BDEAE1D,
438
439 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
440 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
441 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
442 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
443 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
444 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
445 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
446 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
447 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
448 0x2D02EF8D};
449
450 for (size_t i = 0; i < n_bytes; ++i) {
451 *crc ^= ((uint8_t*)data)[i];
452 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
453 }
454}
455
Paul Lawrenced41a9392019-01-22 14:31:43 -0800456// A map of relocations.
457// The map must be initialized so that relocations[0] = 0
458// During restore, we replay the log records in reverse, copying from dest to
459// source
460// To validate, we must be able to read the 'dest' sectors as though they had
461// been copied but without actually copying. This map represents how the sectors
462// would have been moved. To read a sector s, find the index <= s and read
463// relocations[index] + s - index
464typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800465
Paul Lawrenced41a9392019-01-22 14:31:43 -0800466void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
467 // Find first one we're equal to or greater than
468 auto s = --relocations.upper_bound(source);
469
470 // Take slice
471 Relocations slice;
472 slice[dest] = source - s->first + s->second;
473 ++s;
474
475 // Add rest of elements
476 for (; s != relocations.end() && s->first < source + count; ++s)
477 slice[dest - source + s->first] = s->second;
478
479 // Split range at end of dest
480 auto dest_end = --relocations.upper_bound(dest + count);
481 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
482
483 // Remove all elements in [dest, dest + count)
484 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
485
486 // Add new elements
487 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800488}
489
Daniel Rosenberg52985932019-03-01 22:01:22 -0800490// A map of sectors that have been written to.
491// The final entry must always be False.
492// When we restart the restore after an interruption, we must take care that
493// when we copy from dest to source, that the block we copy to was not
494// previously copied from.
495// i e. A->B C->A; If we replay this sequence, we end up copying C->B
496// We must save our partial result whenever we finish a page, or when we copy
497// to a location that was copied from earlier (our source is an earlier dest)
498typedef std::map<sector_t, bool> Used_Sectors;
499
500bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
501 auto second_overlap = used_sectors.upper_bound(start);
502 auto first_overlap = --second_overlap;
503
504 if (first_overlap->second) {
505 return true;
506 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
507 return true;
508 }
509 return false;
510}
511
512void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
513 auto start_pos = used_sectors.insert_or_assign(start, true).first;
514 auto end_pos = used_sectors.insert_or_assign(end, false).first;
515
516 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
517 start_pos++;
518 }
519 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
520 end_pos++;
521 }
522 if (start_pos->first < end_pos->first) {
523 used_sectors.erase(start_pos, end_pos);
524 }
525}
526
527// Restores the given log_entry's data from dest -> source
528// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
529void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
530 log_entry* le, std::vector<char>& buffer) {
531 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
532 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
533 int count = (le->size - 1) / kSectorSize + 1;
534
535 if (checkCollision(used_sectors, le->source, le->source + count)) {
536 fsync(device_fd);
537 lseek64(device_fd, 0, SEEK_SET);
538 ls.count = index + 1;
539 ls.magic = kPartialRestoreMagic;
540 write(device_fd, &ls_buffer[0], ls.block_size);
541 fsync(device_fd);
542 used_sectors.clear();
543 used_sectors[0] = false;
544 }
545
546 markUsed(used_sectors, le->dest, le->dest + count);
547
548 if (index == 0 && ls.sequence != 0) {
549 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
550 if (next->magic == kMagic) {
551 next->magic = kPartialRestoreMagic;
552 }
553 }
554
555 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
556 write(device_fd, &buffer[0], le->size);
557
558 if (index == 0) {
559 fsync(device_fd);
560 }
561}
562
Paul Lawrenced41a9392019-01-22 14:31:43 -0800563// Read from the device
564// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800565std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
566 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800567 if (!validating) {
568 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800569 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
570 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800571 return buffer;
572 }
573
Paul Lawrence27691c22018-11-20 14:07:59 -0800574 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800575 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
576 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800577 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
578 SEEK_SET);
579 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800580 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800581
582 return buffer;
583}
584
Paul Lawrence4f13a902019-01-10 13:06:07 -0800585} // namespace
586
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800587Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800588 bool validating = true;
589 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800590 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700591
Paul Lawrence27691c22018-11-20 14:07:59 -0800592 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800593 Relocations relocations;
594 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800595 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700596
Paul Lawrence27691c22018-11-20 14:07:59 -0800597 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700598 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700599 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800600
Paul Lawrencef5077682019-01-18 10:28:34 -0800601 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800602 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800603 if (original_ls.magic == kPartialRestoreMagic) {
604 validating = false;
605 action = "Restoring";
606 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700607 return error(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700608 }
609
Paul Lawrence4f13a902019-01-10 13:06:07 -0800610 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700611
Paul Lawrence4f13a902019-01-10 13:06:07 -0800612 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800613 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
614 original_ls.block_size, original_ls.block_size);
615 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
616
617 Used_Sectors used_sectors;
618 used_sectors[0] = false;
619
620 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700621 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800622 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700623 }
624
Paul Lawrence4f13a902019-01-10 13:06:07 -0800625 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700626 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800627 break;
628 }
629
Paul Lawrence27691c22018-11-20 14:07:59 -0800630 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700631 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
632 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800633 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700634 }
635
Paul Lawrence27691c22018-11-20 14:07:59 -0800636 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800637 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800638 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
639 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800640 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800641 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
642 << " to " << le->source << " with checksum " << std::hex
643 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800644
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800645 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800646 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800647 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
648 for (size_t i = 0; i < le->size; i += ls.block_size) {
649 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800650 }
651
652 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700653 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800654 break;
655 }
656
Paul Lawrenced41a9392019-01-22 14:31:43 -0800657 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800658 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800659 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800660 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800661 restore_count++;
662 if (restore_limit && restore_count >= restore_limit) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700663 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800664 break;
665 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800666 }
667 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700668 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800669
670 if (!status.isOk()) {
671 if (!validating) {
672 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
673 return status;
674 }
675
676 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800677 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800678 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800679 lseek64(device_fd, 0, SEEK_SET);
680 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800681 return Status::ok();
682 }
683
684 if (!validating) break;
685
686 validating = false;
687 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700688 }
689
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700690 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700691}
692
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700693Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700694 std::string oldContent, newContent;
695 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700696 struct stat st;
697 int result = stat(kMetadataCPFile.c_str(), &st);
698
699 // If the file doesn't exist, we aren't managing a checkpoint retry counter
700 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700701 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
702 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700703 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700704
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700705 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700706 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700707 if (retry > 0) {
708 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700709
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700710 newContent = std::to_string(retry);
711 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700712 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700713 }
714 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700715}
716
717} // namespace vold
718} // namespace android