1 /* 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 17 #include "allocate.h" 18 19 #include <stdio.h> 20 #include <stdlib.h> 21 22 #include <sparse/sparse.h> 23 24 #include "ext4_utils/ext4_utils.h" 25 26 struct xattr_list_element { 27 struct ext4_inode *inode; 28 struct ext4_xattr_header *header; 29 struct xattr_list_element *next; 30 }; 31 32 struct block_allocation *create_allocation() 33 { 34 struct block_allocation *alloc = malloc(sizeof(struct block_allocation)); 35 alloc->list.first = NULL; 36 alloc->list.last = NULL; 37 alloc->oob_list.first = NULL; 38 alloc->oob_list.last = NULL; 39 alloc->list.iter = NULL; 40 alloc->list.partial_iter = 0; 41 alloc->oob_list.iter = NULL; 42 alloc->oob_list.partial_iter = 0; 43 alloc->filename = NULL; 44 alloc->next = NULL; 45 return alloc; 46 } 47 48 static struct ext4_xattr_header *xattr_list_find(struct ext4_inode *inode) 49 { 50 struct xattr_list_element *element; 51 for (element = aux_info.xattrs; element != NULL; element = element->next) { 52 if (element->inode == inode) 53 return element->header; 54 } 55 return NULL; 56 } 57 58 static void xattr_list_insert(struct ext4_inode *inode, struct ext4_xattr_header *header) 59 { 60 struct xattr_list_element *element = malloc(sizeof(struct xattr_list_element)); 61 element->inode = inode; 62 element->header = header; 63 element->next = aux_info.xattrs; 64 aux_info.xattrs = element; 65 } 66 67 static void region_list_remove(struct region_list *list, struct region *reg) 68 { 69 if (reg->prev) 70 reg->prev->next = reg->next; 71 72 if (reg->next) 73 reg->next->prev = reg->prev; 74 75 if (list->first == reg) 76 list->first = reg->next; 77 78 if (list->last == reg) 79 list->last = reg->prev; 80 81 reg->next = NULL; 82 reg->prev = NULL; 83 } 84 85 void region_list_append(struct region_list *list, struct region *reg) 86 { 87 if (list->first == NULL) { 88 list->first = reg; 89 list->last = reg; 90 list->iter = reg; 91 list->partial_iter = 0; 92 reg->prev = NULL; 93 } else { 94 list->last->next = reg; 95 reg->prev = list->last; 96 list->last = reg; 97 } 98 reg->next = NULL; 99 } 100 101 void region_list_merge(struct region_list *list1, struct region_list *list2) 102 { 103 if (list1->first == NULL) { 104 list1->first = list2->first; 105 list1->last = list2->last; 106 list1->iter = list2->first; 107 list1->partial_iter = 0; 108 list1->first->prev = NULL; 109 } else { 110 list1->last->next = list2->first; 111 list2->first->prev = list1->last; 112 list1->last = list2->last; 113 } 114 } 115 #if 0 116 static void dump_starting_from(struct region *reg) 117 { 118 for (; reg; reg = reg->next) { 119 printf("%p: Blocks %d-%d (%d)\n", reg, 120 reg->block, reg->block + reg->len - 1, reg->len) 121 } 122 } 123 124 static void dump_region_lists(struct block_allocation *alloc) { 125 126 printf("Main list:\n"); 127 dump_starting_from(alloc->list.first); 128 129 printf("OOB list:\n"); 130 dump_starting_from(alloc->oob_list.first); 131 } 132 #endif 133 134 void print_blocks(FILE* f, struct block_allocation *alloc, char separator) 135 { 136 struct region *reg; 137 fputc(' ', f); 138 for (reg = alloc->list.first; reg; reg = reg->next) { 139 if (reg->len == 1) { 140 fprintf(f, "%d", reg->block); 141 } else { 142 fprintf(f, "%d-%d", reg->block, reg->block + reg->len - 1); 143 } 144 fputc(separator, f); 145 } 146 fputc('\n', f); 147 } 148 149 void append_region(struct block_allocation *alloc, 150 u32 block, u32 len, int bg_num) 151 { 152 struct region *reg; 153 reg = malloc(sizeof(struct region)); 154 reg->block = block; 155 reg->len = len; 156 reg->bg = bg_num; 157 reg->next = NULL; 158 159 region_list_append(&alloc->list, reg); 160 } 161 162 static void allocate_bg_inode_table(struct block_group_info *bg) 163 { 164 if (bg->inode_table != NULL) 165 return; 166 167 u32 block = bg->first_block + 2; 168 169 if (bg->has_superblock) 170 block += aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks + 1; 171 172 bg->inode_table = calloc(aux_info.inode_table_blocks, info.block_size); 173 if (bg->inode_table == NULL) 174 critical_error_errno("calloc"); 175 176 sparse_file_add_data(ext4_sparse_file, bg->inode_table, 177 aux_info.inode_table_blocks * info.block_size, block); 178 179 bg->flags &= ~EXT4_BG_INODE_UNINIT; 180 } 181 182 static int bitmap_set_bit(u8 *bitmap, u32 bit) 183 { 184 if (bitmap[bit / 8] & 1 << (bit % 8)) 185 return 1; 186 187 bitmap[bit / 8] |= 1 << (bit % 8); 188 return 0; 189 } 190 191 static int bitmap_set_8_bits(u8 *bitmap, u32 bit) 192 { 193 int ret = bitmap[bit / 8]; 194 bitmap[bit / 8] = 0xFF; 195 return ret; 196 } 197 198 /* Marks a the first num_blocks blocks in a block group as used, and accounts 199 for them in the block group free block info. */ 200 static int reserve_blocks(struct block_group_info *bg, u32 bg_num, u32 start, u32 num) 201 { 202 unsigned int i = 0; 203 204 u32 block = start; 205 for (i = 0; i < num && block % 8 != 0; i++, block++) { 206 if (bitmap_set_bit(bg->block_bitmap, block)) { 207 error("attempted to reserve already reserved block %d in block group %d", block, bg_num); 208 return -1; 209 } 210 } 211 212 for (; i + 8 <= (num & ~7); i += 8, block += 8) { 213 if (bitmap_set_8_bits(bg->block_bitmap, block)) { 214 error("attempted to reserve already reserved block %d in block group %d", block, bg_num); 215 return -1; 216 } 217 } 218 219 for (; i < num; i++, block++) { 220 if (bitmap_set_bit(bg->block_bitmap, block)) { 221 error("attempted to reserve already reserved block %d in block group %d", block, bg_num); 222 return -1; 223 } 224 } 225 226 bg->free_blocks -= num; 227 228 return 0; 229 } 230 231 static void free_blocks(struct block_group_info *bg, u32 block, u32 num_blocks) 232 { 233 unsigned int i; 234 for (i = 0; i < num_blocks; i++, block--) 235 bg->block_bitmap[block / 8] &= ~(1 << (block % 8)); 236 bg->free_blocks += num_blocks; 237 for (i = bg->chunk_count; i > 0 ;) { 238 --i; 239 if (bg->chunks[i].len >= num_blocks && bg->chunks[i].block <= block) { 240 if (bg->chunks[i].block == block) { 241 bg->chunks[i].block += num_blocks; 242 bg->chunks[i].len -= num_blocks; 243 } else if (bg->chunks[i].block + bg->chunks[i].len - 1 == block + num_blocks) { 244 bg->chunks[i].len -= num_blocks; 245 } 246 break; 247 } 248 } 249 } 250 251 /* Reduces an existing allocation by len blocks by return the last blocks 252 to the free pool in their block group. Assumes that the blocks being 253 returned were the last ones allocated out of the block group */ 254 void reduce_allocation(struct block_allocation *alloc, u32 len) 255 { 256 while (len) { 257 struct region *last_reg = alloc->list.last; 258 struct block_group_info *bg = &aux_info.bgs[last_reg->bg]; 259 260 if (last_reg->len > len) { 261 free_blocks(bg, last_reg->block + last_reg->len - bg->first_block - 1, len); 262 last_reg->len -= len; 263 len = 0; 264 } else { 265 struct region *reg = alloc->list.last->prev; 266 free_blocks(bg, last_reg->block + last_reg->len - bg->first_block - 1, last_reg->len); 267 len -= last_reg->len; 268 if (reg) { 269 reg->next = NULL; 270 } else { 271 alloc->list.first = NULL; 272 alloc->list.last = NULL; 273 alloc->list.iter = NULL; 274 alloc->list.partial_iter = 0; 275 } 276 free(last_reg); 277 } 278 } 279 } 280 281 static void init_bg(struct block_group_info *bg, unsigned int i) 282 { 283 int header_blocks = 2 + aux_info.inode_table_blocks; 284 285 bg->has_superblock = ext4_bg_has_super_block(i); 286 287 if (bg->has_superblock) 288 header_blocks += 1 + aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks; 289 290 bg->bitmaps = calloc(info.block_size, 2); 291 bg->block_bitmap = bg->bitmaps; 292 bg->inode_bitmap = bg->bitmaps + info.block_size; 293 294 bg->header_blocks = header_blocks; 295 bg->first_block = aux_info.first_data_block + i * info.blocks_per_group; 296 297 u32 block = bg->first_block; 298 if (bg->has_superblock) 299 block += 1 + aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks; 300 sparse_file_add_data(ext4_sparse_file, bg->bitmaps, 2 * info.block_size, 301 block); 302 303 bg->data_blocks_used = 0; 304 bg->free_blocks = info.blocks_per_group; 305 bg->free_inodes = info.inodes_per_group; 306 bg->first_free_inode = 1; 307 bg->flags = EXT4_BG_INODE_UNINIT; 308 309 bg->chunk_count = 0; 310 bg->max_chunk_count = 1; 311 bg->chunks = (struct region*) calloc(bg->max_chunk_count, sizeof(struct region)); 312 313 if (reserve_blocks(bg, i, 0, bg->header_blocks) < 0) 314 error("failed to reserve %u blocks in block group %u\n", bg->header_blocks, i); 315 // Add empty starting delimiter chunk 316 reserve_bg_chunk(i, bg->header_blocks, 0); 317 318 if (bg->first_block + info.blocks_per_group > aux_info.len_blocks) { 319 u32 overrun = bg->first_block + info.blocks_per_group - aux_info.len_blocks; 320 reserve_blocks(bg, i, info.blocks_per_group - overrun, overrun); 321 // Add empty ending delimiter chunk 322 reserve_bg_chunk(i, info.blocks_per_group - overrun, 0); 323 } else { 324 reserve_bg_chunk(i, info.blocks_per_group - 1, 0); 325 } 326 327 } 328 329 void block_allocator_init() 330 { 331 unsigned int i; 332 333 aux_info.bgs = calloc(sizeof(struct block_group_info), aux_info.groups); 334 if (aux_info.bgs == NULL) 335 critical_error_errno("calloc"); 336 337 for (i = 0; i < aux_info.groups; i++) 338 init_bg(&aux_info.bgs[i], i); 339 } 340 341 void block_allocator_free() 342 { 343 unsigned int i; 344 345 for (i = 0; i < aux_info.groups; i++) { 346 free(aux_info.bgs[i].bitmaps); 347 free(aux_info.bgs[i].inode_table); 348 } 349 free(aux_info.bgs); 350 } 351 352 /* Allocate a single block and return its block number */ 353 u32 allocate_block() 354 { 355 u32 block; 356 struct block_allocation *blk_alloc = allocate_blocks(1); 357 if (!blk_alloc) { 358 return EXT4_ALLOCATE_FAILED; 359 } 360 block = blk_alloc->list.first->block; 361 free_alloc(blk_alloc); 362 return block; 363 } 364 365 static struct region *ext4_allocate_best_fit_partial(u32 len) 366 { 367 unsigned int i; 368 int j; 369 unsigned int found_bg = 0, found_prev_chunk = 0, found_block = 0; 370 u32 found_allocate_len = 0; 371 bool minimize = false; 372 struct block_group_info *bgs = aux_info.bgs; 373 struct region *reg; 374 375 for (i = 0; i < aux_info.groups; i++) { 376 for (j = 1; j < bgs[i].chunk_count; j++) { 377 u32 hole_start, hole_size; 378 hole_start = bgs[i].chunks[j-1].block + bgs[i].chunks[j-1].len; 379 hole_size = bgs[i].chunks[j].block - hole_start; 380 if (hole_size == len) { 381 // Perfect fit i.e. right between 2 chunks no need to keep searching 382 found_bg = i; 383 found_prev_chunk = j - 1; 384 found_block = hole_start; 385 found_allocate_len = hole_size; 386 goto done; 387 } else if (hole_size > len && (found_allocate_len == 0 || (found_allocate_len > hole_size))) { 388 found_bg = i; 389 found_prev_chunk = j - 1; 390 found_block = hole_start; 391 found_allocate_len = hole_size; 392 minimize = true; 393 } else if (!minimize) { 394 if (found_allocate_len < hole_size) { 395 found_bg = i; 396 found_prev_chunk = j - 1; 397 found_block = hole_start; 398 found_allocate_len = hole_size; 399 } 400 } 401 } 402 } 403 404 if (found_allocate_len == 0) { 405 error("failed to allocate %u blocks, out of space?", len); 406 return NULL; 407 } 408 if (found_allocate_len > len) found_allocate_len = len; 409 done: 410 // reclaim allocated space in chunk 411 bgs[found_bg].chunks[found_prev_chunk].len += found_allocate_len; 412 if (reserve_blocks(&bgs[found_bg], 413 found_bg, 414 found_block, 415 found_allocate_len) < 0) { 416 error("failed to reserve %u blocks in block group %u\n", found_allocate_len, found_bg); 417 return NULL; 418 } 419 bgs[found_bg].data_blocks_used += found_allocate_len; 420 reg = malloc(sizeof(struct region)); 421 reg->block = found_block + bgs[found_bg].first_block; 422 reg->len = found_allocate_len; 423 reg->next = NULL; 424 reg->prev = NULL; 425 reg->bg = found_bg; 426 return reg; 427 } 428 429 static struct region *ext4_allocate_best_fit(u32 len) 430 { 431 struct region *first_reg = NULL; 432 struct region *prev_reg = NULL; 433 struct region *reg; 434 435 while (len > 0) { 436 reg = ext4_allocate_best_fit_partial(len); 437 if (reg == NULL) 438 return NULL; 439 440 if (first_reg == NULL) 441 first_reg = reg; 442 443 if (prev_reg) { 444 prev_reg->next = reg; 445 reg->prev = prev_reg; 446 } 447 448 prev_reg = reg; 449 len -= reg->len; 450 } 451 452 return first_reg; 453 } 454 455 /* Allocate len blocks. The blocks may be spread across multiple block groups, 456 and are returned in a linked list of the blocks in each block group. The 457 allocation algorithm is: 458 1. If the remaining allocation is larger than any available contiguous region, 459 allocate the largest contiguous region and loop 460 2. Otherwise, allocate the smallest contiguous region that it fits in 461 */ 462 struct block_allocation *allocate_blocks(u32 len) 463 { 464 struct region *reg = ext4_allocate_best_fit(len); 465 466 if (reg == NULL) 467 return NULL; 468 469 struct block_allocation *alloc = create_allocation(); 470 alloc->list.first = reg; 471 while (reg->next != NULL) 472 reg = reg->next; 473 alloc->list.last = reg; 474 alloc->list.iter = alloc->list.first; 475 alloc->list.partial_iter = 0; 476 return alloc; 477 } 478 479 /* Returns the number of discontiguous regions used by an allocation */ 480 int block_allocation_num_regions(struct block_allocation *alloc) 481 { 482 unsigned int i; 483 struct region *reg = alloc->list.first; 484 485 for (i = 0; reg != NULL; reg = reg->next) 486 i++; 487 488 return i; 489 } 490 491 int block_allocation_len(struct block_allocation *alloc) 492 { 493 unsigned int i; 494 struct region *reg = alloc->list.first; 495 496 for (i = 0; reg != NULL; reg = reg->next) 497 i += reg->len; 498 499 return i; 500 } 501 502 /* Returns the block number of the block'th block in an allocation */ 503 u32 get_block(struct block_allocation *alloc, u32 block) 504 { 505 struct region *reg = alloc->list.iter; 506 block += alloc->list.partial_iter; 507 508 for (; reg; reg = reg->next) { 509 if (block < reg->len) 510 return reg->block + block; 511 block -= reg->len; 512 } 513 return EXT4_ALLOCATE_FAILED; 514 } 515 516 u32 get_oob_block(struct block_allocation *alloc, u32 block) 517 { 518 struct region *reg = alloc->oob_list.iter; 519 block += alloc->oob_list.partial_iter; 520 521 for (; reg; reg = reg->next) { 522 if (block < reg->len) 523 return reg->block + block; 524 block -= reg->len; 525 } 526 return EXT4_ALLOCATE_FAILED; 527 } 528 529 /* Gets the starting block and length in blocks of the first region 530 of an allocation */ 531 void get_region(struct block_allocation *alloc, u32 *block, u32 *len) 532 { 533 *block = alloc->list.iter->block; 534 *len = alloc->list.iter->len - alloc->list.partial_iter; 535 } 536 537 /* Move to the next region in an allocation */ 538 void get_next_region(struct block_allocation *alloc) 539 { 540 alloc->list.iter = alloc->list.iter->next; 541 alloc->list.partial_iter = 0; 542 } 543 544 /* Returns the number of free blocks in a block group */ 545 u32 get_free_blocks(u32 bg) 546 { 547 return aux_info.bgs[bg].free_blocks; 548 } 549 550 int last_region(struct block_allocation *alloc) 551 { 552 return (alloc->list.iter == NULL); 553 } 554 555 void rewind_alloc(struct block_allocation *alloc) 556 { 557 alloc->list.iter = alloc->list.first; 558 alloc->list.partial_iter = 0; 559 } 560 561 static struct region *do_split_allocation(struct block_allocation *alloc, u32 len) 562 { 563 struct region *reg = alloc->list.iter; 564 struct region *new; 565 struct region *tmp; 566 567 while (reg && len >= reg->len) { 568 len -= reg->len; 569 reg = reg->next; 570 } 571 572 if (reg == NULL && len > 0) 573 return NULL; 574 575 if (len > 0) { 576 new = malloc(sizeof(struct region)); 577 578 new->bg = reg->bg; 579 new->block = reg->block + len; 580 new->len = reg->len - len; 581 new->next = reg->next; 582 new->prev = reg; 583 584 reg->next = new; 585 reg->len = len; 586 587 tmp = alloc->list.iter; 588 alloc->list.iter = new; 589 return tmp; 590 } else { 591 return reg; 592 } 593 } 594 595 /* Splits an allocation into two allocations. The returned allocation will 596 point to the first half, and the original allocation ptr will point to the 597 second half. */ 598 static struct region *split_allocation(struct block_allocation *alloc, u32 len) 599 { 600 /* First make sure there is a split at the current ptr */ 601 do_split_allocation(alloc, alloc->list.partial_iter); 602 603 /* Then split off len blocks */ 604 struct region *middle = do_split_allocation(alloc, len); 605 alloc->list.partial_iter = 0; 606 return middle; 607 } 608 609 /* Reserve the next blocks for oob data (indirect or extent blocks) */ 610 int reserve_oob_blocks(struct block_allocation *alloc, int blocks) 611 { 612 struct region *oob = split_allocation(alloc, blocks); 613 struct region *next; 614 615 if (oob == NULL) 616 return -1; 617 618 while (oob && oob != alloc->list.iter) { 619 next = oob->next; 620 region_list_remove(&alloc->list, oob); 621 region_list_append(&alloc->oob_list, oob); 622 oob = next; 623 } 624 625 return 0; 626 } 627 628 static int advance_list_ptr(struct region_list *list, int blocks) 629 { 630 struct region *reg = list->iter; 631 632 while (reg != NULL && blocks > 0) { 633 if (reg->len > list->partial_iter + blocks) { 634 list->partial_iter += blocks; 635 return 0; 636 } 637 638 blocks -= (reg->len - list->partial_iter); 639 list->partial_iter = 0; 640 reg = reg->next; 641 } 642 643 if (blocks > 0) 644 return -1; 645 646 return 0; 647 } 648 649 /* Move the allocation pointer forward */ 650 int advance_blocks(struct block_allocation *alloc, int blocks) 651 { 652 return advance_list_ptr(&alloc->list, blocks); 653 } 654 655 int advance_oob_blocks(struct block_allocation *alloc, int blocks) 656 { 657 return advance_list_ptr(&alloc->oob_list, blocks); 658 } 659 660 int append_oob_allocation(struct block_allocation *alloc, u32 len) 661 { 662 struct region *reg = ext4_allocate_best_fit(len); 663 664 if (reg == NULL) { 665 error("failed to allocate %d blocks", len); 666 return -1; 667 } 668 669 for (; reg; reg = reg->next) 670 region_list_append(&alloc->oob_list, reg); 671 672 return 0; 673 } 674 675 /* Returns an ext4_inode structure for an inode number */ 676 struct ext4_inode *get_inode(u32 inode) 677 { 678 inode -= 1; 679 int bg = inode / info.inodes_per_group; 680 inode %= info.inodes_per_group; 681 682 allocate_bg_inode_table(&aux_info.bgs[bg]); 683 return (struct ext4_inode *)(aux_info.bgs[bg].inode_table + inode * 684 info.inode_size); 685 } 686 687 struct ext4_xattr_header *get_xattr_block_for_inode(struct ext4_inode *inode) 688 { 689 struct ext4_xattr_header *block = xattr_list_find(inode); 690 if (block != NULL) 691 return block; 692 693 u32 block_num = allocate_block(); 694 block = calloc(info.block_size, 1); 695 if (block == NULL) { 696 error("get_xattr: failed to allocate %d", info.block_size); 697 return NULL; 698 } 699 700 block->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC); 701 block->h_refcount = cpu_to_le32(1); 702 block->h_blocks = cpu_to_le32(1); 703 inode->i_blocks_lo = cpu_to_le32(le32_to_cpu(inode->i_blocks_lo) + (info.block_size / 512)); 704 inode->i_file_acl_lo = cpu_to_le32(block_num); 705 706 int result = sparse_file_add_data(ext4_sparse_file, block, info.block_size, block_num); 707 if (result != 0) { 708 error("get_xattr: sparse_file_add_data failure %d", result); 709 free(block); 710 return NULL; 711 } 712 xattr_list_insert(inode, block); 713 return block; 714 } 715 716 /* Mark the first len inodes in a block group as used */ 717 u32 reserve_inodes(int bg, u32 num) 718 { 719 unsigned int i; 720 u32 inode; 721 722 if (get_free_inodes(bg) < num) 723 return EXT4_ALLOCATE_FAILED; 724 725 for (i = 0; i < num; i++) { 726 inode = aux_info.bgs[bg].first_free_inode + i - 1; 727 aux_info.bgs[bg].inode_bitmap[inode / 8] |= 1 << (inode % 8); 728 } 729 730 inode = aux_info.bgs[bg].first_free_inode; 731 732 aux_info.bgs[bg].first_free_inode += num; 733 aux_info.bgs[bg].free_inodes -= num; 734 735 return inode; 736 } 737 738 /* Returns the first free inode number 739 TODO: Inodes should be allocated in the block group of the data? */ 740 u32 allocate_inode() 741 { 742 unsigned int bg; 743 u32 inode; 744 745 for (bg = 0; bg < aux_info.groups; bg++) { 746 inode = reserve_inodes(bg, 1); 747 if (inode != EXT4_ALLOCATE_FAILED) 748 return bg * info.inodes_per_group + inode; 749 } 750 751 return EXT4_ALLOCATE_FAILED; 752 } 753 754 /* Returns the number of free inodes in a block group */ 755 u32 get_free_inodes(u32 bg) 756 { 757 return aux_info.bgs[bg].free_inodes; 758 } 759 760 /* Increments the directory count of the block group that contains inode */ 761 void add_directory(u32 inode) 762 { 763 int bg = (inode - 1) / info.inodes_per_group; 764 aux_info.bgs[bg].used_dirs += 1; 765 } 766 767 /* Returns the number of inodes in a block group that are directories */ 768 u16 get_directories(int bg) 769 { 770 return aux_info.bgs[bg].used_dirs; 771 } 772 773 /* Returns the flags for a block group */ 774 u16 get_bg_flags(int bg) 775 { 776 return aux_info.bgs[bg].flags; 777 } 778 779 /* Frees the memory used by a linked list of allocation regions */ 780 void free_alloc(struct block_allocation *alloc) 781 { 782 struct region *reg; 783 784 reg = alloc->list.first; 785 while (reg) { 786 struct region *next = reg->next; 787 free(reg); 788 reg = next; 789 } 790 791 reg = alloc->oob_list.first; 792 while (reg) { 793 struct region *next = reg->next; 794 free(reg); 795 reg = next; 796 } 797 798 free(alloc); 799 } 800 801 void reserve_bg_chunk(int bg, u32 start_block, u32 size) { 802 struct block_group_info *bgs = aux_info.bgs; 803 int chunk_count; 804 if (bgs[bg].chunk_count == bgs[bg].max_chunk_count) { 805 bgs[bg].max_chunk_count *= 2; 806 bgs[bg].chunks = realloc(bgs[bg].chunks, bgs[bg].max_chunk_count * sizeof(struct region)); 807 if (!bgs[bg].chunks) 808 critical_error("realloc failed"); 809 } 810 chunk_count = bgs[bg].chunk_count; 811 bgs[bg].chunks[chunk_count].block = start_block; 812 bgs[bg].chunks[chunk_count].len = size; 813 bgs[bg].chunks[chunk_count].bg = bg; 814 bgs[bg].chunk_count++; 815 } 816 817 int reserve_blocks_for_allocation(struct block_allocation *alloc) { 818 struct region *reg; 819 struct block_group_info *bgs = aux_info.bgs; 820 821 if (!alloc) return 0; 822 reg = alloc->list.first; 823 while (reg != NULL) { 824 if (reserve_blocks(&bgs[reg->bg], reg->bg, reg->block - bgs[reg->bg].first_block, reg->len) < 0) { 825 return -1; 826 } 827 reg = reg->next; 828 } 829 return 0; 830 } 831 832