blob: 1a89039d92a73eb78c57fb981c6b67cccf0ffadb [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 {
264const std::string kSleepTimeProp = "ro.sys.cp_usleeptime";
265const uint32_t usleeptime_default = 1000; // 1 s
266
267const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
268const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
269
270const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
271const bool commit_on_full_default = true;
272
273static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
274 struct statvfs data;
275 uint64_t free_bytes = 0;
276 uint32_t usleeptime = GetUintProperty(kSleepTimeProp, usleeptime_default, (uint32_t)-1);
277 uint64_t min_free_bytes = GetUintProperty(kSleepTimeProp, min_free_bytes_default, (uint64_t)-1);
278 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
279
280 while (isCheckpointing) {
281 if (is_fs_cp) {
282 statvfs(mnt_pnt.c_str(), &data);
283 free_bytes = data.f_bavail * data.f_frsize;
284 } else {
285 int ret;
286 std::string size_filename = std::string("/sys/") + blk_device.substr(5) + "/bow/free";
287 std::string content;
288 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
289 if (ret) {
290 free_bytes = std::strtoul(content.c_str(), NULL, 10);
291 }
292 }
293 if (free_bytes < min_free_bytes) {
294 if (commit_on_full) {
295 LOG(INFO) << "Low space for checkpointing. Commiting changes";
296 cp_commitChanges();
297 break;
298 } else {
299 LOG(INFO) << "Low space for checkpointing. Rebooting";
300 cp_abortChanges("checkpoint,low_space", false);
301 break;
302 }
303 }
304 usleep(usleeptime);
305 }
306}
307
308} // namespace
309
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700310Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800311 if (!isCheckpointing) {
312 return Status::ok();
313 }
314
Tom Cherry4c5bde22019-01-29 14:34:01 -0800315 Fstab mounts;
316 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
317 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
318 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700319
Tom Cherry4c5bde22019-01-29 14:34:01 -0800320 for (const auto& mount_rec : mounts) {
321 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700322 if (!fstab_rec) continue;
323
Tom Cherry4c5bde22019-01-29 14:34:01 -0800324 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700325 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800326 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700327 if (!fd) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800328 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700329 continue;
330 }
331
332 struct fstrim_range range = {};
333 range.len = ULLONG_MAX;
334 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800335 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700336 continue;
337 }
338
Tom Cherry4c5bde22019-01-29 14:34:01 -0800339 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700340 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800341 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
342 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
343 std::string(mount_rec.mount_point),
344 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
345 .detach();
346 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700347 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700348 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700349}
350
351namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700352const int kSectorSize = 512;
353
354typedef uint64_t sector_t;
355
356struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800357 sector_t source; // in sectors of size kSectorSize
358 sector_t dest; // in sectors of size kSectorSize
359 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700360 uint32_t checksum;
361} __attribute__((packed));
362
Paul Lawrencef5077682019-01-18 10:28:34 -0800363struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700364 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800365 uint16_t header_version;
366 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800367 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700368 uint32_t count;
369 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800370 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700371} __attribute__((packed));
372
373// MAGIC is BOW in ascii
374const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800375// Partially restored MAGIC is WOB in ascii
376const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700377
378void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
379 static uint32_t table[0x100] = {
380 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
381 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
382 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
383 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
384 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
385 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
386 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
387 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
388 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
389 0xB6662D3D,
390
391 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
392 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
393 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
394 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
395 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
396 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
397 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
398 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
399 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
400 0xC0BA6CAD,
401
402 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
403 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
404 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
405 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
406 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
407 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
408 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
409 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
410 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
411 0x5BDEAE1D,
412
413 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
414 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
415 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
416 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
417 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
418 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
419 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
420 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
421 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
422 0x2D02EF8D};
423
424 for (size_t i = 0; i < n_bytes; ++i) {
425 *crc ^= ((uint8_t*)data)[i];
426 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
427 }
428}
429
Paul Lawrenced41a9392019-01-22 14:31:43 -0800430// A map of relocations.
431// The map must be initialized so that relocations[0] = 0
432// During restore, we replay the log records in reverse, copying from dest to
433// source
434// To validate, we must be able to read the 'dest' sectors as though they had
435// been copied but without actually copying. This map represents how the sectors
436// would have been moved. To read a sector s, find the index <= s and read
437// relocations[index] + s - index
438typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800439
Paul Lawrenced41a9392019-01-22 14:31:43 -0800440void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
441 // Find first one we're equal to or greater than
442 auto s = --relocations.upper_bound(source);
443
444 // Take slice
445 Relocations slice;
446 slice[dest] = source - s->first + s->second;
447 ++s;
448
449 // Add rest of elements
450 for (; s != relocations.end() && s->first < source + count; ++s)
451 slice[dest - source + s->first] = s->second;
452
453 // Split range at end of dest
454 auto dest_end = --relocations.upper_bound(dest + count);
455 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
456
457 // Remove all elements in [dest, dest + count)
458 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
459
460 // Add new elements
461 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800462}
463
Daniel Rosenberg52985932019-03-01 22:01:22 -0800464// A map of sectors that have been written to.
465// The final entry must always be False.
466// When we restart the restore after an interruption, we must take care that
467// when we copy from dest to source, that the block we copy to was not
468// previously copied from.
469// i e. A->B C->A; If we replay this sequence, we end up copying C->B
470// We must save our partial result whenever we finish a page, or when we copy
471// to a location that was copied from earlier (our source is an earlier dest)
472typedef std::map<sector_t, bool> Used_Sectors;
473
474bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
475 auto second_overlap = used_sectors.upper_bound(start);
476 auto first_overlap = --second_overlap;
477
478 if (first_overlap->second) {
479 return true;
480 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
481 return true;
482 }
483 return false;
484}
485
486void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
487 auto start_pos = used_sectors.insert_or_assign(start, true).first;
488 auto end_pos = used_sectors.insert_or_assign(end, false).first;
489
490 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
491 start_pos++;
492 }
493 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
494 end_pos++;
495 }
496 if (start_pos->first < end_pos->first) {
497 used_sectors.erase(start_pos, end_pos);
498 }
499}
500
501// Restores the given log_entry's data from dest -> source
502// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
503void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
504 log_entry* le, std::vector<char>& buffer) {
505 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
506 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
507 int count = (le->size - 1) / kSectorSize + 1;
508
509 if (checkCollision(used_sectors, le->source, le->source + count)) {
510 fsync(device_fd);
511 lseek64(device_fd, 0, SEEK_SET);
512 ls.count = index + 1;
513 ls.magic = kPartialRestoreMagic;
514 write(device_fd, &ls_buffer[0], ls.block_size);
515 fsync(device_fd);
516 used_sectors.clear();
517 used_sectors[0] = false;
518 }
519
520 markUsed(used_sectors, le->dest, le->dest + count);
521
522 if (index == 0 && ls.sequence != 0) {
523 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
524 if (next->magic == kMagic) {
525 next->magic = kPartialRestoreMagic;
526 }
527 }
528
529 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
530 write(device_fd, &buffer[0], le->size);
531
532 if (index == 0) {
533 fsync(device_fd);
534 }
535}
536
Paul Lawrenced41a9392019-01-22 14:31:43 -0800537// Read from the device
538// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800539std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
540 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800541 if (!validating) {
542 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800543 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
544 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800545 return buffer;
546 }
547
Paul Lawrence27691c22018-11-20 14:07:59 -0800548 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800549 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
550 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800551 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
552 SEEK_SET);
553 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800554 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800555
556 return buffer;
557}
558
Paul Lawrence4f13a902019-01-10 13:06:07 -0800559} // namespace
560
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800561Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800562 bool validating = true;
563 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800564 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700565
Paul Lawrence27691c22018-11-20 14:07:59 -0800566 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800567 Relocations relocations;
568 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800569 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700570
Paul Lawrence27691c22018-11-20 14:07:59 -0800571 LOG(INFO) << action << " checkpoint on " << blockDevice;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800572 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR));
573 if (device_fd < 0) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800574 PLOG(ERROR) << "Cannot open " << blockDevice;
575 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
576 }
Paul Lawrence4f13a902019-01-10 13:06:07 -0800577
Paul Lawrencef5077682019-01-18 10:28:34 -0800578 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800579 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800580 if (original_ls.magic == kPartialRestoreMagic) {
581 validating = false;
582 action = "Restoring";
583 } else if (original_ls.magic != kMagic) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800584 LOG(ERROR) << "No magic";
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700585 return Status::fromExceptionCode(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700586 }
587
Paul Lawrence4f13a902019-01-10 13:06:07 -0800588 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700589
Paul Lawrence4f13a902019-01-10 13:06:07 -0800590 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800591 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
592 original_ls.block_size, original_ls.block_size);
593 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
594
595 Used_Sectors used_sectors;
596 used_sectors[0] = false;
597
598 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800599 LOG(ERROR) << "No magic!";
600 status = Status::fromExceptionCode(EINVAL, "No magic");
601 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700602 }
603
Paul Lawrence4f13a902019-01-10 13:06:07 -0800604 if (ls.block_size != original_ls.block_size) {
605 LOG(ERROR) << "Block size mismatch!";
606 status = Status::fromExceptionCode(EINVAL, "Block size mismatch");
607 break;
608 }
609
Paul Lawrence27691c22018-11-20 14:07:59 -0800610 if ((int)ls.sequence != sequence) {
611 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
612 status = Status::fromExceptionCode(
613 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
614 std::to_string(ls.sequence))
615 .c_str());
616 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700617 }
618
Paul Lawrence27691c22018-11-20 14:07:59 -0800619 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800620 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800621 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
622 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800623 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800624 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
625 << " to " << le->source << " with checksum " << std::hex
626 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800627
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800628 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800629 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800630 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
631 for (size_t i = 0; i < le->size; i += ls.block_size) {
632 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800633 }
634
635 if (le->checksum && checksum != le->checksum) {
636 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
637 status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
638 break;
639 }
640
Paul Lawrenced41a9392019-01-22 14:31:43 -0800641 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800642 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800643 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800644 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800645 restore_count++;
646 if (restore_limit && restore_count >= restore_limit) {
647 LOG(WARNING) << "Hit the test limit";
648 status = Status::fromExceptionCode(EAGAIN, "Hit the test limit");
649 break;
650 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800651 }
652 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700653 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800654
655 if (!status.isOk()) {
656 if (!validating) {
657 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
658 return status;
659 }
660
661 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800662 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800663 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800664 lseek64(device_fd, 0, SEEK_SET);
665 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800666 return Status::ok();
667 }
668
669 if (!validating) break;
670
671 validating = false;
672 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700673 }
674
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700675 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700676}
677
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700678Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700679 std::string oldContent, newContent;
680 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700681 struct stat st;
682 int result = stat(kMetadataCPFile.c_str(), &st);
683
684 // If the file doesn't exist, we aren't managing a checkpoint retry counter
685 if (result != 0) return Status::ok();
686 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
687 PLOG(ERROR) << "Failed to read checkpoint file";
688 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
689 }
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700690 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700691
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700692 if (!android::base::ParseInt(retryContent, &retry))
693 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
694 if (retry > 0) {
695 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700696
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700697 newContent = std::to_string(retry);
698 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
699 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
700 }
701 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700702}
703
704} // namespace vold
705} // namespace android