blob: 0605c72d67cb3815a20c4d11afda796b8c16f0ec [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) {
75 if (block_device.substr(0, 5) != "/dev/") {
76 LOG(ERROR) << "Expected block device, got " << block_device;
77 return false;
78 }
79
80 std::string state_filename = std::string("/sys/") + block_device.substr(5) + "/bow/state";
81 if (!android::base::WriteStringToFile(state, state_filename)) {
82 PLOG(ERROR) << "Failed to write to file " << state_filename;
83 return false;
84 }
85
86 return true;
87}
88
89} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070090
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080091Status cp_supportsCheckpoint(bool& result) {
92 result = false;
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080093
Tom Cherry4c5bde22019-01-29 14:34:01 -080094 for (const auto& entry : fstab_default) {
95 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080096 result = true;
97 return Status::ok();
98 }
99 }
100 return Status::ok();
101}
102
Paul Lawrencec5c79c52019-03-18 13:36:40 -0700103Status cp_supportsBlockCheckpoint(bool& result) {
104 result = false;
105
106 for (const auto& entry : fstab_default) {
107 if (entry.fs_mgr_flags.checkpoint_blk) {
108 result = true;
109 return Status::ok();
110 }
111 }
112 return Status::ok();
113}
114
115Status cp_supportsFileCheckpoint(bool& result) {
116 result = false;
117
118 for (const auto& entry : fstab_default) {
119 if (entry.fs_mgr_flags.checkpoint_fs) {
120 result = true;
121 return Status::ok();
122 }
123 }
124 return Status::ok();
125}
126
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700127Status cp_startCheckpoint(int retry) {
Paul Lawrencec2a145f2019-05-15 09:42:04 -0700128 bool result;
129 if (!cp_supportsCheckpoint(result).isOk() || !result)
130 return error(ENOTSUP, "Checkpoints not supported");
131
Paul Lawrence82b35052019-04-19 14:26:39 -0700132 if (retry < -1) return error(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700133 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700134 if (retry == -1) {
135 sp<IBootControl> module = IBootControl::getService();
136 if (module) {
137 std::string suffix;
138 auto cb = [&suffix](hidl_string s) { suffix = s; };
139 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
140 }
141 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700142 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700143 return error("Failed to write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700144 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700145}
146
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800147namespace {
148
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800149volatile bool isCheckpointing = false;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800150}
151
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700152Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800153 if (!isCheckpointing) {
154 return Status::ok();
155 }
Paul Lawrence3f1ce062019-06-12 12:03:01 -0700156 if (android::base::GetProperty("persist.vold.dont_commit_checkpoint", "0") == "1") {
157 LOG(WARNING)
158 << "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
159 return Status::ok();
160 }
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800161 sp<IBootControl> module = IBootControl::getService();
162 if (module) {
163 CommandResult cr;
164 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
Paul Lawrence82b35052019-04-19 14:26:39 -0700165 if (!cr.success)
166 return error(EINVAL, "Error marking booted successfully: " + std::string(cr.errMsg));
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800167 LOG(INFO) << "Marked slot as booted successfully.";
168 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700169 // Must take action for list of mounted checkpointed things here
170 // To do this, we walk the list of mounted file systems.
171 // But we also need to get the matching fstab entries to see
172 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700173 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700174
Tom Cherry4c5bde22019-01-29 14:34:01 -0800175 Fstab mounts;
176 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700177 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800178 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700179
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700180 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800181 for (const auto& mount_rec : mounts) {
182 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700183 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700184
Tom Cherry4c5bde22019-01-29 14:34:01 -0800185 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
186 if (fstab_rec->fs_type == "f2fs") {
187 std::string options = mount_rec.fs_options + ",checkpoint=enable";
188 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800189 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700190 return error(EINVAL, "Failed to remount");
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800191 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700192 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800193 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
194 if (!setBowState(mount_rec.blk_device, "2"))
Paul Lawrence82b35052019-04-19 14:26:39 -0700195 return error(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700196 }
197 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800198 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800199 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800200 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800201 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Paul Lawrence82b35052019-04-19 14:26:39 -0700202 return error(err_str.c_str());
203
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700204 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700205}
206
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700207namespace {
208void abort_metadata_file() {
209 std::string oldContent, newContent;
210 int retry = 0;
211 struct stat st;
212 int result = stat(kMetadataCPFile.c_str(), &st);
213
214 // If the file doesn't exist, we aren't managing a checkpoint retry counter
215 if (result != 0) return;
216 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
217 PLOG(ERROR) << "Failed to read checkpoint file";
218 return;
219 }
220 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
221
222 if (!android::base::ParseInt(retryContent, &retry)) {
223 PLOG(ERROR) << "Could not parse retry count";
224 return;
225 }
226 if (retry > 0) {
227 newContent = "0";
228 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
229 PLOG(ERROR) << "Could not write checkpoint file";
230 }
231}
232} // namespace
233
234void cp_abortChanges(const std::string& message, bool retry) {
235 if (!cp_needsCheckpoint()) return;
236 if (!retry) abort_metadata_file();
237 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700238}
239
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700240bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700241 std::string content;
242 bool ret;
243
244 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700245 if (ret) {
246 if (content == "0") return true;
247 if (content.substr(0, 3) == "-1 ") {
248 std::string oldSuffix = content.substr(3);
249 sp<IBootControl> module = IBootControl::getService();
250 std::string newSuffix;
251
252 if (module) {
253 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
254 module->getSuffix(module->getCurrentSlot(), cb);
255 if (oldSuffix == newSuffix) return true;
256 }
257 }
258 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700259 return false;
260}
261
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700262bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700263 bool ret;
264 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700265 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700266
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700267 if (isCheckpointing) return isCheckpointing;
268
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800269 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
270 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700271 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800272 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700273 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800274 if (ret) {
275 ret = content != "0";
276 isCheckpointing = ret;
277 return ret;
278 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700279 return false;
280}
281
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800282namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700283const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
284const uint32_t msleeptime_default = 1000; // 1 s
285const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800286
287const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
288const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
289
290const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
291const bool commit_on_full_default = true;
292
293static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
294 struct statvfs data;
295 uint64_t free_bytes = 0;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700296 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900297 uint64_t min_free_bytes =
298 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800299 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
300
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700301 struct timespec req;
302 req.tv_sec = msleeptime / 1000;
303 msleeptime %= 1000;
304 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800305 while (isCheckpointing) {
306 if (is_fs_cp) {
307 statvfs(mnt_pnt.c_str(), &data);
308 free_bytes = data.f_bavail * data.f_frsize;
309 } else {
310 int ret;
311 std::string size_filename = std::string("/sys/") + blk_device.substr(5) + "/bow/free";
312 std::string content;
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700313 ret = android::base::ReadFileToString(size_filename, &content);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800314 if (ret) {
315 free_bytes = std::strtoul(content.c_str(), NULL, 10);
316 }
317 }
318 if (free_bytes < min_free_bytes) {
319 if (commit_on_full) {
320 LOG(INFO) << "Low space for checkpointing. Commiting changes";
321 cp_commitChanges();
322 break;
323 } else {
324 LOG(INFO) << "Low space for checkpointing. Rebooting";
325 cp_abortChanges("checkpoint,low_space", false);
326 break;
327 }
328 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700329 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800330 }
331}
332
333} // namespace
334
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700335Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800336 if (!isCheckpointing) {
337 return Status::ok();
338 }
339
Tom Cherry4c5bde22019-01-29 14:34:01 -0800340 Fstab mounts;
341 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700342 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800343 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700344
Tom Cherry4c5bde22019-01-29 14:34:01 -0800345 for (const auto& mount_rec : mounts) {
346 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700347 if (!fstab_rec) continue;
348
Tom Cherry4c5bde22019-01-29 14:34:01 -0800349 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700350 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800351 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900352 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800353 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700354 continue;
355 }
356
357 struct fstrim_range range = {};
358 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700359 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700360 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800361 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700362 continue;
363 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700364 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
365 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
366 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700367
Tom Cherry4c5bde22019-01-29 14:34:01 -0800368 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700369 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800370 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
371 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700372 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800373 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
374 .detach();
375 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700376 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700377 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700378}
379
380namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700381const int kSectorSize = 512;
382
383typedef uint64_t sector_t;
384
385struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800386 sector_t source; // in sectors of size kSectorSize
387 sector_t dest; // in sectors of size kSectorSize
388 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700389 uint32_t checksum;
390} __attribute__((packed));
391
Paul Lawrencef5077682019-01-18 10:28:34 -0800392struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700393 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800394 uint16_t header_version;
395 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800396 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700397 uint32_t count;
398 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800399 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700400} __attribute__((packed));
401
402// MAGIC is BOW in ascii
403const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800404// Partially restored MAGIC is WOB in ascii
405const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700406
407void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
408 static uint32_t table[0x100] = {
409 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
410 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
411 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
412 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
413 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
414 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
415 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
416 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
417 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
418 0xB6662D3D,
419
420 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
421 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
422 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
423 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
424 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
425 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
426 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
427 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
428 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
429 0xC0BA6CAD,
430
431 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
432 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
433 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
434 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
435 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
436 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
437 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
438 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
439 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
440 0x5BDEAE1D,
441
442 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
443 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
444 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
445 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
446 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
447 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
448 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
449 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
450 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
451 0x2D02EF8D};
452
453 for (size_t i = 0; i < n_bytes; ++i) {
454 *crc ^= ((uint8_t*)data)[i];
455 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
456 }
457}
458
Paul Lawrenced41a9392019-01-22 14:31:43 -0800459// A map of relocations.
460// The map must be initialized so that relocations[0] = 0
461// During restore, we replay the log records in reverse, copying from dest to
462// source
463// To validate, we must be able to read the 'dest' sectors as though they had
464// been copied but without actually copying. This map represents how the sectors
465// would have been moved. To read a sector s, find the index <= s and read
466// relocations[index] + s - index
467typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800468
Paul Lawrenced41a9392019-01-22 14:31:43 -0800469void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
470 // Find first one we're equal to or greater than
471 auto s = --relocations.upper_bound(source);
472
473 // Take slice
474 Relocations slice;
475 slice[dest] = source - s->first + s->second;
476 ++s;
477
478 // Add rest of elements
479 for (; s != relocations.end() && s->first < source + count; ++s)
480 slice[dest - source + s->first] = s->second;
481
482 // Split range at end of dest
483 auto dest_end = --relocations.upper_bound(dest + count);
484 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
485
486 // Remove all elements in [dest, dest + count)
487 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
488
489 // Add new elements
490 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800491}
492
Daniel Rosenberg52985932019-03-01 22:01:22 -0800493// A map of sectors that have been written to.
494// The final entry must always be False.
495// When we restart the restore after an interruption, we must take care that
496// when we copy from dest to source, that the block we copy to was not
497// previously copied from.
498// i e. A->B C->A; If we replay this sequence, we end up copying C->B
499// We must save our partial result whenever we finish a page, or when we copy
500// to a location that was copied from earlier (our source is an earlier dest)
501typedef std::map<sector_t, bool> Used_Sectors;
502
503bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
504 auto second_overlap = used_sectors.upper_bound(start);
505 auto first_overlap = --second_overlap;
506
507 if (first_overlap->second) {
508 return true;
509 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
510 return true;
511 }
512 return false;
513}
514
515void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
516 auto start_pos = used_sectors.insert_or_assign(start, true).first;
517 auto end_pos = used_sectors.insert_or_assign(end, false).first;
518
519 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
520 start_pos++;
521 }
522 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
523 end_pos++;
524 }
525 if (start_pos->first < end_pos->first) {
526 used_sectors.erase(start_pos, end_pos);
527 }
528}
529
530// Restores the given log_entry's data from dest -> source
531// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
532void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
533 log_entry* le, std::vector<char>& buffer) {
534 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
535 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
536 int count = (le->size - 1) / kSectorSize + 1;
537
538 if (checkCollision(used_sectors, le->source, le->source + count)) {
539 fsync(device_fd);
540 lseek64(device_fd, 0, SEEK_SET);
541 ls.count = index + 1;
542 ls.magic = kPartialRestoreMagic;
543 write(device_fd, &ls_buffer[0], ls.block_size);
544 fsync(device_fd);
545 used_sectors.clear();
546 used_sectors[0] = false;
547 }
548
549 markUsed(used_sectors, le->dest, le->dest + count);
550
551 if (index == 0 && ls.sequence != 0) {
552 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
553 if (next->magic == kMagic) {
554 next->magic = kPartialRestoreMagic;
555 }
556 }
557
558 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
559 write(device_fd, &buffer[0], le->size);
560
561 if (index == 0) {
562 fsync(device_fd);
563 }
564}
565
Paul Lawrenced41a9392019-01-22 14:31:43 -0800566// Read from the device
567// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800568std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
569 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800570 if (!validating) {
571 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800572 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
573 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800574 return buffer;
575 }
576
Paul Lawrence27691c22018-11-20 14:07:59 -0800577 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800578 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
579 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800580 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
581 SEEK_SET);
582 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800583 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800584
585 return buffer;
586}
587
Paul Lawrence4f13a902019-01-10 13:06:07 -0800588} // namespace
589
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800590Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800591 bool validating = true;
592 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800593 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700594
Paul Lawrence27691c22018-11-20 14:07:59 -0800595 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800596 Relocations relocations;
597 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800598 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700599
Paul Lawrence27691c22018-11-20 14:07:59 -0800600 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700601 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700602 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800603
Paul Lawrencef5077682019-01-18 10:28:34 -0800604 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800605 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800606 if (original_ls.magic == kPartialRestoreMagic) {
607 validating = false;
608 action = "Restoring";
609 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700610 return error(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700611 }
612
Paul Lawrence4f13a902019-01-10 13:06:07 -0800613 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700614
Paul Lawrence4f13a902019-01-10 13:06:07 -0800615 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800616 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
617 original_ls.block_size, original_ls.block_size);
618 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
619
620 Used_Sectors used_sectors;
621 used_sectors[0] = false;
622
623 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700624 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800625 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700626 }
627
Paul Lawrence4f13a902019-01-10 13:06:07 -0800628 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700629 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800630 break;
631 }
632
Paul Lawrence27691c22018-11-20 14:07:59 -0800633 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700634 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
635 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800636 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700637 }
638
Paul Lawrence27691c22018-11-20 14:07:59 -0800639 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800640 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800641 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
642 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800643 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800644 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
645 << " to " << le->source << " with checksum " << std::hex
646 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800647
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800648 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800649 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800650 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
651 for (size_t i = 0; i < le->size; i += ls.block_size) {
652 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800653 }
654
655 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700656 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800657 break;
658 }
659
Paul Lawrenced41a9392019-01-22 14:31:43 -0800660 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800661 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800662 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800663 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800664 restore_count++;
665 if (restore_limit && restore_count >= restore_limit) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700666 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800667 break;
668 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800669 }
670 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700671 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800672
673 if (!status.isOk()) {
674 if (!validating) {
675 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
676 return status;
677 }
678
679 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800680 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800681 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800682 lseek64(device_fd, 0, SEEK_SET);
683 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800684 return Status::ok();
685 }
686
687 if (!validating) break;
688
689 validating = false;
690 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700691 }
692
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700693 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700694}
695
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700696Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700697 std::string oldContent, newContent;
698 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700699 struct stat st;
700 int result = stat(kMetadataCPFile.c_str(), &st);
701
702 // If the file doesn't exist, we aren't managing a checkpoint retry counter
703 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700704 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
705 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700706 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700707
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700708 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700709 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700710 if (retry > 0) {
711 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700712
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700713 newContent = std::to_string(retry);
714 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700715 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700716 }
717 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700718}
719
720} // namespace vold
721} // namespace android