blob: 8715bfa84e7ffb8630e9b77604b2607d9194652f [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 Lawrence82b35052019-04-19 14:26:39 -0700128 if (retry < -1) return error(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700129 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700130 if (retry == -1) {
131 sp<IBootControl> module = IBootControl::getService();
132 if (module) {
133 std::string suffix;
134 auto cb = [&suffix](hidl_string s) { suffix = s; };
135 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
136 }
137 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700138 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700139 return error("Failed to write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700140 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700141}
142
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800143namespace {
144
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800145volatile bool isCheckpointing = false;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800146}
147
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700148Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800149 if (!isCheckpointing) {
150 return Status::ok();
151 }
Paul Lawrencea7972dc2019-06-12 12:03:01 -0700152 if (android::base::GetProperty("persist.vold.dont_commit_checkpoint", "0") == "1") {
153 LOG(WARNING)
154 << "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
155 return Status::ok();
156 }
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800157 sp<IBootControl> module = IBootControl::getService();
158 if (module) {
159 CommandResult cr;
160 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
Paul Lawrence82b35052019-04-19 14:26:39 -0700161 if (!cr.success)
162 return error(EINVAL, "Error marking booted successfully: " + std::string(cr.errMsg));
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800163 LOG(INFO) << "Marked slot as booted successfully.";
164 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700165 // Must take action for list of mounted checkpointed things here
166 // To do this, we walk the list of mounted file systems.
167 // But we also need to get the matching fstab entries to see
168 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700169 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700170
Tom Cherry4c5bde22019-01-29 14:34:01 -0800171 Fstab mounts;
172 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700173 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800174 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700175
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700176 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800177 for (const auto& mount_rec : mounts) {
178 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700179 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700180
Tom Cherry4c5bde22019-01-29 14:34:01 -0800181 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
182 if (fstab_rec->fs_type == "f2fs") {
183 std::string options = mount_rec.fs_options + ",checkpoint=enable";
184 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800185 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700186 return error(EINVAL, "Failed to remount");
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800187 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700188 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800189 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
190 if (!setBowState(mount_rec.blk_device, "2"))
Paul Lawrence82b35052019-04-19 14:26:39 -0700191 return error(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700192 }
193 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800194 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800195 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800196 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800197 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Paul Lawrence82b35052019-04-19 14:26:39 -0700198 return error(err_str.c_str());
199
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700200 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700201}
202
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700203namespace {
204void abort_metadata_file() {
205 std::string oldContent, newContent;
206 int retry = 0;
207 struct stat st;
208 int result = stat(kMetadataCPFile.c_str(), &st);
209
210 // If the file doesn't exist, we aren't managing a checkpoint retry counter
211 if (result != 0) return;
212 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
213 PLOG(ERROR) << "Failed to read checkpoint file";
214 return;
215 }
216 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
217
218 if (!android::base::ParseInt(retryContent, &retry)) {
219 PLOG(ERROR) << "Could not parse retry count";
220 return;
221 }
222 if (retry > 0) {
223 newContent = "0";
224 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
225 PLOG(ERROR) << "Could not write checkpoint file";
226 }
227}
228} // namespace
229
230void cp_abortChanges(const std::string& message, bool retry) {
231 if (!cp_needsCheckpoint()) return;
232 if (!retry) abort_metadata_file();
233 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700234}
235
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700236bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700237 std::string content;
238 bool ret;
239
240 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700241 if (ret) {
242 if (content == "0") return true;
243 if (content.substr(0, 3) == "-1 ") {
244 std::string oldSuffix = content.substr(3);
245 sp<IBootControl> module = IBootControl::getService();
246 std::string newSuffix;
247
248 if (module) {
249 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
250 module->getSuffix(module->getCurrentSlot(), cb);
251 if (oldSuffix == newSuffix) return true;
252 }
253 }
254 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700255 return false;
256}
257
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700258bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700259 bool ret;
260 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700261 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700262
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700263 if (isCheckpointing) return isCheckpointing;
264
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800265 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
266 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700267 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800268 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700269 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800270 if (ret) {
271 ret = content != "0";
272 isCheckpointing = ret;
273 return ret;
274 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700275 return false;
276}
277
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800278namespace {
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700279const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
280const uint32_t msleeptime_default = 1000; // 1 s
281const uint32_t max_msleeptime = 3600000; // 1 h
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800282
283const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
284const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
285
286const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
287const bool commit_on_full_default = true;
288
289static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
290 struct statvfs data;
291 uint64_t free_bytes = 0;
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700292 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
Satoshi Futenma18d10d42019-03-25 23:13:36 +0900293 uint64_t min_free_bytes =
294 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800295 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
296
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700297 struct timespec req;
298 req.tv_sec = msleeptime / 1000;
299 msleeptime %= 1000;
300 req.tv_nsec = msleeptime * 1000000;
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800301 while (isCheckpointing) {
302 if (is_fs_cp) {
303 statvfs(mnt_pnt.c_str(), &data);
304 free_bytes = data.f_bavail * data.f_frsize;
305 } else {
306 int ret;
307 std::string size_filename = std::string("/sys/") + blk_device.substr(5) + "/bow/free";
308 std::string content;
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700309 ret = android::base::ReadFileToString(size_filename, &content);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800310 if (ret) {
311 free_bytes = std::strtoul(content.c_str(), NULL, 10);
312 }
313 }
314 if (free_bytes < min_free_bytes) {
315 if (commit_on_full) {
316 LOG(INFO) << "Low space for checkpointing. Commiting changes";
317 cp_commitChanges();
318 break;
319 } else {
320 LOG(INFO) << "Low space for checkpointing. Rebooting";
321 cp_abortChanges("checkpoint,low_space", false);
322 break;
323 }
324 }
Daniel Rosenbergb7dddd02019-03-26 14:42:14 -0700325 nanosleep(&req, NULL);
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800326 }
327}
328
329} // namespace
330
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700331Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800332 if (!isCheckpointing) {
333 return Status::ok();
334 }
335
Tom Cherry4c5bde22019-01-29 14:34:01 -0800336 Fstab mounts;
337 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700338 return error(EINVAL, "Failed to get /proc/mounts");
Tom Cherry4c5bde22019-01-29 14:34:01 -0800339 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700340
Tom Cherry4c5bde22019-01-29 14:34:01 -0800341 for (const auto& mount_rec : mounts) {
342 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700343 if (!fstab_rec) continue;
344
Tom Cherry4c5bde22019-01-29 14:34:01 -0800345 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700346 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800347 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Bernie Innocentiebe293a2019-03-28 15:24:30 +0900348 if (fd == -1) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800349 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700350 continue;
351 }
352
353 struct fstrim_range range = {};
354 range.len = ULLONG_MAX;
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700355 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700356 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800357 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700358 continue;
359 }
Sandeep Patilf8da61f2019-04-15 08:45:27 -0700360 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
361 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
362 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700363
Tom Cherry4c5bde22019-01-29 14:34:01 -0800364 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700365 }
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800366 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
367 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
Paul Lawrencee81f4c12019-03-29 13:06:34 -0700368 std::string(mount_rec.blk_device),
Daniel Rosenberg8daeec02018-11-20 19:03:11 -0800369 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
370 .detach();
371 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700372 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700373 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700374}
375
376namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700377const int kSectorSize = 512;
378
379typedef uint64_t sector_t;
380
381struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800382 sector_t source; // in sectors of size kSectorSize
383 sector_t dest; // in sectors of size kSectorSize
384 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700385 uint32_t checksum;
386} __attribute__((packed));
387
Paul Lawrencef5077682019-01-18 10:28:34 -0800388struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700389 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800390 uint16_t header_version;
391 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800392 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700393 uint32_t count;
394 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800395 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700396} __attribute__((packed));
397
398// MAGIC is BOW in ascii
399const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800400// Partially restored MAGIC is WOB in ascii
401const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700402
403void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
404 static uint32_t table[0x100] = {
405 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
406 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
407 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
408 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
409 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
410 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
411 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
412 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
413 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
414 0xB6662D3D,
415
416 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
417 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
418 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
419 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
420 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
421 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
422 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
423 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
424 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
425 0xC0BA6CAD,
426
427 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
428 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
429 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
430 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
431 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
432 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
433 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
434 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
435 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
436 0x5BDEAE1D,
437
438 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
439 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
440 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
441 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
442 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
443 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
444 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
445 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
446 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
447 0x2D02EF8D};
448
449 for (size_t i = 0; i < n_bytes; ++i) {
450 *crc ^= ((uint8_t*)data)[i];
451 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
452 }
453}
454
Paul Lawrenced41a9392019-01-22 14:31:43 -0800455// A map of relocations.
456// The map must be initialized so that relocations[0] = 0
457// During restore, we replay the log records in reverse, copying from dest to
458// source
459// To validate, we must be able to read the 'dest' sectors as though they had
460// been copied but without actually copying. This map represents how the sectors
461// would have been moved. To read a sector s, find the index <= s and read
462// relocations[index] + s - index
463typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800464
Paul Lawrenced41a9392019-01-22 14:31:43 -0800465void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
466 // Find first one we're equal to or greater than
467 auto s = --relocations.upper_bound(source);
468
469 // Take slice
470 Relocations slice;
471 slice[dest] = source - s->first + s->second;
472 ++s;
473
474 // Add rest of elements
475 for (; s != relocations.end() && s->first < source + count; ++s)
476 slice[dest - source + s->first] = s->second;
477
478 // Split range at end of dest
479 auto dest_end = --relocations.upper_bound(dest + count);
480 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
481
482 // Remove all elements in [dest, dest + count)
483 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
484
485 // Add new elements
486 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800487}
488
Daniel Rosenberg52985932019-03-01 22:01:22 -0800489// A map of sectors that have been written to.
490// The final entry must always be False.
491// When we restart the restore after an interruption, we must take care that
492// when we copy from dest to source, that the block we copy to was not
493// previously copied from.
494// i e. A->B C->A; If we replay this sequence, we end up copying C->B
495// We must save our partial result whenever we finish a page, or when we copy
496// to a location that was copied from earlier (our source is an earlier dest)
497typedef std::map<sector_t, bool> Used_Sectors;
498
499bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
500 auto second_overlap = used_sectors.upper_bound(start);
501 auto first_overlap = --second_overlap;
502
503 if (first_overlap->second) {
504 return true;
505 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
506 return true;
507 }
508 return false;
509}
510
511void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
512 auto start_pos = used_sectors.insert_or_assign(start, true).first;
513 auto end_pos = used_sectors.insert_or_assign(end, false).first;
514
515 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
516 start_pos++;
517 }
518 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
519 end_pos++;
520 }
521 if (start_pos->first < end_pos->first) {
522 used_sectors.erase(start_pos, end_pos);
523 }
524}
525
526// Restores the given log_entry's data from dest -> source
527// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
528void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
529 log_entry* le, std::vector<char>& buffer) {
530 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
531 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
532 int count = (le->size - 1) / kSectorSize + 1;
533
534 if (checkCollision(used_sectors, le->source, le->source + count)) {
535 fsync(device_fd);
536 lseek64(device_fd, 0, SEEK_SET);
537 ls.count = index + 1;
538 ls.magic = kPartialRestoreMagic;
539 write(device_fd, &ls_buffer[0], ls.block_size);
540 fsync(device_fd);
541 used_sectors.clear();
542 used_sectors[0] = false;
543 }
544
545 markUsed(used_sectors, le->dest, le->dest + count);
546
547 if (index == 0 && ls.sequence != 0) {
548 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
549 if (next->magic == kMagic) {
550 next->magic = kPartialRestoreMagic;
551 }
552 }
553
554 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
555 write(device_fd, &buffer[0], le->size);
556
557 if (index == 0) {
558 fsync(device_fd);
559 }
560}
561
Paul Lawrenced41a9392019-01-22 14:31:43 -0800562// Read from the device
563// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800564std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
565 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800566 if (!validating) {
567 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800568 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
569 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800570 return buffer;
571 }
572
Paul Lawrence27691c22018-11-20 14:07:59 -0800573 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800574 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
575 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800576 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
577 SEEK_SET);
578 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800579 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800580
581 return buffer;
582}
583
Paul Lawrence4f13a902019-01-10 13:06:07 -0800584} // namespace
585
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800586Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800587 bool validating = true;
588 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800589 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700590
Paul Lawrence27691c22018-11-20 14:07:59 -0800591 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800592 Relocations relocations;
593 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800594 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700595
Paul Lawrence27691c22018-11-20 14:07:59 -0800596 LOG(INFO) << action << " checkpoint on " << blockDevice;
Nick Kraleviche7e89ac2019-03-29 16:03:51 -0700597 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
Paul Lawrence82b35052019-04-19 14:26:39 -0700598 if (device_fd < 0) return error("Cannot open " + blockDevice);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800599
Paul Lawrencef5077682019-01-18 10:28:34 -0800600 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800601 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800602 if (original_ls.magic == kPartialRestoreMagic) {
603 validating = false;
604 action = "Restoring";
605 } else if (original_ls.magic != kMagic) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700606 return error(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700607 }
608
Paul Lawrence4f13a902019-01-10 13:06:07 -0800609 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700610
Paul Lawrence4f13a902019-01-10 13:06:07 -0800611 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800612 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
613 original_ls.block_size, original_ls.block_size);
614 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
615
616 Used_Sectors used_sectors;
617 used_sectors[0] = false;
618
619 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700620 status = error(EINVAL, "No magic");
Paul Lawrence27691c22018-11-20 14:07:59 -0800621 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700622 }
623
Paul Lawrence4f13a902019-01-10 13:06:07 -0800624 if (ls.block_size != original_ls.block_size) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700625 status = error(EINVAL, "Block size mismatch");
Paul Lawrence4f13a902019-01-10 13:06:07 -0800626 break;
627 }
628
Paul Lawrence27691c22018-11-20 14:07:59 -0800629 if ((int)ls.sequence != sequence) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700630 status = error(EINVAL, "Expecting log sector " + std::to_string(sequence) +
631 " but got " + std::to_string(ls.sequence));
Paul Lawrence27691c22018-11-20 14:07:59 -0800632 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700633 }
634
Paul Lawrence27691c22018-11-20 14:07:59 -0800635 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800636 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800637 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
638 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800639 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800640 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
641 << " to " << le->source << " with checksum " << std::hex
642 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800643
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800644 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800645 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800646 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
647 for (size_t i = 0; i < le->size; i += ls.block_size) {
648 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800649 }
650
651 if (le->checksum && checksum != le->checksum) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700652 status = error(EINVAL, "Checksums don't match");
Paul Lawrence27691c22018-11-20 14:07:59 -0800653 break;
654 }
655
Paul Lawrenced41a9392019-01-22 14:31:43 -0800656 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800657 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800658 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800659 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800660 restore_count++;
661 if (restore_limit && restore_count >= restore_limit) {
Paul Lawrence82b35052019-04-19 14:26:39 -0700662 status = error(EAGAIN, "Hit the test limit");
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800663 break;
664 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800665 }
666 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700667 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800668
669 if (!status.isOk()) {
670 if (!validating) {
671 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
672 return status;
673 }
674
675 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800676 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800677 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800678 lseek64(device_fd, 0, SEEK_SET);
679 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800680 return Status::ok();
681 }
682
683 if (!validating) break;
684
685 validating = false;
686 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700687 }
688
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700689 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700690}
691
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700692Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700693 std::string oldContent, newContent;
694 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700695 struct stat st;
696 int result = stat(kMetadataCPFile.c_str(), &st);
697
698 // If the file doesn't exist, we aren't managing a checkpoint retry counter
699 if (result != 0) return Status::ok();
Paul Lawrence82b35052019-04-19 14:26:39 -0700700 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent))
701 return error("Failed to read checkpoint file");
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700702 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700703
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700704 if (!android::base::ParseInt(retryContent, &retry))
Paul Lawrence82b35052019-04-19 14:26:39 -0700705 return error(EINVAL, "Could not parse retry count");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700706 if (retry > 0) {
707 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700708
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700709 newContent = std::to_string(retry);
710 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
Paul Lawrence82b35052019-04-19 14:26:39 -0700711 return error("Could not write checkpoint file");
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700712 }
713 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700714}
715
716} // namespace vold
717} // namespace android