blob: 3392be52f91f709994ddc4df70bae02da1d32913 [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";
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900265const uint32_t usleeptime_default = 1000000; // 1 s
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800266
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);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900277 uint64_t min_free_bytes =
278 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800279 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
280
281 while (isCheckpointing) {
282 if (is_fs_cp) {
283 statvfs(mnt_pnt.c_str(), &data);
284 free_bytes = data.f_bavail * data.f_frsize;
285 } else {
286 int ret;
287 std::string size_filename = std::string("/sys/") + blk_device.substr(5) + "/bow/free";
288 std::string content;
289 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
290 if (ret) {
291 free_bytes = std::strtoul(content.c_str(), NULL, 10);
292 }
293 }
294 if (free_bytes < min_free_bytes) {
295 if (commit_on_full) {
296 LOG(INFO) << "Low space for checkpointing. Commiting changes";
297 cp_commitChanges();
298 break;
299 } else {
300 LOG(INFO) << "Low space for checkpointing. Rebooting";
301 cp_abortChanges("checkpoint,low_space", false);
302 break;
303 }
304 }
305 usleep(usleeptime);
306 }
307}
308
309} // namespace
310
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700311Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800312 if (!isCheckpointing) {
313 return Status::ok();
314 }
315
Tom Cherry4c5bde22019-01-29 14:34:01 -0800316 Fstab mounts;
317 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
318 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
319 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700320
Tom Cherry4c5bde22019-01-29 14:34:01 -0800321 for (const auto& mount_rec : mounts) {
322 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700323 if (!fstab_rec) continue;
324
Tom Cherry4c5bde22019-01-29 14:34:01 -0800325 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700326 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800327 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700328 if (!fd) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800329 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700330 continue;
331 }
332
333 struct fstrim_range range = {};
334 range.len = ULLONG_MAX;
335 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800336 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700337 continue;
338 }
339
Tom Cherry4c5bde22019-01-29 14:34:01 -0800340 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700341 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800342 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
343 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
344 std::string(mount_rec.mount_point),
345 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
346 .detach();
347 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700348 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700349 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700350}
351
352namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700353const int kSectorSize = 512;
354
355typedef uint64_t sector_t;
356
357struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800358 sector_t source; // in sectors of size kSectorSize
359 sector_t dest; // in sectors of size kSectorSize
360 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700361 uint32_t checksum;
362} __attribute__((packed));
363
Paul Lawrencef5077682019-01-18 10:28:34 -0800364struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700365 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800366 uint16_t header_version;
367 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800368 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700369 uint32_t count;
370 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800371 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700372} __attribute__((packed));
373
374// MAGIC is BOW in ascii
375const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800376// Partially restored MAGIC is WOB in ascii
377const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700378
379void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
380 static uint32_t table[0x100] = {
381 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
382 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
383 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
384 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
385 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
386 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
387 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
388 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
389 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
390 0xB6662D3D,
391
392 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
393 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
394 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
395 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
396 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
397 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
398 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
399 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
400 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
401 0xC0BA6CAD,
402
403 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
404 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
405 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
406 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
407 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
408 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
409 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
410 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
411 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
412 0x5BDEAE1D,
413
414 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
415 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
416 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
417 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
418 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
419 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
420 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
421 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
422 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
423 0x2D02EF8D};
424
425 for (size_t i = 0; i < n_bytes; ++i) {
426 *crc ^= ((uint8_t*)data)[i];
427 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
428 }
429}
430
Paul Lawrenced41a9392019-01-22 14:31:43 -0800431// A map of relocations.
432// The map must be initialized so that relocations[0] = 0
433// During restore, we replay the log records in reverse, copying from dest to
434// source
435// To validate, we must be able to read the 'dest' sectors as though they had
436// been copied but without actually copying. This map represents how the sectors
437// would have been moved. To read a sector s, find the index <= s and read
438// relocations[index] + s - index
439typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800440
Paul Lawrenced41a9392019-01-22 14:31:43 -0800441void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
442 // Find first one we're equal to or greater than
443 auto s = --relocations.upper_bound(source);
444
445 // Take slice
446 Relocations slice;
447 slice[dest] = source - s->first + s->second;
448 ++s;
449
450 // Add rest of elements
451 for (; s != relocations.end() && s->first < source + count; ++s)
452 slice[dest - source + s->first] = s->second;
453
454 // Split range at end of dest
455 auto dest_end = --relocations.upper_bound(dest + count);
456 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
457
458 // Remove all elements in [dest, dest + count)
459 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
460
461 // Add new elements
462 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800463}
464
Daniel Rosenberg52985932019-03-01 22:01:22 -0800465// A map of sectors that have been written to.
466// The final entry must always be False.
467// When we restart the restore after an interruption, we must take care that
468// when we copy from dest to source, that the block we copy to was not
469// previously copied from.
470// i e. A->B C->A; If we replay this sequence, we end up copying C->B
471// We must save our partial result whenever we finish a page, or when we copy
472// to a location that was copied from earlier (our source is an earlier dest)
473typedef std::map<sector_t, bool> Used_Sectors;
474
475bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
476 auto second_overlap = used_sectors.upper_bound(start);
477 auto first_overlap = --second_overlap;
478
479 if (first_overlap->second) {
480 return true;
481 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
482 return true;
483 }
484 return false;
485}
486
487void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
488 auto start_pos = used_sectors.insert_or_assign(start, true).first;
489 auto end_pos = used_sectors.insert_or_assign(end, false).first;
490
491 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
492 start_pos++;
493 }
494 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
495 end_pos++;
496 }
497 if (start_pos->first < end_pos->first) {
498 used_sectors.erase(start_pos, end_pos);
499 }
500}
501
502// Restores the given log_entry's data from dest -> source
503// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
504void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
505 log_entry* le, std::vector<char>& buffer) {
506 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
507 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
508 int count = (le->size - 1) / kSectorSize + 1;
509
510 if (checkCollision(used_sectors, le->source, le->source + count)) {
511 fsync(device_fd);
512 lseek64(device_fd, 0, SEEK_SET);
513 ls.count = index + 1;
514 ls.magic = kPartialRestoreMagic;
515 write(device_fd, &ls_buffer[0], ls.block_size);
516 fsync(device_fd);
517 used_sectors.clear();
518 used_sectors[0] = false;
519 }
520
521 markUsed(used_sectors, le->dest, le->dest + count);
522
523 if (index == 0 && ls.sequence != 0) {
524 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
525 if (next->magic == kMagic) {
526 next->magic = kPartialRestoreMagic;
527 }
528 }
529
530 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
531 write(device_fd, &buffer[0], le->size);
532
533 if (index == 0) {
534 fsync(device_fd);
535 }
536}
537
Paul Lawrenced41a9392019-01-22 14:31:43 -0800538// Read from the device
539// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800540std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
541 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800542 if (!validating) {
543 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800544 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
545 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800546 return buffer;
547 }
548
Paul Lawrence27691c22018-11-20 14:07:59 -0800549 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800550 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
551 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800552 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
553 SEEK_SET);
554 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800555 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800556
557 return buffer;
558}
559
Paul Lawrence4f13a902019-01-10 13:06:07 -0800560} // namespace
561
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800562Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800563 bool validating = true;
564 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800565 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700566
Paul Lawrence27691c22018-11-20 14:07:59 -0800567 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800568 Relocations relocations;
569 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800570 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700571
Paul Lawrence27691c22018-11-20 14:07:59 -0800572 LOG(INFO) << action << " checkpoint on " << blockDevice;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800573 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR));
574 if (device_fd < 0) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800575 PLOG(ERROR) << "Cannot open " << blockDevice;
576 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
577 }
Paul Lawrence4f13a902019-01-10 13:06:07 -0800578
Paul Lawrencef5077682019-01-18 10:28:34 -0800579 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800580 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800581 if (original_ls.magic == kPartialRestoreMagic) {
582 validating = false;
583 action = "Restoring";
584 } else if (original_ls.magic != kMagic) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800585 LOG(ERROR) << "No magic";
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700586 return Status::fromExceptionCode(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700587 }
588
Paul Lawrence4f13a902019-01-10 13:06:07 -0800589 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700590
Paul Lawrence4f13a902019-01-10 13:06:07 -0800591 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800592 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
593 original_ls.block_size, original_ls.block_size);
594 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
595
596 Used_Sectors used_sectors;
597 used_sectors[0] = false;
598
599 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800600 LOG(ERROR) << "No magic!";
601 status = Status::fromExceptionCode(EINVAL, "No magic");
602 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700603 }
604
Paul Lawrence4f13a902019-01-10 13:06:07 -0800605 if (ls.block_size != original_ls.block_size) {
606 LOG(ERROR) << "Block size mismatch!";
607 status = Status::fromExceptionCode(EINVAL, "Block size mismatch");
608 break;
609 }
610
Paul Lawrence27691c22018-11-20 14:07:59 -0800611 if ((int)ls.sequence != sequence) {
612 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
613 status = Status::fromExceptionCode(
614 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
615 std::to_string(ls.sequence))
616 .c_str());
617 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700618 }
619
Paul Lawrence27691c22018-11-20 14:07:59 -0800620 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800621 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800622 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
623 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800624 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800625 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
626 << " to " << le->source << " with checksum " << std::hex
627 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800628
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800629 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800630 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800631 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
632 for (size_t i = 0; i < le->size; i += ls.block_size) {
633 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800634 }
635
636 if (le->checksum && checksum != le->checksum) {
637 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
638 status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
639 break;
640 }
641
Paul Lawrenced41a9392019-01-22 14:31:43 -0800642 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800643 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800644 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800645 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800646 restore_count++;
647 if (restore_limit && restore_count >= restore_limit) {
648 LOG(WARNING) << "Hit the test limit";
649 status = Status::fromExceptionCode(EAGAIN, "Hit the test limit");
650 break;
651 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800652 }
653 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700654 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800655
656 if (!status.isOk()) {
657 if (!validating) {
658 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
659 return status;
660 }
661
662 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800663 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800664 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800665 lseek64(device_fd, 0, SEEK_SET);
666 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800667 return Status::ok();
668 }
669
670 if (!validating) break;
671
672 validating = false;
673 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700674 }
675
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700676 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700677}
678
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700679Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700680 std::string oldContent, newContent;
681 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700682 struct stat st;
683 int result = stat(kMetadataCPFile.c_str(), &st);
684
685 // If the file doesn't exist, we aren't managing a checkpoint retry counter
686 if (result != 0) return Status::ok();
687 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
688 PLOG(ERROR) << "Failed to read checkpoint file";
689 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
690 }
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700691 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700692
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700693 if (!android::base::ParseInt(retryContent, &retry))
694 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
695 if (retry > 0) {
696 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700697
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700698 newContent = std::to_string(retry);
699 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
700 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
701 }
702 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700703}
704
705} // namespace vold
706} // namespace android