blob: 616365fbad220a0dc0650f5cf27cfa6937ee7829 [file] [log] [blame]
Daniel Rosenberg65f99c92018-08-28 01:58:49 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "Checkpoint"
18#include "Checkpoint.h"
Daniel Rosenberg253b44e2019-02-01 19:25:47 -080019#include "VoldUtil.h"
Sandeep Patilf8da61f2019-04-15 08:45:27 -070020#include "VolumeManager.h"
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070021
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070022#include <fstream>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070023#include <list>
Paul Lawrence20400892018-10-03 14:14:52 -070024#include <memory>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070025#include <string>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080026#include <thread>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070027#include <vector>
28
29#include <android-base/file.h>
30#include <android-base/logging.h>
31#include <android-base/parseint.h>
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080032#include <android-base/properties.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070033#include <android-base/unique_fd.h>
Daniel Rosenbergd3992492018-10-02 17:40:44 -070034#include <android/hardware/boot/1.0/IBootControl.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070035#include <cutils/android_reboot.h>
36#include <fcntl.h>
37#include <fs_mgr.h>
38#include <linux/fs.h>
39#include <mntent.h>
40#include <sys/mount.h>
41#include <sys/stat.h>
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080042#include <sys/statvfs.h>
43#include <unistd.h>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070044
Daniel Rosenberg8daeec02018-11-20 19:03:11 -080045using android::base::GetBoolProperty;
46using android::base::GetUintProperty;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080047using android::base::SetProperty;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070048using android::binder::Status;
Tom Cherry4c5bde22019-01-29 14:34:01 -080049using android::fs_mgr::Fstab;
50using android::fs_mgr::ReadDefaultFstab;
51using android::fs_mgr::ReadFstabFromFile;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070052using android::hardware::hidl_string;
53using android::hardware::boot::V1_0::BoolResult;
Daniel Rosenberg886915b2019-01-23 15:16:04 -080054using android::hardware::boot::V1_0::CommandResult;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070055using android::hardware::boot::V1_0::IBootControl;
56using android::hardware::boot::V1_0::Slot;
57
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070058namespace android {
59namespace vold {
60
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070061namespace {
62const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
63
Paul Lawrence82b35052019-04-19 14:26:39 -070064binder::Status error(const std::string& msg) {
65 PLOG(ERROR) << msg;
66 return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str()));
67}
68
69binder::Status error(int error, const std::string& msg) {
70 LOG(ERROR) << msg;
71 return binder::Status::fromServiceSpecificError(error, String8(msg.c_str()));
72}
73
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070074bool setBowState(std::string const& block_device, std::string const& state) {
Paul Lawrence236e5e82019-06-25 14:44:33 -070075 std::string bow_device = fs_mgr_find_bow_device(block_device);
76 if (bow_device.empty()) return false;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070077
Paul Lawrence236e5e82019-06-25 14:44:33 -070078 if (!android::base::WriteStringToFile(state, bow_device + "/bow/state")) {
79 PLOG(ERROR) << "Failed to write to file " << bow_device + "/bow/state";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070080 return false;
81 }
82
83 return true;
84}
85
86} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070087
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080088Status cp_supportsCheckpoint(bool& result) {
89 result = false;
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080090
Tom Cherry4c5bde22019-01-29 14:34:01 -080091 for (const auto& entry : fstab_default) {
92 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080093 result = true;
94 return Status::ok();
95 }
96 }
97 return Status::ok();
98}
99
Paul Lawrencec5c79c52019-03-18 13:36:40 -0700100Status cp_supportsBlockCheckpoint(bool& result) {
101 result = false;
102
103 for (const auto& entry : fstab_default) {
104 if (entry.fs_mgr_flags.checkpoint_blk) {
105 result = true;
106 return Status::ok();
107 }
108 }
109 return Status::ok();
110}
111
112Status cp_supportsFileCheckpoint(bool& result) {
113 result = false;
114
115 for (const auto& entry : fstab_default) {
116 if (entry.fs_mgr_flags.checkpoint_fs) {
117 result = true;
118 return Status::ok();
119 }
120 }
121 return Status::ok();
122}
123
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700124Status cp_startCheckpoint(int retry) {
Paul Lawrencec2a145f2019-05-15 09:42:04 -0700125 bool result;
126 if (!cp_supportsCheckpoint(result).isOk() || !result)
127 return error(ENOTSUP, "Checkpoints not supported");
128
Paul Lawrence82b35052019-04-19 14:26:39 -0700129 if (retry < -1) return error(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700130 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700131 if (retry == -1) {
132 sp<IBootControl> module = IBootControl::getService();
133 if (module) {
134 std::string suffix;
135 auto cb = [&suffix](hidl_string s) { suffix = s; };
136 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
137 }
138 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700139 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700140 return error("Failed to write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700141 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700142}
143
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800144namespace {
145
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800146volatile bool isCheckpointing = false;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800147}
148
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700149Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800150 if (!isCheckpointing) {
151 return Status::ok();
152 }
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800153 sp<IBootControl> module = IBootControl::getService();
154 if (module) {
155 CommandResult cr;
156 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
Paul Lawrence82b35052019-04-19 14:26:39 -0700157 if (!cr.success)
158 return error(EINVAL, "Error marking booted successfully: " + std::string(cr.errMsg));
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800159 LOG(INFO) << "Marked slot as booted successfully.";
160 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700161 // Must take action for list of mounted checkpointed things here
162 // To do this, we walk the list of mounted file systems.
163 // But we also need to get the matching fstab entries to see
164 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700165 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700166
Tom Cherry4c5bde22019-01-29 14:34:01 -0800167 Fstab mounts;
168 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700169 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800170 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700171
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700172 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800173 for (const auto& mount_rec : mounts) {
174 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700175 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700176
Tom Cherry4c5bde22019-01-29 14:34:01 -0800177 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
178 if (fstab_rec->fs_type == "f2fs") {
179 std::string options = mount_rec.fs_options + ",checkpoint=enable";
180 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800181 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700182 return error(EINVAL, "Failed to remount");
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800183 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700184 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800185 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
186 if (!setBowState(mount_rec.blk_device, "2"))
Paul Lawrence82b35052019-04-19 14:26:39 -0700187 return error(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700188 }
189 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800190 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800191 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800192 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800193 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Paul Lawrence82b35052019-04-19 14:26:39 -0700194 return error(err_str.c_str());
195
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700196 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700197}
198
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700199namespace {
200void abort_metadata_file() {
201 std::string oldContent, newContent;
202 int retry = 0;
203 struct stat st;
204 int result = stat(kMetadataCPFile.c_str(), &st);
205
206 // If the file doesn't exist, we aren't managing a checkpoint retry counter
207 if (result != 0) return;
208 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
209 PLOG(ERROR) << "Failed to read checkpoint file";
210 return;
211 }
212 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
213
214 if (!android::base::ParseInt(retryContent, &retry)) {
215 PLOG(ERROR) << "Could not parse retry count";
216 return;
217 }
218 if (retry > 0) {
219 newContent = "0";
220 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
221 PLOG(ERROR) << "Could not write checkpoint file";
222 }
223}
224} // namespace
225
226void cp_abortChanges(const std::string& message, bool retry) {
227 if (!cp_needsCheckpoint()) return;
228 if (!retry) abort_metadata_file();
229 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700230}
231
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700232bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700233 std::string content;
234 bool ret;
235
236 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700237 if (ret) {
238 if (content == "0") return true;
239 if (content.substr(0, 3) == "-1 ") {
240 std::string oldSuffix = content.substr(3);
241 sp<IBootControl> module = IBootControl::getService();
242 std::string newSuffix;
243
244 if (module) {
245 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
246 module->getSuffix(module->getCurrentSlot(), cb);
247 if (oldSuffix == newSuffix) return true;
248 }
249 }
250 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700251 return false;
252}
253
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700254bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700255 bool ret;
256 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700257 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700258
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700259 if (isCheckpointing) return isCheckpointing;
260
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800261 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
262 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700263 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800264 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700265 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800266 if (ret) {
267 ret = content != "0";
268 isCheckpointing = ret;
269 return ret;
270 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700271 return false;
272}
273
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800274namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700275const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
276const uint32_t msleeptime_default = 1000; // 1 s
277const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800278
279const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
280const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
281
282const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
283const bool commit_on_full_default = true;
284
285static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
286 struct statvfs data;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700287 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900288 uint64_t min_free_bytes =
289 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800290 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
291
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700292 struct timespec req;
293 req.tv_sec = msleeptime / 1000;
294 msleeptime %= 1000;
295 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800296 while (isCheckpointing) {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700297 uint64_t free_bytes = 0;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800298 if (is_fs_cp) {
299 statvfs(mnt_pnt.c_str(), &data);
300 free_bytes = data.f_bavail * data.f_frsize;
301 } else {
Paul Lawrence236e5e82019-06-25 14:44:33 -0700302 std::string bow_device = fs_mgr_find_bow_device(blk_device);
303 if (!bow_device.empty()) {
304 std::string content;
305 if (android::base::ReadFileToString(bow_device + "/bow/free", &content)) {
306 free_bytes = std::strtoul(content.c_str(), NULL, 10);
307 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800308 }
309 }
310 if (free_bytes < min_free_bytes) {
311 if (commit_on_full) {
312 LOG(INFO) << "Low space for checkpointing. Commiting changes";
313 cp_commitChanges();
314 break;
315 } else {
316 LOG(INFO) << "Low space for checkpointing. Rebooting";
317 cp_abortChanges("checkpoint,low_space", false);
318 break;
319 }
320 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700321 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800322 }
323}
324
325} // namespace
326
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700327Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800328 if (!isCheckpointing) {
329 return Status::ok();
330 }
331
Tom Cherry4c5bde22019-01-29 14:34:01 -0800332 Fstab mounts;
333 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700334 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800335 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700336
Tom Cherry4c5bde22019-01-29 14:34:01 -0800337 for (const auto& mount_rec : mounts) {
338 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700339 if (!fstab_rec) continue;
340
Tom Cherry4c5bde22019-01-29 14:34:01 -0800341 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700342 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800343 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900344 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800345 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700346 continue;
347 }
348
349 struct fstrim_range range = {};
350 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700351 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700352 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800353 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700354 continue;
355 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700356 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
357 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
358 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700359
Tom Cherry4c5bde22019-01-29 14:34:01 -0800360 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700361 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800362 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
363 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700364 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800365 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
366 .detach();
367 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700368 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700369 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700370}
371
372namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700373const int kSectorSize = 512;
374
375typedef uint64_t sector_t;
376
377struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800378 sector_t source; // in sectors of size kSectorSize
379 sector_t dest; // in sectors of size kSectorSize
380 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700381 uint32_t checksum;
382} __attribute__((packed));
383
Paul Lawrencef5077682019-01-18 10:28:34 -0800384struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700385 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800386 uint16_t header_version;
387 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800388 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700389 uint32_t count;
390 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800391 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700392} __attribute__((packed));
393
394// MAGIC is BOW in ascii
395const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800396// Partially restored MAGIC is WOB in ascii
397const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700398
399void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
400 static uint32_t table[0x100] = {
401 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
402 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
403 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
404 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
405 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
406 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
407 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
408 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
409 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
410 0xB6662D3D,
411
412 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
413 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
414 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
415 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
416 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
417 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
418 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
419 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
420 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
421 0xC0BA6CAD,
422
423 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
424 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
425 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
426 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
427 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
428 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
429 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
430 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
431 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
432 0x5BDEAE1D,
433
434 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
435 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
436 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
437 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
438 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
439 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
440 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
441 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
442 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
443 0x2D02EF8D};
444
445 for (size_t i = 0; i < n_bytes; ++i) {
446 *crc ^= ((uint8_t*)data)[i];
447 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
448 }
449}
450
Paul Lawrenced41a9392019-01-22 14:31:43 -0800451// A map of relocations.
452// The map must be initialized so that relocations[0] = 0
453// During restore, we replay the log records in reverse, copying from dest to
454// source
455// To validate, we must be able to read the 'dest' sectors as though they had
456// been copied but without actually copying. This map represents how the sectors
457// would have been moved. To read a sector s, find the index <= s and read
458// relocations[index] + s - index
459typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800460
Paul Lawrenced41a9392019-01-22 14:31:43 -0800461void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
462 // Find first one we're equal to or greater than
463 auto s = --relocations.upper_bound(source);
464
465 // Take slice
466 Relocations slice;
467 slice[dest] = source - s->first + s->second;
468 ++s;
469
470 // Add rest of elements
471 for (; s != relocations.end() && s->first < source + count; ++s)
472 slice[dest - source + s->first] = s->second;
473
474 // Split range at end of dest
475 auto dest_end = --relocations.upper_bound(dest + count);
476 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
477
478 // Remove all elements in [dest, dest + count)
479 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
480
481 // Add new elements
482 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800483}
484
Daniel Rosenberg52985932019-03-01 22:01:22 -0800485// A map of sectors that have been written to.
486// The final entry must always be False.
487// When we restart the restore after an interruption, we must take care that
488// when we copy from dest to source, that the block we copy to was not
489// previously copied from.
490// i e. A->B C->A; If we replay this sequence, we end up copying C->B
491// We must save our partial result whenever we finish a page, or when we copy
492// to a location that was copied from earlier (our source is an earlier dest)
493typedef std::map<sector_t, bool> Used_Sectors;
494
495bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
496 auto second_overlap = used_sectors.upper_bound(start);
497 auto first_overlap = --second_overlap;
498
499 if (first_overlap->second) {
500 return true;
501 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
502 return true;
503 }
504 return false;
505}
506
507void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
508 auto start_pos = used_sectors.insert_or_assign(start, true).first;
509 auto end_pos = used_sectors.insert_or_assign(end, false).first;
510
511 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
512 start_pos++;
513 }
514 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
515 end_pos++;
516 }
517 if (start_pos->first < end_pos->first) {
518 used_sectors.erase(start_pos, end_pos);
519 }
520}
521
522// Restores the given log_entry's data from dest -> source
523// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
524void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
525 log_entry* le, std::vector<char>& buffer) {
526 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
527 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
528 int count = (le->size - 1) / kSectorSize + 1;
529
530 if (checkCollision(used_sectors, le->source, le->source + count)) {
531 fsync(device_fd);
532 lseek64(device_fd, 0, SEEK_SET);
533 ls.count = index + 1;
534 ls.magic = kPartialRestoreMagic;
535 write(device_fd, &ls_buffer[0], ls.block_size);
536 fsync(device_fd);
537 used_sectors.clear();
538 used_sectors[0] = false;
539 }
540
541 markUsed(used_sectors, le->dest, le->dest + count);
542
543 if (index == 0 && ls.sequence != 0) {
544 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
545 if (next->magic == kMagic) {
546 next->magic = kPartialRestoreMagic;
547 }
548 }
549
550 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
551 write(device_fd, &buffer[0], le->size);
552
553 if (index == 0) {
554 fsync(device_fd);
555 }
556}
557
Paul Lawrenced41a9392019-01-22 14:31:43 -0800558// Read from the device
559// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800560std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
561 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800562 if (!validating) {
563 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800564 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
565 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800566 return buffer;
567 }
568
Paul Lawrence27691c22018-11-20 14:07:59 -0800569 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800570 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
571 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800572 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
573 SEEK_SET);
574 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800575 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800576
577 return buffer;
578}
579
Paul Lawrence4f13a902019-01-10 13:06:07 -0800580} // namespace
581
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800582Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800583 bool validating = true;
584 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800585 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700586
Paul Lawrence27691c22018-11-20 14:07:59 -0800587 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800588 Relocations relocations;
589 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800590 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700591
Paul Lawrence27691c22018-11-20 14:07:59 -0800592 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700593 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700594 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800595
Paul Lawrencef5077682019-01-18 10:28:34 -0800596 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800597 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800598 if (original_ls.magic == kPartialRestoreMagic) {
599 validating = false;
600 action = "Restoring";
601 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700602 return error(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700603 }
604
Paul Lawrence4f13a902019-01-10 13:06:07 -0800605 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700606
Paul Lawrence4f13a902019-01-10 13:06:07 -0800607 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800608 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
609 original_ls.block_size, original_ls.block_size);
610 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
611
612 Used_Sectors used_sectors;
613 used_sectors[0] = false;
614
615 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700616 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800617 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700618 }
619
Paul Lawrence4f13a902019-01-10 13:06:07 -0800620 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700621 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800622 break;
623 }
624
Paul Lawrence27691c22018-11-20 14:07:59 -0800625 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700626 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
627 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800628 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700629 }
630
Paul Lawrence27691c22018-11-20 14:07:59 -0800631 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800632 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800633 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
634 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800635 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800636 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
637 << " to " << le->source << " with checksum " << std::hex
638 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800639
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800640 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800641 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800642 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
643 for (size_t i = 0; i < le->size; i += ls.block_size) {
644 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800645 }
646
647 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700648 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800649 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) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700658 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800659 break;
660 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800661 }
662 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700663 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800664
665 if (!status.isOk()) {
666 if (!validating) {
667 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
668 return status;
669 }
670
671 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800672 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800673 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800674 lseek64(device_fd, 0, SEEK_SET);
675 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800676 return Status::ok();
677 }
678
679 if (!validating) break;
680
681 validating = false;
682 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700683 }
684
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700685 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700686}
687
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700688Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700689 std::string oldContent, newContent;
690 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700691 struct stat st;
692 int result = stat(kMetadataCPFile.c_str(), &st);
693
694 // If the file doesn't exist, we aren't managing a checkpoint retry counter
695 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700696 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
697 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700698 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700699
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700700 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700701 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700702 if (retry > 0) {
703 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700704
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700705 newContent = std::to_string(retry);
706 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700707 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700708 }
709 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700710}
711
712} // namespace vold
713} // namespace android