OSDN Git Service

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