blob: 1762521cd3760dfa11e2996f43cdd8cf4b6ccd8c [file] [log] [blame]
Daniel Rosenberg65f99c92018-08-28 01:58:49 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "Checkpoint"
18#include "Checkpoint.h"
Daniel Rosenberg253b44e2019-02-01 19:25:47 -080019#include "VoldUtil.h"
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070020
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070021#include <fstream>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070022#include <list>
Paul Lawrence20400892018-10-03 14:14:52 -070023#include <memory>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070024#include <string>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070025#include <vector>
26
27#include <android-base/file.h>
28#include <android-base/logging.h>
29#include <android-base/parseint.h>
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080030#include <android-base/properties.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070031#include <android-base/unique_fd.h>
Daniel Rosenbergd3992492018-10-02 17:40:44 -070032#include <android/hardware/boot/1.0/IBootControl.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070033#include <cutils/android_reboot.h>
34#include <fcntl.h>
35#include <fs_mgr.h>
36#include <linux/fs.h>
37#include <mntent.h>
38#include <sys/mount.h>
39#include <sys/stat.h>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070040
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080041using android::base::SetProperty;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070042using android::binder::Status;
Tom Cherry4c5bde22019-01-29 14:34:01 -080043using android::fs_mgr::Fstab;
44using android::fs_mgr::ReadDefaultFstab;
45using android::fs_mgr::ReadFstabFromFile;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070046using android::hardware::hidl_string;
47using android::hardware::boot::V1_0::BoolResult;
Daniel Rosenberg886915b2019-01-23 15:16:04 -080048using android::hardware::boot::V1_0::CommandResult;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070049using android::hardware::boot::V1_0::IBootControl;
50using android::hardware::boot::V1_0::Slot;
51
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070052namespace android {
53namespace vold {
54
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070055namespace {
56const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
57
58bool setBowState(std::string const& block_device, std::string const& state) {
59 if (block_device.substr(0, 5) != "/dev/") {
60 LOG(ERROR) << "Expected block device, got " << block_device;
61 return false;
62 }
63
64 std::string state_filename = std::string("/sys/") + block_device.substr(5) + "/bow/state";
65 if (!android::base::WriteStringToFile(state, state_filename)) {
66 PLOG(ERROR) << "Failed to write to file " << state_filename;
67 return false;
68 }
69
70 return true;
71}
72
73} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070074
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080075Status cp_supportsCheckpoint(bool& result) {
76 result = false;
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080077
Tom Cherry4c5bde22019-01-29 14:34:01 -080078 for (const auto& entry : fstab_default) {
79 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
Daniel Rosenberg9b667fb2019-01-22 17:27:25 -080080 result = true;
81 return Status::ok();
82 }
83 }
84 return Status::ok();
85}
86
Paul Lawrencec5c79c52019-03-18 13:36:40 -070087Status cp_supportsBlockCheckpoint(bool& result) {
88 result = false;
89
90 for (const auto& entry : fstab_default) {
91 if (entry.fs_mgr_flags.checkpoint_blk) {
92 result = true;
93 return Status::ok();
94 }
95 }
96 return Status::ok();
97}
98
99Status cp_supportsFileCheckpoint(bool& result) {
100 result = false;
101
102 for (const auto& entry : fstab_default) {
103 if (entry.fs_mgr_flags.checkpoint_fs) {
104 result = true;
105 return Status::ok();
106 }
107 }
108 return Status::ok();
109}
110
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700111Status cp_startCheckpoint(int retry) {
112 if (retry < -1) return Status::fromExceptionCode(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700113 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700114 if (retry == -1) {
115 sp<IBootControl> module = IBootControl::getService();
116 if (module) {
117 std::string suffix;
118 auto cb = [&suffix](hidl_string s) { suffix = s; };
119 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
120 }
121 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700122 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
123 return Status::fromExceptionCode(errno, "Failed to write checkpoint file");
124 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700125}
126
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800127namespace {
128
129bool isCheckpointing = false;
130}
131
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700132Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800133 if (!isCheckpointing) {
134 return Status::ok();
135 }
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800136 sp<IBootControl> module = IBootControl::getService();
137 if (module) {
138 CommandResult cr;
139 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
140 if (!cr.success) {
141 std::string msg = "Error marking booted successfully: " + std::string(cr.errMsg);
142 return Status::fromExceptionCode(EINVAL, String8(msg.c_str()));
143 }
144 LOG(INFO) << "Marked slot as booted successfully.";
145 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700146 // Must take action for list of mounted checkpointed things here
147 // To do this, we walk the list of mounted file systems.
148 // But we also need to get the matching fstab entries to see
149 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700150 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700151
Tom Cherry4c5bde22019-01-29 14:34:01 -0800152 Fstab mounts;
153 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
154 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
155 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700156
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700157 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800158 for (const auto& mount_rec : mounts) {
159 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700160 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700161
Tom Cherry4c5bde22019-01-29 14:34:01 -0800162 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
163 if (fstab_rec->fs_type == "f2fs") {
164 std::string options = mount_rec.fs_options + ",checkpoint=enable";
165 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800166 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800167 return Status::fromExceptionCode(EINVAL, "Failed to remount");
168 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700169 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800170 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
171 if (!setBowState(mount_rec.blk_device, "2"))
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800172 return Status::fromExceptionCode(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700173 }
174 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800175 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800176 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800177 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800178 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700179 return Status::fromExceptionCode(errno, err_str.c_str());
180 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700181}
182
Daniel Rosenberga59e4392019-03-20 17:02:47 -0700183namespace {
184void abort_metadata_file() {
185 std::string oldContent, newContent;
186 int retry = 0;
187 struct stat st;
188 int result = stat(kMetadataCPFile.c_str(), &st);
189
190 // If the file doesn't exist, we aren't managing a checkpoint retry counter
191 if (result != 0) return;
192 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
193 PLOG(ERROR) << "Failed to read checkpoint file";
194 return;
195 }
196 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
197
198 if (!android::base::ParseInt(retryContent, &retry)) {
199 PLOG(ERROR) << "Could not parse retry count";
200 return;
201 }
202 if (retry > 0) {
203 newContent = "0";
204 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
205 PLOG(ERROR) << "Could not write checkpoint file";
206 }
207}
208} // namespace
209
210void cp_abortChanges(const std::string& message, bool retry) {
211 if (!cp_needsCheckpoint()) return;
212 if (!retry) abort_metadata_file();
213 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700214}
215
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700216bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700217 std::string content;
218 bool ret;
219
220 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700221 if (ret) {
222 if (content == "0") return true;
223 if (content.substr(0, 3) == "-1 ") {
224 std::string oldSuffix = content.substr(3);
225 sp<IBootControl> module = IBootControl::getService();
226 std::string newSuffix;
227
228 if (module) {
229 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
230 module->getSuffix(module->getCurrentSlot(), cb);
231 if (oldSuffix == newSuffix) return true;
232 }
233 }
234 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700235 return false;
236}
237
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700238bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700239 bool ret;
240 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700241 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700242
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700243 if (isCheckpointing) return isCheckpointing;
244
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800245 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
246 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700247 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800248 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700249 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800250 if (ret) {
251 ret = content != "0";
252 isCheckpointing = ret;
253 return ret;
254 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700255 return false;
256}
257
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700258Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800259 if (!isCheckpointing) {
260 return Status::ok();
261 }
262
Tom Cherry4c5bde22019-01-29 14:34:01 -0800263 Fstab mounts;
264 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
265 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
266 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700267
Tom Cherry4c5bde22019-01-29 14:34:01 -0800268 for (const auto& mount_rec : mounts) {
269 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700270 if (!fstab_rec) continue;
271
Tom Cherry4c5bde22019-01-29 14:34:01 -0800272 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700273 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800274 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700275 if (!fd) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800276 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700277 continue;
278 }
279
280 struct fstrim_range range = {};
281 range.len = ULLONG_MAX;
282 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800283 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700284 continue;
285 }
286
Tom Cherry4c5bde22019-01-29 14:34:01 -0800287 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700288 }
289 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700290 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700291}
292
293namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700294const int kSectorSize = 512;
295
296typedef uint64_t sector_t;
297
298struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800299 sector_t source; // in sectors of size kSectorSize
300 sector_t dest; // in sectors of size kSectorSize
301 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700302 uint32_t checksum;
303} __attribute__((packed));
304
Paul Lawrencef5077682019-01-18 10:28:34 -0800305struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700306 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800307 uint16_t header_version;
308 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800309 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700310 uint32_t count;
311 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800312 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700313} __attribute__((packed));
314
315// MAGIC is BOW in ascii
316const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800317// Partially restored MAGIC is WOB in ascii
318const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700319
320void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
321 static uint32_t table[0x100] = {
322 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
323 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
324 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
325 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
326 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
327 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
328 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
329 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
330 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
331 0xB6662D3D,
332
333 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
334 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
335 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
336 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
337 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
338 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
339 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
340 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
341 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
342 0xC0BA6CAD,
343
344 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
345 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
346 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
347 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
348 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
349 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
350 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
351 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
352 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
353 0x5BDEAE1D,
354
355 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
356 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
357 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
358 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
359 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
360 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
361 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
362 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
363 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
364 0x2D02EF8D};
365
366 for (size_t i = 0; i < n_bytes; ++i) {
367 *crc ^= ((uint8_t*)data)[i];
368 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
369 }
370}
371
Paul Lawrenced41a9392019-01-22 14:31:43 -0800372// A map of relocations.
373// The map must be initialized so that relocations[0] = 0
374// During restore, we replay the log records in reverse, copying from dest to
375// source
376// To validate, we must be able to read the 'dest' sectors as though they had
377// been copied but without actually copying. This map represents how the sectors
378// would have been moved. To read a sector s, find the index <= s and read
379// relocations[index] + s - index
380typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800381
Paul Lawrenced41a9392019-01-22 14:31:43 -0800382void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
383 // Find first one we're equal to or greater than
384 auto s = --relocations.upper_bound(source);
385
386 // Take slice
387 Relocations slice;
388 slice[dest] = source - s->first + s->second;
389 ++s;
390
391 // Add rest of elements
392 for (; s != relocations.end() && s->first < source + count; ++s)
393 slice[dest - source + s->first] = s->second;
394
395 // Split range at end of dest
396 auto dest_end = --relocations.upper_bound(dest + count);
397 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
398
399 // Remove all elements in [dest, dest + count)
400 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
401
402 // Add new elements
403 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800404}
405
Daniel Rosenberg52985932019-03-01 22:01:22 -0800406// A map of sectors that have been written to.
407// The final entry must always be False.
408// When we restart the restore after an interruption, we must take care that
409// when we copy from dest to source, that the block we copy to was not
410// previously copied from.
411// i e. A->B C->A; If we replay this sequence, we end up copying C->B
412// We must save our partial result whenever we finish a page, or when we copy
413// to a location that was copied from earlier (our source is an earlier dest)
414typedef std::map<sector_t, bool> Used_Sectors;
415
416bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
417 auto second_overlap = used_sectors.upper_bound(start);
418 auto first_overlap = --second_overlap;
419
420 if (first_overlap->second) {
421 return true;
422 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
423 return true;
424 }
425 return false;
426}
427
428void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
429 auto start_pos = used_sectors.insert_or_assign(start, true).first;
430 auto end_pos = used_sectors.insert_or_assign(end, false).first;
431
432 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
433 start_pos++;
434 }
435 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
436 end_pos++;
437 }
438 if (start_pos->first < end_pos->first) {
439 used_sectors.erase(start_pos, end_pos);
440 }
441}
442
443// Restores the given log_entry's data from dest -> source
444// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
445void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
446 log_entry* le, std::vector<char>& buffer) {
447 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
448 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
449 int count = (le->size - 1) / kSectorSize + 1;
450
451 if (checkCollision(used_sectors, le->source, le->source + count)) {
452 fsync(device_fd);
453 lseek64(device_fd, 0, SEEK_SET);
454 ls.count = index + 1;
455 ls.magic = kPartialRestoreMagic;
456 write(device_fd, &ls_buffer[0], ls.block_size);
457 fsync(device_fd);
458 used_sectors.clear();
459 used_sectors[0] = false;
460 }
461
462 markUsed(used_sectors, le->dest, le->dest + count);
463
464 if (index == 0 && ls.sequence != 0) {
465 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
466 if (next->magic == kMagic) {
467 next->magic = kPartialRestoreMagic;
468 }
469 }
470
471 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
472 write(device_fd, &buffer[0], le->size);
473
474 if (index == 0) {
475 fsync(device_fd);
476 }
477}
478
Paul Lawrenced41a9392019-01-22 14:31:43 -0800479// Read from the device
480// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800481std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
482 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800483 if (!validating) {
484 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800485 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
486 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800487 return buffer;
488 }
489
Paul Lawrence27691c22018-11-20 14:07:59 -0800490 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800491 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
492 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800493 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
494 SEEK_SET);
495 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800496 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800497
498 return buffer;
499}
500
Paul Lawrence4f13a902019-01-10 13:06:07 -0800501} // namespace
502
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800503Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800504 bool validating = true;
505 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800506 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700507
Paul Lawrence27691c22018-11-20 14:07:59 -0800508 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800509 Relocations relocations;
510 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800511 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700512
Paul Lawrence27691c22018-11-20 14:07:59 -0800513 LOG(INFO) << action << " checkpoint on " << blockDevice;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800514 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR));
515 if (device_fd < 0) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800516 PLOG(ERROR) << "Cannot open " << blockDevice;
517 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
518 }
Paul Lawrence4f13a902019-01-10 13:06:07 -0800519
Paul Lawrencef5077682019-01-18 10:28:34 -0800520 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800521 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800522 if (original_ls.magic == kPartialRestoreMagic) {
523 validating = false;
524 action = "Restoring";
525 } else if (original_ls.magic != kMagic) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800526 LOG(ERROR) << "No magic";
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700527 return Status::fromExceptionCode(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700528 }
529
Paul Lawrence4f13a902019-01-10 13:06:07 -0800530 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700531
Paul Lawrence4f13a902019-01-10 13:06:07 -0800532 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800533 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
534 original_ls.block_size, original_ls.block_size);
535 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
536
537 Used_Sectors used_sectors;
538 used_sectors[0] = false;
539
540 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800541 LOG(ERROR) << "No magic!";
542 status = Status::fromExceptionCode(EINVAL, "No magic");
543 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700544 }
545
Paul Lawrence4f13a902019-01-10 13:06:07 -0800546 if (ls.block_size != original_ls.block_size) {
547 LOG(ERROR) << "Block size mismatch!";
548 status = Status::fromExceptionCode(EINVAL, "Block size mismatch");
549 break;
550 }
551
Paul Lawrence27691c22018-11-20 14:07:59 -0800552 if ((int)ls.sequence != sequence) {
553 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
554 status = Status::fromExceptionCode(
555 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
556 std::to_string(ls.sequence))
557 .c_str());
558 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700559 }
560
Paul Lawrence27691c22018-11-20 14:07:59 -0800561 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800562 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800563 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
564 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800565 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800566 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
567 << " to " << le->source << " with checksum " << std::hex
568 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800569
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800570 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800571 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800572 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
573 for (size_t i = 0; i < le->size; i += ls.block_size) {
574 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800575 }
576
577 if (le->checksum && checksum != le->checksum) {
578 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
579 status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
580 break;
581 }
582
Paul Lawrenced41a9392019-01-22 14:31:43 -0800583 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800584 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800585 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800586 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800587 restore_count++;
588 if (restore_limit && restore_count >= restore_limit) {
589 LOG(WARNING) << "Hit the test limit";
590 status = Status::fromExceptionCode(EAGAIN, "Hit the test limit");
591 break;
592 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800593 }
594 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700595 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800596
597 if (!status.isOk()) {
598 if (!validating) {
599 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
600 return status;
601 }
602
603 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800604 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800605 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800606 lseek64(device_fd, 0, SEEK_SET);
607 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800608 return Status::ok();
609 }
610
611 if (!validating) break;
612
613 validating = false;
614 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700615 }
616
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700617 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700618}
619
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700620Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700621 std::string oldContent, newContent;
622 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700623 struct stat st;
624 int result = stat(kMetadataCPFile.c_str(), &st);
625
626 // If the file doesn't exist, we aren't managing a checkpoint retry counter
627 if (result != 0) return Status::ok();
628 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
629 PLOG(ERROR) << "Failed to read checkpoint file";
630 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
631 }
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700632 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700633
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700634 if (!android::base::ParseInt(retryContent, &retry))
635 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
636 if (retry > 0) {
637 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700638
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700639 newContent = std::to_string(retry);
640 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
641 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
642 }
643 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700644}
645
646} // namespace vold
647} // namespace android