blob: 19c1f3cc9f426678285080c123b618a2454e7217 [file] [log] [blame]
Daniel Rosenberg65f99c92018-08-28 01:58:49 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "Checkpoint"
18#include "Checkpoint.h"
Daniel Rosenberg253b44e2019-02-01 19:25:47 -080019#include "VoldUtil.h"
Sandeep Patilf8da61f2019-04-15 08:45:27 -070020#include "VolumeManager.h"
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070021
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070022#include <fstream>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070023#include <list>
Paul Lawrence20400892018-10-03 14:14:52 -070024#include <memory>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070025#include <string>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080026#include <thread>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070027#include <vector>
28
29#include <android-base/file.h>
30#include <android-base/logging.h>
31#include <android-base/parseint.h>
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080032#include <android-base/properties.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070033#include <android-base/unique_fd.h>
Daniel Rosenbergd3992492018-10-02 17:40:44 -070034#include <android/hardware/boot/1.0/IBootControl.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070035#include <cutils/android_reboot.h>
36#include <fcntl.h>
37#include <fs_mgr.h>
38#include <linux/fs.h>
39#include <mntent.h>
40#include <sys/mount.h>
41#include <sys/stat.h>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080042#include <sys/statvfs.h>
43#include <unistd.h>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070044
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080045using android::base::GetBoolProperty;
46using android::base::GetUintProperty;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080047using android::base::SetProperty;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070048using android::binder::Status;
Tom Cherry4c5bde22019-01-29 14:34:01 -080049using android::fs_mgr::Fstab;
50using android::fs_mgr::ReadDefaultFstab;
51using android::fs_mgr::ReadFstabFromFile;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070052using android::hardware::hidl_string;
53using android::hardware::boot::V1_0::BoolResult;
Daniel Rosenberg886915b2019-01-23 15:16:04 -080054using android::hardware::boot::V1_0::CommandResult;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070055using android::hardware::boot::V1_0::IBootControl;
56using android::hardware::boot::V1_0::Slot;
57
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070058namespace android {
59namespace vold {
60
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070061namespace {
62const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
63
64bool setBowState(std::string const& block_device, std::string const& state) {
65 if (block_device.substr(0, 5) != "/dev/") {
66 LOG(ERROR) << "Expected block device, got " << block_device;
67 return false;
68 }
69
70 std::string state_filename = std::string("/sys/") + block_device.substr(5) + "/bow/state";
71 if (!android::base::WriteStringToFile(state, state_filename)) {
72 PLOG(ERROR) << "Failed to write to file " << state_filename;
73 return false;
74 }
75
76 return true;
77}
78
79} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070080
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080081Status cp_supportsCheckpoint(bool& result) {
82 result = false;
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080083
Tom Cherry4c5bde22019-01-29 14:34:01 -080084 for (const auto& entry : fstab_default) {
85 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080086 result = true;
87 return Status::ok();
88 }
89 }
90 return Status::ok();
91}
92
Paul Lawrencec5c79c52019-03-18 13:36:40 -070093Status cp_supportsBlockCheckpoint(bool& result) {
94 result = false;
95
96 for (const auto& entry : fstab_default) {
97 if (entry.fs_mgr_flags.checkpoint_blk) {
98 result = true;
99 return Status::ok();
100 }
101 }
102 return Status::ok();
103}
104
105Status cp_supportsFileCheckpoint(bool& result) {
106 result = false;
107
108 for (const auto& entry : fstab_default) {
109 if (entry.fs_mgr_flags.checkpoint_fs) {
110 result = true;
111 return Status::ok();
112 }
113 }
114 return Status::ok();
115}
116
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700117Status cp_startCheckpoint(int retry) {
118 if (retry < -1) return Status::fromExceptionCode(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700119 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700120 if (retry == -1) {
121 sp<IBootControl> module = IBootControl::getService();
122 if (module) {
123 std::string suffix;
124 auto cb = [&suffix](hidl_string s) { suffix = s; };
125 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
126 }
127 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700128 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
129 return Status::fromExceptionCode(errno, "Failed to write checkpoint file");
130 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700131}
132
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800133namespace {
134
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800135volatile bool isCheckpointing = false;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800136}
137
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700138Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800139 if (!isCheckpointing) {
140 return Status::ok();
141 }
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800142 sp<IBootControl> module = IBootControl::getService();
143 if (module) {
144 CommandResult cr;
145 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
146 if (!cr.success) {
147 std::string msg = "Error marking booted successfully: " + std::string(cr.errMsg);
148 return Status::fromExceptionCode(EINVAL, String8(msg.c_str()));
149 }
150 LOG(INFO) << "Marked slot as booted successfully.";
151 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700152 // Must take action for list of mounted checkpointed things here
153 // To do this, we walk the list of mounted file systems.
154 // But we also need to get the matching fstab entries to see
155 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700156 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700157
Tom Cherry4c5bde22019-01-29 14:34:01 -0800158 Fstab mounts;
159 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
160 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
161 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700162
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700163 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800164 for (const auto& mount_rec : mounts) {
165 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700166 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700167
Tom Cherry4c5bde22019-01-29 14:34:01 -0800168 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
169 if (fstab_rec->fs_type == "f2fs") {
170 std::string options = mount_rec.fs_options + ",checkpoint=enable";
171 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800172 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800173 return Status::fromExceptionCode(EINVAL, "Failed to remount");
174 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700175 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800176 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
177 if (!setBowState(mount_rec.blk_device, "2"))
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800178 return Status::fromExceptionCode(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700179 }
180 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800181 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800182 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800183 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800184 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700185 return Status::fromExceptionCode(errno, err_str.c_str());
186 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700187}
188
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700189namespace {
190void abort_metadata_file() {
191 std::string oldContent, newContent;
192 int retry = 0;
193 struct stat st;
194 int result = stat(kMetadataCPFile.c_str(), &st);
195
196 // If the file doesn't exist, we aren't managing a checkpoint retry counter
197 if (result != 0) return;
198 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
199 PLOG(ERROR) << "Failed to read checkpoint file";
200 return;
201 }
202 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
203
204 if (!android::base::ParseInt(retryContent, &retry)) {
205 PLOG(ERROR) << "Could not parse retry count";
206 return;
207 }
208 if (retry > 0) {
209 newContent = "0";
210 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
211 PLOG(ERROR) << "Could not write checkpoint file";
212 }
213}
214} // namespace
215
216void cp_abortChanges(const std::string& message, bool retry) {
217 if (!cp_needsCheckpoint()) return;
218 if (!retry) abort_metadata_file();
219 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700220}
221
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700222bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700223 std::string content;
224 bool ret;
225
226 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700227 if (ret) {
228 if (content == "0") return true;
229 if (content.substr(0, 3) == "-1 ") {
230 std::string oldSuffix = content.substr(3);
231 sp<IBootControl> module = IBootControl::getService();
232 std::string newSuffix;
233
234 if (module) {
235 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
236 module->getSuffix(module->getCurrentSlot(), cb);
237 if (oldSuffix == newSuffix) return true;
238 }
239 }
240 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700241 return false;
242}
243
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700244bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700245 bool ret;
246 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700247 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700248
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700249 if (isCheckpointing) return isCheckpointing;
250
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800251 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
252 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700253 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800254 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700255 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800256 if (ret) {
257 ret = content != "0";
258 isCheckpointing = ret;
259 return ret;
260 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700261 return false;
262}
263
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800264namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700265const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
266const uint32_t msleeptime_default = 1000; // 1 s
267const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800268
269const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
270const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
271
272const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
273const bool commit_on_full_default = true;
274
275static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
276 struct statvfs data;
277 uint64_t free_bytes = 0;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700278 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900279 uint64_t min_free_bytes =
280 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800281 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
282
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700283 struct timespec req;
284 req.tv_sec = msleeptime / 1000;
285 msleeptime %= 1000;
286 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800287 while (isCheckpointing) {
288 if (is_fs_cp) {
289 statvfs(mnt_pnt.c_str(), &data);
290 free_bytes = data.f_bavail * data.f_frsize;
291 } else {
292 int ret;
293 std::string size_filename = std::string("/sys/") + blk_device.substr(5) + "/bow/free";
294 std::string content;
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700295 ret = android::base::ReadFileToString(size_filename, &content);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800296 if (ret) {
297 free_bytes = std::strtoul(content.c_str(), NULL, 10);
298 }
299 }
300 if (free_bytes < min_free_bytes) {
301 if (commit_on_full) {
302 LOG(INFO) << "Low space for checkpointing. Commiting changes";
303 cp_commitChanges();
304 break;
305 } else {
306 LOG(INFO) << "Low space for checkpointing. Rebooting";
307 cp_abortChanges("checkpoint,low_space", false);
308 break;
309 }
310 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700311 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800312 }
313}
314
315} // namespace
316
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700317Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800318 if (!isCheckpointing) {
319 return Status::ok();
320 }
321
Tom Cherry4c5bde22019-01-29 14:34:01 -0800322 Fstab mounts;
323 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
324 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
325 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700326
Tom Cherry4c5bde22019-01-29 14:34:01 -0800327 for (const auto& mount_rec : mounts) {
328 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700329 if (!fstab_rec) continue;
330
Tom Cherry4c5bde22019-01-29 14:34:01 -0800331 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700332 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800333 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900334 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800335 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700336 continue;
337 }
338
339 struct fstrim_range range = {};
340 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700341 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700342 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800343 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700344 continue;
345 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700346 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
347 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
348 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700349
Tom Cherry4c5bde22019-01-29 14:34:01 -0800350 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700351 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800352 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
353 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700354 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800355 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
356 .detach();
357 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700358 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700359 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700360}
361
362namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700363const int kSectorSize = 512;
364
365typedef uint64_t sector_t;
366
367struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800368 sector_t source; // in sectors of size kSectorSize
369 sector_t dest; // in sectors of size kSectorSize
370 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700371 uint32_t checksum;
372} __attribute__((packed));
373
Paul Lawrencef5077682019-01-18 10:28:34 -0800374struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700375 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800376 uint16_t header_version;
377 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800378 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700379 uint32_t count;
380 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800381 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700382} __attribute__((packed));
383
384// MAGIC is BOW in ascii
385const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800386// Partially restored MAGIC is WOB in ascii
387const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700388
389void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
390 static uint32_t table[0x100] = {
391 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
392 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
393 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
394 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
395 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
396 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
397 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
398 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
399 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
400 0xB6662D3D,
401
402 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
403 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
404 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
405 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
406 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
407 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
408 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
409 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
410 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
411 0xC0BA6CAD,
412
413 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
414 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
415 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
416 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
417 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
418 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
419 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
420 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
421 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
422 0x5BDEAE1D,
423
424 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
425 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
426 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
427 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
428 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
429 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
430 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
431 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
432 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
433 0x2D02EF8D};
434
435 for (size_t i = 0; i < n_bytes; ++i) {
436 *crc ^= ((uint8_t*)data)[i];
437 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
438 }
439}
440
Paul Lawrenced41a9392019-01-22 14:31:43 -0800441// A map of relocations.
442// The map must be initialized so that relocations[0] = 0
443// During restore, we replay the log records in reverse, copying from dest to
444// source
445// To validate, we must be able to read the 'dest' sectors as though they had
446// been copied but without actually copying. This map represents how the sectors
447// would have been moved. To read a sector s, find the index <= s and read
448// relocations[index] + s - index
449typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800450
Paul Lawrenced41a9392019-01-22 14:31:43 -0800451void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
452 // Find first one we're equal to or greater than
453 auto s = --relocations.upper_bound(source);
454
455 // Take slice
456 Relocations slice;
457 slice[dest] = source - s->first + s->second;
458 ++s;
459
460 // Add rest of elements
461 for (; s != relocations.end() && s->first < source + count; ++s)
462 slice[dest - source + s->first] = s->second;
463
464 // Split range at end of dest
465 auto dest_end = --relocations.upper_bound(dest + count);
466 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
467
468 // Remove all elements in [dest, dest + count)
469 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
470
471 // Add new elements
472 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800473}
474
Daniel Rosenberg52985932019-03-01 22:01:22 -0800475// A map of sectors that have been written to.
476// The final entry must always be False.
477// When we restart the restore after an interruption, we must take care that
478// when we copy from dest to source, that the block we copy to was not
479// previously copied from.
480// i e. A->B C->A; If we replay this sequence, we end up copying C->B
481// We must save our partial result whenever we finish a page, or when we copy
482// to a location that was copied from earlier (our source is an earlier dest)
483typedef std::map<sector_t, bool> Used_Sectors;
484
485bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
486 auto second_overlap = used_sectors.upper_bound(start);
487 auto first_overlap = --second_overlap;
488
489 if (first_overlap->second) {
490 return true;
491 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
492 return true;
493 }
494 return false;
495}
496
497void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
498 auto start_pos = used_sectors.insert_or_assign(start, true).first;
499 auto end_pos = used_sectors.insert_or_assign(end, false).first;
500
501 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
502 start_pos++;
503 }
504 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
505 end_pos++;
506 }
507 if (start_pos->first < end_pos->first) {
508 used_sectors.erase(start_pos, end_pos);
509 }
510}
511
512// Restores the given log_entry's data from dest -> source
513// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
514void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
515 log_entry* le, std::vector<char>& buffer) {
516 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
517 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
518 int count = (le->size - 1) / kSectorSize + 1;
519
520 if (checkCollision(used_sectors, le->source, le->source + count)) {
521 fsync(device_fd);
522 lseek64(device_fd, 0, SEEK_SET);
523 ls.count = index + 1;
524 ls.magic = kPartialRestoreMagic;
525 write(device_fd, &ls_buffer[0], ls.block_size);
526 fsync(device_fd);
527 used_sectors.clear();
528 used_sectors[0] = false;
529 }
530
531 markUsed(used_sectors, le->dest, le->dest + count);
532
533 if (index == 0 && ls.sequence != 0) {
534 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
535 if (next->magic == kMagic) {
536 next->magic = kPartialRestoreMagic;
537 }
538 }
539
540 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
541 write(device_fd, &buffer[0], le->size);
542
543 if (index == 0) {
544 fsync(device_fd);
545 }
546}
547
Paul Lawrenced41a9392019-01-22 14:31:43 -0800548// Read from the device
549// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800550std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
551 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800552 if (!validating) {
553 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800554 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
555 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800556 return buffer;
557 }
558
Paul Lawrence27691c22018-11-20 14:07:59 -0800559 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800560 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
561 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800562 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
563 SEEK_SET);
564 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800565 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800566
567 return buffer;
568}
569
Paul Lawrence4f13a902019-01-10 13:06:07 -0800570} // namespace
571
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800572Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800573 bool validating = true;
574 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800575 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700576
Paul Lawrence27691c22018-11-20 14:07:59 -0800577 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800578 Relocations relocations;
579 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800580 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700581
Paul Lawrence27691c22018-11-20 14:07:59 -0800582 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700583 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800584 if (device_fd < 0) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800585 PLOG(ERROR) << "Cannot open " << blockDevice;
586 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
587 }
Paul Lawrence4f13a902019-01-10 13:06:07 -0800588
Paul Lawrencef5077682019-01-18 10:28:34 -0800589 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800590 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800591 if (original_ls.magic == kPartialRestoreMagic) {
592 validating = false;
593 action = "Restoring";
594 } else if (original_ls.magic != kMagic) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800595 LOG(ERROR) << "No magic";
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700596 return Status::fromExceptionCode(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700597 }
598
Paul Lawrence4f13a902019-01-10 13:06:07 -0800599 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700600
Paul Lawrence4f13a902019-01-10 13:06:07 -0800601 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800602 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
603 original_ls.block_size, original_ls.block_size);
604 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
605
606 Used_Sectors used_sectors;
607 used_sectors[0] = false;
608
609 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800610 LOG(ERROR) << "No magic!";
611 status = Status::fromExceptionCode(EINVAL, "No magic");
612 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700613 }
614
Paul Lawrence4f13a902019-01-10 13:06:07 -0800615 if (ls.block_size != original_ls.block_size) {
616 LOG(ERROR) << "Block size mismatch!";
617 status = Status::fromExceptionCode(EINVAL, "Block size mismatch");
618 break;
619 }
620
Paul Lawrence27691c22018-11-20 14:07:59 -0800621 if ((int)ls.sequence != sequence) {
622 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
623 status = Status::fromExceptionCode(
624 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
625 std::to_string(ls.sequence))
626 .c_str());
627 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700628 }
629
Paul Lawrence27691c22018-11-20 14:07:59 -0800630 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800631 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800632 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
633 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800634 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800635 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
636 << " to " << le->source << " with checksum " << std::hex
637 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800638
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800639 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800640 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800641 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
642 for (size_t i = 0; i < le->size; i += ls.block_size) {
643 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800644 }
645
646 if (le->checksum && checksum != le->checksum) {
647 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
648 status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
649 break;
650 }
651
Paul Lawrenced41a9392019-01-22 14:31:43 -0800652 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800653 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800654 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800655 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800656 restore_count++;
657 if (restore_limit && restore_count >= restore_limit) {
658 LOG(WARNING) << "Hit the test limit";
659 status = Status::fromExceptionCode(EAGAIN, "Hit the test limit");
660 break;
661 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800662 }
663 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700664 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800665
666 if (!status.isOk()) {
667 if (!validating) {
668 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
669 return status;
670 }
671
672 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800673 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800674 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800675 lseek64(device_fd, 0, SEEK_SET);
676 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800677 return Status::ok();
678 }
679
680 if (!validating) break;
681
682 validating = false;
683 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700684 }
685
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700686 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700687}
688
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700689Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700690 std::string oldContent, newContent;
691 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700692 struct stat st;
693 int result = stat(kMetadataCPFile.c_str(), &st);
694
695 // If the file doesn't exist, we aren't managing a checkpoint retry counter
696 if (result != 0) return Status::ok();
697 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
698 PLOG(ERROR) << "Failed to read checkpoint file";
699 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
700 }
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700701 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700702
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700703 if (!android::base::ParseInt(retryContent, &retry))
704 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
705 if (retry > 0) {
706 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700707
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700708 newContent = std::to_string(retry);
709 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
710 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
711 }
712 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700713}
714
715} // namespace vold
716} // namespace android