1 /*
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"
19 #include "VoldUtil.h"
20 #include "VolumeManager.h"
21
22 #include <fstream>
23 #include <list>
24 #include <memory>
25 #include <string>
26 #include <thread>
27 #include <vector>
28
29 #include <android-base/file.h>
30 #include <android-base/logging.h>
31 #include <android-base/parseint.h>
32 #include <android-base/properties.h>
33 #include <android-base/unique_fd.h>
34 #include <android/hardware/boot/1.0/IBootControl.h>
35 #include <cutils/android_reboot.h>
36 #include <fcntl.h>
37 #include <fs_mgr.h>
38 #include <linux/fs.h>
39 #include <mntent.h>
40 #include <sys/mount.h>
41 #include <sys/stat.h>
42 #include <sys/statvfs.h>
43 #include <unistd.h>
44
45 using android::base::GetBoolProperty;
46 using android::base::GetUintProperty;
47 using android::base::SetProperty;
48 using android::binder::Status;
49 using android::fs_mgr::Fstab;
50 using android::fs_mgr::ReadDefaultFstab;
51 using android::fs_mgr::ReadFstabFromFile;
52 using android::hardware::hidl_string;
53 using android::hardware::boot::V1_0::BoolResult;
54 using android::hardware::boot::V1_0::CommandResult;
55 using android::hardware::boot::V1_0::IBootControl;
56 using android::hardware::boot::V1_0::Slot;
57
58 namespace android {
59 namespace vold {
60
61 namespace {
62 const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
63
setBowState(std::string const & block_device,std::string const & state)64 bool setBowState(std::string const& block_device, std::string const& state) {
65 std::string bow_device = fs_mgr_find_bow_device(block_device);
66 if (bow_device.empty()) return false;
67
68 if (!android::base::WriteStringToFile(state, bow_device + "/bow/state")) {
69 PLOG(ERROR) << "Failed to write to file " << bow_device + "/bow/state";
70 return false;
71 }
72
73 return true;
74 }
75
76 } // namespace
77
cp_supportsCheckpoint(bool & result)78 Status cp_supportsCheckpoint(bool& result) {
79 result = false;
80
81 for (const auto& entry : fstab_default) {
82 if (entry.fs_mgr_flags.checkpoint_blk || entry.fs_mgr_flags.checkpoint_fs) {
83 result = true;
84 return Status::ok();
85 }
86 }
87 return Status::ok();
88 }
89
cp_supportsBlockCheckpoint(bool & result)90 Status cp_supportsBlockCheckpoint(bool& result) {
91 result = false;
92
93 for (const auto& entry : fstab_default) {
94 if (entry.fs_mgr_flags.checkpoint_blk) {
95 result = true;
96 return Status::ok();
97 }
98 }
99 return Status::ok();
100 }
101
cp_supportsFileCheckpoint(bool & result)102 Status cp_supportsFileCheckpoint(bool& result) {
103 result = false;
104
105 for (const auto& entry : fstab_default) {
106 if (entry.fs_mgr_flags.checkpoint_fs) {
107 result = true;
108 return Status::ok();
109 }
110 }
111 return Status::ok();
112 }
113
cp_startCheckpoint(int retry)114 Status cp_startCheckpoint(int retry) {
115 if (retry < -1) return Status::fromExceptionCode(EINVAL, "Retry count must be more than -1");
116 std::string content = std::to_string(retry + 1);
117 if (retry == -1) {
118 sp<IBootControl> module = IBootControl::getService();
119 if (module) {
120 std::string suffix;
121 auto cb = [&suffix](hidl_string s) { suffix = s; };
122 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
123 }
124 }
125 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
126 return Status::fromExceptionCode(errno, "Failed to write checkpoint file");
127 return Status::ok();
128 }
129
130 namespace {
131
132 volatile bool isCheckpointing = false;
133 }
134
cp_commitChanges()135 Status cp_commitChanges() {
136 if (!isCheckpointing) {
137 return Status::ok();
138 }
139 if (android::base::GetProperty("persist.vold.dont_commit_checkpoint", "0") == "1") {
140 LOG(WARNING)
141 << "NOT COMMITTING CHECKPOINT BECAUSE persist.vold.dont_commit_checkpoint IS 1";
142 return Status::ok();
143 }
144 sp<IBootControl> module = IBootControl::getService();
145 if (module) {
146 CommandResult cr;
147 module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
148 if (!cr.success) {
149 std::string msg = "Error marking booted successfully: " + std::string(cr.errMsg);
150 return Status::fromExceptionCode(EINVAL, String8(msg.c_str()));
151 }
152 LOG(INFO) << "Marked slot as booted successfully.";
153 }
154 // Must take action for list of mounted checkpointed things here
155 // To do this, we walk the list of mounted file systems.
156 // But we also need to get the matching fstab entries to see
157 // the original flags
158 std::string err_str;
159
160 Fstab mounts;
161 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
162 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
163 }
164
165 // Walk mounted file systems
166 for (const auto& mount_rec : mounts) {
167 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
168 if (!fstab_rec) continue;
169
170 if (fstab_rec->fs_mgr_flags.checkpoint_fs) {
171 if (fstab_rec->fs_type == "f2fs") {
172 std::string options = mount_rec.fs_options + ",checkpoint=enable";
173 if (mount(mount_rec.blk_device.c_str(), mount_rec.mount_point.c_str(), "none",
174 MS_REMOUNT | fstab_rec->flags, options.c_str())) {
175 return Status::fromExceptionCode(EINVAL, "Failed to remount");
176 }
177 }
178 } else if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
179 if (!setBowState(mount_rec.blk_device, "2"))
180 return Status::fromExceptionCode(EINVAL, "Failed to set bow state");
181 }
182 }
183 SetProperty("vold.checkpoint_committed", "1");
184 LOG(INFO) << "Checkpoint has been committed.";
185 isCheckpointing = false;
186 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
187 return Status::fromExceptionCode(errno, err_str.c_str());
188 return Status::ok();
189 }
190
191 namespace {
abort_metadata_file()192 void abort_metadata_file() {
193 std::string oldContent, newContent;
194 int retry = 0;
195 struct stat st;
196 int result = stat(kMetadataCPFile.c_str(), &st);
197
198 // If the file doesn't exist, we aren't managing a checkpoint retry counter
199 if (result != 0) return;
200 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
201 PLOG(ERROR) << "Failed to read checkpoint file";
202 return;
203 }
204 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
205
206 if (!android::base::ParseInt(retryContent, &retry)) {
207 PLOG(ERROR) << "Could not parse retry count";
208 return;
209 }
210 if (retry > 0) {
211 newContent = "0";
212 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
213 PLOG(ERROR) << "Could not write checkpoint file";
214 }
215 }
216 } // namespace
217
cp_abortChanges(const std::string & message,bool retry)218 void cp_abortChanges(const std::string& message, bool retry) {
219 if (!cp_needsCheckpoint()) return;
220 if (!retry) abort_metadata_file();
221 android_reboot(ANDROID_RB_RESTART2, 0, message.c_str());
222 }
223
cp_needsRollback()224 bool cp_needsRollback() {
225 std::string content;
226 bool ret;
227
228 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
229 if (ret) {
230 if (content == "0") return true;
231 if (content.substr(0, 3) == "-1 ") {
232 std::string oldSuffix = content.substr(3);
233 sp<IBootControl> module = IBootControl::getService();
234 std::string newSuffix;
235
236 if (module) {
237 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
238 module->getSuffix(module->getCurrentSlot(), cb);
239 if (oldSuffix == newSuffix) return true;
240 }
241 }
242 }
243 return false;
244 }
245
cp_needsCheckpoint()246 bool cp_needsCheckpoint() {
247 bool ret;
248 std::string content;
249 sp<IBootControl> module = IBootControl::getService();
250
251 if (isCheckpointing) return isCheckpointing;
252
253 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
254 isCheckpointing = true;
255 return true;
256 }
257 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
258 if (ret) {
259 ret = content != "0";
260 isCheckpointing = ret;
261 return ret;
262 }
263 return false;
264 }
265
266 namespace {
267 const std::string kSleepTimeProp = "ro.sys.cp_msleeptime";
268 const uint32_t msleeptime_default = 1000; // 1 s
269 const uint32_t max_msleeptime = 3600000; // 1 h
270
271 const std::string kMinFreeBytesProp = "ro.sys.cp_min_free_bytes";
272 const uint64_t min_free_bytes_default = 100 * (1 << 20); // 100 MiB
273
274 const std::string kCommitOnFullProp = "ro.sys.cp_commit_on_full";
275 const bool commit_on_full_default = true;
276
cp_healthDaemon(std::string mnt_pnt,std::string blk_device,bool is_fs_cp)277 static void cp_healthDaemon(std::string mnt_pnt, std::string blk_device, bool is_fs_cp) {
278 struct statvfs data;
279 uint32_t msleeptime = GetUintProperty(kSleepTimeProp, msleeptime_default, max_msleeptime);
280 uint64_t min_free_bytes =
281 GetUintProperty(kMinFreeBytesProp, min_free_bytes_default, (uint64_t)-1);
282 bool commit_on_full = GetBoolProperty(kCommitOnFullProp, commit_on_full_default);
283
284 struct timespec req;
285 req.tv_sec = msleeptime / 1000;
286 msleeptime %= 1000;
287 req.tv_nsec = msleeptime * 1000000;
288 while (isCheckpointing) {
289 uint64_t free_bytes = 0;
290 if (is_fs_cp) {
291 statvfs(mnt_pnt.c_str(), &data);
292 free_bytes = data.f_bavail * data.f_frsize;
293 } else {
294 std::string bow_device = fs_mgr_find_bow_device(blk_device);
295 if (!bow_device.empty()) {
296 std::string content;
297 if (android::base::ReadFileToString(bow_device + "/bow/free", &content)) {
298 free_bytes = std::strtoul(content.c_str(), NULL, 10);
299 }
300 }
301 }
302 if (free_bytes < min_free_bytes) {
303 if (commit_on_full) {
304 LOG(INFO) << "Low space for checkpointing. Commiting changes";
305 cp_commitChanges();
306 break;
307 } else {
308 LOG(INFO) << "Low space for checkpointing. Rebooting";
309 cp_abortChanges("checkpoint,low_space", false);
310 break;
311 }
312 }
313 nanosleep(&req, NULL);
314 }
315 }
316
317 } // namespace
318
cp_prepareCheckpoint()319 Status cp_prepareCheckpoint() {
320 if (!isCheckpointing) {
321 return Status::ok();
322 }
323
324 Fstab mounts;
325 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
326 return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
327 }
328
329 for (const auto& mount_rec : mounts) {
330 const auto fstab_rec = GetEntryForMountPoint(&fstab_default, mount_rec.mount_point);
331 if (!fstab_rec) continue;
332
333 if (fstab_rec->fs_mgr_flags.checkpoint_blk) {
334 android::base::unique_fd fd(
335 TEMP_FAILURE_RETRY(open(mount_rec.mount_point.c_str(), O_RDONLY | O_CLOEXEC)));
336 if (fd == -1) {
337 PLOG(ERROR) << "Failed to open mount point" << mount_rec.mount_point;
338 continue;
339 }
340
341 struct fstrim_range range = {};
342 range.len = ULLONG_MAX;
343 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
344 if (ioctl(fd, FITRIM, &range)) {
345 PLOG(ERROR) << "Failed to trim " << mount_rec.mount_point;
346 continue;
347 }
348 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
349 LOG(INFO) << "Trimmed " << range.len << " bytes on " << mount_rec.mount_point << " in "
350 << nanoseconds_to_milliseconds(time) << "ms for checkpoint";
351
352 setBowState(mount_rec.blk_device, "1");
353 }
354 if (fstab_rec->fs_mgr_flags.checkpoint_blk || fstab_rec->fs_mgr_flags.checkpoint_fs) {
355 std::thread(cp_healthDaemon, std::string(mount_rec.mount_point),
356 std::string(mount_rec.blk_device),
357 fstab_rec->fs_mgr_flags.checkpoint_fs == 1)
358 .detach();
359 }
360 }
361 return Status::ok();
362 }
363
364 namespace {
365 const int kSectorSize = 512;
366
367 typedef uint64_t sector_t;
368
369 struct log_entry {
370 sector_t source; // in sectors of size kSectorSize
371 sector_t dest; // in sectors of size kSectorSize
372 uint32_t size; // in bytes
373 uint32_t checksum;
374 } __attribute__((packed));
375
376 struct log_sector_v1_0 {
377 uint32_t magic;
378 uint16_t header_version;
379 uint16_t header_size;
380 uint32_t block_size;
381 uint32_t count;
382 uint32_t sequence;
383 uint64_t sector0;
384 } __attribute__((packed));
385
386 // MAGIC is BOW in ascii
387 const int kMagic = 0x00574f42;
388 // Partially restored MAGIC is WOB in ascii
389 const int kPartialRestoreMagic = 0x00424f57;
390
crc32(const void * data,size_t n_bytes,uint32_t * crc)391 void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
392 static uint32_t table[0x100] = {
393 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
394 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
395 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
396 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
397 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
398 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
399 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
400 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
401 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
402 0xB6662D3D,
403
404 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
405 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
406 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
407 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
408 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
409 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
410 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
411 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
412 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
413 0xC0BA6CAD,
414
415 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
416 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
417 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
418 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
419 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
420 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
421 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
422 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
423 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
424 0x5BDEAE1D,
425
426 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
427 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
428 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
429 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
430 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
431 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
432 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
433 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
434 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
435 0x2D02EF8D};
436
437 for (size_t i = 0; i < n_bytes; ++i) {
438 *crc ^= ((uint8_t*)data)[i];
439 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
440 }
441 }
442
443 // A map of relocations.
444 // The map must be initialized so that relocations[0] = 0
445 // During restore, we replay the log records in reverse, copying from dest to
446 // source
447 // To validate, we must be able to read the 'dest' sectors as though they had
448 // been copied but without actually copying. This map represents how the sectors
449 // would have been moved. To read a sector s, find the index <= s and read
450 // relocations[index] + s - index
451 typedef std::map<sector_t, sector_t> Relocations;
452
relocate(Relocations & relocations,sector_t dest,sector_t source,int count)453 void relocate(Relocations& relocations, sector_t dest, sector_t source, int count) {
454 // Find first one we're equal to or greater than
455 auto s = --relocations.upper_bound(source);
456
457 // Take slice
458 Relocations slice;
459 slice[dest] = source - s->first + s->second;
460 ++s;
461
462 // Add rest of elements
463 for (; s != relocations.end() && s->first < source + count; ++s)
464 slice[dest - source + s->first] = s->second;
465
466 // Split range at end of dest
467 auto dest_end = --relocations.upper_bound(dest + count);
468 relocations[dest + count] = dest + count - dest_end->first + dest_end->second;
469
470 // Remove all elements in [dest, dest + count)
471 relocations.erase(relocations.lower_bound(dest), relocations.lower_bound(dest + count));
472
473 // Add new elements
474 relocations.insert(slice.begin(), slice.end());
475 }
476
477 // A map of sectors that have been written to.
478 // The final entry must always be False.
479 // When we restart the restore after an interruption, we must take care that
480 // when we copy from dest to source, that the block we copy to was not
481 // previously copied from.
482 // i e. A->B C->A; If we replay this sequence, we end up copying C->B
483 // We must save our partial result whenever we finish a page, or when we copy
484 // to a location that was copied from earlier (our source is an earlier dest)
485 typedef std::map<sector_t, bool> Used_Sectors;
486
checkCollision(Used_Sectors & used_sectors,sector_t start,sector_t end)487 bool checkCollision(Used_Sectors& used_sectors, sector_t start, sector_t end) {
488 auto second_overlap = used_sectors.upper_bound(start);
489 auto first_overlap = --second_overlap;
490
491 if (first_overlap->second) {
492 return true;
493 } else if (second_overlap != used_sectors.end() && second_overlap->first < end) {
494 return true;
495 }
496 return false;
497 }
498
markUsed(Used_Sectors & used_sectors,sector_t start,sector_t end)499 void markUsed(Used_Sectors& used_sectors, sector_t start, sector_t end) {
500 auto start_pos = used_sectors.insert_or_assign(start, true).first;
501 auto end_pos = used_sectors.insert_or_assign(end, false).first;
502
503 if (start_pos == used_sectors.begin() || !std::prev(start_pos)->second) {
504 start_pos++;
505 }
506 if (std::next(end_pos) != used_sectors.end() && !std::next(end_pos)->second) {
507 end_pos++;
508 }
509 if (start_pos->first < end_pos->first) {
510 used_sectors.erase(start_pos, end_pos);
511 }
512 }
513
514 // Restores the given log_entry's data from dest -> source
515 // If that entry is a log sector, set the magic to kPartialRestoreMagic and flush.
restoreSector(int device_fd,Used_Sectors & used_sectors,std::vector<char> & ls_buffer,log_entry * le,std::vector<char> & buffer)516 void restoreSector(int device_fd, Used_Sectors& used_sectors, std::vector<char>& ls_buffer,
517 log_entry* le, std::vector<char>& buffer) {
518 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
519 uint32_t index = le - ((log_entry*)&ls_buffer[ls.header_size]);
520 int count = (le->size - 1) / kSectorSize + 1;
521
522 if (checkCollision(used_sectors, le->source, le->source + count)) {
523 fsync(device_fd);
524 lseek64(device_fd, 0, SEEK_SET);
525 ls.count = index + 1;
526 ls.magic = kPartialRestoreMagic;
527 write(device_fd, &ls_buffer[0], ls.block_size);
528 fsync(device_fd);
529 used_sectors.clear();
530 used_sectors[0] = false;
531 }
532
533 markUsed(used_sectors, le->dest, le->dest + count);
534
535 if (index == 0 && ls.sequence != 0) {
536 log_sector_v1_0* next = reinterpret_cast<log_sector_v1_0*>(&buffer[0]);
537 if (next->magic == kMagic) {
538 next->magic = kPartialRestoreMagic;
539 }
540 }
541
542 lseek64(device_fd, le->source * kSectorSize, SEEK_SET);
543 write(device_fd, &buffer[0], le->size);
544
545 if (index == 0) {
546 fsync(device_fd);
547 }
548 }
549
550 // Read from the device
551 // If we are validating, the read occurs as though the relocations had happened
relocatedRead(int device_fd,Relocations const & relocations,bool validating,sector_t sector,uint32_t size,uint32_t block_size)552 std::vector<char> relocatedRead(int device_fd, Relocations const& relocations, bool validating,
553 sector_t sector, uint32_t size, uint32_t block_size) {
554 if (!validating) {
555 std::vector<char> buffer(size);
556 lseek64(device_fd, sector * kSectorSize, SEEK_SET);
557 read(device_fd, &buffer[0], size);
558 return buffer;
559 }
560
561 std::vector<char> buffer(size);
562 for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) {
563 auto relocation = --relocations.upper_bound(sector);
564 lseek64(device_fd, (sector + relocation->second - relocation->first) * kSectorSize,
565 SEEK_SET);
566 read(device_fd, &buffer[i], block_size);
567 }
568
569 return buffer;
570 }
571
572 } // namespace
573
cp_restoreCheckpoint(const std::string & blockDevice,int restore_limit)574 Status cp_restoreCheckpoint(const std::string& blockDevice, int restore_limit) {
575 bool validating = true;
576 std::string action = "Validating";
577 int restore_count = 0;
578
579 for (;;) {
580 Relocations relocations;
581 relocations[0] = 0;
582 Status status = Status::ok();
583
584 LOG(INFO) << action << " checkpoint on " << blockDevice;
585 base::unique_fd device_fd(open(blockDevice.c_str(), O_RDWR | O_CLOEXEC));
586 if (device_fd < 0) {
587 PLOG(ERROR) << "Cannot open " << blockDevice;
588 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
589 }
590
591 log_sector_v1_0 original_ls;
592 read(device_fd, reinterpret_cast<char*>(&original_ls), sizeof(original_ls));
593 if (original_ls.magic == kPartialRestoreMagic) {
594 validating = false;
595 action = "Restoring";
596 } else if (original_ls.magic != kMagic) {
597 LOG(ERROR) << "No magic";
598 return Status::fromExceptionCode(EINVAL, "No magic");
599 }
600
601 LOG(INFO) << action << " " << original_ls.sequence << " log sectors";
602
603 for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) {
604 auto ls_buffer = relocatedRead(device_fd, relocations, validating, 0,
605 original_ls.block_size, original_ls.block_size);
606 log_sector_v1_0& ls = *reinterpret_cast<log_sector_v1_0*>(&ls_buffer[0]);
607
608 Used_Sectors used_sectors;
609 used_sectors[0] = false;
610
611 if (ls.magic != kMagic && (ls.magic != kPartialRestoreMagic || validating)) {
612 LOG(ERROR) << "No magic!";
613 status = Status::fromExceptionCode(EINVAL, "No magic");
614 break;
615 }
616
617 if (ls.block_size != original_ls.block_size) {
618 LOG(ERROR) << "Block size mismatch!";
619 status = Status::fromExceptionCode(EINVAL, "Block size mismatch");
620 break;
621 }
622
623 if ((int)ls.sequence != sequence) {
624 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
625 status = Status::fromExceptionCode(
626 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
627 std::to_string(ls.sequence))
628 .c_str());
629 break;
630 }
631
632 LOG(INFO) << action << " from log sector " << ls.sequence;
633 for (log_entry* le =
634 reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]) + ls.count - 1;
635 le >= reinterpret_cast<log_entry*>(&ls_buffer[ls.header_size]); --le) {
636 // This is very noisy - limit to DEBUG only
637 LOG(VERBOSE) << action << " " << le->size << " bytes from sector " << le->dest
638 << " to " << le->source << " with checksum " << std::hex
639 << le->checksum;
640
641 auto buffer = relocatedRead(device_fd, relocations, validating, le->dest, le->size,
642 ls.block_size);
643 uint32_t checksum = le->source / (ls.block_size / kSectorSize);
644 for (size_t i = 0; i < le->size; i += ls.block_size) {
645 crc32(&buffer[i], ls.block_size, &checksum);
646 }
647
648 if (le->checksum && checksum != le->checksum) {
649 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
650 status = Status::fromExceptionCode(EINVAL, "Checksums don't match");
651 break;
652 }
653
654 if (validating) {
655 relocate(relocations, le->source, le->dest, (le->size - 1) / kSectorSize + 1);
656 } else {
657 restoreSector(device_fd, used_sectors, ls_buffer, le, buffer);
658 restore_count++;
659 if (restore_limit && restore_count >= restore_limit) {
660 LOG(WARNING) << "Hit the test limit";
661 status = Status::fromExceptionCode(EAGAIN, "Hit the test limit");
662 break;
663 }
664 }
665 }
666 }
667
668 if (!status.isOk()) {
669 if (!validating) {
670 LOG(ERROR) << "Checkpoint restore failed even though checkpoint validation passed";
671 return status;
672 }
673
674 LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward";
675 auto buffer = relocatedRead(device_fd, relocations, false, original_ls.sector0,
676 original_ls.block_size, original_ls.block_size);
677 lseek64(device_fd, 0, SEEK_SET);
678 write(device_fd, &buffer[0], original_ls.block_size);
679 return Status::ok();
680 }
681
682 if (!validating) break;
683
684 validating = false;
685 action = "Restoring";
686 }
687
688 return Status::ok();
689 }
690
cp_markBootAttempt()691 Status cp_markBootAttempt() {
692 std::string oldContent, newContent;
693 int retry = 0;
694 struct stat st;
695 int result = stat(kMetadataCPFile.c_str(), &st);
696
697 // If the file doesn't exist, we aren't managing a checkpoint retry counter
698 if (result != 0) return Status::ok();
699 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
700 PLOG(ERROR) << "Failed to read checkpoint file";
701 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
702 }
703 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
704
705 if (!android::base::ParseInt(retryContent, &retry))
706 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
707 if (retry > 0) {
708 retry--;
709
710 newContent = std::to_string(retry);
711 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
712 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
713 }
714 return Status::ok();
715 }
716
717 } // namespace vold
718 } // namespace android
719