blob: d9c0cd107dbb3ee96e935721d5640faff5536b4b [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"
19
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070020#include <fstream>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070021#include <list>
22#include <string>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070023#include <vector>
24
25#include <android-base/file.h>
26#include <android-base/logging.h>
27#include <android-base/parseint.h>
28#include <android-base/unique_fd.h>
29#include <cutils/android_reboot.h>
30#include <fcntl.h>
31#include <fs_mgr.h>
32#include <linux/fs.h>
33#include <mntent.h>
34#include <sys/mount.h>
35#include <sys/stat.h>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070036
37namespace android {
38namespace vold {
39
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070040namespace {
41const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
42
43bool setBowState(std::string const& block_device, std::string const& state) {
44 if (block_device.substr(0, 5) != "/dev/") {
45 LOG(ERROR) << "Expected block device, got " << block_device;
46 return false;
47 }
48
49 std::string state_filename = std::string("/sys/") + block_device.substr(5) + "/bow/state";
50 if (!android::base::WriteStringToFile(state, state_filename)) {
51 PLOG(ERROR) << "Failed to write to file " << state_filename;
52 return false;
53 }
54
55 return true;
56}
57
58} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070059
60bool cp_startCheckpoint(int retry) {
61 if (retry < -1) return false;
62 std::string content = std::to_string(retry);
63 return android::base::WriteStringToFile(content, kMetadataCPFile);
64}
65
66bool cp_commitChanges() {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070067 // Must take action for list of mounted checkpointed things here
68 // To do this, we walk the list of mounted file systems.
69 // But we also need to get the matching fstab entries to see
70 // the original flags
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070071 struct fstab* fstab = fs_mgr_read_fstab_default();
72 if (!fstab) return false;
73
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070074 struct fstab* mounts = fs_mgr_read_fstab("/proc/mounts");
75 if (mounts == NULL) {
76 fs_mgr_free_fstab(fstab);
77 return false;
78 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070079
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070080 // Walk mounted file systems
81 for (int i = 0; i < mounts->num_entries; ++i) {
82 const fstab_rec* mount_rec = &mounts->recs[i];
83 const fstab_rec* fstab_rec = fs_mgr_get_entry_for_mount_point(fstab, mount_rec->mount_point);
84 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070085
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070086 if (fs_mgr_is_checkpoint_fs(fstab_rec)) {
87 if (!strcmp(fstab_rec->fs_type, "f2fs")) {
88 mount(mount_rec->blk_device, mount_rec->mount_point, "none",
89 MS_REMOUNT | fstab_rec->flags, "checkpoint=enable");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070090 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070091 } else if (fs_mgr_is_checkpoint_blk(fstab_rec)) {
92 setBowState(mount_rec->blk_device, "2");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070093 }
94 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070095 fs_mgr_free_fstab(mounts);
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070096 fs_mgr_free_fstab(fstab);
97 return android::base::RemoveFileIfExists(kMetadataCPFile);
98}
99
100void cp_abortChanges() {
101 android_reboot(ANDROID_RB_RESTART2, 0, nullptr);
102}
103
104bool cp_needRollback(const std::string& id) {
105 std::string content;
106 bool ret;
107
108 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
109 if (ret) return content == "0";
110 return false;
111}
112
113bool cp_needsCheckpoint(void) {
114 bool ret;
115 std::string content;
116
117 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
118 if (ret) return content != "0";
119 return false;
120}
121
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700122bool cp_prepareDriveForCheckpoint(const std::string&) {
123 struct fstab* fstab = fs_mgr_read_fstab_default();
124 if (!fstab) return false;
125
126 struct fstab* mounts = fs_mgr_read_fstab("/proc/mounts");
127 if (mounts == NULL) {
128 fs_mgr_free_fstab(fstab);
129 return false;
130 }
131
132 for (int i = 0; i < mounts->num_entries; ++i) {
133 const fstab_rec* mount_rec = &mounts->recs[i];
134 const fstab_rec* fstab_rec = fs_mgr_get_entry_for_mount_point(fstab, mount_rec->mount_point);
135 if (!fstab_rec) continue;
136
137 if (fs_mgr_is_checkpoint_blk(fstab_rec)) {
138 android::base::unique_fd fd(
139 TEMP_FAILURE_RETRY(open(mount_rec->mount_point, O_RDONLY | O_CLOEXEC)));
140 if (!fd) {
141 PLOG(ERROR) << "Failed to open mount point" << mount_rec->mount_point;
142 continue;
143 }
144
145 struct fstrim_range range = {};
146 range.len = ULLONG_MAX;
147 if (ioctl(fd, FITRIM, &range)) {
148 PLOG(ERROR) << "Failed to trim " << mount_rec->mount_point;
149 continue;
150 }
151
152 setBowState(mount_rec->blk_device, "1");
153 }
154 }
155 fs_mgr_free_fstab(mounts);
156 fs_mgr_free_fstab(fstab);
157 return true;
158}
159
160namespace {
161const int kBlockSize = 4096;
162const int kSectorSize = 512;
163
164typedef uint64_t sector_t;
165
166struct log_entry {
167 sector_t source;
168 sector_t dest;
169 uint32_t size;
170 uint32_t checksum;
171} __attribute__((packed));
172
173struct log_sector {
174 uint32_t magic;
175 uint32_t count;
176 uint32_t sequence;
177 struct log_entry entries[];
178} __attribute__((packed));
179
180// MAGIC is BOW in ascii
181const int kMagic = 0x00574f42;
182
183void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
184 static uint32_t table[0x100] = {
185 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
186 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
187 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
188 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
189 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
190 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
191 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
192 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
193 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
194 0xB6662D3D,
195
196 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
197 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
198 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
199 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
200 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
201 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
202 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
203 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
204 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
205 0xC0BA6CAD,
206
207 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
208 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
209 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
210 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
211 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
212 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
213 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
214 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
215 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
216 0x5BDEAE1D,
217
218 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
219 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
220 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
221 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
222 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
223 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
224 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
225 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
226 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
227 0x2D02EF8D};
228
229 for (size_t i = 0; i < n_bytes; ++i) {
230 *crc ^= ((uint8_t*)data)[i];
231 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
232 }
233}
234
235} // namespace
236
237bool cp_restoreCheckpoint(const std::string& blockDevice) {
238 LOG(ERROR) << "Restoring checkpoint on " << blockDevice;
239 std::fstream device(blockDevice, std::ios::binary | std::ios::in | std::ios::out);
240 if (!device) {
241 PLOG(ERROR) << "Cannot open " << blockDevice;
242 return false;
243 }
244 char buffer[kBlockSize];
245 device.read(buffer, kBlockSize);
246 log_sector& ls = *(log_sector*)buffer;
247 if (ls.magic != kMagic) {
248 LOG(ERROR) << "No magic";
249 return false;
250 }
251
252 LOG(INFO) << "Restoring " << ls.sequence << " log sectors";
253
254 for (int sequence = ls.sequence; sequence >= 0; sequence--) {
255 char buffer[kBlockSize];
256 device.seekg(0);
257 device.read(buffer, kBlockSize);
258 log_sector& ls = *(log_sector*)buffer;
259 if (ls.magic != kMagic) {
260 LOG(ERROR) << "No magic!";
261 return false;
262 }
263
264 if ((int)ls.sequence != sequence) {
265 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
266 return false;
267 }
268
269 LOG(INFO) << "Restoring from log sector " << ls.sequence;
270
271 for (log_entry* le = &ls.entries[ls.count - 1]; le >= ls.entries; --le) {
272 LOG(INFO) << "Restoring " << le->size << " bytes from sector " << le->dest << " to "
273 << le->source << " with checksum " << std::hex << le->checksum;
274 std::vector<char> buffer(le->size);
275 device.seekg(le->dest * kSectorSize);
276 device.read(&buffer[0], le->size);
277
278 uint32_t checksum = le->source / (kBlockSize / kSectorSize);
279 for (size_t i = 0; i < le->size; i += kBlockSize) {
280 crc32(&buffer[i], kBlockSize, &checksum);
281 }
282
283 if (le->checksum && checksum != le->checksum) {
284 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
285 return false;
286 }
287
288 device.seekg(le->source * kSectorSize);
289 device.write(&buffer[0], le->size);
290 }
291 }
292
293 return true;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700294}
295
296bool cp_markBootAttempt() {
297 std::string oldContent, newContent;
298 int retry = 0;
299 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) return false;
300
301 if (!android::base::ParseInt(oldContent, &retry)) return false;
302 if (retry > 0) retry--;
303
304 newContent = std::to_string(retry);
305 return android::base::WriteStringToFile(newContent, kMetadataCPFile);
306}
307
308} // namespace vold
309} // namespace android