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