blob: 75a22ecd27b0879776370a302f3ebfb1bbbf199c [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
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070087Status cp_startCheckpoint(int retry) {
88 if (retry < -1) return Status::fromExceptionCode(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -070089 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -070090 if (retry == -1) {
91 sp<IBootControl> module = IBootControl::getService();
92 if (module) {
93 std::string suffix;
94 auto cb = [&suffix](hidl_string s) { suffix = s; };
95 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
96 }
97 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070098 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
99 return Status::fromExceptionCode(errno, "Failed to write checkpoint file");
100 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700101}
102
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800103namespace {
104
105bool isCheckpointing = false;
106}
107
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700108Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800109 if (!isCheckpointing) {
110 return Status::ok();
111 }
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800112 sp<IBootControl> module = IBootControl::getService();
113 if (module) {
114 CommandResult cr;
115 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
116 if (!cr.success) {
117 std::string msg = "Error marking booted successfully: " + std::string(cr.errMsg);
118 return Status::fromExceptionCode(EINVAL, String8(msg.c_str()));
119 }
120 LOG(INFO) << "Marked slot as booted successfully.";
121 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700122 // Must take action for list of mounted checkpointed things here
123 // To do this, we walk the list of mounted file systems.
124 // But we also need to get the matching fstab entries to see
125 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700126 std::string err_str;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700127
Tom Cherry4c5bde22019-01-29 14:34:01 -0800128 Fstab mounts;
129 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
130 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
131 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700132
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700133 // Walk mounted file systems
Tom Cherry4c5bde22019-01-29 14:34:01 -0800134 for (const auto& mount_rec : mounts) {
135 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700136 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700137
Tom Cherry4c5bde22019-01-29 14:34:01 -0800138 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
139 if (fstab_rec->fs_type == "f2fs") {
140 std::string options = mount_rec.fs_options + ",checkpoint=enable";
141 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
Daniel Rosenberg14ca4ac2019-01-24 18:23:18 -0800142 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800143 return Status::fromExceptionCode(EINVAL, "Failed to remount");
144 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700145 }
Tom Cherry4c5bde22019-01-29 14:34:01 -0800146 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
147 if (!setBowState(mount_rec.blk_device, "2"))
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800148 return Status::fromExceptionCode(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700149 }
150 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800151 SetProperty("vold.checkpoint_committed", "1");
Daniel Rosenberg886915b2019-01-23 15:16:04 -0800152 LOG(INFO) << "Checkpoint has been committed.";
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800153 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800154 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700155 return Status::fromExceptionCode(errno, err_str.c_str());
156 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700157}
158
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700159Status cp_abortChanges() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700160 android_reboot(ANDROID_RB_RESTART2, 0, nullptr);
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700161 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700162}
163
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700164bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700165 std::string content;
166 bool ret;
167
168 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700169 if (ret) {
170 if (content == "0") return true;
171 if (content.substr(0, 3) == "-1 ") {
172 std::string oldSuffix = content.substr(3);
173 sp<IBootControl> module = IBootControl::getService();
174 std::string newSuffix;
175
176 if (module) {
177 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
178 module->getSuffix(module->getCurrentSlot(), cb);
179 if (oldSuffix == newSuffix) return true;
180 }
181 }
182 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700183 return false;
184}
185
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700186bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700187 bool ret;
188 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700189 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700190
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800191 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
192 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700193 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800194 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700195 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800196 if (ret) {
197 ret = content != "0";
198 isCheckpointing = ret;
199 return ret;
200 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700201 return false;
202}
203
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700204Status cp_prepareCheckpoint() {
Paul Lawrencedb086942019-02-19 14:18:54 -0800205 if (!isCheckpointing) {
206 return Status::ok();
207 }
208
Tom Cherry4c5bde22019-01-29 14:34:01 -0800209 Fstab mounts;
210 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
211 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
212 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700213
Tom Cherry4c5bde22019-01-29 14:34:01 -0800214 for (const auto& mount_rec : mounts) {
215 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700216 if (!fstab_rec) continue;
217
Tom Cherry4c5bde22019-01-29 14:34:01 -0800218 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700219 android::base::unique_fd fd(
Tom Cherry4c5bde22019-01-29 14:34:01 -0800220 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700221 if (!fd) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800222 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700223 continue;
224 }
225
226 struct fstrim_range range = {};
227 range.len = ULLONG_MAX;
228 if (ioctl(fd, FITRIM, &range)) {
Tom Cherry4c5bde22019-01-29 14:34:01 -0800229 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700230 continue;
231 }
232
Tom Cherry4c5bde22019-01-29 14:34:01 -0800233 setBowState(mount_rec.blk_device, "1");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700234 }
235 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700236 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700237}
238
239namespace {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700240const int kSectorSize = 512;
241
242typedef uint64_t sector_t;
243
244struct log_entry {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800245 sector_t source; // in sectors of size kSectorSize
246 sector_t dest; // in sectors of size kSectorSize
247 uint32_t size; // in bytes
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700248 uint32_t checksum;
249} __attribute__((packed));
250
Paul Lawrencef5077682019-01-18 10:28:34 -0800251struct log_sector_v1_0 {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700252 uint32_t magic;
Paul Lawrencef5077682019-01-18 10:28:34 -0800253 uint16_t header_version;
254 uint16_t header_size;
Paul Lawrence4f13a902019-01-10 13:06:07 -0800255 uint32_t block_size;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700256 uint32_t count;
257 uint32_t sequence;
Paul Lawrence27691c22018-11-20 14:07:59 -0800258 uint64_t sector0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700259} __attribute__((packed));
260
261// MAGIC is BOW in ascii
262const int kMagic = 0x00574f42;
Daniel Rosenberg52985932019-03-01 22:01:22 -0800263// Partially restored MAGIC is WOB in ascii
264const int kPartialRestoreMagic = 0x00424f57;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700265
266void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
267 static uint32_t table[0x100] = {
268 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
269 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
270 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
271 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
272 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
273 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
274 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
275 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
276 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
277 0xB6662D3D,
278
279 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
280 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
281 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
282 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
283 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
284 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
285 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
286 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
287 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
288 0xC0BA6CAD,
289
290 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
291 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
292 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
293 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
294 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
295 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
296 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
297 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
298 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
299 0x5BDEAE1D,
300
301 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
302 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
303 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
304 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
305 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
306 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
307 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
308 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
309 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
310 0x2D02EF8D};
311
312 for (size_t i = 0; i < n_bytes; ++i) {
313 *crc ^= ((uint8_t*)data)[i];
314 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
315 }
316}
317
Paul Lawrenced41a9392019-01-22 14:31:43 -0800318// A map of relocations.
319// The map must be initialized so that relocations[0] = 0
320// During restore, we replay the log records in reverse, copying from dest to
321// source
322// To validate, we must be able to read the 'dest' sectors as though they had
323// been copied but without actually copying. This map represents how the sectors
324// would have been moved. To read a sector s, find the index <= s and read
325// relocations[index] + s - index
326typedef std::map<sector_t, sector_t> Relocations;
Paul Lawrence27691c22018-11-20 14:07:59 -0800327
Paul Lawrenced41a9392019-01-22 14:31:43 -0800328void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
329 // Find first one we're equal to or greater than
330 auto s = --relocations.upper_bound(source);
331
332 // Take slice
333 Relocations slice;
334 slice[dest] = source - s->first + s->second;
335 ++s;
336
337 // Add rest of elements
338 for (; s != relocations.end() && s->first < source + count; ++s)
339 slice[dest - source + s->first] = s->second;
340
341 // Split range at end of dest
342 auto dest_end = --relocations.upper_bound(dest + count);
343 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
344
345 // Remove all elements in [dest, dest + count)
346 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
347
348 // Add new elements
349 relocations.insert(slice.begin(), slice.end());
Paul Lawrence27691c22018-11-20 14:07:59 -0800350}
351
Daniel Rosenberg52985932019-03-01 22:01:22 -0800352// A map of sectors that have been written to.
353// The final entry must always be False.
354// When we restart the restore after an interruption, we must take care that
355// when we copy from dest to source, that the block we copy to was not
356// previously copied from.
357// i e. A->B C->A; If we replay this sequence, we end up copying C->B
358// We must save our partial result whenever we finish a page, or when we copy
359// to a location that was copied from earlier (our source is an earlier dest)
360typedef std::map<sector_t, bool> Used_Sectors;
361
362bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
363 auto second_overlap = used_sectors.upper_bound(start);
364 auto first_overlap = --second_overlap;
365
366 if (first_overlap->second) {
367 return true;
368 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
369 return true;
370 }
371 return false;
372}
373
374void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
375 auto start_pos = used_sectors.insert_or_assign(start, true).first;
376 auto end_pos = used_sectors.insert_or_assign(end, false).first;
377
378 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
379 start_pos++;
380 }
381 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
382 end_pos++;
383 }
384 if (start_pos->first < end_pos->first) {
385 used_sectors.erase(start_pos, end_pos);
386 }
387}
388
389// Restores the given log_entry's data from dest -> source
390// If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
391void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
392 log_entry* le, std::vector<char>& buffer) {
393 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
394 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
395 int count = (le->size - 1) / kSectorSize + 1;
396
397 if (checkCollision(used_sectors, le->source, le->source + count)) {
398 fsync(device_fd);
399 lseek64(device_fd, 0, SEEK_SET);
400 ls.count = index + 1;
401 ls.magic = kPartialRestoreMagic;
402 write(device_fd, &ls_buffer[0], ls.block_size);
403 fsync(device_fd);
404 used_sectors.clear();
405 used_sectors[0] = false;
406 }
407
408 markUsed(used_sectors, le->dest, le->dest + count);
409
410 if (index == 0 && ls.sequence != 0) {
411 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
412 if (next->magic == kMagic) {
413 next->magic = kPartialRestoreMagic;
414 }
415 }
416
417 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
418 write(device_fd, &buffer[0], le->size);
419
420 if (index == 0) {
421 fsync(device_fd);
422 }
423}
424
Paul Lawrenced41a9392019-01-22 14:31:43 -0800425// Read from the device
426// If we are validating, the read occurs as though the relocations had happened
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800427std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
428 sector_t sector, uint32_t size, uint32_t block_size) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800429 if (!validating) {
430 std::vector<char> buffer(size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800431 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
432 read(device_fd, &buffer[0], size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800433 return buffer;
434 }
435
Paul Lawrence27691c22018-11-20 14:07:59 -0800436 std::vector<char> buffer(size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800437 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
438 auto relocation = --relocations.upper_bound(sector);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800439 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
440 SEEK_SET);
441 read(device_fd, &buffer[i], block_size);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800442 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800443
444 return buffer;
445}
446
Paul Lawrence4f13a902019-01-10 13:06:07 -0800447} // namespace
448
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800449Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800450 bool validating = true;
451 std::string action = "Validating";
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800452 int restore_count = 0;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700453
Paul Lawrence27691c22018-11-20 14:07:59 -0800454 for (;;) {
Paul Lawrenced41a9392019-01-22 14:31:43 -0800455 Relocations relocations;
456 relocations[0] = 0;
Paul Lawrence27691c22018-11-20 14:07:59 -0800457 Status status = Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700458
Paul Lawrence27691c22018-11-20 14:07:59 -0800459 LOG(INFO) << action << " checkpoint on " << blockDevice;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800460 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR));
461 if (device_fd < 0) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800462 PLOG(ERROR) << "Cannot open " << blockDevice;
463 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
464 }
Paul Lawrence4f13a902019-01-10 13:06:07 -0800465
Paul Lawrencef5077682019-01-18 10:28:34 -0800466 log_sector_v1_0 original_ls;
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800467 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
Daniel Rosenberg52985932019-03-01 22:01:22 -0800468 if (original_ls.magic == kPartialRestoreMagic) {
469 validating = false;
470 action = "Restoring";
471 } else if (original_ls.magic != kMagic) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800472 LOG(ERROR) << "No magic";
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700473 return Status::fromExceptionCode(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700474 }
475
Paul Lawrence4f13a902019-01-10 13:06:07 -0800476 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700477
Paul Lawrence4f13a902019-01-10 13:06:07 -0800478 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800479 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
480 original_ls.block_size, original_ls.block_size);
481 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
482
483 Used_Sectors used_sectors;
484 used_sectors[0] = false;
485
486 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
Paul Lawrence27691c22018-11-20 14:07:59 -0800487 LOG(ERROR) << "No magic!";
488 status = Status::fromExceptionCode(EINVAL, "No magic");
489 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700490 }
491
Paul Lawrence4f13a902019-01-10 13:06:07 -0800492 if (ls.block_size != original_ls.block_size) {
493 LOG(ERROR) << "Block size mismatch!";
494 status = Status::fromExceptionCode(EINVAL, "Block size mismatch");
495 break;
496 }
497
Paul Lawrence27691c22018-11-20 14:07:59 -0800498 if ((int)ls.sequence != sequence) {
499 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
500 status = Status::fromExceptionCode(
501 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
502 std::to_string(ls.sequence))
503 .c_str());
504 break;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700505 }
506
Paul Lawrence27691c22018-11-20 14:07:59 -0800507 LOG(INFO) << action << " from log sector " << ls.sequence;
Paul Lawrencef5077682019-01-18 10:28:34 -0800508 for (log_entry* le =
Daniel Rosenberg52985932019-03-01 22:01:22 -0800509 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
510 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
Paul Lawrencef5077682019-01-18 10:28:34 -0800511 // This is very noisy - limit to DEBUG only
Paul Lawrenced41a9392019-01-22 14:31:43 -0800512 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
513 << " to " << le->source << " with checksum " << std::hex
514 << le->checksum;
Paul Lawrencef5077682019-01-18 10:28:34 -0800515
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800516 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800517 ls.block_size);
Paul Lawrence4f13a902019-01-10 13:06:07 -0800518 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
519 for (size_t i = 0; i < le->size; i += ls.block_size) {
520 crc32(&buffer[i], ls.block_size, &checksum);
Paul Lawrence27691c22018-11-20 14:07:59 -0800521 }
522
523 if (le->checksum && checksum != le->checksum) {
524 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
525 status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
526 break;
527 }
528
Paul Lawrenced41a9392019-01-22 14:31:43 -0800529 if (validating) {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800530 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
Paul Lawrenced41a9392019-01-22 14:31:43 -0800531 } else {
Daniel Rosenberg52985932019-03-01 22:01:22 -0800532 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
Daniel Rosenbergdda59812019-03-06 17:45:17 -0800533 restore_count++;
534 if (restore_limit && restore_count >= restore_limit) {
535 LOG(WARNING) << "Hit the test limit";
536 status = Status::fromExceptionCode(EAGAIN, "Hit the test limit");
537 break;
538 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800539 }
540 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700541 }
Paul Lawrence27691c22018-11-20 14:07:59 -0800542
543 if (!status.isOk()) {
544 if (!validating) {
545 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
546 return status;
547 }
548
549 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800550 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
Paul Lawrenced41a9392019-01-22 14:31:43 -0800551 original_ls.block_size, original_ls.block_size);
Daniel Rosenberg8271ae92019-03-04 21:46:31 -0800552 lseek64(device_fd, 0, SEEK_SET);
553 write(device_fd, &buffer[0], original_ls.block_size);
Paul Lawrence27691c22018-11-20 14:07:59 -0800554 return Status::ok();
555 }
556
557 if (!validating) break;
558
559 validating = false;
560 action = "Restoring";
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700561 }
562
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700563 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700564}
565
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700566Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700567 std::string oldContent, newContent;
568 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700569 struct stat st;
570 int result = stat(kMetadataCPFile.c_str(), &st);
571
572 // If the file doesn't exist, we aren't managing a checkpoint retry counter
573 if (result != 0) return Status::ok();
574 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
575 PLOG(ERROR) << "Failed to read checkpoint file";
576 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
577 }
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700578 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700579
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700580 if (!android::base::ParseInt(retryContent, &retry))
581 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
582 if (retry > 0) {
583 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700584
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700585 newContent = std::to_string(retry);
586 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
587 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
588 }
589 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700590}
591
592} // namespace vold
593} // namespace android