Changes in uspace/lib/ext4/libext4_balloc.c [24df0de6:38542dc] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/ext4/libext4_balloc.c
r24df0de6 r38542dc 39 39 #include "libext4.h" 40 40 41 /** Compute number of block group from block address. 42 * 43 * @param sb Superblock pointer. 44 * @param block_addr Absolute address of block. 45 * 46 * @return Block group index 47 * 48 */ 49 static uint32_t ext4_balloc_get_bgid_of_block(ext4_superblock_t *sb, 50 uint32_t block_addr) 51 { 52 uint32_t blocks_per_group = 53 ext4_superblock_get_blocks_per_group(sb); 54 uint32_t first_block = 55 ext4_superblock_get_first_data_block(sb); 56 57 /* First block == 0 or 1 */ 58 if (first_block == 0) 59 return block_addr / blocks_per_group; 60 else 61 return (block_addr - 1) / blocks_per_group; 62 } 63 41 64 /** Free block. 42 65 * … … 53 76 54 77 /* Compute indexes */ 55 uint32_t block_group = ext4_ filesystem_blockaddr2group(sb, block_addr);78 uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, block_addr); 56 79 uint32_t index_in_group = 57 80 ext4_filesystem_blockaddr2_index_in_group(sb, block_addr); … … 68 91 block_t *bitmap_block; 69 92 rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, 0); 70 if (rc != EOK) { 71 ext4_filesystem_put_block_group_ref(bg_ref); 72 return rc; 73 } 93 if (rc != EOK) 94 return rc; 74 95 75 96 /* Modify bitmap */ … … 109 130 110 131 /* Release block group reference */ 111 return ext4_filesystem_put_block_group_ref(bg_ref); 132 rc = ext4_filesystem_put_block_group_ref(bg_ref); 133 if (rc != EOK) 134 return rc; 135 136 return EOK; 112 137 } 113 138 114 static int ext4_balloc_free_blocks_internal(ext4_inode_ref_t *inode_ref, 139 /** Free continuous set of blocks. 140 * 141 * @param inode_ref Inode, where the blocks are allocated 142 * @param first First block to release 143 * @param count Number of blocks to release 144 * 145 */ 146 int ext4_balloc_free_blocks(ext4_inode_ref_t *inode_ref, 115 147 uint32_t first, uint32_t count) 116 148 { 117 149 ext4_filesystem_t *fs = inode_ref->fs; 118 150 ext4_superblock_t *sb = fs->superblock; 119 151 120 152 /* Compute indexes */ 121 uint32_t block_group_first = ext4_filesystem_blockaddr2group(sb,122 first);123 uint32_t block_group_last = ext4_filesystem_blockaddr2group(sb,124 first + count - 1);125 153 uint32_t block_group_first = 154 ext4_balloc_get_bgid_of_block(sb, first); 155 uint32_t block_group_last = 156 ext4_balloc_get_bgid_of_block(sb, first + count - 1); 157 126 158 assert(block_group_first == block_group_last); 127 159 128 160 /* Load block group reference */ 129 161 ext4_block_group_ref_t *bg_ref; … … 131 163 if (rc != EOK) 132 164 return rc; 133 165 134 166 uint32_t index_in_group_first = 135 167 ext4_filesystem_blockaddr2_index_in_group(sb, first); 136 168 137 169 /* Load block with bitmap */ 138 170 uint32_t bitmap_block_addr = 139 171 ext4_block_group_get_block_bitmap(bg_ref->block_group, sb); 140 172 141 173 block_t *bitmap_block; 142 174 rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, 0); 143 if (rc != EOK) { 144 ext4_filesystem_put_block_group_ref(bg_ref); 145 return rc; 146 } 147 175 if (rc != EOK) 176 return rc; 177 148 178 /* Modify bitmap */ 149 179 ext4_bitmap_free_bits(bitmap_block->data, index_in_group_first, count); 150 180 bitmap_block->dirty = true; 151 181 152 182 /* Release block with bitmap */ 153 183 rc = block_put(bitmap_block); … … 157 187 return rc; 158 188 } 159 189 160 190 uint32_t block_size = ext4_superblock_get_block_size(sb); 161 191 162 192 /* Update superblock free blocks count */ 163 193 uint32_t sb_free_blocks = … … 165 195 sb_free_blocks += count; 166 196 ext4_superblock_set_free_blocks_count(sb, sb_free_blocks); 167 197 168 198 /* Update inode blocks count */ 169 199 uint64_t ino_blocks = … … 172 202 ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks); 173 203 inode_ref->dirty = true; 174 204 175 205 /* Update block group free blocks count */ 176 206 uint32_t free_blocks = … … 180 210 sb, free_blocks); 181 211 bg_ref->dirty = true; 182 212 183 213 /* Release block group reference */ 184 return ext4_filesystem_put_block_group_ref(bg_ref); 185 } 186 187 /** Free continuous set of blocks. 188 * 189 * @param inode_ref Inode, where the blocks are allocated 190 * @param first First block to release 191 * @param count Number of blocks to release 192 * 193 */ 194 int ext4_balloc_free_blocks(ext4_inode_ref_t *inode_ref, 195 uint32_t first, uint32_t count) 196 { 197 int r; 198 uint32_t gid; 199 uint64_t limit; 200 ext4_filesystem_t *fs = inode_ref->fs; 201 ext4_superblock_t *sb = fs->superblock; 202 203 while (count) { 204 gid = ext4_filesystem_blockaddr2group(sb, first); 205 limit = ext4_filesystem_index_in_group2blockaddr(sb, 0, 206 gid + 1); 207 208 if ((first + count) >= limit) { 209 /* This extent spans over 2 or more block groups, 210 * we'll break it into smaller parts. 211 */ 212 uint32_t s = limit - first; 213 214 r = ext4_balloc_free_blocks_internal(inode_ref, 215 first, s); 216 if (r != EOK) 217 return r; 218 219 first = limit; 220 count -= s; 221 } else { 222 return ext4_balloc_free_blocks_internal(inode_ref, 223 first, count); 224 } 225 } 226 214 rc = ext4_filesystem_put_block_group_ref(bg_ref); 215 if (rc != EOK) 216 return rc; 217 227 218 return EOK; 228 219 } … … 240 231 ext4_block_group_ref_t *bg_ref) 241 232 { 242 uint32_t r; 243 uint64_t itable = ext4_block_group_get_inode_table_first_block( 244 bg_ref->block_group, sb); 245 uint32_t itable_sz = ext4_filesystem_bg_get_itable_size(sb, bg_ref); 246 247 if (!ext4_superblock_has_feature_incompatible(sb, 248 EXT4_FEATURE_INCOMPAT_FLEX_BG)) { 249 /* If we are not using FLEX_BG, the first data block 250 * is always after the inode table. 251 */ 252 r = itable + itable_sz; 253 return ext4_filesystem_blockaddr2_index_in_group(sb, r); 254 } 255 256 uint64_t bbmap = ext4_block_group_get_block_bitmap(bg_ref->block_group, 257 sb); 258 uint64_t ibmap = ext4_block_group_get_inode_bitmap(bg_ref->block_group, 259 sb); 260 261 r = ext4_filesystem_index_in_group2blockaddr(sb, 0, bg_ref->index); 262 r += ext4_filesystem_bg_get_backup_blocks(bg_ref); 263 264 if (ext4_filesystem_blockaddr2group(sb, bbmap) != bg_ref->index) 265 bbmap = -1; /* Invalid */ 266 267 if (ext4_filesystem_blockaddr2group(sb, ibmap) != bg_ref->index) 268 ibmap = -1; 269 270 while (1) { 271 if (r == bbmap || r == ibmap) 272 r++; 273 else if (r >= itable && r < (itable + itable_sz)) 274 r = itable + itable_sz; 275 else 276 break; 277 } 278 279 return r; 233 uint32_t block_group_count = ext4_superblock_get_block_group_count(sb); 234 uint32_t inode_table_first_block = 235 ext4_block_group_get_inode_table_first_block(bg_ref->block_group, sb); 236 uint16_t inode_table_item_size = ext4_superblock_get_inode_size(sb); 237 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb); 238 uint32_t block_size = ext4_superblock_get_block_size(sb); 239 uint32_t inode_table_bytes; 240 241 if (bg_ref->index < block_group_count - 1) { 242 inode_table_bytes = inodes_per_group * inode_table_item_size; 243 } else { 244 /* Last block group could be smaller */ 245 uint32_t inodes_count_total = ext4_superblock_get_inodes_count(sb); 246 inode_table_bytes = 247 (inodes_count_total - ((block_group_count - 1) * inodes_per_group)) * 248 inode_table_item_size; 249 } 250 251 uint32_t inode_table_blocks = inode_table_bytes / block_size; 252 253 if (inode_table_bytes % block_size) 254 inode_table_blocks++; 255 256 return inode_table_first_block + inode_table_blocks; 280 257 } 281 258 … … 287 264 * 288 265 */ 289 static int ext4_balloc_find_goal(ext4_inode_ref_t *inode_ref, uint32_t *goal)266 static uint32_t ext4_balloc_find_goal(ext4_inode_ref_t *inode_ref) 290 267 { 291 *goal = 0; 268 uint32_t goal = 0; 269 292 270 ext4_superblock_t *sb = inode_ref->fs->superblock; 293 271 294 272 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode); 295 273 uint32_t block_size = ext4_superblock_get_block_size(sb); 296 274 uint32_t inode_block_count = inode_size / block_size; 297 275 298 276 if (inode_size % block_size != 0) 299 277 inode_block_count++; 300 278 301 279 /* If inode has some blocks, get last block address + 1 */ 302 280 if (inode_block_count > 0) { 303 281 int rc = ext4_filesystem_get_inode_data_block_index(inode_ref, 304 inode_block_count - 1, goal);282 inode_block_count - 1, &goal); 305 283 if (rc != EOK) 306 return rc;307 284 return 0; 285 308 286 if (goal != 0) { 309 (*goal)++;310 return EOK;287 goal++; 288 return goal; 311 289 } 290 312 291 /* If goal == 0, sparse file -> continue */ 313 292 } 314 293 315 294 /* Identify block group of inode */ 316 295 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb); 317 296 uint32_t block_group = (inode_ref->index - 1) / inodes_per_group; 318 297 block_size = ext4_superblock_get_block_size(sb); 298 319 299 /* Load block group reference */ 320 300 ext4_block_group_ref_t *bg_ref; … … 322 302 block_group, &bg_ref); 323 303 if (rc != EOK) 324 return rc; 325 326 *goal = ext4_balloc_get_first_data_block_in_group(sb, bg_ref); 327 328 return ext4_filesystem_put_block_group_ref(bg_ref); 304 return 0; 305 306 /* Compute indexes */ 307 uint32_t block_group_count = ext4_superblock_get_block_group_count(sb); 308 uint32_t inode_table_first_block = 309 ext4_block_group_get_inode_table_first_block(bg_ref->block_group, sb); 310 uint16_t inode_table_item_size = ext4_superblock_get_inode_size(sb); 311 uint32_t inode_table_bytes; 312 313 /* Check for last block group */ 314 if (block_group < block_group_count - 1) { 315 inode_table_bytes = inodes_per_group * inode_table_item_size; 316 } else { 317 /* Last block group could be smaller */ 318 uint32_t inodes_count_total = ext4_superblock_get_inodes_count(sb); 319 inode_table_bytes = 320 (inodes_count_total - ((block_group_count - 1) * inodes_per_group)) * 321 inode_table_item_size; 322 } 323 324 uint32_t inode_table_blocks = inode_table_bytes / block_size; 325 326 if (inode_table_bytes % block_size) 327 inode_table_blocks++; 328 329 goal = inode_table_first_block + inode_table_blocks; 330 331 ext4_filesystem_put_block_group_ref(bg_ref); 332 333 return goal; 329 334 } 330 335 … … 344 349 block_t *bitmap_block; 345 350 uint32_t rel_block_idx = 0; 346 uint32_t free_blocks;347 uint32_t goal;348 351 349 352 /* Find GOAL */ 350 int rc = ext4_balloc_find_goal(inode_ref, &goal); 351 if (rc != EOK) 352 return rc; 353 353 uint32_t goal = ext4_balloc_find_goal(inode_ref); 354 if (goal == 0) { 355 /* no goal found => partition is full */ 356 return ENOSPC; 357 } 358 354 359 ext4_superblock_t *sb = inode_ref->fs->superblock; 355 360 356 361 /* Load block group number for goal and relative index */ 357 uint32_t block_group = ext4_ filesystem_blockaddr2group(sb, goal);362 uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, goal); 358 363 uint32_t index_in_group = 359 364 ext4_filesystem_blockaddr2_index_in_group(sb, goal); … … 361 366 /* Load block group reference */ 362 367 ext4_block_group_ref_t *bg_ref; 363 rc = ext4_filesystem_get_block_group_ref(inode_ref->fs,368 int rc = ext4_filesystem_get_block_group_ref(inode_ref->fs, 364 369 block_group, &bg_ref); 365 370 if (rc != EOK) 366 371 return rc; 367 368 free_blocks =369 ext4_block_group_get_free_blocks_count(bg_ref->block_group, sb);370 if (free_blocks == 0) {371 /* This group has no free blocks */372 goto goal_failed;373 }374 372 375 373 /* Compute indexes */ … … 469 467 470 468 /* No free block found yet */ 471 rc = block_put(bitmap_block); 472 if (rc != EOK) { 473 ext4_filesystem_put_block_group_ref(bg_ref); 474 return rc; 475 } 476 477 goal_failed: 478 479 rc = ext4_filesystem_put_block_group_ref(bg_ref); 480 if (rc != EOK) 481 return rc; 469 block_put(bitmap_block); 470 ext4_filesystem_put_block_group_ref(bg_ref); 482 471 483 472 /* Try other block groups */ … … 492 481 if (rc != EOK) 493 482 return rc; 494 495 free_blocks = 496 ext4_block_group_get_free_blocks_count(bg_ref->block_group, sb); 497 if (free_blocks == 0) { 498 /* This group has no free blocks */ 499 goto next_group; 500 } 501 483 502 484 /* Load block with bitmap */ 503 485 bitmap_block_addr = … … 530 512 bitmap_block->dirty = true; 531 513 rc = block_put(bitmap_block); 532 if (rc != EOK) { 533 ext4_filesystem_put_block_group_ref(bg_ref); 514 if (rc != EOK) 534 515 return rc; 535 }536 516 537 517 allocated_block = … … 548 528 bitmap_block->dirty = true; 549 529 rc = block_put(bitmap_block); 550 if (rc != EOK) { 551 ext4_filesystem_put_block_group_ref(bg_ref); 530 if (rc != EOK) 552 531 return rc; 553 }554 532 555 533 allocated_block = … … 560 538 } 561 539 562 rc = block_put(bitmap_block); 563 if (rc != EOK) { 564 ext4_filesystem_put_block_group_ref(bg_ref); 565 return rc; 566 } 567 568 next_group: 569 rc = ext4_filesystem_put_block_group_ref(bg_ref); 570 if (rc != EOK) 571 return rc; 540 block_put(bitmap_block); 541 ext4_filesystem_put_block_group_ref(bg_ref); 572 542 573 543 /* Goto next group */ … … 604 574 bg_ref->dirty = true; 605 575 606 rc =ext4_filesystem_put_block_group_ref(bg_ref);576 ext4_filesystem_put_block_group_ref(bg_ref); 607 577 608 578 *fblock = allocated_block; 609 return rc;579 return EOK; 610 580 } 611 581 … … 622 592 bool *free) 623 593 { 624 int rc ;594 int rc = EOK; 625 595 626 596 ext4_filesystem_t *fs = inode_ref->fs; … … 628 598 629 599 /* Compute indexes */ 630 uint32_t block_group = ext4_ filesystem_blockaddr2group(sb, fblock);600 uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, fblock); 631 601 uint32_t index_in_group = 632 602 ext4_filesystem_blockaddr2_index_in_group(sb, fblock); … … 643 613 block_t *bitmap_block; 644 614 rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, 0); 645 if (rc != EOK) { 646 ext4_filesystem_put_block_group_ref(bg_ref); 647 return rc; 648 } 615 if (rc != EOK) 616 return rc; 649 617 650 618 /* Check if block is free */
Note:
See TracChangeset
for help on using the changeset viewer.