1 /*
2 * Copyright (C) 2015-2016 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 #include <assert.h>
18 #include <inttypes.h>
19 #include <lk/compiler.h>
20 #include <stdbool.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include "array.h"
26 #include "block_allocator.h"
27 #include "block_set.h"
28 #include "debug.h"
29 #include "transaction.h"
30
31 static bool print_check_errors;
32
33 /**
34 * block_range_init_from_path
35 * @range: range object to initialize.
36 * @path: Block tree path.
37 *
38 * Helper function to initialize a block_range from a tree entry.
39 */
block_range_init_from_path(struct block_range * range,struct block_tree_path * path)40 static void block_range_init_from_path(struct block_range* range,
41 struct block_tree_path* path) {
42 if (!path->count) {
43 block_range_clear(range);
44 return;
45 }
46 range->start = block_tree_path_get_key(path);
47 range->end = block_tree_path_get_data(path);
48 assert(!range->end == !range->start);
49 }
50
51 /**
52 * block_range_extend - Extend range if possible
53 * @range: range object to initialize.
54 * @add_range: Range to add
55 *
56 * Return: %true if @add_range was adjacent to @range, %false otherwise.
57 */
block_range_extend(struct block_range * range,struct block_range add_range)58 static bool block_range_extend(struct block_range* range,
59 struct block_range add_range) {
60 pr_write("%" PRIu64 "-%" PRIu64 ", %" PRIu64 "-%" PRIu64 "\n", range->start,
61 range->end - 1, add_range.start, add_range.end - 1);
62 assert(!block_range_empty(add_range));
63 assert(!block_range_overlap(*range, add_range));
64 if (block_range_empty(*range)) {
65 pr_write("failed, *range is empty\n");
66 return false;
67 }
68 if (add_range.end == range->start) {
69 range->start = add_range.start;
70 } else if (add_range.start == range->end) {
71 range->end = add_range.end;
72 } else {
73 pr_write("failed\n");
74 return false;
75 }
76
77 pr_write("now %" PRIu64 "-%" PRIu64 "\n", range->start, range->end - 1);
78
79 return true;
80 }
81
82 /**
83 * block_range_shrink - Shrink range if possible
84 * @range: range object to initialize.
85 * @remove_range: Range to remove
86 *
87 * Return: %true if @remove_range was at either end of @range, %false otherwise.
88 */
block_range_shrink(struct block_range * range,struct block_range remove_range)89 static bool block_range_shrink(struct block_range* range,
90 struct block_range remove_range) {
91 pr_write("%" PRIu64 "-%" PRIu64 ", %" PRIu64 "-%" PRIu64 "\n", range->start,
92 range->end - 1, remove_range.start, remove_range.end - 1);
93 assert(block_range_is_sub_range(*range, remove_range));
94 if (remove_range.start == range->start) {
95 assert(!block_range_empty(*range));
96 range->start = remove_range.end;
97 } else if (remove_range.end == range->end) {
98 assert(!block_range_empty(*range));
99 range->end = remove_range.start;
100 } else {
101 pr_write("%s: failed\n", __func__);
102 return false;
103 }
104
105 pr_write("now %" PRIu64 "-%" PRIu64 "\n", range->start, range->end - 1);
106
107 return true;
108 }
109
110 /**
111 * block_set_print_ranges - Print block-set range
112 * @tr: Transaction object.
113 * @range: Range to print.
114 */
block_set_print_range(struct block_range range,int * split_line)115 static void block_set_print_range(struct block_range range, int* split_line) {
116 if (*split_line >= 8) {
117 *split_line = 0;
118 printf("\n");
119 }
120 (*split_line)++;
121 if (range.start == range.end - 1) {
122 printf(" %3" PRIu64 " ", range.start);
123 } else {
124 printf(" %3" PRIu64 " - %3" PRIu64 "", range.start, range.end - 1);
125 }
126 (*split_line)++;
127 }
128
129 /**
130 * block_set_print_ranges - Print block-set ranges
131 * @tr: Transaction object.
132 * @set: Block-set object.
133 */
block_set_print_ranges(struct transaction * tr,struct block_set * set)134 static void block_set_print_ranges(struct transaction* tr,
135 struct block_set* set) {
136 struct block_tree_path path;
137 struct block_range range;
138 int split_line = 0;
139
140 printf("set:\n");
141
142 block_tree_walk(tr, &set->block_tree, 0, true, &path);
143 block_range_init_from_path(&range, &path);
144 while (!block_range_empty(range)) {
145 block_set_print_range(range, &split_line);
146 block_tree_path_next(&path);
147 block_range_init_from_path(&range, &path);
148 }
149 printf("\n");
150
151 if (!block_range_empty(set->initial_range)) {
152 printf("initial_range: ");
153 split_line = 0;
154 block_set_print_range(set->initial_range, &split_line);
155 printf("\n");
156 }
157 }
158
159 /**
160 * block_set_print - Print block-set ranges and the tree that stored them
161 * @tr: Transaction object.
162 * @set: Block-set object.
163 */
block_set_print(struct transaction * tr,struct block_set * set)164 void block_set_print(struct transaction* tr, struct block_set* set) {
165 printf("block_tree:\n");
166 block_tree_print(tr, &set->block_tree);
167 block_set_print_ranges(tr, set);
168 }
169
170 /**
171 * block_set_check_ranges - Check that ranges in block-set are valid
172 * @tr: Transaction object.
173 * @set: Block-set object.
174 *
175 * Check that ranges in @set are valid, sorted, non-overlapping, non-adjacent
176 * and only contain blocks that are valid for @tr.
177 *
178 * Return: %true if the ranges in @set are valid, %false otherwise.
179 */
block_set_check_ranges(struct transaction * tr,struct block_set * set)180 static bool block_set_check_ranges(struct transaction* tr,
181 struct block_set* set) {
182 struct block_tree_path path;
183 data_block_t min = tr->fs->min_block_num;
184 data_block_t max = tr->fs->dev->block_count;
185 struct block_range range;
186
187 block_tree_walk(tr, &set->block_tree, 0, true, &path);
188 block_range_init_from_path(&range, &path);
189 while (!block_range_empty(range)) {
190 if (range.start < min) {
191 pr_err("bad range start %" PRIu64 " < %" PRIu64 "\n", range.start,
192 min);
193 return false;
194 }
195 if (range.end <= range.start) {
196 pr_err("bad range end %" PRIu64 " <= start %" PRIu64 "\n",
197 range.end, range.start);
198 return false;
199 }
200 if (range.end > max) {
201 pr_err("bad range end %" PRIu64 " > max %" PRIu64 "\n", range.end,
202 max);
203 return false;
204 }
205 min = range.end + 1;
206 block_tree_path_next(&path);
207 block_range_init_from_path(&range, &path);
208 }
209
210 return true;
211 }
212
213 /**
214 * block_set_check - Check block-set tree and ranges
215 * @tr: Transaction object.
216 * @set: Block-set object.
217 *
218 * Return: %true if the tree and ranges in @set are valid, %false otherwise.
219 */
block_set_check(struct transaction * tr,struct block_set * set)220 bool block_set_check(struct transaction* tr, struct block_set* set) {
221 bool valid;
222
223 valid = block_tree_check(tr, &set->block_tree);
224 if (!valid) {
225 return false;
226 }
227 valid = block_set_check_ranges(tr, set);
228 if (!valid && print_check_errors) {
229 printf("%s: invalid block_set:\n", __func__);
230 block_set_print(tr, set);
231 }
232 return valid;
233 }
234
235 /**
236 * block_set_find_next_block - find a block in or not in set
237 * @tr: Transaction object.
238 * @set: Block-set object.
239 * @min_block: Block number to start search at.
240 * @in_set: If %true look for a block in @set. If %false, look for a block
241 * not in @set.
242 *
243 * Return: First block in or not in @set >= @min_block, or 0 if no match is
244 * is found.
245 */
block_set_find_next_block(struct transaction * tr,struct block_set * set,data_block_t min_block,bool in_set)246 data_block_t block_set_find_next_block(struct transaction* tr,
247 struct block_set* set,
248 data_block_t min_block,
249 bool in_set) {
250 struct block_tree_path path;
251 struct block_range range;
252
253 block_tree_walk(tr, &set->block_tree, min_block, true, &path);
254 block_range_init_from_path(&range, &path);
255 if (!block_range_empty(range) && range.end <= min_block) {
256 block_tree_path_next(&path);
257 block_range_init_from_path(&range, &path);
258 }
259 if (block_range_empty(range)) {
260 range = set->initial_range;
261 if (range.end <= min_block) {
262 block_range_clear(&range);
263 }
264 }
265
266 pr_read("set at %" PRIu64 ", %" PRIu64 " in_set %d, [%" PRIu64 "-%" PRIu64
267 "]\n",
268 block_mac_to_block(tr, &set->block_tree.root), min_block, in_set,
269 range.start, range.end - 1);
270
271 /* The block tree walk should not find an empty range that is not 0, 0 */
272 assert(!block_range_empty(range) || !range.start);
273
274 if (block_in_range(range, min_block) == in_set) {
275 pr_read("%" PRIu64 " in_set %d, return min_block, %" PRIu64 "\n",
276 min_block, in_set, min_block);
277 return min_block;
278 } else {
279 if (!in_set) {
280 assert(!block_range_empty(range));
281 pr_read("%" PRIu64 " in_set %d, return range.end, %" PRIu64 "\n",
282 min_block, in_set, range.end);
283 return range.end;
284 } else {
285 pr_read("%" PRIu64 " in_set %d, return range.start, %" PRIu64 "\n",
286 min_block, in_set, range.start);
287 return range.start;
288 }
289 }
290 }
291
292 /**
293 * block_set_find_next_range - find a range in set
294 * @tr: Transaction object.
295 * @set: Block-set object.
296 * @min_block: Block number to start search at.
297 *
298 * Return: First block range in @set >= @min_block, or and empty range if no
299 * match is is found. If the matching range in @set starts before @min_block,
300 * the returned range will start at @min_block, not at start of the range in
301 * @set.
302 */
block_set_find_next_range(struct transaction * tr,struct block_set * set,data_block_t min_block)303 struct block_range block_set_find_next_range(struct transaction* tr,
304 struct block_set* set,
305 data_block_t min_block) {
306 struct block_range range;
307 range.start = block_set_find_next_block(tr, set, min_block, true);
308 if (range.start) {
309 range.end = block_set_find_next_block(tr, set, range.start, false);
310 } else {
311 range.end = 0;
312 }
313 return range;
314 }
315
316 /**
317 * block_set_block_in_set - Check if block is in set
318 * @tr: Transaction object.
319 * @set: Block-set object.
320 * @block: Block number.
321 *
322 * Return: %true if @block is in @set, %false if @block is not on set/
323 */
block_set_block_in_set(struct transaction * tr,struct block_set * set,data_block_t block)324 bool block_set_block_in_set(struct transaction* tr,
325 struct block_set* set,
326 data_block_t block) {
327 return block_set_find_next_block(tr, set, block, true) == block;
328 }
329
330 /**
331 * block_set_range_in_set - Check if block range is in set
332 * @tr: Transaction object.
333 * @set: Block-set object.
334 * @range: Block range to check.
335 *
336 * Return: %true if all of @range is in @set, %false if a block in @range is not
337 * in @set.
338 */
block_set_range_in_set(struct transaction * tr,struct block_set * set,struct block_range range)339 bool block_set_range_in_set(struct transaction* tr,
340 struct block_set* set,
341 struct block_range range) {
342 return block_set_find_next_block(tr, set, range.start, true) ==
343 range.start &&
344 block_set_find_next_block(tr, set, range.start, false) >= range.end;
345 }
346
347 /**
348 * block_set_range_in_set - Check if block range is not set
349 * @tr: Transaction object.
350 * @set: Block-set object.
351 * @range: Block range to check.
352 *
353 * Return: %true if all of @range is not in @set, %false if a block in @range is
354 * in @set.
355 */
block_set_range_not_in_set(struct transaction * tr,struct block_set * set,struct block_range range)356 bool block_set_range_not_in_set(struct transaction* tr,
357 struct block_set* set,
358 struct block_range range) {
359 data_block_t block = block_set_find_next_block(tr, set, range.start, true);
360 return !block || block >= range.end;
361 }
362
363 /**
364 * block_set_overlap - Check if block sets have any overlap
365 * @tr: Transaction object.
366 * @set_a: Block-set object.
367 * @set_b: Block-set object.
368 *
369 * Return: %true a block is in both @set_s and @set_b, %false if no such block
370 * exists.
371 */
block_set_overlap(struct transaction * tr,struct block_set * set_a,struct block_set * set_b)372 bool block_set_overlap(struct transaction* tr,
373 struct block_set* set_a,
374 struct block_set* set_b) {
375 struct block_range range_a;
376 struct block_range range_b = BLOCK_RANGE_INITIAL_VALUE(range_b);
377
378 while (true) {
379 range_a = block_set_find_next_range(tr, set_a, range_b.start);
380 if (block_range_empty(range_a)) {
381 return false; /* No overlap as there a no more ranges in set_a */
382 }
383 if (block_in_range(range_b, range_a.start)) {
384 return true;
385 }
386
387 /* range_a must start after range_b except first iteration */
388 assert(range_a.start >= range_b.start);
389
390 range_b = block_set_find_next_range(tr, set_b, range_a.start);
391 if (block_range_empty(range_b)) {
392 return false; /* No overlap as there a no more ranges in set_b */
393 }
394 if (block_in_range(range_a, range_b.start)) {
395 return true;
396 }
397
398 assert(range_b.start > range_a.start);
399 }
400 }
401
402 /**
403 * block_set_add_range - Add a range to block set
404 * @tr: Transaction object.
405 * @set: Block-set object.
406 * @range: Block range to add.
407 *
408 * Add @range to block set b+tree either by extending an existing range in the
409 * tree, or by adding a new range to the tree. If an existing tree entry is
410 * extended check if the next entry can be merged.
411 */
block_set_add_range(struct transaction * tr,struct block_set * set,struct block_range range)412 void block_set_add_range(struct transaction* tr,
413 struct block_set* set,
414 struct block_range range) {
415 struct block_range tree_range;
416 struct block_range new_tree_range;
417 bool extended;
418 struct block_tree_path path;
419 bool extend_left = false;
420 bool merge;
421
422 assert(!block_range_empty(range));
423 assert(block_range_empty(set->initial_range));
424
425 if (tr->failed) {
426 pr_warn("transaction failed, ignore\n");
427 return;
428 }
429
430 pr_write("set %" PRIu64 ", add %" PRIu64 "-%" PRIu64 ", updating %d\n",
431 block_mac_to_block(tr, &set->block_tree.root), range.start,
432 range.end - 1, set->updating);
433
434 assert(!set->updating);
435 set->updating = true;
436
437 full_assert(block_set_check(tr, set));
438 assert(block_set_range_not_in_set(tr, set, range));
439
440 block_tree_walk(tr, &set->block_tree, range.start - 1, true, &path);
441 block_range_init_from_path(&tree_range, &path);
442
443 if (!block_range_empty(tree_range) && tree_range.end < range.start) {
444 block_tree_path_next(&path);
445 block_range_init_from_path(&tree_range, &path);
446 if (tree_range.start == range.end) {
447 extend_left = true;
448 } else {
449 /* rewind */
450 block_tree_walk(tr, &set->block_tree, range.start - 1, true, &path);
451 block_range_init_from_path(&tree_range, &path);
452 }
453 }
454 if (tr->failed) {
455 pr_warn("transaction failed, abort\n");
456 return;
457 }
458
459 assert(!tree_range.end || !block_range_overlap(tree_range, range));
460 new_tree_range = tree_range;
461 extended = block_range_extend(&new_tree_range, range);
462 if (!extended) {
463 assert(!extend_left);
464 /* TODO: use path for insert point */
465 block_tree_insert(tr, &set->block_tree, range.start, range.end);
466 } else {
467 block_tree_path_next(&path);
468 if (tr->failed) {
469 pr_warn("transaction failed, abort\n");
470 return;
471 }
472 merge = block_tree_path_get_key(&path) == new_tree_range.end;
473 if (merge) {
474 assert(block_tree_path_get_data(&path) > new_tree_range.end);
475 new_tree_range.end = block_tree_path_get_data(&path);
476 }
477 /* TODO: use path? */
478 block_tree_update(tr, &set->block_tree, tree_range.start,
479 tree_range.end, new_tree_range.start,
480 new_tree_range.end);
481 if (tr->failed) {
482 pr_warn("transaction failed, abort\n");
483 return;
484 }
485 if (merge) {
486 /* set has overlapping ranges at this point, TODO: check that set is
487 * readable in this state */
488 block_tree_remove(tr, &set->block_tree,
489 block_tree_path_get_key(&path),
490 block_tree_path_get_data(&path));
491 }
492 }
493
494 if (tr->failed) {
495 pr_warn("transaction failed, abort\n");
496 return;
497 }
498
499 assert(set->updating);
500 set->updating = false;
501
502 full_assert(block_set_check(tr, set));
503 pr_write("set %" PRIu64 ", add %" PRIu64 "-%" PRIu64 " done\n",
504 block_mac_to_block(tr, &set->block_tree.root), range.start,
505 range.end - 1);
506 }
507
508 /**
509 * block_set_remove_range - Remove a range from block set
510 * @tr: Transaction object.
511 * @set: Block-set object.
512 * @range: Block range to remove.
513 *
514 * Remove @range from block set b+tree either by shrinking an existing range
515 * in the tree, or by splitting an existing range in the tree.
516 */
block_set_remove_range(struct transaction * tr,struct block_set * set,struct block_range range)517 void block_set_remove_range(struct transaction* tr,
518 struct block_set* set,
519 struct block_range range) {
520 struct block_tree_path path;
521 struct block_range tree_range;
522 struct block_range new_tree_range;
523 bool shrunk;
524
525 assert(!block_range_empty(range));
526 assert(block_range_empty(set->initial_range));
527
528 if (tr->failed) {
529 pr_warn("transaction failed, ignore\n");
530 return;
531 }
532
533 pr_write("set %" PRIu64 ", remove %" PRIu64 "-%" PRIu64 ", updating %d\n",
534 block_mac_to_block(tr, &set->block_tree.root), range.start,
535 range.end - 1, set->updating);
536
537 assert(block_set_range_in_set(tr, set, range) || tr->failed);
538
539 assert(!set->updating);
540 set->updating = true;
541
542 full_assert(block_set_check(tr, set));
543
544 block_tree_walk(tr, &set->block_tree, range.start, true, &path);
545 block_range_init_from_path(&tree_range, &path);
546
547 if (tr->failed) {
548 pr_warn("transaction failed, abort\n");
549 return;
550 }
551
552 assert(path.count > 0);
553
554 assert(block_range_is_sub_range(tree_range, range));
555 new_tree_range = tree_range;
556 shrunk = block_range_shrink(&new_tree_range, range);
557 if (!shrunk) {
558 block_tree_insert(tr, &set->block_tree, range.end, tree_range.end);
559 if (tr->failed) {
560 pr_warn("transaction failed, abort\n");
561 return;
562 }
563 new_tree_range.end = range.start;
564 }
565 if (block_range_empty(new_tree_range)) {
566 block_tree_remove(tr, &set->block_tree, tree_range.start,
567 tree_range.end);
568 } else {
569 /* TODO: use path? */
570 block_tree_update(tr, &set->block_tree, tree_range.start,
571 tree_range.end, new_tree_range.start,
572 new_tree_range.end);
573 }
574
575 if (tr->failed) {
576 pr_warn("transaction failed, abort\n");
577 return;
578 }
579
580 assert(set->updating);
581 set->updating = false;
582
583 full_assert(block_set_check(tr, set));
584
585 pr_write("set %" PRIu64 ", remove %" PRIu64 "-%" PRIu64 " done\n",
586 block_mac_to_block(tr, &set->block_tree.root), range.start,
587 range.end - 1);
588 }
589
590 /**
591 * block_set_add_block - Add block to block set
592 * @tr: Transaction object.
593 * @set: Block-set object.
594 * @block: Block to add.
595 */
block_set_add_block(struct transaction * tr,struct block_set * set,data_block_t block)596 void block_set_add_block(struct transaction* tr,
597 struct block_set* set,
598 data_block_t block) {
599 struct block_range range;
600
601 block_range_init_single(&range, block);
602 block_set_add_range(tr, set, range);
603 }
604
605 /**
606 * block_set_remove_block - Remove block from block set
607 * @tr: Transaction object.
608 * @set: Block-set object.
609 * @block: Block to remove.
610 */
block_set_remove_block(struct transaction * tr,struct block_set * set,data_block_t block)611 void block_set_remove_block(struct transaction* tr,
612 struct block_set* set,
613 data_block_t block) {
614 struct block_range range;
615
616 block_range_init_single(&range, block);
617 block_set_remove_range(tr, set, range);
618 }
619
620 /**
621 * block_set_init - Initialize block set
622 * @fs: File system state object.
623 * @set: Block-set object.
624 *
625 * Clear block set, get block_num_size and mac_size from @fs and intialize
626 * tree.
627 */
block_set_init(struct fs * fs,struct block_set * set)628 void block_set_init(struct fs* fs, struct block_set* set) {
629 assert(fs);
630 assert(fs->dev);
631
632 memset(set, 0, sizeof(*set));
633 block_tree_init(&set->block_tree, fs->dev->block_size, fs->block_num_size,
634 fs->block_num_size + fs->mac_size, fs->block_num_size);
635 }
636
637 /**
638 * block_set_add_initial_range - Add a range to an empty block set without
639 * updating tree
640 * @set: Block-set object.
641 * @range: Block range to add.
642 *
643 */
block_set_add_initial_range(struct block_set * set,struct block_range range)644 void block_set_add_initial_range(struct block_set* set,
645 struct block_range range) {
646 assert(block_range_empty(set->initial_range));
647 set->initial_range = range;
648 }
649
650 /**
651 * block_set_copy - Initialize a writable copy of a copy-on-write block set
652 * @tr: Transaction object.
653 * @dest: New writable block-set object.
654 * @src: Read-only block-set object.
655 */
block_set_copy(struct transaction * tr,struct block_set * dest,const struct block_set * src)656 void block_set_copy(struct transaction* tr,
657 struct block_set* dest,
658 const struct block_set* src) {
659 assert(src->block_tree.copy_on_write);
660 assert(!src->block_tree.allow_copy_on_write);
661
662 block_set_init(tr->fs, dest);
663 dest->block_tree.copy_on_write = true;
664 dest->block_tree.allow_copy_on_write = true;
665 dest->block_tree.root = src->block_tree.root;
666 if (!block_mac_valid(tr, &dest->block_tree.root)) {
667 /* special case for newly created empty fs */
668 assert(!block_range_empty(src->initial_range));
669 block_set_add_range(tr, dest, src->initial_range);
670 } else {
671 assert(block_range_empty(src->initial_range));
672 }
673 }
674
675 /**
676 * block_set_copy_ro_fs - Initialize a read-only copy of a block set
677 * @fs: File-system that contains @src.
678 * @dest: Output read-only copy of block-set object.
679 * @src: Read-only block-set object.
680 */
block_set_copy_ro_fs(struct fs * fs,struct block_set * dest,const struct block_set * src)681 void block_set_copy_ro_fs(struct fs* fs,
682 struct block_set* dest,
683 const struct block_set* src) {
684 block_set_init(fs, dest);
685 dest->block_tree.root = src->block_tree.root;
686 if (!block_range_empty(src->initial_range)) {
687 block_set_add_initial_range(dest, src->initial_range);
688 }
689 }
690
691 /**
692 * block_set_copy_ro - Initialize a read-only copy of a block set
693 * @tr: Transaction object.
694 * @dest: Output read-only copy of block-set object.
695 * @src: Read-only block-set object.
696 */
block_set_copy_ro(struct transaction * tr,struct block_set * dest,const struct block_set * src)697 void block_set_copy_ro(struct transaction* tr,
698 struct block_set* dest,
699 const struct block_set* src) {
700 block_set_copy_ro_fs(tr->fs, dest, src);
701 }
702