blob: e784c9150e6732bbcdbc7a38c9d7fbbc4c97c808 [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"
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070020
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070021#include <fstream>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070022#include <list>
Paul Lawrence20400892018-10-03 14:14:52 -070023#include <memory>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070024#include <string>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080025#include <thread>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070026#include <vector>
27
28#include <android-base/file.h>
29#include <android-base/logging.h>
30#include <android-base/parseint.h>
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080031#include <android-base/properties.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070032#include <android-base/unique_fd.h>
Daniel Rosenbergd3992492018-10-02 17:40:44 -070033#include <android/hardware/boot/1.0/IBootControl.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070034#include <cutils/android_reboot.h>
35#include <fcntl.h>
36#include <fs_mgr.h>
37#include <linux/fs.h>
38#include <mntent.h>
39#include <sys/mount.h>
40#include <sys/stat.h>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080041#include <sys/statvfs.h>
42#include <unistd.h>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070043
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080044using android::base::GetBoolProperty;
45using android::base::GetUintProperty;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080046using android::base::SetProperty;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070047using android::binder::Status;
Tom Cherry4c5bde22019-01-29 14:34:01 -080048using android::fs_mgr::Fstab;
49using android::fs_mgr::ReadDefaultFstab;
50using android::fs_mgr::ReadFstabFromFile;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070051using android::hardware::hidl_string;
52using android::hardware::boot::V1_0::BoolResult;
Daniel Rosenberg886915b2019-01-23 15:16:04 -080053using android::hardware::boot::V1_0::CommandResult;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070054using android::hardware::boot::V1_0::IBootControl;
55using android::hardware::boot::V1_0::Slot;
56
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070057namespace android {
58namespace vold {
59
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070060namespace {
61const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
62
63bool setBowState(std::string const& block_device, std::string const& state) {
64 if (block_device.substr(0, 5) != "/dev/") {
65 LOG(ERROR) << "Expected block device, got " << block_device;
66 return false;
67 }
68
69 std::string state_filename = std::string("/sys/") + block_device.substr(5) + "/bow/state";
70 if (!android::base::WriteStringToFile(state, state_filename)) {
71 PLOG(ERROR) << "Failed to write to file " << state_filename;
72 return false;
73 }
74
75 return true;
76}
77
78} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070079
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080080Status cp_supportsCheckpoint(bool& result) {
81 result = false;
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080082
Tom Cherry4c5bde22019-01-29 14:34:01 -080083 for (const auto& entry : fstab_default) {
84 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080085 result = true;
86 return Status::ok();
87 }
88 }
89 return Status::ok();
90}
91
Paul Lawrencec5c79c52019-03-18 13:36:40 -070092Status cp_supportsBlockCheckpoint(bool& result) {
93 result = false;
94
95 for (const auto& entry : fstab_default) {
96 if (entry.fs_mgr_flags.checkpoint_blk) {
97 result = true;
98 return Status::ok();
99 }
100 }
101 return Status::ok();
102}
103
104Status cp_supportsFileCheckpoint(bool& result) {
105 result = false;
106
107 for (const auto& entry : fstab_default) {
108 if (entry.fs_mgr_flags.checkpoint_fs) {
109 result = true;
110 return Status::ok();
111 }
112 }
113 return Status::ok();
114}
115
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700116Status cp_startCheckpoint(int retry) {
117 if (retry < -1) return Status::fromExceptionCode(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700118 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700119 if (retry == -1) {
120 sp<IBootControl> module = IBootControl::getService();
121 if (module) {
122 std::string suffix;
123 auto cb = [&suffix](hidl_string s) { suffix = s; };
124 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
125 }
126 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700127 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
128 return Status::fromExceptionCode(errno, "Failed to write checkpoint file");
129 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700130}
131
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800132namespace {
133
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800134volatile bool isCheckpointing = false;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800135}
136
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700137Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800138 if (!isCheckpointing) {
139 return Status::ok();
140 }
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800141 sp<IBootControl> module = IBootControl::getService();
142 if (module) {
143 CommandResult cr;
144 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
145 if (!cr.success) {
146 std::string msg = "Error marking booted successfully: " + std::string(cr.errMsg);
147 return Status::fromExceptionCode(EINVAL, String8(msg.c_str()));
148 }
149 LOG(INFO) << "Marked slot as booted successfully.";
150 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700151 // Must take action for list of mounted checkpointed things here
152 // To do this, we walk the list of mounted file systems.
153 // But we also need to get the matching fstab entries to see
154 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700155 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700156
Tom Cherry4c5bde22019-01-29 14:34:01 -0800157 Fstab mounts;
158 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
159 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
160 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700161
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700162 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800163 for (const auto& mount_rec : mounts) {
164 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700165 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700166
Tom Cherry4c5bde22019-01-29 14:34:01 -0800167 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
168 if (fstab_rec->fs_type == "f2fs") {
169 std::string options = mount_rec.fs_options + ",checkpoint=enable";
170 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800171 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800172 return Status::fromExceptionCode(EINVAL, "Failed to remount");
173 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700174 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800175 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
176 if (!setBowState(mount_rec.blk_device, "2"))
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800177 return Status::fromExceptionCode(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700178 }
179 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800180 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800181 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800182 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800183 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700184 return Status::fromExceptionCode(errno, err_str.c_str());
185 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700186}
187
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700188namespace {
189void abort_metadata_file() {
190 std::string oldContent, newContent;
191 int retry = 0;
192 struct stat st;
193 int result = stat(kMetadataCPFile.c_str(), &st);
194
195 // If the file doesn't exist, we aren't managing a checkpoint retry counter
196 if (result != 0) return;
197 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
198 PLOG(ERROR) << "Failed to read checkpoint file";
199 return;
200 }
201 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
202
203 if (!android::base::ParseInt(retryContent, &retry)) {
204 PLOG(ERROR) << "Could not parse retry count";
205 return;
206 }
207 if (retry > 0) {
208 newContent = "0";
209 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
210 PLOG(ERROR) << "Could not write checkpoint file";
211 }
212}
213} // namespace
214
215void cp_abortChanges(const std::string& message, bool retry) {
216 if (!cp_needsCheckpoint()) return;
217 if (!retry) abort_metadata_file();
218 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700219}
220
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700221bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700222 std::string content;
223 bool ret;
224
225 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700226 if (ret) {
227 if (content == "0") return true;
228 if (content.substr(0, 3) == "-1 ") {
229 std::string oldSuffix = content.substr(3);
230 sp<IBootControl> module = IBootControl::getService();
231 std::string newSuffix;
232
233 if (module) {
234 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
235 module->getSuffix(module->getCurrentSlot(), cb);
236 if (oldSuffix == newSuffix) return true;
237 }
238 }
239 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700240 return false;
241}
242
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700243bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700244 bool ret;
245 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700246 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700247
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700248 if (isCheckpointing) return isCheckpointing;
249
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800250 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
251 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700252 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800253 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700254 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800255 if (ret) {
256 ret = content != "0";
257 isCheckpointing = ret;
258 return ret;
259 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700260 return false;
261}
262
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800263namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700264const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
265const uint32_t msleeptime_default = 1000; // 1 s
266const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800267
268const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
269const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
270
271const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
272const bool commit_on_full_default = true;
273
274static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
275 struct statvfs data;
276 uint64_t free_bytes = 0;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700277 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900278 uint64_t min_free_bytes =
279 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800280 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
281
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700282 struct timespec req;
283 req.tv_sec = msleeptime / 1000;
284 msleeptime %= 1000;
285 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800286 while (isCheckpointing) {
287 if (is_fs_cp) {
288 statvfs(mnt_pnt.c_str(), &data);
289 free_bytes = data.f_bavail * data.f_frsize;
290 } else {
291 int ret;
292 std::string size_filename = std::string("/sys/") + blk_device.substr(5) + "/bow/free";
293 std::string content;
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700294 ret = android::base::ReadFileToString(size_filename, &content);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800295 if (ret) {
296 free_bytes = std::strtoul(content.c_str(), NULL, 10);
297 }
298 }
299 if (free_bytes < min_free_bytes) {
300 if (commit_on_full) {
301 LOG(INFO) << "Low space for checkpointing. Commiting changes";
302 cp_commitChanges();
303 break;
304 } else {
305 LOG(INFO) << "Low space for checkpointing. Rebooting";
306 cp_abortChanges("checkpoint,low_space", false);
307 break;
308 }
309 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700310 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800311 }
312}
313
314} // namespace
315
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700316Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800317 if (!isCheckpointing) {
318 return Status::ok();
319 }
320
Tom Cherry4c5bde22019-01-29 14:34:01 -0800321 Fstab mounts;
322 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
323 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
324 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700325
Tom Cherry4c5bde22019-01-29 14:34:01 -0800326 for (const auto& mount_rec : mounts) {
327 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700328 if (!fstab_rec) continue;
329
Tom Cherry4c5bde22019-01-29 14:34:01 -0800330 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700331 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800332 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900333 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800334 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700335 continue;
336 }
337
338 struct fstrim_range range = {};
339 range.len = ULLONG_MAX;
340 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800341 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700342 continue;
343 }
344
Tom Cherry4c5bde22019-01-29 14:34:01 -0800345 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700346 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800347 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
348 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700349 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800350 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
351 .detach();
352 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700353 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700354 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700355}
356
357namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700358const int kSectorSize = 512;
359
360typedef uint64_t sector_t;
361
362struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800363 sector_t source; // in sectors of size kSectorSize
364 sector_t dest; // in sectors of size kSectorSize
365 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700366 uint32_t checksum;
367} __attribute__((packed));
368
Paul Lawrencef5077682019-01-18 10:28:34 -0800369struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700370 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800371 uint16_t header_version;
372 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800373 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700374 uint32_t count;
375 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800376 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700377} __attribute__((packed));
378
379// MAGIC is BOW in ascii
380const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800381// Partially restored MAGIC is WOB in ascii
382const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700383
384void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
385 static uint32_t table[0x100] = {
386 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
387 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
388 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
389 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
390 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
391 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
392 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
393 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
394 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
395 0xB6662D3D,
396
397 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
398 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
399 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
400 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
401 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
402 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
403 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
404 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
405 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
406 0xC0BA6CAD,
407
408 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
409 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
410 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
411 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
412 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
413 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
414 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
415 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
416 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
417 0x5BDEAE1D,
418
419 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
420 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
421 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
422 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
423 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
424 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
425 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
426 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
427 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
428 0x2D02EF8D};
429
430 for (size_t i = 0; i < n_bytes; ++i) {
431 *crc ^= ((uint8_t*)data)[i];
432 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
433 }
434}
435
Paul Lawrenced41a9392019-01-22 14:31:43 -0800436// A map of relocations.
437// The map must be initialized so that relocations[0] = 0
438// During restore, we replay the log records in reverse, copying from dest to
439// source
440// To validate, we must be able to read the 'dest' sectors as though they had
441// been copied but without actually copying. This map represents how the sectors
442// would have been moved. To read a sector s, find the index <= s and read
443// relocations[index] + s - index
444typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800445
Paul Lawrenced41a9392019-01-22 14:31:43 -0800446void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
447 // Find first one we're equal to or greater than
448 auto s = --relocations.upper_bound(source);
449
450 // Take slice
451 Relocations slice;
452 slice[dest] = source - s->first + s->second;
453 ++s;
454
455 // Add rest of elements
456 for (; s != relocations.end() && s->first < source + count; ++s)
457 slice[dest - source + s->first] = s->second;
458
459 // Split range at end of dest
460 auto dest_end = --relocations.upper_bound(dest + count);
461 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
462
463 // Remove all elements in [dest, dest + count)
464 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
465
466 // Add new elements
467 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800468}
469
Daniel Rosenberg52985932019-03-01 22:01:22 -0800470// A map of sectors that have been written to.
471// The final entry must always be False.
472// When we restart the restore after an interruption, we must take care that
473// when we copy from dest to source, that the block we copy to was not
474// previously copied from.
475// i e. A->B C->A; If we replay this sequence, we end up copying C->B
476// We must save our partial result whenever we finish a page, or when we copy
477// to a location that was copied from earlier (our source is an earlier dest)
478typedef std::map<sector_t, bool> Used_Sectors;
479
480bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
481 auto second_overlap = used_sectors.upper_bound(start);
482 auto first_overlap = --second_overlap;
483
484 if (first_overlap->second) {
485 return true;
486 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
487 return true;
488 }
489 return false;
490}
491
492void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
493 auto start_pos = used_sectors.insert_or_assign(start, true).first;
494 auto end_pos = used_sectors.insert_or_assign(end, false).first;
495
496 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
497 start_pos++;
498 }
499 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
500 end_pos++;
501 }
502 if (start_pos->first < end_pos->first) {
503 used_sectors.erase(start_pos, end_pos);
504 }
505}
506
507// Restores the given log_entry's data from dest -> source
508// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
509void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
510 log_entry* le, std::vector<char>& buffer) {
511 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
512 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
513 int count = (le->size - 1) / kSectorSize + 1;
514
515 if (checkCollision(used_sectors, le->source, le->source + count)) {
516 fsync(device_fd);
517 lseek64(device_fd, 0, SEEK_SET);
518 ls.count = index + 1;
519 ls.magic = kPartialRestoreMagic;
520 write(device_fd, &ls_buffer[0], ls.block_size);
521 fsync(device_fd);
522 used_sectors.clear();
523 used_sectors[0] = false;
524 }
525
526 markUsed(used_sectors, le->dest, le->dest + count);
527
528 if (index == 0 && ls.sequence != 0) {
529 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
530 if (next->magic == kMagic) {
531 next->magic = kPartialRestoreMagic;
532 }
533 }
534
535 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
536 write(device_fd, &buffer[0], le->size);
537
538 if (index == 0) {
539 fsync(device_fd);
540 }
541}
542
Paul Lawrenced41a9392019-01-22 14:31:43 -0800543// Read from the device
544// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800545std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
546 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800547 if (!validating) {
548 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800549 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
550 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800551 return buffer;
552 }
553
Paul Lawrence27691c22018-11-20 14:07:59 -0800554 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800555 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
556 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800557 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
558 SEEK_SET);
559 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800560 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800561
562 return buffer;
563}
564
Paul Lawrence4f13a902019-01-10 13:06:07 -0800565} // namespace
566
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800567Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800568 bool validating = true;
569 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800570 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700571
Paul Lawrence27691c22018-11-20 14:07:59 -0800572 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800573 Relocations relocations;
574 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800575 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700576
Paul Lawrence27691c22018-11-20 14:07:59 -0800577 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700578 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800579 if (device_fd < 0) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800580 PLOG(ERROR) << "Cannot open " << blockDevice;
581 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
582 }
Paul Lawrence4f13a902019-01-10 13:06:07 -0800583
Paul Lawrencef5077682019-01-18 10:28:34 -0800584 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800585 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800586 if (original_ls.magic == kPartialRestoreMagic) {
587 validating = false;
588 action = "Restoring";
589 } else if (original_ls.magic != kMagic) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800590 LOG(ERROR) << "No magic";
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700591 return Status::fromExceptionCode(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700592 }
593
Paul Lawrence4f13a902019-01-10 13:06:07 -0800594 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700595
Paul Lawrence4f13a902019-01-10 13:06:07 -0800596 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800597 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
598 original_ls.block_size, original_ls.block_size);
599 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
600
601 Used_Sectors used_sectors;
602 used_sectors[0] = false;
603
604 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800605 LOG(ERROR) << "No magic!";
606 status = Status::fromExceptionCode(EINVAL, "No magic");
607 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700608 }
609
Paul Lawrence4f13a902019-01-10 13:06:07 -0800610 if (ls.block_size != original_ls.block_size) {
611 LOG(ERROR) << "Block size mismatch!";
612 status = Status::fromExceptionCode(EINVAL, "Block size mismatch");
613 break;
614 }
615
Paul Lawrence27691c22018-11-20 14:07:59 -0800616 if ((int)ls.sequence != sequence) {
617 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
618 status = Status::fromExceptionCode(
619 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
620 std::to_string(ls.sequence))
621 .c_str());
622 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700623 }
624
Paul Lawrence27691c22018-11-20 14:07:59 -0800625 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800626 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800627 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
628 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800629 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800630 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
631 << " to " << le->source << " with checksum " << std::hex
632 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800633
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800634 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800635 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800636 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
637 for (size_t i = 0; i < le->size; i += ls.block_size) {
638 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800639 }
640
641 if (le->checksum && checksum != le->checksum) {
642 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
643 status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
644 break;
645 }
646
Paul Lawrenced41a9392019-01-22 14:31:43 -0800647 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800648 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800649 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800650 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800651 restore_count++;
652 if (restore_limit && restore_count >= restore_limit) {
653 LOG(WARNING) << "Hit the test limit";
654 status = Status::fromExceptionCode(EAGAIN, "Hit the test limit");
655 break;
656 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800657 }
658 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700659 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800660
661 if (!status.isOk()) {
662 if (!validating) {
663 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
664 return status;
665 }
666
667 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800668 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800669 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800670 lseek64(device_fd, 0, SEEK_SET);
671 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800672 return Status::ok();
673 }
674
675 if (!validating) break;
676
677 validating = false;
678 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700679 }
680
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700681 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700682}
683
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700684Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700685 std::string oldContent, newContent;
686 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700687 struct stat st;
688 int result = stat(kMetadataCPFile.c_str(), &st);
689
690 // If the file doesn't exist, we aren't managing a checkpoint retry counter
691 if (result != 0) return Status::ok();
692 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
693 PLOG(ERROR) << "Failed to read checkpoint file";
694 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
695 }
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700696 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700697
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700698 if (!android::base::ParseInt(retryContent, &retry))
699 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
700 if (retry > 0) {
701 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700702
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700703 newContent = std::to_string(retry);
704 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
705 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
706 }
707 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700708}
709
710} // namespace vold
711} // namespace android