blob: 6229e7c6ed803e701d72bca174cec3b1f2bb9a91 [file] [log] [blame]
Colin Cross28fa5bc2012-05-20 13:28:05 -07001/*
2 * Copyright (C) 2010 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
Colin Crossb55dcee2012-04-24 23:07:49 -070017#include <assert.h>
18#include <errno.h>
19#include <stdint.h>
Colin Cross28fa5bc2012-05-20 13:28:05 -070020#include <stdlib.h>
21#include <string.h>
22
23#include "backed_block.h"
Colin Crossbe8ddcb2012-04-25 21:02:16 -070024#include "sparse_defs.h"
Colin Cross28fa5bc2012-05-20 13:28:05 -070025
Colin Crossb55dcee2012-04-24 23:07:49 -070026struct backed_block {
Jerry Zhang7b444f02018-06-12 16:42:09 -070027 unsigned int block;
Hyeongseok Kime8d02c52020-08-10 12:11:57 +090028 uint64_t len;
Jerry Zhang7b444f02018-06-12 16:42:09 -070029 enum backed_block_type type;
30 union {
31 struct {
32 void* data;
33 } data;
34 struct {
35 char* filename;
36 int64_t offset;
37 } file;
38 struct {
39 int fd;
40 int64_t offset;
41 } fd;
42 struct {
43 uint32_t val;
44 } fill;
45 };
46 struct backed_block* next;
Colin Cross28fa5bc2012-05-20 13:28:05 -070047};
48
Colin Cross411619e2012-04-24 18:51:42 -070049struct backed_block_list {
Jerry Zhang7b444f02018-06-12 16:42:09 -070050 struct backed_block* data_blocks;
51 struct backed_block* last_used;
52 unsigned int block_size;
Colin Cross411619e2012-04-24 18:51:42 -070053};
Colin Cross28fa5bc2012-05-20 13:28:05 -070054
Jerry Zhang7b444f02018-06-12 16:42:09 -070055struct backed_block* backed_block_iter_new(struct backed_block_list* bbl) {
56 return bbl->data_blocks;
Colin Crossb55dcee2012-04-24 23:07:49 -070057}
58
Jerry Zhang7b444f02018-06-12 16:42:09 -070059struct backed_block* backed_block_iter_next(struct backed_block* bb) {
60 return bb->next;
Colin Crossb55dcee2012-04-24 23:07:49 -070061}
62
Hyeongseok Kime8d02c52020-08-10 12:11:57 +090063uint64_t backed_block_len(struct backed_block* bb) {
Jerry Zhang7b444f02018-06-12 16:42:09 -070064 return bb->len;
Colin Crossb55dcee2012-04-24 23:07:49 -070065}
66
Jerry Zhang7b444f02018-06-12 16:42:09 -070067unsigned int backed_block_block(struct backed_block* bb) {
68 return bb->block;
Colin Crossb55dcee2012-04-24 23:07:49 -070069}
70
Jerry Zhang7b444f02018-06-12 16:42:09 -070071void* backed_block_data(struct backed_block* bb) {
72 assert(bb->type == BACKED_BLOCK_DATA);
73 return bb->data.data;
Colin Crossb55dcee2012-04-24 23:07:49 -070074}
75
Jerry Zhang7b444f02018-06-12 16:42:09 -070076const char* backed_block_filename(struct backed_block* bb) {
77 assert(bb->type == BACKED_BLOCK_FILE);
78 return bb->file.filename;
Colin Crossb55dcee2012-04-24 23:07:49 -070079}
80
Jerry Zhang7b444f02018-06-12 16:42:09 -070081int backed_block_fd(struct backed_block* bb) {
82 assert(bb->type == BACKED_BLOCK_FD);
83 return bb->fd.fd;
Colin Cross9e1f17e2012-04-25 18:31:39 -070084}
85
Jerry Zhang7b444f02018-06-12 16:42:09 -070086int64_t backed_block_file_offset(struct backed_block* bb) {
87 assert(bb->type == BACKED_BLOCK_FILE || bb->type == BACKED_BLOCK_FD);
88 if (bb->type == BACKED_BLOCK_FILE) {
89 return bb->file.offset;
90 } else { /* bb->type == BACKED_BLOCK_FD */
91 return bb->fd.offset;
92 }
Colin Crossb55dcee2012-04-24 23:07:49 -070093}
94
Jerry Zhang7b444f02018-06-12 16:42:09 -070095uint32_t backed_block_fill_val(struct backed_block* bb) {
96 assert(bb->type == BACKED_BLOCK_FILL);
97 return bb->fill.val;
Colin Crossb55dcee2012-04-24 23:07:49 -070098}
99
Jerry Zhang7b444f02018-06-12 16:42:09 -0700100enum backed_block_type backed_block_type(struct backed_block* bb) {
101 return bb->type;
Colin Crossb55dcee2012-04-24 23:07:49 -0700102}
103
Jerry Zhang7b444f02018-06-12 16:42:09 -0700104void backed_block_destroy(struct backed_block* bb) {
105 if (bb->type == BACKED_BLOCK_FILE) {
106 free(bb->file.filename);
107 }
Colin Crossbe8ddcb2012-04-25 21:02:16 -0700108
Jerry Zhang7b444f02018-06-12 16:42:09 -0700109 free(bb);
Colin Crossbe8ddcb2012-04-25 21:02:16 -0700110}
111
Jerry Zhang7b444f02018-06-12 16:42:09 -0700112struct backed_block_list* backed_block_list_new(unsigned int block_size) {
113 struct backed_block_list* b =
114 reinterpret_cast<backed_block_list*>(calloc(sizeof(struct backed_block_list), 1));
115 b->block_size = block_size;
116 return b;
Colin Cross411619e2012-04-24 18:51:42 -0700117}
118
Jerry Zhang7b444f02018-06-12 16:42:09 -0700119void backed_block_list_destroy(struct backed_block_list* bbl) {
120 if (bbl->data_blocks) {
121 struct backed_block* bb = bbl->data_blocks;
122 while (bb) {
123 struct backed_block* next = bb->next;
124 backed_block_destroy(bb);
125 bb = next;
126 }
127 }
Colin Cross411619e2012-04-24 18:51:42 -0700128
Jerry Zhang7b444f02018-06-12 16:42:09 -0700129 free(bbl);
Colin Cross411619e2012-04-24 18:51:42 -0700130}
131
Jerry Zhang7b444f02018-06-12 16:42:09 -0700132void backed_block_list_move(struct backed_block_list* from, struct backed_block_list* to,
133 struct backed_block* start, struct backed_block* end) {
134 struct backed_block* bb;
Colin Crossbdc6d392012-05-02 15:18:22 -0700135
Yi Kong17ba95e2018-07-23 16:31:11 -0700136 if (start == nullptr) {
Jerry Zhang7b444f02018-06-12 16:42:09 -0700137 start = from->data_blocks;
138 }
Colin Crossbdc6d392012-05-02 15:18:22 -0700139
Jerry Zhang7b444f02018-06-12 16:42:09 -0700140 if (!end) {
141 for (end = start; end && end->next; end = end->next)
142 ;
143 }
Colin Crossbdc6d392012-05-02 15:18:22 -0700144
Yi Kong17ba95e2018-07-23 16:31:11 -0700145 if (start == nullptr || end == nullptr) {
Jerry Zhang7b444f02018-06-12 16:42:09 -0700146 return;
147 }
Colin Crossbdc6d392012-05-02 15:18:22 -0700148
Yi Kong17ba95e2018-07-23 16:31:11 -0700149 from->last_used = nullptr;
150 to->last_used = nullptr;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700151 if (from->data_blocks == start) {
152 from->data_blocks = end->next;
153 } else {
154 for (bb = from->data_blocks; bb; bb = bb->next) {
155 if (bb->next == start) {
156 bb->next = end->next;
157 break;
158 }
159 }
160 }
Colin Crossbdc6d392012-05-02 15:18:22 -0700161
Jerry Zhang7b444f02018-06-12 16:42:09 -0700162 if (!to->data_blocks) {
163 to->data_blocks = start;
Yi Kong17ba95e2018-07-23 16:31:11 -0700164 end->next = nullptr;
Jerry Zhang7b444f02018-06-12 16:42:09 -0700165 } else {
166 for (bb = to->data_blocks; bb; bb = bb->next) {
167 if (!bb->next || bb->next->block > start->block) {
168 end->next = bb->next;
169 bb->next = start;
170 break;
171 }
172 }
173 }
Colin Crossbdc6d392012-05-02 15:18:22 -0700174}
175
Colin Crossbe8ddcb2012-04-25 21:02:16 -0700176/* may free b */
Jerry Zhang7b444f02018-06-12 16:42:09 -0700177static int merge_bb(struct backed_block_list* bbl, struct backed_block* a, struct backed_block* b) {
178 unsigned int block_len;
Colin Crossbe8ddcb2012-04-25 21:02:16 -0700179
Jerry Zhang7b444f02018-06-12 16:42:09 -0700180 /* Block doesn't exist (possible if one block is the last block) */
181 if (!a || !b) {
182 return -EINVAL;
183 }
Colin Crossbe8ddcb2012-04-25 21:02:16 -0700184
Jerry Zhang7b444f02018-06-12 16:42:09 -0700185 assert(a->block < b->block);
Colin Crossbe8ddcb2012-04-25 21:02:16 -0700186
Jerry Zhang7b444f02018-06-12 16:42:09 -0700187 /* Blocks are of different types */
188 if (a->type != b->type) {
189 return -EINVAL;
190 }
Colin Crossbe8ddcb2012-04-25 21:02:16 -0700191
Jerry Zhang7b444f02018-06-12 16:42:09 -0700192 /* Blocks are not adjacent */
193 block_len = a->len / bbl->block_size; /* rounds down */
194 if (a->block + block_len != b->block) {
195 return -EINVAL;
196 }
Colin Crossbe8ddcb2012-04-25 21:02:16 -0700197
Jerry Zhang7b444f02018-06-12 16:42:09 -0700198 switch (a->type) {
199 case BACKED_BLOCK_DATA:
200 /* Don't support merging data for now */
201 return -EINVAL;
202 case BACKED_BLOCK_FILL:
203 if (a->fill.val != b->fill.val) {
204 return -EINVAL;
205 }
206 break;
207 case BACKED_BLOCK_FILE:
208 /* Already make sure b->type is BACKED_BLOCK_FILE */
209 if (strcmp(a->file.filename, b->file.filename) || a->file.offset + a->len != b->file.offset) {
210 return -EINVAL;
211 }
212 break;
213 case BACKED_BLOCK_FD:
214 if (a->fd.fd != b->fd.fd || a->fd.offset + a->len != b->fd.offset) {
215 return -EINVAL;
216 }
217 break;
218 }
Colin Crossbe8ddcb2012-04-25 21:02:16 -0700219
Jerry Zhang7b444f02018-06-12 16:42:09 -0700220 /* Blocks are compatible and adjacent, with a before b. Merge b into a,
221 * and free b */
222 a->len += b->len;
223 a->next = b->next;
Colin Crossbe8ddcb2012-04-25 21:02:16 -0700224
Jerry Zhang7b444f02018-06-12 16:42:09 -0700225 backed_block_destroy(b);
Colin Crossbe8ddcb2012-04-25 21:02:16 -0700226
Jerry Zhang7b444f02018-06-12 16:42:09 -0700227 return 0;
Colin Crossbe8ddcb2012-04-25 21:02:16 -0700228}
229
Jerry Zhang7b444f02018-06-12 16:42:09 -0700230static int queue_bb(struct backed_block_list* bbl, struct backed_block* new_bb) {
231 struct backed_block* bb;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700232
Yi Kong17ba95e2018-07-23 16:31:11 -0700233 if (bbl->data_blocks == nullptr) {
Jerry Zhang7b444f02018-06-12 16:42:09 -0700234 bbl->data_blocks = new_bb;
235 return 0;
236 }
Colin Cross28fa5bc2012-05-20 13:28:05 -0700237
Jerry Zhang7b444f02018-06-12 16:42:09 -0700238 if (bbl->data_blocks->block > new_bb->block) {
239 new_bb->next = bbl->data_blocks;
240 bbl->data_blocks = new_bb;
241 return 0;
242 }
Colin Cross28fa5bc2012-05-20 13:28:05 -0700243
Jerry Zhang7b444f02018-06-12 16:42:09 -0700244 /* Optimization: blocks are mostly queued in sequence, so save the
245 pointer to the last bb that was added, and start searching from
246 there if the next block number is higher */
247 if (bbl->last_used && new_bb->block > bbl->last_used->block)
248 bb = bbl->last_used;
249 else
250 bb = bbl->data_blocks;
251 bbl->last_used = new_bb;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700252
Jerry Zhang7b444f02018-06-12 16:42:09 -0700253 for (; bb->next && bb->next->block < new_bb->block; bb = bb->next)
254 ;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700255
Yi Kong17ba95e2018-07-23 16:31:11 -0700256 if (bb->next == nullptr) {
Jerry Zhang7b444f02018-06-12 16:42:09 -0700257 bb->next = new_bb;
258 } else {
259 new_bb->next = bb->next;
260 bb->next = new_bb;
261 }
Colin Crossb55dcee2012-04-24 23:07:49 -0700262
Jerry Zhang7b444f02018-06-12 16:42:09 -0700263 merge_bb(bbl, new_bb, new_bb->next);
264 if (!merge_bb(bbl, bb, new_bb)) {
265 /* new_bb destroyed, point to retained as last_used */
266 bbl->last_used = bb;
267 }
Colin Crossbe8ddcb2012-04-25 21:02:16 -0700268
Jerry Zhang7b444f02018-06-12 16:42:09 -0700269 return 0;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700270}
271
272/* Queues a fill block of memory to be written to the specified data blocks */
Hyeongseok Kime8d02c52020-08-10 12:11:57 +0900273int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, uint64_t len,
Jerry Zhang7b444f02018-06-12 16:42:09 -0700274 unsigned int block) {
275 struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
Yi Kong17ba95e2018-07-23 16:31:11 -0700276 if (bb == nullptr) {
Jerry Zhang7b444f02018-06-12 16:42:09 -0700277 return -ENOMEM;
278 }
Colin Cross28fa5bc2012-05-20 13:28:05 -0700279
Jerry Zhang7b444f02018-06-12 16:42:09 -0700280 bb->block = block;
281 bb->len = len;
282 bb->type = BACKED_BLOCK_FILL;
283 bb->fill.val = fill_val;
Yi Kong17ba95e2018-07-23 16:31:11 -0700284 bb->next = nullptr;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700285
Jerry Zhang7b444f02018-06-12 16:42:09 -0700286 return queue_bb(bbl, bb);
Colin Cross28fa5bc2012-05-20 13:28:05 -0700287}
288
289/* Queues a block of memory to be written to the specified data blocks */
Hyeongseok Kime8d02c52020-08-10 12:11:57 +0900290int backed_block_add_data(struct backed_block_list* bbl, void* data, uint64_t len,
Jerry Zhang7b444f02018-06-12 16:42:09 -0700291 unsigned int block) {
292 struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
Yi Kong17ba95e2018-07-23 16:31:11 -0700293 if (bb == nullptr) {
Jerry Zhang7b444f02018-06-12 16:42:09 -0700294 return -ENOMEM;
295 }
Colin Cross28fa5bc2012-05-20 13:28:05 -0700296
Jerry Zhang7b444f02018-06-12 16:42:09 -0700297 bb->block = block;
298 bb->len = len;
299 bb->type = BACKED_BLOCK_DATA;
300 bb->data.data = data;
Yi Kong17ba95e2018-07-23 16:31:11 -0700301 bb->next = nullptr;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700302
Jerry Zhang7b444f02018-06-12 16:42:09 -0700303 return queue_bb(bbl, bb);
Colin Cross28fa5bc2012-05-20 13:28:05 -0700304}
305
306/* Queues a chunk of a file on disk to be written to the specified data blocks */
Jerry Zhang7b444f02018-06-12 16:42:09 -0700307int backed_block_add_file(struct backed_block_list* bbl, const char* filename, int64_t offset,
Hyeongseok Kime8d02c52020-08-10 12:11:57 +0900308 uint64_t len, unsigned int block) {
Jerry Zhang7b444f02018-06-12 16:42:09 -0700309 struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
Yi Kong17ba95e2018-07-23 16:31:11 -0700310 if (bb == nullptr) {
Jerry Zhang7b444f02018-06-12 16:42:09 -0700311 return -ENOMEM;
312 }
Colin Cross28fa5bc2012-05-20 13:28:05 -0700313
Jerry Zhang7b444f02018-06-12 16:42:09 -0700314 bb->block = block;
315 bb->len = len;
316 bb->type = BACKED_BLOCK_FILE;
317 bb->file.filename = strdup(filename);
318 bb->file.offset = offset;
Yi Kong17ba95e2018-07-23 16:31:11 -0700319 bb->next = nullptr;
Colin Cross28fa5bc2012-05-20 13:28:05 -0700320
Jerry Zhang7b444f02018-06-12 16:42:09 -0700321 return queue_bb(bbl, bb);
Colin Cross28fa5bc2012-05-20 13:28:05 -0700322}
Colin Cross9e1f17e2012-04-25 18:31:39 -0700323
324/* Queues a chunk of a fd to be written to the specified data blocks */
Hyeongseok Kime8d02c52020-08-10 12:11:57 +0900325int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, uint64_t len,
Jerry Zhang7b444f02018-06-12 16:42:09 -0700326 unsigned int block) {
327 struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
Yi Kong17ba95e2018-07-23 16:31:11 -0700328 if (bb == nullptr) {
Jerry Zhang7b444f02018-06-12 16:42:09 -0700329 return -ENOMEM;
330 }
Colin Cross9e1f17e2012-04-25 18:31:39 -0700331
Jerry Zhang7b444f02018-06-12 16:42:09 -0700332 bb->block = block;
333 bb->len = len;
334 bb->type = BACKED_BLOCK_FD;
335 bb->fd.fd = fd;
336 bb->fd.offset = offset;
Yi Kong17ba95e2018-07-23 16:31:11 -0700337 bb->next = nullptr;
Colin Cross9e1f17e2012-04-25 18:31:39 -0700338
Jerry Zhang7b444f02018-06-12 16:42:09 -0700339 return queue_bb(bbl, bb);
Colin Cross9e1f17e2012-04-25 18:31:39 -0700340}
Colin Crossbdc6d392012-05-02 15:18:22 -0700341
Jerry Zhang7b444f02018-06-12 16:42:09 -0700342int backed_block_split(struct backed_block_list* bbl, struct backed_block* bb,
343 unsigned int max_len) {
344 struct backed_block* new_bb;
Colin Crossbdc6d392012-05-02 15:18:22 -0700345
Jerry Zhang7b444f02018-06-12 16:42:09 -0700346 max_len = ALIGN_DOWN(max_len, bbl->block_size);
Colin Crossbdc6d392012-05-02 15:18:22 -0700347
Jerry Zhang7b444f02018-06-12 16:42:09 -0700348 if (bb->len <= max_len) {
349 return 0;
350 }
Colin Crossbdc6d392012-05-02 15:18:22 -0700351
Jerry Zhang7b444f02018-06-12 16:42:09 -0700352 new_bb = reinterpret_cast<backed_block*>(malloc(sizeof(struct backed_block)));
Yi Kong17ba95e2018-07-23 16:31:11 -0700353 if (new_bb == nullptr) {
Jerry Zhang7b444f02018-06-12 16:42:09 -0700354 return -ENOMEM;
355 }
Colin Crossbdc6d392012-05-02 15:18:22 -0700356
Jerry Zhang7b444f02018-06-12 16:42:09 -0700357 *new_bb = *bb;
Colin Crossbdc6d392012-05-02 15:18:22 -0700358
Jerry Zhang7b444f02018-06-12 16:42:09 -0700359 new_bb->len = bb->len - max_len;
360 new_bb->block = bb->block + max_len / bbl->block_size;
361 new_bb->next = bb->next;
362 bb->next = new_bb;
363 bb->len = max_len;
Colin Crossbdc6d392012-05-02 15:18:22 -0700364
Jerry Zhang7b444f02018-06-12 16:42:09 -0700365 switch (bb->type) {
366 case BACKED_BLOCK_DATA:
367 new_bb->data.data = (char*)bb->data.data + max_len;
368 break;
369 case BACKED_BLOCK_FILE:
370 new_bb->file.offset += max_len;
371 break;
372 case BACKED_BLOCK_FD:
373 new_bb->fd.offset += max_len;
374 break;
375 case BACKED_BLOCK_FILL:
376 break;
377 }
Colin Crossbdc6d392012-05-02 15:18:22 -0700378
Jerry Zhang7b444f02018-06-12 16:42:09 -0700379 return 0;
Colin Crossbdc6d392012-05-02 15:18:22 -0700380}