Changeset 38542dc in mainline for uspace/lib/ext4/libext4_filesystem.c
- Timestamp:
- 2012-08-12T18:36:10Z (12 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 49505fe
- Parents:
- b08e7970
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/ext4/libext4_filesystem.c
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 32 31 */ 33 32 /** 34 * @file 35 * @brief 33 * @file libext4_filesystem.c 34 * @brief More complex filesystem operations. 36 35 */ 37 36 … … 43 42 /** Initialize filesystem and read all needed data. 44 43 * 45 * @param fs filesystem instance to be initialized 46 * @param service_id identifier if device with the filesystem 47 * @return error code 44 * @param fs Filesystem instance to be initialized 45 * @param service_id Identifier if device with the filesystem 46 * 47 * @return Error code 48 * 48 49 */ 49 50 int ext4_filesystem_init(ext4_filesystem_t *fs, service_id_t service_id, 50 enum cache_mode cmode) 51 { 52 int rc; 53 51 enum cache_mode cmode) 52 { 54 53 fs->device = service_id; 55 54 56 55 /* Initialize block library (4096 is size of communication channel) */ 57 rc = block_init(EXCHANGE_SERIALIZE, fs->device, 4096);58 if (rc != EOK) {56 int rc = block_init(EXCHANGE_SERIALIZE, fs->device, 4096); 57 if (rc != EOK) 59 58 return rc; 60 } 61 59 62 60 /* Read superblock from device to memory */ 63 61 ext4_superblock_t *temp_superblock; … … 67 65 return rc; 68 66 } 69 67 70 68 /* Read block size from superblock and check */ 71 69 uint32_t block_size = ext4_superblock_get_block_size(temp_superblock); … … 74 72 return ENOTSUP; 75 73 } 76 74 77 75 /* Initialize block caching by libblock */ 78 76 rc = block_cache_init(service_id, block_size, 0, cmode); … … 81 79 return rc; 82 80 } 83 81 84 82 /* Compute limits for indirect block levels */ 85 83 uint32_t block_ids_per_block = block_size / sizeof(uint32_t); 86 84 fs->inode_block_limits[0] = EXT4_INODE_DIRECT_BLOCK_COUNT; 87 85 fs->inode_blocks_per_level[0] = 1; 88 for ( int i = 1; i < 4; i++) {89 fs->inode_blocks_per_level[i] = fs->inode_blocks_per_level[i -1] *86 for (unsigned int i = 1; i < 4; i++) { 87 fs->inode_blocks_per_level[i] = fs->inode_blocks_per_level[i - 1] * 90 88 block_ids_per_block; 91 fs->inode_block_limits[i] = fs->inode_block_limits[i -1] +92 93 } 94 89 fs->inode_block_limits[i] = fs->inode_block_limits[i - 1] + 90 fs->inode_blocks_per_level[i]; 91 } 92 95 93 /* Return loaded superblock */ 96 94 fs->superblock = temp_superblock; 97 95 98 96 uint16_t state = ext4_superblock_get_state(fs->superblock); 99 97 100 98 if (state != EXT4_SUPERBLOCK_STATE_VALID_FS) { 101 99 block_cache_fini(fs->device); … … 103 101 return ENOTSUP; 104 102 } 105 103 106 104 /* Mark system as mounted */ 107 105 ext4_superblock_set_state(fs->superblock, EXT4_SUPERBLOCK_STATE_ERROR_FS); … … 112 110 return rc; 113 111 } 114 112 115 113 uint16_t mnt_count = ext4_superblock_get_mount_count(fs->superblock); 116 114 ext4_superblock_set_mount_count(fs->superblock, mnt_count + 1); 117 115 118 116 return EOK; 119 117 } … … 121 119 /** Destroy filesystem instance (used by unmount operation). 122 120 * 123 * @param fs filesystem to be destroyed 124 * @param write_sb flag if superblock should be written to device 125 * @return error code 121 * @param fs Filesystem to be destroyed 122 * 123 * @return Error code 124 * 126 125 */ 127 126 int ext4_filesystem_fini(ext4_filesystem_t *fs) 128 127 { 129 int rc = EOK;130 131 128 /* Write the superblock to the device */ 132 129 ext4_superblock_set_state(fs->superblock, EXT4_SUPERBLOCK_STATE_VALID_FS); 133 rc = ext4_superblock_write_direct(fs->device, fs->superblock);134 130 int rc = ext4_superblock_write_direct(fs->device, fs->superblock); 131 135 132 /* Release memory space for superblock */ 136 133 free(fs->superblock); 137 134 138 135 /* Finish work with block library */ 139 136 block_cache_fini(fs->device); 140 137 block_fini(fs->device); 141 138 142 139 return rc; 143 140 } … … 147 144 * Main is the check of the superblock structure. 148 145 * 149 * @param fs filesystem to be checked 150 * @return error code 146 * @param fs Filesystem to be checked 147 * 148 * @return Error code 149 * 151 150 */ 152 151 int ext4_filesystem_check_sanity(ext4_filesystem_t *fs) 153 152 { 154 int rc;155 156 153 /* Check superblock */ 157 rc = ext4_superblock_check_sanity(fs->superblock); 158 if (rc != EOK) { 159 return rc; 160 } 161 162 return EOK; 154 return ext4_superblock_check_sanity(fs->superblock); 163 155 } 164 156 … … 169 161 * during some write operations. 170 162 * 171 * @param fs filesystem to be checked 172 * @param read_only flag if filesystem should be mounted only for reading 173 * @return error code 163 * @param fs Filesystem to be checked 164 * @param read_only Flag if filesystem should be mounted only for reading 165 * 166 * @return Error code 167 * 174 168 */ 175 169 int ext4_filesystem_check_features(ext4_filesystem_t *fs, bool *read_only) … … 180 174 return EOK; 181 175 } 182 183 /* Check incompatible features - if filesystem has some, 176 177 /* 178 * Check incompatible features - if filesystem has some, 184 179 * volume can't be mounted 185 180 */ 186 181 uint32_t incompatible_features; 187 incompatible_features = ext4_superblock_get_features_incompatible(fs->superblock); 182 incompatible_features = 183 ext4_superblock_get_features_incompatible(fs->superblock); 188 184 incompatible_features &= ~EXT4_FEATURE_INCOMPAT_SUPP; 189 if (incompatible_features > 0) {185 if (incompatible_features > 0) 190 186 return ENOTSUP; 191 }192 193 /* Check read-only features, if filesystem has some,187 188 /* 189 * Check read-only features, if filesystem has some, 194 190 * volume can be mount only in read-only mode 195 191 */ 196 192 uint32_t compatible_read_only; 197 compatible_read_only = ext4_superblock_get_features_read_only(fs->superblock); 193 compatible_read_only = 194 ext4_superblock_get_features_read_only(fs->superblock); 198 195 compatible_read_only &= ~EXT4_FEATURE_RO_COMPAT_SUPP; 199 196 if (compatible_read_only > 0) { … … 201 198 return EOK; 202 199 } 203 200 204 201 return EOK; 205 202 } … … 208 205 /** Convert block address to relative index in block group. 209 206 * 210 * @param sb superblock pointer 211 * @param block_addr block number to convert 212 * @return relative number of block 207 * @param sb Superblock pointer 208 * @param block_addr Block number to convert 209 * 210 * @return Relative number of block 211 * 213 212 */ 214 213 uint32_t ext4_filesystem_blockaddr2_index_in_group(ext4_superblock_t *sb, 215 214 uint32_t block_addr) 216 215 { 217 216 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb); 218 217 uint32_t first_block = ext4_superblock_get_first_data_block(sb); 219 218 220 219 /* First block == 0 or 1 */ 221 if (first_block == 0) {220 if (first_block == 0) 222 221 return block_addr % blocks_per_group; 223 } else {222 else 224 223 return (block_addr - 1) % blocks_per_group; 225 }226 224 } 227 225 … … 229 227 /** Convert relative block address in group to absolute address. 230 228 * 231 * @param sb superblock pointer 232 * @param block_addr block number to convert 233 * @return absolute block address 229 * @param sb Superblock pointer 230 * 231 * @return Absolute block address 232 * 234 233 */ 235 234 uint32_t ext4_filesystem_index_in_group2blockaddr(ext4_superblock_t *sb, 236 235 uint32_t index, uint32_t bgid) 237 236 { 238 237 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb); 239 240 if (ext4_superblock_get_first_data_block(sb) == 0) {238 239 if (ext4_superblock_get_first_data_block(sb) == 0) 241 240 return bgid * blocks_per_group + index; 242 } else {241 else 243 242 return bgid * blocks_per_group + index + 1; 244 }245 246 243 } 247 244 248 245 /** Initialize block bitmap in block group. 249 * 250 * @param bg_ref reference to block group 251 * @return error code 246 * 247 * @param bg_ref Reference to block group 248 * 249 * @return Error code 250 * 252 251 */ 253 252 static int ext4_filesystem_init_block_bitmap(ext4_block_group_ref_t *bg_ref) 254 253 { 255 int rc;256 257 254 /* Load bitmap */ 258 255 uint32_t bitmap_block_addr = ext4_block_group_get_block_bitmap( 259 bg_ref->block_group, bg_ref->fs->superblock); 256 bg_ref->block_group, bg_ref->fs->superblock); 257 260 258 block_t *bitmap_block; 261 262 rc = block_get(&bitmap_block, bg_ref->fs->device, 263 bitmap_block_addr, BLOCK_FLAGS_NOREAD); 264 if (rc != EOK) { 259 int rc = block_get(&bitmap_block, bg_ref->fs->device, 260 bitmap_block_addr, BLOCK_FLAGS_NOREAD); 261 if (rc != EOK) 265 262 return rc; 266 } 267 263 268 264 uint8_t *bitmap = bitmap_block->data; 269 265 270 266 /* Initialize all bitmap bits to zero */ 271 267 uint32_t block_size = ext4_superblock_get_block_size(bg_ref->fs->superblock); 272 268 memset(bitmap, 0, block_size); 273 269 274 270 /* Determine first block and first data block in group */ 275 271 uint32_t first_idx = 0; 276 272 277 273 uint32_t first_data = ext4_balloc_get_first_data_block_in_group( 278 274 bg_ref->fs->superblock, bg_ref); 279 275 uint32_t first_data_idx = ext4_filesystem_blockaddr2_index_in_group( 280 281 276 bg_ref->fs->superblock, first_data); 277 282 278 /* Set bits from to first block to first data block - 1 to one (allocated) */ 283 for (uint32_t block = first_idx; block < first_data_idx; ++block) {279 for (uint32_t block = first_idx; block < first_data_idx; ++block) 284 280 ext4_bitmap_set_bit(bitmap, block); 285 } 286 281 287 282 bitmap_block->dirty = true; 288 283 289 284 /* Save bitmap */ 290 rc = block_put(bitmap_block); 291 if (rc != EOK) { 292 return rc; 293 } 294 295 return EOK; 285 return block_put(bitmap_block); 296 286 } 297 287 298 288 /** Initialize i-node bitmap in block group. 299 * 300 * @param bg_ref reference to block group 301 * @return error code 289 * 290 * @param bg_ref Reference to block group 291 * 292 * @return Error code 293 * 302 294 */ 303 295 static int ext4_filesystem_init_inode_bitmap(ext4_block_group_ref_t *bg_ref) 304 296 { 305 int rc;306 307 297 /* Load bitmap */ 308 298 uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap( 309 299 bg_ref->block_group, bg_ref->fs->superblock); 310 300 block_t *bitmap_block; 311 312 rc = block_get(&bitmap_block, bg_ref->fs->device,313 314 if (rc != EOK) {301 302 int rc = block_get(&bitmap_block, bg_ref->fs->device, 303 bitmap_block_addr, BLOCK_FLAGS_NOREAD); 304 if (rc != EOK) 315 305 return rc; 316 } 317 306 318 307 uint8_t *bitmap = bitmap_block->data; 319 308 320 309 /* Initialize all bitmap bits to zero */ 321 310 uint32_t block_size = ext4_superblock_get_block_size(bg_ref->fs->superblock); 322 311 uint32_t inodes_per_group = 323 312 ext4_superblock_get_inodes_per_group(bg_ref->fs->superblock); 324 313 memset(bitmap, 0, (inodes_per_group + 7) / 8); 325 314 326 315 uint32_t start_bit = inodes_per_group; 327 316 uint32_t end_bit = block_size * 8; 328 317 329 318 uint32_t i; 330 for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) {319 for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) 331 320 ext4_bitmap_set_bit(bitmap, i); 332 } 333 334 if (i < end_bit) { 321 322 if (i < end_bit) 335 323 memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); 336 } 337 324 338 325 bitmap_block->dirty = true; 339 326 340 327 /* Save bitmap */ 341 rc = block_put(bitmap_block); 342 if (rc != EOK) { 343 return rc; 344 } 345 346 return EOK; 328 return block_put(bitmap_block); 347 329 } 348 330 349 331 /** Initialize i-node table in block group. 350 * 351 * @param bg_ref reference to block group 352 * @return error code 332 * 333 * @param bg_ref Reference to block group 334 * 335 * @return Error code 336 * 353 337 */ 354 338 static int ext4_filesystem_init_inode_table(ext4_block_group_ref_t *bg_ref) 355 339 { 356 int rc;357 358 340 ext4_superblock_t *sb = bg_ref->fs->superblock; 359 341 360 342 uint32_t inode_size = ext4_superblock_get_inode_size(sb); 361 343 uint32_t block_size = ext4_superblock_get_block_size(sb); 362 344 uint32_t inodes_per_block = block_size / inode_size; 363 345 364 346 uint32_t inodes_in_group = 365 366 347 ext4_superblock_get_inodes_in_group(sb, bg_ref->index); 348 367 349 uint32_t table_blocks = inodes_in_group / inodes_per_block; 368 369 if (inodes_in_group % inodes_per_block) {350 351 if (inodes_in_group % inodes_per_block) 370 352 table_blocks++; 371 } 372 353 373 354 /* Compute initialization bounds */ 374 355 uint32_t first_block = ext4_block_group_get_inode_table_first_block( 375 376 356 bg_ref->block_group, sb); 357 377 358 uint32_t last_block = first_block + table_blocks - 1; 378 359 379 360 /* Initialization of all itable blocks */ 380 361 for (uint32_t fblock = first_block; fblock <= last_block; ++fblock) { 381 362 block_t *block; 382 rc = block_get(&block, bg_ref->fs->device, fblock, BLOCK_FLAGS_NOREAD);383 if (rc != EOK) {384 return rc;385 }386 363 int rc = block_get(&block, bg_ref->fs->device, fblock, 364 BLOCK_FLAGS_NOREAD); 365 if (rc != EOK) 366 return rc; 367 387 368 memset(block->data, 0, block_size); 388 369 block->dirty = true; 389 370 390 371 rc = block_put(block); 391 if (rc != EOK) { 392 return rc; 393 } 394 } 395 372 if (rc != EOK) 373 return rc; 374 } 375 396 376 return EOK; 397 377 } … … 399 379 /** Get reference to block group specified by index. 400 380 * 401 * @param fs filesystem to find block group on 402 * @param bgid index of block group to load 403 * @param ref output pointer for reference 404 * @return error code 381 * @param fs Filesystem to find block group on 382 * @param bgid Index of block group to load 383 * @param ref Output pointer for reference 384 * 385 * @return Error code 386 * 405 387 */ 406 388 int ext4_filesystem_get_block_group_ref(ext4_filesystem_t *fs, uint32_t bgid, 407 389 ext4_block_group_ref_t **ref) 408 390 { 409 int rc;410 411 391 /* Allocate memory for new structure */ 412 ext4_block_group_ref_t *newref = malloc(sizeof(ext4_block_group_ref_t)); 413 if (newref == NULL) { 392 ext4_block_group_ref_t *newref = 393 malloc(sizeof(ext4_block_group_ref_t)); 394 if (newref == NULL) 414 395 return ENOMEM; 415 } 416 396 417 397 /* Compute number of descriptors, that fits in one data block */ 418 uint32_t descriptors_per_block = ext4_superblock_get_block_size(fs->superblock) 419 / ext4_superblock_get_desc_size(fs->superblock); 420 398 uint32_t descriptors_per_block = 399 ext4_superblock_get_block_size(fs->superblock) / 400 ext4_superblock_get_desc_size(fs->superblock); 401 421 402 /* Block group descriptor table starts at the next block after superblock */ 422 aoff64_t block_id = ext4_superblock_get_first_data_block(fs->superblock) + 1; 423 403 aoff64_t block_id = 404 ext4_superblock_get_first_data_block(fs->superblock) + 1; 405 424 406 /* Find the block containing the descriptor we are looking for */ 425 407 block_id += bgid / descriptors_per_block; 426 uint32_t offset = (bgid % descriptors_per_block) * ext4_superblock_get_desc_size(fs->superblock); 427 408 uint32_t offset = (bgid % descriptors_per_block) * 409 ext4_superblock_get_desc_size(fs->superblock); 410 428 411 /* Load block with descriptors */ 429 rc = block_get(&newref->block, fs->device, block_id, 0);412 int rc = block_get(&newref->block, fs->device, block_id, 0); 430 413 if (rc != EOK) { 431 414 free(newref); 432 415 return rc; 433 416 } 434 417 435 418 /* Inititialize in-memory representation */ 436 419 newref->block_group = newref->block->data + offset; … … 438 421 newref->index = bgid; 439 422 newref->dirty = false; 440 423 441 424 *ref = newref; 442 425 443 426 if (ext4_block_group_has_flag(newref->block_group, 444 EXT4_BLOCK_GROUP_BLOCK_UNINIT)) { 445 427 EXT4_BLOCK_GROUP_BLOCK_UNINIT)) { 446 428 rc = ext4_filesystem_init_block_bitmap(newref); 447 429 if (rc != EOK) { … … 450 432 return rc; 451 433 } 434 452 435 ext4_block_group_clear_flag(newref->block_group, 453 454 436 EXT4_BLOCK_GROUP_BLOCK_UNINIT); 437 455 438 newref->dirty = true; 456 439 } 457 440 458 441 if (ext4_block_group_has_flag(newref->block_group, 459 EXT4_BLOCK_GROUP_INODE_UNINIT)) { 460 442 EXT4_BLOCK_GROUP_INODE_UNINIT)) { 461 443 rc = ext4_filesystem_init_inode_bitmap(newref); 462 444 if (rc != EOK) { … … 465 447 return rc; 466 448 } 467 449 468 450 ext4_block_group_clear_flag(newref->block_group, 469 EXT4_BLOCK_GROUP_INODE_UNINIT); 470 471 if (! ext4_block_group_has_flag(newref->block_group, 472 EXT4_BLOCK_GROUP_ITABLE_ZEROED)) { 473 451 EXT4_BLOCK_GROUP_INODE_UNINIT); 452 453 if (!ext4_block_group_has_flag(newref->block_group, 454 EXT4_BLOCK_GROUP_ITABLE_ZEROED)) { 474 455 rc = ext4_filesystem_init_inode_table(newref); 475 if (rc != EOK) {456 if (rc != EOK) 476 457 return rc; 477 } 478 458 479 459 ext4_block_group_set_flag(newref->block_group, 480 EXT4_BLOCK_GROUP_ITABLE_ZEROED); 481 460 EXT4_BLOCK_GROUP_ITABLE_ZEROED); 482 461 } 462 483 463 newref->dirty = true; 484 485 } 486 464 } 465 487 466 return EOK; 488 467 } … … 492 471 * It uses crc functions from Linux kernel implementation. 493 472 * 494 * @param sb superblock 495 * @param bgid index of block group in the filesystem 496 * @param bg block group to compute checksum for 497 * @return checksum value 473 * @param sb Superblock 474 * @param bgid Index of block group in the filesystem 475 * @param bg Block group to compute checksum for 476 * 477 * @return Checksum value 478 * 498 479 */ 499 480 static uint16_t ext4_filesystem_bg_checksum(ext4_superblock_t *sb, uint32_t bgid, 500 481 ext4_block_group_t *bg) 501 482 { 502 483 /* If checksum not supported, 0 will be returned */ 503 484 uint16_t crc = 0; 504 485 505 486 /* Compute the checksum only if the filesystem supports it */ 506 if (ext4_superblock_has_feature_read_only(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {507 487 if (ext4_superblock_has_feature_read_only(sb, 488 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { 508 489 void *base = bg; 509 490 void *checksum = &bg->checksum; 510 511 uint32_t offset = (uint32_t) (checksum - base);512 491 492 uint32_t offset = (uint32_t) (checksum - base); 493 513 494 /* Convert block group index to little endian */ 514 495 uint32_t le_group = host2uint32_t_le(bgid); 515 496 516 497 /* Initialization */ 517 498 crc = crc16(~0, sb->uuid, sizeof(sb->uuid)); 518 499 519 500 /* Include index of block group */ 520 crc = crc16(crc, (uint8_t *) &le_group, sizeof(le_group));521 501 crc = crc16(crc, (uint8_t *) &le_group, sizeof(le_group)); 502 522 503 /* Compute crc from the first part (stop before checksum field) */ 523 crc = crc16(crc, (uint8_t *) bg, offset);524 504 crc = crc16(crc, (uint8_t *) bg, offset); 505 525 506 /* Skip checksum */ 526 507 offset += sizeof(bg->checksum); 527 508 528 509 /* Checksum of the rest of block group descriptor */ 529 if ((ext4_superblock_has_feature_incompatible(sb, EXT4_FEATURE_INCOMPAT_64BIT)) &&530 offset < ext4_superblock_get_desc_size(sb)) {531 532 crc = crc16(crc, ((uint8_t *) bg) + offset, ext4_superblock_get_desc_size(sb) - offset);533 }534 } 535 510 if ((ext4_superblock_has_feature_incompatible(sb, 511 EXT4_FEATURE_INCOMPAT_64BIT)) && 512 (offset < ext4_superblock_get_desc_size(sb))) 513 crc = crc16(crc, ((uint8_t *) bg) + offset, 514 ext4_superblock_get_desc_size(sb) - offset); 515 } 516 536 517 return crc; 537 538 518 } 539 519 540 520 /** Put reference to block group. 541 521 * 542 * @oaram ref pointer for reference to be put back 543 * @return error code 522 * @oaram ref Pointer for reference to be put back 523 * 524 * @return Error code 525 * 544 526 */ 545 527 int ext4_filesystem_put_block_group_ref(ext4_block_group_ref_t *ref) 546 528 { 547 int rc;548 549 529 /* Check if reference modified */ 550 530 if (ref->dirty) { 551 552 531 /* Compute new checksum of block group */ 553 uint16_t checksum = ext4_filesystem_bg_checksum( 554 ref->fs->superblock, ref->index, ref->block_group); 532 uint16_t checksum = 533 ext4_filesystem_bg_checksum(ref->fs->superblock, ref->index, 534 ref->block_group); 555 535 ext4_block_group_set_checksum(ref->block_group, checksum); 556 536 557 537 /* Mark block dirty for writing changes to physical device */ 558 538 ref->block->dirty = true; 559 539 } 560 540 561 541 /* Put back block, that contains block group descriptor */ 562 rc = block_put(ref->block);542 int rc = block_put(ref->block); 563 543 free(ref); 564 544 565 545 return rc; 566 546 } … … 568 548 /** Get reference to i-node specified by index. 569 549 * 570 * @param fs filesystem to find i-node on 571 * @param index index of i-node to load 572 * @oaram ref output pointer for reference 573 * @return error code 550 * @param fs Filesystem to find i-node on 551 * @param index Index of i-node to load 552 * @oaram ref Output pointer for reference 553 * 554 * @return Error code 555 * 574 556 */ 575 557 int ext4_filesystem_get_inode_ref(ext4_filesystem_t *fs, uint32_t index, 576 558 ext4_inode_ref_t **ref) 577 559 { 578 int rc;579 580 560 /* Allocate memory for new structure */ 581 ext4_inode_ref_t *newref = malloc(sizeof(ext4_inode_ref_t)); 582 if (newref == NULL) { 561 ext4_inode_ref_t *newref = 562 malloc(sizeof(ext4_inode_ref_t)); 563 if (newref == NULL) 583 564 return ENOMEM; 584 } 585 565 586 566 /* Compute number of i-nodes, that fits in one data block */ 587 567 uint32_t inodes_per_group = 588 ext4_superblock_get_inodes_per_group(fs->superblock); 589 590 /* Inode numbers are 1-based, but it is simpler to work with 0-based 568 ext4_superblock_get_inodes_per_group(fs->superblock); 569 570 /* 571 * Inode numbers are 1-based, but it is simpler to work with 0-based 591 572 * when computing indices 592 573 */ … … 594 575 uint32_t block_group = index / inodes_per_group; 595 576 uint32_t offset_in_group = index % inodes_per_group; 596 577 597 578 /* Load block group, where i-node is located */ 598 579 ext4_block_group_ref_t *bg_ref; 599 rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref);580 int rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref); 600 581 if (rc != EOK) { 601 582 free(newref); 602 583 return rc; 603 584 } 604 585 605 586 /* Load block address, where i-node table is located */ 606 uint32_t inode_table_start = ext4_block_group_get_inode_table_first_block( 607 bg_ref->block_group, fs->superblock); 608 587 uint32_t inode_table_start = 588 ext4_block_group_get_inode_table_first_block(bg_ref->block_group, 589 fs->superblock); 590 609 591 /* Put back block group reference (not needed more) */ 610 592 rc = ext4_filesystem_put_block_group_ref(bg_ref); … … 613 595 return rc; 614 596 } 615 597 616 598 /* Compute position of i-node in the block group */ 617 599 uint16_t inode_size = ext4_superblock_get_inode_size(fs->superblock); 618 600 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock); 619 601 uint32_t byte_offset_in_group = offset_in_group * inode_size; 620 602 621 603 /* Compute block address */ 622 604 aoff64_t block_id = inode_table_start + (byte_offset_in_group / block_size); … … 626 608 return rc; 627 609 } 628 610 629 611 /* Compute position of i-node in the data block */ 630 612 uint32_t offset_in_block = byte_offset_in_group % block_size; 631 613 newref->inode = newref->block->data + offset_in_block; 632 614 633 615 /* We need to store the original value of index in the reference */ 634 616 newref->index = index + 1; 635 617 newref->fs = fs; 636 618 newref->dirty = false; 637 619 638 620 *ref = newref; 639 621 640 622 return EOK; 641 623 } … … 643 625 /** Put reference to i-node. 644 626 * 645 * @param ref pointer for reference to be put back 646 * @return error code 627 * @param ref Pointer for reference to be put back 628 * 629 * @return Error code 630 * 647 631 */ 648 632 int ext4_filesystem_put_inode_ref(ext4_inode_ref_t *ref) 649 633 { 650 int rc;651 652 634 /* Check if reference modified */ 653 635 if (ref->dirty) { 654 655 636 /* Mark block dirty for writing changes to physical device */ 656 637 ref->block->dirty = true; 657 638 } 658 639 659 640 /* Put back block, that contains i-node */ 660 rc = block_put(ref->block);641 int rc = block_put(ref->block); 661 642 free(ref); 662 643 663 644 return rc; 664 645 } … … 666 647 /** Allocate new i-node in the filesystem. 667 648 * 668 * @param fs filesystem to allocated i-node on 669 * @param inode_ref output pointer to return reference to allocated i-node 670 * @param flags flags to be set for newly created i-node 671 * @return error code 649 * @param fs Filesystem to allocated i-node on 650 * @param inode_ref Output pointer to return reference to allocated i-node 651 * @param flags Flags to be set for newly created i-node 652 * 653 * @return Error code 654 * 672 655 */ 673 656 int ext4_filesystem_alloc_inode(ext4_filesystem_t *fs, 674 ext4_inode_ref_t **inode_ref, int flags) 675 { 676 int rc; 677 657 ext4_inode_ref_t **inode_ref, int flags) 658 { 678 659 /* Check if newly allocated i-node will be a directory */ 679 660 bool is_dir = false; 680 if (flags & L_DIRECTORY) {661 if (flags & L_DIRECTORY) 681 662 is_dir = true; 682 } 683 663 684 664 /* Allocate inode by allocation algorithm */ 685 665 uint32_t index; 686 rc = ext4_ialloc_alloc_inode(fs, &index, is_dir);687 if (rc != EOK) {666 int rc = ext4_ialloc_alloc_inode(fs, &index, is_dir); 667 if (rc != EOK) 688 668 return rc; 689 } 690 669 691 670 /* Load i-node from on-disk i-node table */ 692 671 rc = ext4_filesystem_get_inode_ref(fs, index, inode_ref); … … 695 674 return rc; 696 675 } 697 676 698 677 /* Initialize i-node */ 699 678 ext4_inode_t *inode = (*inode_ref)->inode; 700 679 701 680 uint16_t mode; 702 681 if (is_dir) { … … 705 684 * 0777 (octal) == rwxrwxrwx 706 685 */ 686 707 687 mode = 0777; 708 688 mode |= EXT4_INODE_MODE_DIRECTORY; 709 689 ext4_inode_set_mode(fs->superblock, inode, mode); 710 ext4_inode_set_links_count(inode, 1); /* '.' entry */690 ext4_inode_set_links_count(inode, 1); /* '.' entry */ 711 691 } else { 712 692 /* … … 714 694 * 0666 (octal) == rw-rw-rw- 715 695 */ 716 696 717 697 mode = 0666; 718 698 mode |= EXT4_INODE_MODE_FILE; … … 720 700 ext4_inode_set_links_count(inode, 0); 721 701 } 722 702 723 703 ext4_inode_set_uid(inode, 0); 724 704 ext4_inode_set_gid(inode, 0); … … 731 711 ext4_inode_set_flags(inode, 0); 732 712 ext4_inode_set_generation(inode, 0); 733 713 734 714 /* Reset blocks array */ 735 for (uint32_t i = 0; i < EXT4_INODE_BLOCKS; i++) {715 for (uint32_t i = 0; i < EXT4_INODE_BLOCKS; i++) 736 716 inode->blocks[i] = 0; 737 } 738 717 739 718 /* Initialize extents if needed */ 740 719 if (ext4_superblock_has_feature_incompatible( 741 fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS)) { 742 720 fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS)) { 743 721 ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS); 744 722 745 723 /* Initialize extent root header */ 746 724 ext4_extent_header_t *header = ext4_inode_get_extent_header(inode); … … 749 727 ext4_extent_header_set_generation(header, 0); 750 728 ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC); 751 752 uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof (uint32_t) - sizeof(ext4_extent_header_t))753 754 729 730 uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof(uint32_t) - 731 sizeof(ext4_extent_header_t)) / sizeof(ext4_extent_t); 732 755 733 ext4_extent_header_set_max_entries_count(header, max_entries); 756 734 } 757 735 758 736 (*inode_ref)->dirty = true; 759 737 760 738 return EOK; 761 739 } … … 763 741 /** Release i-node and mark it as free. 764 742 * 765 * @param inode_ref i-node to be released 766 * @return error code 743 * @param inode_ref I-node to be released 744 * 745 * @return Error code 746 * 767 747 */ 768 748 int ext4_filesystem_free_inode(ext4_inode_ref_t *inode_ref) 769 749 { 770 int rc;771 772 750 ext4_filesystem_t *fs = inode_ref->fs; 773 751 774 752 /* For extents must be data block destroyed by other way */ 775 if (ext4_superblock_has_feature_incompatible( 776 fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) && 777 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) { 778 753 if ((ext4_superblock_has_feature_incompatible(fs->superblock, 754 EXT4_FEATURE_INCOMPAT_EXTENTS)) && 755 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) { 779 756 /* Data structures are released during truncate operation... */ 780 757 goto finish; 781 758 } 782 759 783 760 /* Release all indirect (no data) blocks */ 784 761 785 762 /* 1) Single indirect */ 786 763 uint32_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0); 787 764 if (fblock != 0) { 788 rc = ext4_balloc_free_block(inode_ref, fblock); 789 if (rc != EOK) { 790 return rc; 791 } 792 765 int rc = ext4_balloc_free_block(inode_ref, fblock); 766 if (rc != EOK) 767 return rc; 768 793 769 ext4_inode_set_indirect_block(inode_ref->inode, 0, 0); 794 770 } 795 771 796 772 block_t *block; 797 773 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock); 798 774 uint32_t count = block_size / sizeof(uint32_t); 799 775 800 776 /* 2) Double indirect */ 801 777 fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1); 802 778 if (fblock != 0) { 803 rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE); 804 if (rc != EOK) { 805 return rc; 806 } 807 779 int rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE); 780 if (rc != EOK) 781 return rc; 782 808 783 uint32_t ind_block; 809 784 for (uint32_t offset = 0; offset < count; ++offset) { 810 ind_block = uint32_t_le2host(((uint32_t *)block->data)[offset]);811 785 ind_block = uint32_t_le2host(((uint32_t *) block->data)[offset]); 786 812 787 if (ind_block != 0) { 813 788 rc = ext4_balloc_free_block(inode_ref, ind_block); … … 818 793 } 819 794 } 820 795 821 796 block_put(block); 822 797 rc = ext4_balloc_free_block(inode_ref, fblock); 823 if (rc != EOK) { 824 return rc; 825 } 826 798 if (rc != EOK) 799 return rc; 800 827 801 ext4_inode_set_indirect_block(inode_ref->inode, 1, 0); 828 802 } 829 830 803 831 804 /* 3) Tripple indirect */ 832 805 block_t *subblock; 833 806 fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2); 834 807 if (fblock != 0) { 835 rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE); 836 if (rc != EOK) { 837 return rc; 838 } 839 808 int rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE); 809 if (rc != EOK) 810 return rc; 811 840 812 uint32_t ind_block; 841 813 for (uint32_t offset = 0; offset < count; ++offset) { 842 ind_block = uint32_t_le2host(((uint32_t *)block->data)[offset]);843 814 ind_block = uint32_t_le2host(((uint32_t *) block->data)[offset]); 815 844 816 if (ind_block != 0) { 845 rc = block_get(&subblock, fs->device, ind_block, BLOCK_FLAGS_NONE); 817 rc = block_get(&subblock, fs->device, ind_block, 818 BLOCK_FLAGS_NONE); 846 819 if (rc != EOK) { 847 820 block_put(block); 848 821 return rc; 849 822 } 850 823 851 824 uint32_t ind_subblock; 852 for (uint32_t suboffset = 0; suboffset < count; ++suboffset) { 853 ind_subblock = uint32_t_le2host(((uint32_t*)subblock->data)[suboffset]); 854 825 for (uint32_t suboffset = 0; suboffset < count; 826 ++suboffset) { 827 ind_subblock = uint32_t_le2host(((uint32_t *) 828 subblock->data)[suboffset]); 829 855 830 if (ind_subblock != 0) { 856 831 rc = ext4_balloc_free_block(inode_ref, ind_subblock); … … 861 836 } 862 837 } 863 864 838 } 839 865 840 block_put(subblock); 866 867 841 } 868 842 869 843 rc = ext4_balloc_free_block(inode_ref, ind_block); 870 844 if (rc != EOK) { … … 872 846 return rc; 873 847 } 874 875 876 848 } 877 849 878 850 block_put(block); 879 851 rc = ext4_balloc_free_block(inode_ref, fblock); 880 if (rc != EOK) { 881 return rc; 882 } 883 852 if (rc != EOK) 853 return rc; 854 884 855 ext4_inode_set_indirect_block(inode_ref->inode, 2, 0); 885 856 } 886 857 887 858 finish: 888 889 859 /* Mark inode dirty for writing to the physical device */ 890 860 inode_ref->dirty = true; 891 861 892 862 /* Free block with extended attributes if present */ 893 863 uint32_t xattr_block = ext4_inode_get_file_acl( 894 864 inode_ref->inode, fs->superblock); 895 865 if (xattr_block) { 896 rc = ext4_balloc_free_block(inode_ref, xattr_block); 897 if (rc != EOK) { 898 return rc; 899 } 900 866 int rc = ext4_balloc_free_block(inode_ref, xattr_block); 867 if (rc != EOK) 868 return rc; 869 901 870 ext4_inode_set_file_acl(inode_ref->inode, fs->superblock, 0); 902 871 } 903 872 904 873 /* Free inode by allocator */ 874 int rc; 905 875 if (ext4_inode_is_type(fs->superblock, inode_ref->inode, 906 EXT4_INODE_MODE_DIRECTORY)) {876 EXT4_INODE_MODE_DIRECTORY)) 907 877 rc = ext4_ialloc_free_inode(fs, inode_ref->index, true); 908 } else {878 else 909 879 rc = ext4_ialloc_free_inode(fs, inode_ref->index, false); 910 } 911 if (rc != EOK) { 912 return rc; 913 } 914 915 return EOK; 880 881 return rc; 916 882 } 917 883 918 884 /** Truncate i-node data blocks. 919 885 * 920 * @param inode_ref i-node to be truncated921 * @param new_size new size of inode (must be < current size)922 * @return error code923 * /924 int ext4_filesystem_truncate_inode( 925 ext4_inode_ref_t *inode_ref, aoff64_t new_size) 926 { 927 int rc; 928 886 * @param inode_ref I-node to be truncated 887 * @param new_size New size of inode (must be < current size) 888 * 889 * @return Error code 890 * 891 */ 892 int ext4_filesystem_truncate_inode(ext4_inode_ref_t *inode_ref, 893 aoff64_t new_size) 894 { 929 895 ext4_superblock_t *sb = inode_ref->fs->superblock; 930 896 931 897 /* Check flags, if i-node can be truncated */ 932 if (! ext4_inode_can_truncate(sb, inode_ref->inode)) {898 if (!ext4_inode_can_truncate(sb, inode_ref->inode)) 933 899 return EINVAL; 934 } 935 900 936 901 /* If sizes are equal, nothing has to be done. */ 937 902 aoff64_t old_size = ext4_inode_get_size(sb, inode_ref->inode); 938 if (old_size == new_size) {903 if (old_size == new_size) 939 904 return EOK; 940 } 941 905 942 906 /* It's not suppported to make the larger file by truncate operation */ 943 if (old_size < new_size) {907 if (old_size < new_size) 944 908 return EINVAL; 945 } 946 909 947 910 /* Compute how many blocks will be released */ 948 911 aoff64_t size_diff = old_size - new_size; 949 912 uint32_t block_size = ext4_superblock_get_block_size(sb); 950 913 uint32_t diff_blocks_count = size_diff / block_size; 951 if (size_diff % block_size != 0) {914 if (size_diff % block_size != 0) 952 915 diff_blocks_count++; 953 } 954 916 955 917 uint32_t old_blocks_count = old_size / block_size; 956 if (old_size % block_size != 0) {918 if (old_size % block_size != 0) 957 919 old_blocks_count++; 958 } 959 960 if (ext4_superblock_has_feature_incompatible( 961 inode_ref->fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) && 962 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) { 963 920 921 if ((ext4_superblock_has_feature_incompatible(inode_ref->fs->superblock, 922 EXT4_FEATURE_INCOMPAT_EXTENTS)) && 923 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) { 964 924 /* Extents require special operation */ 965 966 rc = ext4_extent_release_blocks_from(inode_ref, 967 old_blocks_count - diff_blocks_count); 968 if (rc != EOK) { 969 return rc; 970 } 925 int rc = ext4_extent_release_blocks_from(inode_ref, 926 old_blocks_count - diff_blocks_count); 927 if (rc != EOK) 928 return rc; 971 929 } else { 972 973 930 /* Release data blocks from the end of file */ 974 931 975 932 /* Starting from 1 because of logical blocks are numbered from 0 */ 976 933 for (uint32_t i = 1; i <= diff_blocks_count; ++i) { 977 rc = ext4_filesystem_release_inode_block(inode_ref, old_blocks_count - i); 978 if (rc != EOK) { 934 int rc = ext4_filesystem_release_inode_block(inode_ref, 935 old_blocks_count - i); 936 if (rc != EOK) 979 937 return rc; 980 }981 938 } 982 939 } 983 940 984 941 /* Update i-node */ 985 942 ext4_inode_set_size(inode_ref->inode, new_size); 986 943 inode_ref->dirty = true; 987 944 988 945 return EOK; 989 946 } … … 991 948 /** Get physical block address by logical index of the block. 992 949 * 993 * @param inode_ref i-node to read block address from 994 * @param iblock logical index of block 995 * @param fblock output pointer for return physical block address 996 * @return error code 950 * @param inode_ref I-node to read block address from 951 * @param iblock Logical index of block 952 * @param fblock Output pointer for return physical block address 953 * 954 * @return Error code 955 * 997 956 */ 998 957 int ext4_filesystem_get_inode_data_block_index(ext4_inode_ref_t *inode_ref, 999 aoff64_t iblock, uint32_t *fblock) 1000 { 1001 int rc; 1002 958 aoff64_t iblock, uint32_t *fblock) 959 { 1003 960 ext4_filesystem_t *fs = inode_ref->fs; 1004 961 1005 962 /* For empty file is situation simple */ 1006 963 if (ext4_inode_get_size(fs->superblock, inode_ref->inode) == 0) { … … 1008 965 return EOK; 1009 966 } 1010 967 1011 968 uint32_t current_block; 1012 969 1013 970 /* Handle i-node using extents */ 1014 if (ext4_superblock_has_feature_incompatible(fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) && 1015 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) { 1016 1017 rc = ext4_extent_find_block(inode_ref, iblock, ¤t_block); 1018 1019 if (rc != EOK) { 1020 return rc; 1021 } 1022 971 if ((ext4_superblock_has_feature_incompatible(fs->superblock, 972 EXT4_FEATURE_INCOMPAT_EXTENTS)) && 973 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) { 974 int rc = ext4_extent_find_block(inode_ref, iblock, ¤t_block); 975 if (rc != EOK) 976 return rc; 977 1023 978 *fblock = current_block; 1024 979 return EOK; 1025 1026 } 1027 980 } 981 1028 982 ext4_inode_t *inode = inode_ref->inode; 1029 983 1030 984 /* Direct block are read directly from array in i-node structure */ 1031 985 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) { 1032 current_block = ext4_inode_get_direct_block(inode, (uint32_t) iblock);986 current_block = ext4_inode_get_direct_block(inode, (uint32_t) iblock); 1033 987 *fblock = current_block; 1034 988 return EOK; 1035 989 } 1036 990 1037 991 /* Determine indirection level of the target block */ 1038 int level = -1;1039 for ( int i = 1; i < 4; i++) {992 unsigned int level = 0; 993 for (unsigned int i = 1; i < 4; i++) { 1040 994 if (iblock < fs->inode_block_limits[i]) { 1041 995 level = i; … … 1043 997 } 1044 998 } 1045 1046 if (level == -1) {999 1000 if (level == 0) 1047 1001 return EIO; 1048 } 1049 1002 1050 1003 /* Compute offsets for the topmost level */ 1051 aoff64_t block_offset_in_level = iblock - fs->inode_block_limits[level-1]; 1052 current_block = ext4_inode_get_indirect_block(inode, level-1); 1053 uint32_t offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1]; 1054 1004 aoff64_t block_offset_in_level = 1005 iblock - fs->inode_block_limits[level - 1]; 1006 current_block = ext4_inode_get_indirect_block(inode, level - 1); 1007 uint32_t offset_in_block = 1008 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1009 1055 1010 /* Sparse file */ 1056 1011 if (current_block == 0) { … … 1058 1013 return EOK; 1059 1014 } 1060 1015 1061 1016 block_t *block; 1062 1063 /* Navigate through other levels, until we find the block number 1017 1018 /* 1019 * Navigate through other levels, until we find the block number 1064 1020 * or find null reference meaning we are dealing with sparse file 1065 1021 */ 1066 1022 while (level > 0) { 1067 1068 1023 /* Load indirect block */ 1069 rc = block_get(&block, fs->device, current_block, 0); 1070 if (rc != EOK) { 1071 return rc; 1072 } 1073 1024 int rc = block_get(&block, fs->device, current_block, 0); 1025 if (rc != EOK) 1026 return rc; 1027 1074 1028 /* Read block address from indirect block */ 1075 current_block = uint32_t_le2host(((uint32_t*)block->data)[offset_in_block]); 1076 1029 current_block = 1030 uint32_t_le2host(((uint32_t *) block->data)[offset_in_block]); 1031 1077 1032 /* Put back indirect block untouched */ 1078 1033 rc = block_put(block); 1079 if (rc != EOK) { 1080 return rc; 1081 } 1082 1034 if (rc != EOK) 1035 return rc; 1036 1083 1037 /* Check for sparse file */ 1084 1038 if (current_block == 0) { … … 1086 1040 return EOK; 1087 1041 } 1088 1042 1089 1043 /* Jump to the next level */ 1090 level -= 1;1091 1044 level--; 1045 1092 1046 /* Termination condition - we have address of data block loaded */ 1093 if (level == 0) {1047 if (level == 0) 1094 1048 break; 1095 } 1096 1049 1097 1050 /* Visit the next level */ 1098 1051 block_offset_in_level %= fs->inode_blocks_per_level[level]; 1099 offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1]; 1100 } 1101 1052 offset_in_block = 1053 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1054 } 1055 1102 1056 *fblock = current_block; 1103 1057 1104 1058 return EOK; 1105 1059 } … … 1107 1061 /** Set physical block address for the block logical address into the i-node. 1108 1062 * 1109 * @param inode_ref i-node to set block address to 1110 * @param iblock logical index of block 1111 * @param fblock physical block address 1112 * @return error code 1063 * @param inode_ref I-node to set block address to 1064 * @param iblock Logical index of block 1065 * @param fblock Physical block address 1066 * 1067 * @return Error code 1068 * 1113 1069 */ 1114 1070 int ext4_filesystem_set_inode_data_block_index(ext4_inode_ref_t *inode_ref, 1115 aoff64_t iblock, uint32_t fblock) 1116 { 1117 int rc; 1118 1071 aoff64_t iblock, uint32_t fblock) 1072 { 1119 1073 ext4_filesystem_t *fs = inode_ref->fs; 1120 1074 1121 1075 /* Handle inode using extents */ 1122 if (ext4_superblock_has_feature_compatible(fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) && 1123 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) { 1124 /* not reachable !!! */ 1076 if ((ext4_superblock_has_feature_compatible(fs->superblock, 1077 EXT4_FEATURE_INCOMPAT_EXTENTS)) && 1078 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) { 1079 /* Not reachable */ 1125 1080 return ENOTSUP; 1126 1081 } 1127 1082 1128 1083 /* Handle simple case when we are dealing with direct reference */ 1129 1084 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) { 1130 ext4_inode_set_direct_block(inode_ref->inode, (uint32_t) iblock, fblock);1085 ext4_inode_set_direct_block(inode_ref->inode, (uint32_t) iblock, fblock); 1131 1086 inode_ref->dirty = true; 1087 1132 1088 return EOK; 1133 1089 } 1134 1090 1135 1091 /* Determine the indirection level needed to get the desired block */ 1136 int level = -1;1137 for ( int i = 1; i < 4; i++) {1092 unsigned int level = 0; 1093 for (unsigned int i = 1; i < 4; i++) { 1138 1094 if (iblock < fs->inode_block_limits[i]) { 1139 1095 level = i; … … 1141 1097 } 1142 1098 } 1143 1144 if (level == -1) {1099 1100 if (level == 0) 1145 1101 return EIO; 1146 } 1147 1102 1148 1103 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock); 1149 1104 1150 1105 /* Compute offsets for the topmost level */ 1151 aoff64_t block_offset_in_level = iblock - fs->inode_block_limits[level-1]; 1152 uint32_t current_block = ext4_inode_get_indirect_block(inode_ref->inode, level-1); 1153 uint32_t offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1]; 1154 1106 aoff64_t block_offset_in_level = 1107 iblock - fs->inode_block_limits[level - 1]; 1108 uint32_t current_block = 1109 ext4_inode_get_indirect_block(inode_ref->inode, level - 1); 1110 uint32_t offset_in_block = 1111 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1112 1155 1113 uint32_t new_block_addr; 1156 block_t *block, *new_block; 1157 1114 block_t *block; 1115 block_t *new_block; 1116 1158 1117 /* Is needed to allocate indirect block on the i-node level */ 1159 1118 if (current_block == 0) { 1160 1161 1119 /* Allocate new indirect block */ 1162 rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr); 1163 if (rc != EOK) { 1164 return rc; 1165 } 1166 1120 int rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr); 1121 if (rc != EOK) 1122 return rc; 1123 1167 1124 /* Update i-node */ 1168 ext4_inode_set_indirect_block(inode_ref->inode, level - 1, new_block_addr); 1125 ext4_inode_set_indirect_block(inode_ref->inode, level - 1, 1126 new_block_addr); 1169 1127 inode_ref->dirty = true; 1170 1128 1171 1129 /* Load newly allocated block */ 1172 rc = block_get(&new_block, fs->device, new_block_addr, BLOCK_FLAGS_NOREAD); 1130 rc = block_get(&new_block, fs->device, new_block_addr, 1131 BLOCK_FLAGS_NOREAD); 1173 1132 if (rc != EOK) { 1174 1133 ext4_balloc_free_block(inode_ref, new_block_addr); 1175 1134 return rc; 1176 1135 } 1177 1136 1178 1137 /* Initialize new block */ 1179 1138 memset(new_block->data, 0, block_size); 1180 1139 new_block->dirty = true; 1181 1140 1182 1141 /* Put back the allocated block */ 1183 1142 rc = block_put(new_block); 1184 if (rc != EOK) { 1185 return rc; 1186 } 1187 1143 if (rc != EOK) 1144 return rc; 1145 1188 1146 current_block = new_block_addr; 1189 1147 } 1190 1191 /* Navigate through other levels, until we find the block number 1148 1149 /* 1150 * Navigate through other levels, until we find the block number 1192 1151 * or find null reference meaning we are dealing with sparse file 1193 1152 */ 1194 1153 while (level > 0) { 1195 1196 rc = block_get(&block, fs->device, current_block, 0); 1197 if (rc != EOK) { 1198 return rc; 1199 } 1200 1201 current_block = uint32_t_le2host(((uint32_t*)block->data)[offset_in_block]); 1202 1154 int rc = block_get(&block, fs->device, current_block, 0); 1155 if (rc != EOK) 1156 return rc; 1157 1158 current_block = 1159 uint32_t_le2host(((uint32_t *) block->data)[offset_in_block]); 1160 1203 1161 if ((level > 1) && (current_block == 0)) { 1204 1205 1162 /* Allocate new block */ 1206 1163 rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr); … … 1209 1166 return rc; 1210 1167 } 1211 1168 1212 1169 /* Load newly allocated block */ 1213 rc = block_get(&new_block, fs->device, new_block_addr, BLOCK_FLAGS_NOREAD); 1170 rc = block_get(&new_block, fs->device, new_block_addr, 1171 BLOCK_FLAGS_NOREAD); 1214 1172 if (rc != EOK) { 1215 1173 block_put(block); 1216 1174 return rc; 1217 1175 } 1218 1176 1219 1177 /* Initialize allocated block */ 1220 1178 memset(new_block->data, 0, block_size); 1221 1179 new_block->dirty = true; 1222 1180 1223 1181 rc = block_put(new_block); 1224 1182 if (rc != EOK) { … … 1226 1184 return rc; 1227 1185 } 1228 1186 1229 1187 /* Write block address to the parent */ 1230 ((uint32_t*)block->data)[offset_in_block] = host2uint32_t_le(new_block_addr); 1188 ((uint32_t *) block->data)[offset_in_block] = 1189 host2uint32_t_le(new_block_addr); 1231 1190 block->dirty = true; 1232 1191 current_block = new_block_addr; 1233 1192 } 1234 1193 1235 1194 /* Will be finished, write the fblock address */ 1236 1195 if (level == 1) { 1237 ((uint32_t*)block->data)[offset_in_block] = host2uint32_t_le(fblock); 1196 ((uint32_t *) block->data)[offset_in_block] = 1197 host2uint32_t_le(fblock); 1238 1198 block->dirty = true; 1239 1199 } 1240 1200 1241 1201 rc = block_put(block); 1242 if (rc != EOK) {1243 return rc; 1244 }1245 1246 level -= 1;1247 1248 /* If we are on the last level, break here as1202 if (rc != EOK) 1203 return rc; 1204 1205 level--; 1206 1207 /* 1208 * If we are on the last level, break here as 1249 1209 * there is no next level to visit 1250 1210 */ 1251 if (level == 0) {1211 if (level == 0) 1252 1212 break; 1253 } 1254 1213 1255 1214 /* Visit the next level */ 1256 1215 block_offset_in_level %= fs->inode_blocks_per_level[level]; 1257 offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1]; 1258 } 1259 1216 offset_in_block = 1217 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1218 } 1219 1260 1220 return EOK; 1261 1221 } … … 1263 1223 /** Release data block from i-node 1264 1224 * 1265 * @param inode_ref i-node to release block from1266 * @param iblock logical block to be released1267 * @return error code1268 * /1269 int ext4_filesystem_release_inode_block( 1270 ext4_inode_ref_t *inode_ref, uint32_t iblock) 1271 { 1272 int rc; 1273 1225 * @param inode_ref I-node to release block from 1226 * @param iblock Logical block to be released 1227 * 1228 * @return Error code 1229 * 1230 */ 1231 int ext4_filesystem_release_inode_block(ext4_inode_ref_t *inode_ref, 1232 uint32_t iblock) 1233 { 1274 1234 uint32_t fblock; 1275 1235 1276 1236 ext4_filesystem_t *fs = inode_ref->fs; 1277 1278 /* E XTENTSare handled otherwise = there is not support in this function */1279 assert(! 1280 1281 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)));1282 1237 1238 /* Extents are handled otherwise = there is not support in this function */ 1239 assert(!(ext4_superblock_has_feature_incompatible(fs->superblock, 1240 EXT4_FEATURE_INCOMPAT_EXTENTS) && 1241 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)))); 1242 1283 1243 ext4_inode_t *inode = inode_ref->inode; 1284 1244 1285 1245 /* Handle simple case when we are dealing with direct reference */ 1286 1246 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) { 1287 1247 fblock = ext4_inode_get_direct_block(inode, iblock); 1248 1288 1249 /* Sparse file */ 1289 if (fblock == 0) {1250 if (fblock == 0) 1290 1251 return EOK; 1291 } 1292 1252 1293 1253 ext4_inode_set_direct_block(inode, iblock, 0); 1294 1254 return ext4_balloc_free_block(inode_ref, fblock); 1295 1255 } 1296 1297 1256 1298 1257 /* Determine the indirection level needed to get the desired block */ 1299 int level = -1;1300 for ( int i = 1; i < 4; i++) {1258 unsigned int level = 0; 1259 for (unsigned int i = 1; i < 4; i++) { 1301 1260 if (iblock < fs->inode_block_limits[i]) { 1302 1261 level = i; … … 1304 1263 } 1305 1264 } 1306 1307 if (level == -1) {1265 1266 if (level == 0) 1308 1267 return EIO; 1309 } 1310 1268 1311 1269 /* Compute offsets for the topmost level */ 1312 aoff64_t block_offset_in_level = iblock - fs->inode_block_limits[level-1]; 1313 uint32_t current_block = ext4_inode_get_indirect_block(inode, level-1); 1314 uint32_t offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1]; 1315 1316 /* Navigate through other levels, until we find the block number 1270 aoff64_t block_offset_in_level = 1271 iblock - fs->inode_block_limits[level - 1]; 1272 uint32_t current_block = 1273 ext4_inode_get_indirect_block(inode, level - 1); 1274 uint32_t offset_in_block = 1275 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1276 1277 /* 1278 * Navigate through other levels, until we find the block number 1317 1279 * or find null reference meaning we are dealing with sparse file 1318 1280 */ 1319 1281 block_t *block; 1320 1282 while (level > 0) { 1321 rc = block_get(&block, fs->device, current_block, 0);1322 if (rc != EOK) {1323 return rc; 1324 }1325 1326 current_block = uint32_t_le2host(((uint32_t*)block->data)[offset_in_block]);1327 1283 int rc = block_get(&block, fs->device, current_block, 0); 1284 if (rc != EOK) 1285 return rc; 1286 1287 current_block = 1288 uint32_t_le2host(((uint32_t *) block->data)[offset_in_block]); 1289 1328 1290 /* Set zero if physical data block address found */ 1329 1291 if (level == 1) { 1330 ((uint32_t*)block->data)[offset_in_block] = host2uint32_t_le(0); 1292 ((uint32_t *) block->data)[offset_in_block] = 1293 host2uint32_t_le(0); 1331 1294 block->dirty = true; 1332 1295 } 1333 1296 1334 1297 rc = block_put(block); 1335 if (rc != EOK) {1336 return rc; 1337 }1338 1339 level -= 1;1340 1341 /* If we are on the last level, break here as1298 if (rc != EOK) 1299 return rc; 1300 1301 level--; 1302 1303 /* 1304 * If we are on the last level, break here as 1342 1305 * there is no next level to visit 1343 1306 */ 1344 if (level == 0) {1307 if (level == 0) 1345 1308 break; 1346 } 1347 1309 1348 1310 /* Visit the next level */ 1349 1311 block_offset_in_level %= fs->inode_blocks_per_level[level]; 1350 offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1]; 1351 } 1352 1312 offset_in_block = 1313 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1314 } 1315 1353 1316 fblock = current_block; 1354 1355 if (fblock == 0) { 1317 if (fblock == 0) 1356 1318 return EOK; 1357 } 1358 1319 1359 1320 /* Physical block is not referenced, it can be released */ 1360 1361 1321 return ext4_balloc_free_block(inode_ref, fblock); 1362 1363 1322 } 1364 1323 1365 1324 /** Append following logical block to the i-node. 1366 1325 * 1367 * @param inode_ref i-node to append block to 1368 * @param fblock output physical block address of newly allocated block 1369 * @param iblock output logical number of newly allocated block 1370 * @return error code 1326 * @param inode_ref I-node to append block to 1327 * @param fblock Output physical block address of newly allocated block 1328 * @param iblock Output logical number of newly allocated block 1329 * 1330 * @return Error code 1331 * 1371 1332 */ 1372 1333 int ext4_filesystem_append_inode_block(ext4_inode_ref_t *inode_ref, 1373 uint32_t *fblock, uint32_t *iblock) 1374 { 1375 int rc; 1376 1334 uint32_t *fblock, uint32_t *iblock) 1335 { 1377 1336 /* Handle extents separately */ 1378 if (ext4_superblock_has_feature_incompatible( 1379 inode_ref->fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) && 1380 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) { 1381 1337 if ((ext4_superblock_has_feature_incompatible(inode_ref->fs->superblock, 1338 EXT4_FEATURE_INCOMPAT_EXTENTS)) && 1339 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) 1382 1340 return ext4_extent_append_block(inode_ref, iblock, fblock, true); 1383 1384 } 1385 1341 1386 1342 ext4_superblock_t *sb = inode_ref->fs->superblock; 1387 1343 1388 1344 /* Compute next block index and allocate data block */ 1389 1345 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode); 1390 1346 uint32_t block_size = ext4_superblock_get_block_size(sb); 1391 1347 1392 1348 /* Align size i-node size */ 1393 if ((inode_size % block_size) != 0) {1349 if ((inode_size % block_size) != 0) 1394 1350 inode_size += block_size - (inode_size % block_size); 1395 } 1396 1351 1397 1352 /* Logical blocks are numbered from 0 */ 1398 1353 uint32_t new_block_idx = inode_size / block_size; 1399 1354 1400 1355 /* Allocate new physical block */ 1401 1356 uint32_t phys_block; 1402 rc =ext4_balloc_alloc_block(inode_ref, &phys_block);1403 if (rc != EOK) {1357 int rc = ext4_balloc_alloc_block(inode_ref, &phys_block); 1358 if (rc != EOK) 1404 1359 return rc; 1405 } 1406 1360 1407 1361 /* Add physical block address to the i-node */ 1408 rc = ext4_filesystem_set_inode_data_block_index(inode_ref, new_block_idx, phys_block); 1362 rc = ext4_filesystem_set_inode_data_block_index(inode_ref, 1363 new_block_idx, phys_block); 1409 1364 if (rc != EOK) { 1410 1365 ext4_balloc_free_block(inode_ref, phys_block); 1411 1366 return rc; 1412 1367 } 1413 1368 1414 1369 /* Update i-node */ 1415 1370 ext4_inode_set_size(inode_ref->inode, inode_size + block_size); 1416 1371 inode_ref->dirty = true; 1417 1372 1418 1373 *fblock = phys_block; 1419 1374 *iblock = new_block_idx; 1420 1375 1421 1376 return EOK; 1422 1377 } … … 1424 1379 /** 1425 1380 * @} 1426 */ 1381 */
Note:
See TracChangeset
for help on using the changeset viewer.