Changeset a35b458 in mainline for uspace/lib/ext4/src/filesystem.c
- Timestamp:
- 2018-03-02T20:10:49Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- f1380b7
- Parents:
- 3061bc1
- git-author:
- Jiří Zárevúcky <zarevucky.jiri@…> (2018-02-28 17:38:31)
- git-committer:
- Jiří Zárevúcky <zarevucky.jiri@…> (2018-03-02 20:10:49)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/ext4/src/filesystem.c
r3061bc1 ra35b458 289 289 return EOK; 290 290 } 291 291 292 292 /* 293 293 * Check incompatible features - if filesystem has some, … … 300 300 if (incompatible_features > 0) 301 301 return ENOTSUP; 302 302 303 303 /* 304 304 * Check read-only features, if filesystem has some, … … 313 313 return EOK; 314 314 } 315 315 316 316 return EOK; 317 317 } … … 331 331 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb); 332 332 uint32_t first_block = ext4_superblock_get_first_data_block(sb); 333 333 334 334 /* First block == 0 or 1 */ 335 335 if (first_block == 0) … … 351 351 { 352 352 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb); 353 353 354 354 if (ext4_superblock_get_first_data_block(sb) == 0) 355 355 return bgid * blocks_per_group + index; … … 392 392 uint64_t bitmap_inode_addr = ext4_block_group_get_inode_bitmap( 393 393 bg_ref->block_group, bg_ref->fs->superblock); 394 394 395 395 block_t *bitmap_block; 396 396 errno_t rc = block_get(&bitmap_block, bg_ref->fs->device, … … 398 398 if (rc != EOK) 399 399 return rc; 400 400 401 401 uint8_t *bitmap = bitmap_block->data; 402 402 403 403 /* Initialize all bitmap bits to zero */ 404 404 uint32_t block_size = ext4_superblock_get_block_size(sb); 405 405 memset(bitmap, 0, block_size); 406 406 407 407 /* Determine the number of reserved blocks in the group */ 408 408 uint32_t reserved_cnt = ext4_filesystem_bg_get_backup_blocks(bg_ref); … … 439 439 440 440 bitmap_block->dirty = true; 441 441 442 442 /* Save bitmap */ 443 443 return block_put(bitmap_block); … … 457 457 bg_ref->block_group, bg_ref->fs->superblock); 458 458 block_t *bitmap_block; 459 459 460 460 errno_t rc = block_get(&bitmap_block, bg_ref->fs->device, 461 461 bitmap_block_addr, BLOCK_FLAGS_NOREAD); 462 462 if (rc != EOK) 463 463 return rc; 464 464 465 465 uint8_t *bitmap = bitmap_block->data; 466 466 467 467 /* Initialize all bitmap bits to zero */ 468 468 uint32_t block_size = ext4_superblock_get_block_size(bg_ref->fs->superblock); … … 470 470 ext4_superblock_get_inodes_per_group(bg_ref->fs->superblock); 471 471 memset(bitmap, 0, (inodes_per_group + 7) / 8); 472 472 473 473 uint32_t start_bit = inodes_per_group; 474 474 uint32_t end_bit = block_size * 8; 475 475 476 476 uint32_t i; 477 477 for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) 478 478 ext4_bitmap_set_bit(bitmap, i); 479 479 480 480 if (i < end_bit) 481 481 memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); 482 482 483 483 bitmap_block->dirty = true; 484 484 485 485 /* Save bitmap */ 486 486 return block_put(bitmap_block); … … 497 497 { 498 498 ext4_superblock_t *sb = bg_ref->fs->superblock; 499 499 500 500 uint32_t inode_size = ext4_superblock_get_inode_size(sb); 501 501 uint32_t block_size = ext4_superblock_get_block_size(sb); 502 502 uint32_t inodes_per_block = block_size / inode_size; 503 503 504 504 uint32_t inodes_in_group = 505 505 ext4_superblock_get_inodes_in_group(sb, bg_ref->index); 506 506 507 507 uint32_t table_blocks = inodes_in_group / inodes_per_block; 508 508 509 509 if (inodes_in_group % inodes_per_block) 510 510 table_blocks++; 511 511 512 512 /* Compute initialization bounds */ 513 513 uint32_t first_block = ext4_block_group_get_inode_table_first_block( 514 514 bg_ref->block_group, sb); 515 515 516 516 uint32_t last_block = first_block + table_blocks - 1; 517 517 518 518 /* Initialization of all itable blocks */ 519 519 for (uint32_t fblock = first_block; fblock <= last_block; ++fblock) { … … 523 523 if (rc != EOK) 524 524 return rc; 525 525 526 526 memset(block->data, 0, block_size); 527 527 block->dirty = true; 528 528 529 529 rc = block_put(block); 530 530 if (rc != EOK) 531 531 return rc; 532 532 } 533 533 534 534 return EOK; 535 535 } … … 552 552 if (newref == NULL) 553 553 return ENOMEM; 554 554 555 555 /* Compute number of descriptors, that fits in one data block */ 556 556 uint32_t descriptors_per_block = 557 557 ext4_superblock_get_block_size(fs->superblock) / 558 558 ext4_superblock_get_desc_size(fs->superblock); 559 559 560 560 /* Block group descriptor table starts at the next block after superblock */ 561 561 aoff64_t block_id = 562 562 ext4_superblock_get_first_data_block(fs->superblock) + 1; 563 563 564 564 /* Find the block containing the descriptor we are looking for */ 565 565 block_id += bgid / descriptors_per_block; 566 566 uint32_t offset = (bgid % descriptors_per_block) * 567 567 ext4_superblock_get_desc_size(fs->superblock); 568 568 569 569 /* Load block with descriptors */ 570 570 errno_t rc = block_get(&newref->block, fs->device, block_id, 0); … … 573 573 return rc; 574 574 } 575 575 576 576 /* Initialize in-memory representation */ 577 577 newref->block_group = newref->block->data + offset; … … 579 579 newref->index = bgid; 580 580 newref->dirty = false; 581 581 582 582 *ref = newref; 583 583 584 584 if (ext4_block_group_has_flag(newref->block_group, 585 585 EXT4_BLOCK_GROUP_BLOCK_UNINIT)) { … … 590 590 return rc; 591 591 } 592 592 593 593 ext4_block_group_clear_flag(newref->block_group, 594 594 EXT4_BLOCK_GROUP_BLOCK_UNINIT); 595 595 596 596 newref->dirty = true; 597 597 } 598 598 599 599 if (ext4_block_group_has_flag(newref->block_group, 600 600 EXT4_BLOCK_GROUP_INODE_UNINIT)) { … … 605 605 return rc; 606 606 } 607 607 608 608 ext4_block_group_clear_flag(newref->block_group, 609 609 EXT4_BLOCK_GROUP_INODE_UNINIT); 610 610 611 611 if (!ext4_block_group_has_flag(newref->block_group, 612 612 EXT4_BLOCK_GROUP_ITABLE_ZEROED)) { … … 614 614 if (rc != EOK) 615 615 return rc; 616 616 617 617 ext4_block_group_set_flag(newref->block_group, 618 618 EXT4_BLOCK_GROUP_ITABLE_ZEROED); 619 619 } 620 620 621 621 newref->dirty = true; 622 622 } 623 623 624 624 return EOK; 625 625 } … … 645 645 void *base = bg; 646 646 void *checksum = &bg->checksum; 647 647 648 648 uint32_t offset = (uint32_t) (checksum - base); 649 649 650 650 /* Convert block group index to little endian */ 651 651 uint32_t le_group = host2uint32_t_le(bgid); 652 652 653 653 /* Initialization */ 654 654 crc = crc16_ibm(~0, sb->uuid, sizeof(sb->uuid)); 655 655 656 656 /* Include index of block group */ 657 657 crc = crc16_ibm(crc, (uint8_t *) &le_group, sizeof(le_group)); 658 658 659 659 /* Compute crc from the first part (stop before checksum field) */ 660 660 crc = crc16_ibm(crc, (uint8_t *) bg, offset); 661 661 662 662 /* Skip checksum */ 663 663 offset += sizeof(bg->checksum); 664 664 665 665 /* Checksum of the rest of block group descriptor */ 666 666 if ((ext4_superblock_has_feature_incompatible(sb, … … 670 670 ext4_superblock_get_desc_size(sb) - offset); 671 671 } 672 672 673 673 return crc; 674 674 } … … 813 813 ref->block_group); 814 814 ext4_block_group_set_checksum(ref->block_group, checksum); 815 815 816 816 /* Mark block dirty for writing changes to physical device */ 817 817 ref->block->dirty = true; 818 818 } 819 819 820 820 /* Put back block, that contains block group descriptor */ 821 821 errno_t rc = block_put(ref->block); 822 822 free(ref); 823 823 824 824 return rc; 825 825 } … … 842 842 if (newref == NULL) 843 843 return ENOMEM; 844 844 845 845 /* Compute number of i-nodes, that fits in one data block */ 846 846 uint32_t inodes_per_group = 847 847 ext4_superblock_get_inodes_per_group(fs->superblock); 848 848 849 849 /* 850 850 * Inode numbers are 1-based, but it is simpler to work with 0-based … … 854 854 uint32_t block_group = index / inodes_per_group; 855 855 uint32_t offset_in_group = index % inodes_per_group; 856 856 857 857 /* Load block group, where i-node is located */ 858 858 ext4_block_group_ref_t *bg_ref; … … 862 862 return rc; 863 863 } 864 864 865 865 /* Load block address, where i-node table is located */ 866 866 uint32_t inode_table_start = 867 867 ext4_block_group_get_inode_table_first_block(bg_ref->block_group, 868 868 fs->superblock); 869 869 870 870 /* Put back block group reference (not needed more) */ 871 871 rc = ext4_filesystem_put_block_group_ref(bg_ref); … … 874 874 return rc; 875 875 } 876 876 877 877 /* Compute position of i-node in the block group */ 878 878 uint16_t inode_size = ext4_superblock_get_inode_size(fs->superblock); 879 879 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock); 880 880 uint32_t byte_offset_in_group = offset_in_group * inode_size; 881 881 882 882 /* Compute block address */ 883 883 aoff64_t block_id = inode_table_start + (byte_offset_in_group / block_size); … … 887 887 return rc; 888 888 } 889 889 890 890 /* Compute position of i-node in the data block */ 891 891 uint32_t offset_in_block = byte_offset_in_group % block_size; 892 892 newref->inode = newref->block->data + offset_in_block; 893 893 894 894 /* We need to store the original value of index in the reference */ 895 895 newref->index = index + 1; 896 896 newref->fs = fs; 897 897 newref->dirty = false; 898 898 899 899 *ref = newref; 900 900 901 901 return EOK; 902 902 } … … 916 916 ref->block->dirty = true; 917 917 } 918 918 919 919 /* Put back block, that contains i-node */ 920 920 errno_t rc = block_put(ref->block); 921 921 free(ref); 922 922 923 923 return rc; 924 924 } … … 940 940 if (flags & L_DIRECTORY) 941 941 is_dir = true; 942 942 943 943 /* Allocate inode by allocation algorithm */ 944 944 uint32_t index; … … 946 946 if (rc != EOK) 947 947 return rc; 948 948 949 949 /* Load i-node from on-disk i-node table */ 950 950 rc = ext4_filesystem_get_inode_ref(fs, index, inode_ref); … … 953 953 return rc; 954 954 } 955 955 956 956 /* Initialize i-node */ 957 957 ext4_inode_t *inode = (*inode_ref)->inode; 958 958 959 959 uint16_t mode; 960 960 if (is_dir) { … … 963 963 * 0777 (octal) == rwxrwxrwx 964 964 */ 965 965 966 966 mode = 0777; 967 967 mode |= EXT4_INODE_MODE_DIRECTORY; … … 973 973 * 0666 (octal) == rw-rw-rw- 974 974 */ 975 975 976 976 mode = 0666; 977 977 mode |= EXT4_INODE_MODE_FILE; … … 979 979 ext4_inode_set_links_count(inode, 0); 980 980 } 981 981 982 982 ext4_inode_set_uid(inode, 0); 983 983 ext4_inode_set_gid(inode, 0); … … 990 990 ext4_inode_set_flags(inode, 0); 991 991 ext4_inode_set_generation(inode, 0); 992 992 993 993 /* Reset blocks array */ 994 994 for (uint32_t i = 0; i < EXT4_INODE_BLOCKS; i++) 995 995 inode->blocks[i] = 0; 996 996 997 997 /* Initialize extents if needed */ 998 998 if (ext4_superblock_has_feature_incompatible( 999 999 fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS)) { 1000 1000 ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS); 1001 1001 1002 1002 /* Initialize extent root header */ 1003 1003 ext4_extent_header_t *header = ext4_inode_get_extent_header(inode); … … 1006 1006 ext4_extent_header_set_generation(header, 0); 1007 1007 ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC); 1008 1008 1009 1009 uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof(uint32_t) - 1010 1010 sizeof(ext4_extent_header_t)) / sizeof(ext4_extent_t); 1011 1011 1012 1012 ext4_extent_header_set_max_entries_count(header, max_entries); 1013 1013 } 1014 1014 1015 1015 (*inode_ref)->dirty = true; 1016 1016 1017 1017 return EOK; 1018 1018 } … … 1028 1028 { 1029 1029 ext4_filesystem_t *fs = inode_ref->fs; 1030 1030 1031 1031 /* For extents must be data block destroyed by other way */ 1032 1032 if ((ext4_superblock_has_feature_incompatible(fs->superblock, … … 1036 1036 goto finish; 1037 1037 } 1038 1038 1039 1039 /* Release all indirect (no data) blocks */ 1040 1040 1041 1041 /* 1) Single indirect */ 1042 1042 uint32_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0); … … 1045 1045 if (rc != EOK) 1046 1046 return rc; 1047 1047 1048 1048 ext4_inode_set_indirect_block(inode_ref->inode, 0, 0); 1049 1049 } 1050 1050 1051 1051 block_t *block; 1052 1052 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock); 1053 1053 uint32_t count = block_size / sizeof(uint32_t); 1054 1054 1055 1055 /* 2) Double indirect */ 1056 1056 fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1); … … 1059 1059 if (rc != EOK) 1060 1060 return rc; 1061 1061 1062 1062 uint32_t ind_block; 1063 1063 for (uint32_t offset = 0; offset < count; ++offset) { 1064 1064 ind_block = uint32_t_le2host(((uint32_t *) block->data)[offset]); 1065 1065 1066 1066 if (ind_block != 0) { 1067 1067 rc = ext4_balloc_free_block(inode_ref, ind_block); … … 1072 1072 } 1073 1073 } 1074 1074 1075 1075 rc = block_put(block); 1076 1076 if (rc != EOK) … … 1080 1080 if (rc != EOK) 1081 1081 return rc; 1082 1082 1083 1083 ext4_inode_set_indirect_block(inode_ref->inode, 1, 0); 1084 1084 } 1085 1085 1086 1086 /* 3) Tripple indirect */ 1087 1087 block_t *subblock; … … 1091 1091 if (rc != EOK) 1092 1092 return rc; 1093 1093 1094 1094 uint32_t ind_block; 1095 1095 for (uint32_t offset = 0; offset < count; ++offset) { 1096 1096 ind_block = uint32_t_le2host(((uint32_t *) block->data)[offset]); 1097 1097 1098 1098 if (ind_block != 0) { 1099 1099 rc = block_get(&subblock, fs->device, ind_block, … … 1103 1103 return rc; 1104 1104 } 1105 1105 1106 1106 uint32_t ind_subblock; 1107 1107 for (uint32_t suboffset = 0; suboffset < count; … … 1109 1109 ind_subblock = uint32_t_le2host(((uint32_t *) 1110 1110 subblock->data)[suboffset]); 1111 1111 1112 1112 if (ind_subblock != 0) { 1113 1113 rc = ext4_balloc_free_block(inode_ref, ind_subblock); … … 1119 1119 } 1120 1120 } 1121 1121 1122 1122 rc = block_put(subblock); 1123 1123 if (rc != EOK) { … … 1126 1126 } 1127 1127 } 1128 1128 1129 1129 rc = ext4_balloc_free_block(inode_ref, ind_block); 1130 1130 if (rc != EOK) { … … 1133 1133 } 1134 1134 } 1135 1135 1136 1136 rc = block_put(block); 1137 1137 if (rc != EOK) … … 1141 1141 if (rc != EOK) 1142 1142 return rc; 1143 1143 1144 1144 ext4_inode_set_indirect_block(inode_ref->inode, 2, 0); 1145 1145 } 1146 1146 1147 1147 finish: 1148 1148 /* Mark inode dirty for writing to the physical device */ 1149 1149 inode_ref->dirty = true; 1150 1150 1151 1151 /* Free block with extended attributes if present */ 1152 1152 uint32_t xattr_block = ext4_inode_get_file_acl( … … 1156 1156 if (rc != EOK) 1157 1157 return rc; 1158 1158 1159 1159 ext4_inode_set_file_acl(inode_ref->inode, fs->superblock, 0); 1160 1160 } 1161 1161 1162 1162 /* Free inode by allocator */ 1163 1163 errno_t rc; … … 1167 1167 else 1168 1168 rc = ext4_ialloc_free_inode(fs, inode_ref->index, false); 1169 1169 1170 1170 return rc; 1171 1171 } … … 1183 1183 { 1184 1184 ext4_superblock_t *sb = inode_ref->fs->superblock; 1185 1185 1186 1186 /* Check flags, if i-node can be truncated */ 1187 1187 if (!ext4_inode_can_truncate(sb, inode_ref->inode)) 1188 1188 return EINVAL; 1189 1189 1190 1190 /* If sizes are equal, nothing has to be done. */ 1191 1191 aoff64_t old_size = ext4_inode_get_size(sb, inode_ref->inode); 1192 1192 if (old_size == new_size) 1193 1193 return EOK; 1194 1194 1195 1195 /* It's not suppported to make the larger file by truncate operation */ 1196 1196 if (old_size < new_size) 1197 1197 return EINVAL; 1198 1198 1199 1199 /* Compute how many blocks will be released */ 1200 1200 aoff64_t size_diff = old_size - new_size; … … 1203 1203 if (size_diff % block_size != 0) 1204 1204 diff_blocks_count++; 1205 1205 1206 1206 uint32_t old_blocks_count = old_size / block_size; 1207 1207 if (old_size % block_size != 0) 1208 1208 old_blocks_count++; 1209 1209 1210 1210 if ((ext4_superblock_has_feature_incompatible(inode_ref->fs->superblock, 1211 1211 EXT4_FEATURE_INCOMPAT_EXTENTS)) && … … 1218 1218 } else { 1219 1219 /* Release data blocks from the end of file */ 1220 1220 1221 1221 /* Starting from 1 because of logical blocks are numbered from 0 */ 1222 1222 for (uint32_t i = 1; i <= diff_blocks_count; ++i) { … … 1227 1227 } 1228 1228 } 1229 1229 1230 1230 /* Update i-node */ 1231 1231 ext4_inode_set_size(inode_ref->inode, new_size); 1232 1232 inode_ref->dirty = true; 1233 1233 1234 1234 return EOK; 1235 1235 } … … 1248 1248 { 1249 1249 ext4_filesystem_t *fs = inode_ref->fs; 1250 1250 1251 1251 /* For empty file is situation simple */ 1252 1252 if (ext4_inode_get_size(fs->superblock, inode_ref->inode) == 0) { … … 1254 1254 return EOK; 1255 1255 } 1256 1256 1257 1257 uint32_t current_block; 1258 1258 1259 1259 /* Handle i-node using extents */ 1260 1260 if ((ext4_superblock_has_feature_incompatible(fs->superblock, … … 1264 1264 if (rc != EOK) 1265 1265 return rc; 1266 1266 1267 1267 *fblock = current_block; 1268 1268 return EOK; 1269 1269 } 1270 1270 1271 1271 ext4_inode_t *inode = inode_ref->inode; 1272 1272 1273 1273 /* Direct block are read directly from array in i-node structure */ 1274 1274 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) { … … 1277 1277 return EOK; 1278 1278 } 1279 1279 1280 1280 /* Determine indirection level of the target block */ 1281 1281 unsigned int level = 0; … … 1286 1286 } 1287 1287 } 1288 1288 1289 1289 if (level == 0) 1290 1290 return EIO; 1291 1291 1292 1292 /* Compute offsets for the topmost level */ 1293 1293 aoff64_t block_offset_in_level = … … 1296 1296 uint32_t offset_in_block = 1297 1297 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1298 1298 1299 1299 /* Sparse file */ 1300 1300 if (current_block == 0) { … … 1302 1302 return EOK; 1303 1303 } 1304 1304 1305 1305 block_t *block; 1306 1306 1307 1307 /* 1308 1308 * Navigate through other levels, until we find the block number … … 1314 1314 if (rc != EOK) 1315 1315 return rc; 1316 1316 1317 1317 /* Read block address from indirect block */ 1318 1318 current_block = 1319 1319 uint32_t_le2host(((uint32_t *) block->data)[offset_in_block]); 1320 1320 1321 1321 /* Put back indirect block untouched */ 1322 1322 rc = block_put(block); 1323 1323 if (rc != EOK) 1324 1324 return rc; 1325 1325 1326 1326 /* Check for sparse file */ 1327 1327 if (current_block == 0) { … … 1329 1329 return EOK; 1330 1330 } 1331 1331 1332 1332 /* Jump to the next level */ 1333 1333 level--; 1334 1334 1335 1335 /* Termination condition - we have address of data block loaded */ 1336 1336 if (level == 0) 1337 1337 break; 1338 1338 1339 1339 /* Visit the next level */ 1340 1340 block_offset_in_level %= fs->inode_blocks_per_level[level]; … … 1342 1342 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1343 1343 } 1344 1344 1345 1345 *fblock = current_block; 1346 1346 1347 1347 return EOK; 1348 1348 } … … 1361 1361 { 1362 1362 ext4_filesystem_t *fs = inode_ref->fs; 1363 1363 1364 1364 /* Handle inode using extents */ 1365 1365 if ((ext4_superblock_has_feature_compatible(fs->superblock, … … 1369 1369 return ENOTSUP; 1370 1370 } 1371 1371 1372 1372 /* Handle simple case when we are dealing with direct reference */ 1373 1373 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) { 1374 1374 ext4_inode_set_direct_block(inode_ref->inode, (uint32_t) iblock, fblock); 1375 1375 inode_ref->dirty = true; 1376 1376 1377 1377 return EOK; 1378 1378 } 1379 1379 1380 1380 /* Determine the indirection level needed to get the desired block */ 1381 1381 unsigned int level = 0; … … 1386 1386 } 1387 1387 } 1388 1388 1389 1389 if (level == 0) 1390 1390 return EIO; 1391 1391 1392 1392 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock); 1393 1393 1394 1394 /* Compute offsets for the topmost level */ 1395 1395 aoff64_t block_offset_in_level = … … 1399 1399 uint32_t offset_in_block = 1400 1400 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1401 1401 1402 1402 uint32_t new_block_addr; 1403 1403 block_t *block; 1404 1404 block_t *new_block; 1405 1405 1406 1406 /* Is needed to allocate indirect block on the i-node level */ 1407 1407 if (current_block == 0) { … … 1410 1410 if (rc != EOK) 1411 1411 return rc; 1412 1412 1413 1413 /* Update i-node */ 1414 1414 ext4_inode_set_indirect_block(inode_ref->inode, level - 1, 1415 1415 new_block_addr); 1416 1416 inode_ref->dirty = true; 1417 1417 1418 1418 /* Load newly allocated block */ 1419 1419 rc = block_get(&new_block, fs->device, new_block_addr, … … 1423 1423 return rc; 1424 1424 } 1425 1425 1426 1426 /* Initialize new block */ 1427 1427 memset(new_block->data, 0, block_size); 1428 1428 new_block->dirty = true; 1429 1429 1430 1430 /* Put back the allocated block */ 1431 1431 rc = block_put(new_block); 1432 1432 if (rc != EOK) 1433 1433 return rc; 1434 1434 1435 1435 current_block = new_block_addr; 1436 1436 } 1437 1437 1438 1438 /* 1439 1439 * Navigate through other levels, until we find the block number … … 1444 1444 if (rc != EOK) 1445 1445 return rc; 1446 1446 1447 1447 current_block = 1448 1448 uint32_t_le2host(((uint32_t *) block->data)[offset_in_block]); 1449 1449 1450 1450 if ((level > 1) && (current_block == 0)) { 1451 1451 /* Allocate new block */ … … 1455 1455 return rc; 1456 1456 } 1457 1457 1458 1458 /* Load newly allocated block */ 1459 1459 rc = block_get(&new_block, fs->device, new_block_addr, … … 1463 1463 return rc; 1464 1464 } 1465 1465 1466 1466 /* Initialize allocated block */ 1467 1467 memset(new_block->data, 0, block_size); 1468 1468 new_block->dirty = true; 1469 1469 1470 1470 rc = block_put(new_block); 1471 1471 if (rc != EOK) { … … 1473 1473 return rc; 1474 1474 } 1475 1475 1476 1476 /* Write block address to the parent */ 1477 1477 ((uint32_t *) block->data)[offset_in_block] = … … 1480 1480 current_block = new_block_addr; 1481 1481 } 1482 1482 1483 1483 /* Will be finished, write the fblock address */ 1484 1484 if (level == 1) { … … 1487 1487 block->dirty = true; 1488 1488 } 1489 1489 1490 1490 rc = block_put(block); 1491 1491 if (rc != EOK) 1492 1492 return rc; 1493 1493 1494 1494 level--; 1495 1495 1496 1496 /* 1497 1497 * If we are on the last level, break here as … … 1500 1500 if (level == 0) 1501 1501 break; 1502 1502 1503 1503 /* Visit the next level */ 1504 1504 block_offset_in_level %= fs->inode_blocks_per_level[level]; … … 1506 1506 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1507 1507 } 1508 1508 1509 1509 return EOK; 1510 1510 } … … 1522 1522 { 1523 1523 uint32_t fblock; 1524 1524 1525 1525 ext4_filesystem_t *fs = inode_ref->fs; 1526 1526 1527 1527 /* Extents are handled otherwise = there is not support in this function */ 1528 1528 assert(!(ext4_superblock_has_feature_incompatible(fs->superblock, 1529 1529 EXT4_FEATURE_INCOMPAT_EXTENTS) && 1530 1530 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)))); 1531 1531 1532 1532 ext4_inode_t *inode = inode_ref->inode; 1533 1533 1534 1534 /* Handle simple case when we are dealing with direct reference */ 1535 1535 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) { 1536 1536 fblock = ext4_inode_get_direct_block(inode, iblock); 1537 1537 1538 1538 /* Sparse file */ 1539 1539 if (fblock == 0) 1540 1540 return EOK; 1541 1541 1542 1542 ext4_inode_set_direct_block(inode, iblock, 0); 1543 1543 return ext4_balloc_free_block(inode_ref, fblock); 1544 1544 } 1545 1545 1546 1546 /* Determine the indirection level needed to get the desired block */ 1547 1547 unsigned int level = 0; … … 1552 1552 } 1553 1553 } 1554 1554 1555 1555 if (level == 0) 1556 1556 return EIO; 1557 1557 1558 1558 /* Compute offsets for the topmost level */ 1559 1559 aoff64_t block_offset_in_level = … … 1563 1563 uint32_t offset_in_block = 1564 1564 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1565 1565 1566 1566 /* 1567 1567 * Navigate through other levels, until we find the block number … … 1570 1570 block_t *block; 1571 1571 while (level > 0) { 1572 1572 1573 1573 /* Sparse check */ 1574 1574 if (current_block == 0) 1575 1575 return EOK; 1576 1576 1577 1577 errno_t rc = block_get(&block, fs->device, current_block, 0); 1578 1578 if (rc != EOK) 1579 1579 return rc; 1580 1580 1581 1581 current_block = 1582 1582 uint32_t_le2host(((uint32_t *) block->data)[offset_in_block]); 1583 1583 1584 1584 /* Set zero if physical data block address found */ 1585 1585 if (level == 1) { … … 1588 1588 block->dirty = true; 1589 1589 } 1590 1590 1591 1591 rc = block_put(block); 1592 1592 if (rc != EOK) 1593 1593 return rc; 1594 1594 1595 1595 level--; 1596 1596 1597 1597 /* 1598 1598 * If we are on the last level, break here as … … 1601 1601 if (level == 0) 1602 1602 break; 1603 1603 1604 1604 /* Visit the next level */ 1605 1605 block_offset_in_level %= fs->inode_blocks_per_level[level]; … … 1607 1607 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1608 1608 } 1609 1609 1610 1610 fblock = current_block; 1611 1611 if (fblock == 0) 1612 1612 return EOK; 1613 1613 1614 1614 /* Physical block is not referenced, it can be released */ 1615 1615 return ext4_balloc_free_block(inode_ref, fblock); … … 1633 1633 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) 1634 1634 return ext4_extent_append_block(inode_ref, iblock, fblock, true); 1635 1635 1636 1636 ext4_superblock_t *sb = inode_ref->fs->superblock; 1637 1637 1638 1638 /* Compute next block index and allocate data block */ 1639 1639 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode); 1640 1640 uint32_t block_size = ext4_superblock_get_block_size(sb); 1641 1641 1642 1642 /* Align size i-node size */ 1643 1643 if ((inode_size % block_size) != 0) 1644 1644 inode_size += block_size - (inode_size % block_size); 1645 1645 1646 1646 /* Logical blocks are numbered from 0 */ 1647 1647 uint32_t new_block_idx = inode_size / block_size; 1648 1648 1649 1649 /* Allocate new physical block */ 1650 1650 uint32_t phys_block; … … 1652 1652 if (rc != EOK) 1653 1653 return rc; 1654 1654 1655 1655 /* Add physical block address to the i-node */ 1656 1656 rc = ext4_filesystem_set_inode_data_block_index(inode_ref, … … 1660 1660 return rc; 1661 1661 } 1662 1662 1663 1663 /* Update i-node */ 1664 1664 ext4_inode_set_size(inode_ref->inode, inode_size + block_size); 1665 1665 inode_ref->dirty = true; 1666 1666 1667 1667 *fblock = phys_block; 1668 1668 *iblock = new_block_idx; 1669 1669 1670 1670 return EOK; 1671 1671 }
Note:
See TracChangeset
for help on using the changeset viewer.