blob: 30d88aedd881e32385cf1f6870c8d02b71a88fe6 [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 Rosenberg73680ec2018-10-10 18:52:04 -0700183Status cp_abortChanges() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700184 android_reboot(ANDROID_RB_RESTART2, 0, nullptr);
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700185 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700186}
187
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700188bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700189 std::string content;
190 bool ret;
191
192 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700193 if (ret) {
194 if (content == "0") return true;
195 if (content.substr(0, 3) == "-1 ") {
196 std::string oldSuffix = content.substr(3);
197 sp<IBootControl> module = IBootControl::getService();
198 std::string newSuffix;
199
200 if (module) {
201 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
202 module->getSuffix(module->getCurrentSlot(), cb);
203 if (oldSuffix == newSuffix) return true;
204 }
205 }
206 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700207 return false;
208}
209
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700210bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700211 bool ret;
212 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700213 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700214
Daniel Rosenberg84203c12019-03-19 14:02:59 -0700215 if (isCheckpointing) return isCheckpointing;
216
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800217 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
218 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700219 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800220 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700221 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800222 if (ret) {
223 ret = content != "0";
224 isCheckpointing = ret;
225 return ret;
226 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700227 return false;
228}
229
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700230Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800231 if (!isCheckpointing) {
232 return Status::ok();
233 }
234
Tom Cherry4c5bde22019-01-29 14:34:01 -0800235 Fstab mounts;
236 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
237 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
238 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700239
Tom Cherry4c5bde22019-01-29 14:34:01 -0800240 for (const auto& mount_rec : mounts) {
241 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700242 if (!fstab_rec) continue;
243
Tom Cherry4c5bde22019-01-29 14:34:01 -0800244 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700245 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800246 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700247 if (!fd) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800248 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700249 continue;
250 }
251
252 struct fstrim_range range = {};
253 range.len = ULLONG_MAX;
254 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800255 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700256 continue;
257 }
258
Tom Cherry4c5bde22019-01-29 14:34:01 -0800259 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700260 }
261 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700262 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700263}
264
265namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700266const int kSectorSize = 512;
267
268typedef uint64_t sector_t;
269
270struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800271 sector_t source; // in sectors of size kSectorSize
272 sector_t dest; // in sectors of size kSectorSize
273 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700274 uint32_t checksum;
275} __attribute__((packed));
276
Paul Lawrencef5077682019-01-18 10:28:34 -0800277struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700278 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800279 uint16_t header_version;
280 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800281 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700282 uint32_t count;
283 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800284 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700285} __attribute__((packed));
286
287// MAGIC is BOW in ascii
288const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800289// Partially restored MAGIC is WOB in ascii
290const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700291
292void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
293 static uint32_t table[0x100] = {
294 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
295 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
296 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
297 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
298 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
299 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
300 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
301 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
302 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
303 0xB6662D3D,
304
305 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
306 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
307 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
308 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
309 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
310 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
311 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
312 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
313 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
314 0xC0BA6CAD,
315
316 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
317 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
318 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
319 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
320 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
321 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
322 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
323 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
324 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
325 0x5BDEAE1D,
326
327 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
328 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
329 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
330 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
331 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
332 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
333 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
334 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
335 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
336 0x2D02EF8D};
337
338 for (size_t i = 0; i < n_bytes; ++i) {
339 *crc ^= ((uint8_t*)data)[i];
340 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
341 }
342}
343
Paul Lawrenced41a9392019-01-22 14:31:43 -0800344// A map of relocations.
345// The map must be initialized so that relocations[0] = 0
346// During restore, we replay the log records in reverse, copying from dest to
347// source
348// To validate, we must be able to read the 'dest' sectors as though they had
349// been copied but without actually copying. This map represents how the sectors
350// would have been moved. To read a sector s, find the index <= s and read
351// relocations[index] + s - index
352typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800353
Paul Lawrenced41a9392019-01-22 14:31:43 -0800354void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
355 // Find first one we're equal to or greater than
356 auto s = --relocations.upper_bound(source);
357
358 // Take slice
359 Relocations slice;
360 slice[dest] = source - s->first + s->second;
361 ++s;
362
363 // Add rest of elements
364 for (; s != relocations.end() && s->first < source + count; ++s)
365 slice[dest - source + s->first] = s->second;
366
367 // Split range at end of dest
368 auto dest_end = --relocations.upper_bound(dest + count);
369 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
370
371 // Remove all elements in [dest, dest + count)
372 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
373
374 // Add new elements
375 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800376}
377
Daniel Rosenberg52985932019-03-01 22:01:22 -0800378// A map of sectors that have been written to.
379// The final entry must always be False.
380// When we restart the restore after an interruption, we must take care that
381// when we copy from dest to source, that the block we copy to was not
382// previously copied from.
383// i e. A->B C->A; If we replay this sequence, we end up copying C->B
384// We must save our partial result whenever we finish a page, or when we copy
385// to a location that was copied from earlier (our source is an earlier dest)
386typedef std::map<sector_t, bool> Used_Sectors;
387
388bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
389 auto second_overlap = used_sectors.upper_bound(start);
390 auto first_overlap = --second_overlap;
391
392 if (first_overlap->second) {
393 return true;
394 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
395 return true;
396 }
397 return false;
398}
399
400void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
401 auto start_pos = used_sectors.insert_or_assign(start, true).first;
402 auto end_pos = used_sectors.insert_or_assign(end, false).first;
403
404 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
405 start_pos++;
406 }
407 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
408 end_pos++;
409 }
410 if (start_pos->first < end_pos->first) {
411 used_sectors.erase(start_pos, end_pos);
412 }
413}
414
415// Restores the given log_entry's data from dest -> source
416// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
417void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
418 log_entry* le, std::vector<char>& buffer) {
419 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
420 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
421 int count = (le->size - 1) / kSectorSize + 1;
422
423 if (checkCollision(used_sectors, le->source, le->source + count)) {
424 fsync(device_fd);
425 lseek64(device_fd, 0, SEEK_SET);
426 ls.count = index + 1;
427 ls.magic = kPartialRestoreMagic;
428 write(device_fd, &ls_buffer[0], ls.block_size);
429 fsync(device_fd);
430 used_sectors.clear();
431 used_sectors[0] = false;
432 }
433
434 markUsed(used_sectors, le->dest, le->dest + count);
435
436 if (index == 0 && ls.sequence != 0) {
437 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
438 if (next->magic == kMagic) {
439 next->magic = kPartialRestoreMagic;
440 }
441 }
442
443 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
444 write(device_fd, &buffer[0], le->size);
445
446 if (index == 0) {
447 fsync(device_fd);
448 }
449}
450
Paul Lawrenced41a9392019-01-22 14:31:43 -0800451// Read from the device
452// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800453std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
454 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800455 if (!validating) {
456 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800457 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
458 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800459 return buffer;
460 }
461
Paul Lawrence27691c22018-11-20 14:07:59 -0800462 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800463 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
464 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800465 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
466 SEEK_SET);
467 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800468 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800469
470 return buffer;
471}
472
Paul Lawrence4f13a902019-01-10 13:06:07 -0800473} // namespace
474
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800475Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800476 bool validating = true;
477 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800478 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700479
Paul Lawrence27691c22018-11-20 14:07:59 -0800480 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800481 Relocations relocations;
482 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800483 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700484
Paul Lawrence27691c22018-11-20 14:07:59 -0800485 LOG(INFO) << action << " checkpoint on " << blockDevice;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800486 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR));
487 if (device_fd < 0) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800488 PLOG(ERROR) << "Cannot open " << blockDevice;
489 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
490 }
Paul Lawrence4f13a902019-01-10 13:06:07 -0800491
Paul Lawrencef5077682019-01-18 10:28:34 -0800492 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800493 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800494 if (original_ls.magic == kPartialRestoreMagic) {
495 validating = false;
496 action = "Restoring";
497 } else if (original_ls.magic != kMagic) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800498 LOG(ERROR) << "No magic";
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700499 return Status::fromExceptionCode(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700500 }
501
Paul Lawrence4f13a902019-01-10 13:06:07 -0800502 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700503
Paul Lawrence4f13a902019-01-10 13:06:07 -0800504 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800505 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
506 original_ls.block_size, original_ls.block_size);
507 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
508
509 Used_Sectors used_sectors;
510 used_sectors[0] = false;
511
512 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800513 LOG(ERROR) << "No magic!";
514 status = Status::fromExceptionCode(EINVAL, "No magic");
515 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700516 }
517
Paul Lawrence4f13a902019-01-10 13:06:07 -0800518 if (ls.block_size != original_ls.block_size) {
519 LOG(ERROR) << "Block size mismatch!";
520 status = Status::fromExceptionCode(EINVAL, "Block size mismatch");
521 break;
522 }
523
Paul Lawrence27691c22018-11-20 14:07:59 -0800524 if ((int)ls.sequence != sequence) {
525 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
526 status = Status::fromExceptionCode(
527 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
528 std::to_string(ls.sequence))
529 .c_str());
530 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700531 }
532
Paul Lawrence27691c22018-11-20 14:07:59 -0800533 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800534 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800535 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
536 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800537 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800538 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
539 << " to " << le->source << " with checksum " << std::hex
540 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800541
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800542 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800543 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800544 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
545 for (size_t i = 0; i < le->size; i += ls.block_size) {
546 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800547 }
548
549 if (le->checksum && checksum != le->checksum) {
550 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
551 status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
552 break;
553 }
554
Paul Lawrenced41a9392019-01-22 14:31:43 -0800555 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800556 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800557 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800558 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800559 restore_count++;
560 if (restore_limit && restore_count >= restore_limit) {
561 LOG(WARNING) << "Hit the test limit";
562 status = Status::fromExceptionCode(EAGAIN, "Hit the test limit");
563 break;
564 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800565 }
566 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700567 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800568
569 if (!status.isOk()) {
570 if (!validating) {
571 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
572 return status;
573 }
574
575 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800576 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800577 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800578 lseek64(device_fd, 0, SEEK_SET);
579 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800580 return Status::ok();
581 }
582
583 if (!validating) break;
584
585 validating = false;
586 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700587 }
588
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700589 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700590}
591
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700592Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700593 std::string oldContent, newContent;
594 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700595 struct stat st;
596 int result = stat(kMetadataCPFile.c_str(), &st);
597
598 // If the file doesn't exist, we aren't managing a checkpoint retry counter
599 if (result != 0) return Status::ok();
600 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
601 PLOG(ERROR) << "Failed to read checkpoint file";
602 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
603 }
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700604 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700605
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700606 if (!android::base::ParseInt(retryContent, &retry))
607 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
608 if (retry > 0) {
609 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700610
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700611 newContent = std::to_string(retry);
612 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
613 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
614 }
615 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700616}
617
618} // namespace vold
619} // namespace android