Changeset aab85d90 in mainline for uspace/lib/ext4/src/superblock.c
- Timestamp:
- 2018-08-27T14:17:14Z (6 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- c606e33, e43d658
- Parents:
- 8867cf6
- git-author:
- Jiri Svoboda <jiri@…> (2018-08-26 17:15:23)
- git-committer:
- Jiri Svoboda <jiri@…> (2018-08-27 14:17:14)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/ext4/src/superblock.c
r8867cf6 raab85d90 1 1 /* 2 * Copyright (c) 2018 Jiri Svoboda 2 3 * Copyright (c) 2011 Martin Sucha 3 4 * Copyright (c) 2012 Frantisek Princ … … 37 38 */ 38 39 40 #include <align.h> 39 41 #include <block.h> 40 42 #include <byteorder.h> … … 42 44 #include <mem.h> 43 45 #include <stdlib.h> 46 #include <time.h> 44 47 #include "ext4/superblock.h" 45 48 … … 581 584 void ext4_superblock_set_last_check_time(ext4_superblock_t *sb, uint32_t time) 582 585 { 583 sb-> state = host2uint32_t_le(time);586 sb->last_check_time = host2uint32_t_le(time); 584 587 } 585 588 … … 708 711 uint32_t ext4_superblock_get_first_inode(ext4_superblock_t *sb) 709 712 { 713 if (ext4_superblock_get_rev_level(sb) == 0) 714 return EXT4_REV0_FIRST_INO; 715 710 716 return uint32_t_le2host(sb->first_inode); 711 717 } … … 853 859 * 854 860 */ 855 const uint8_t *ext4_superblock_get_uuid(ext4_superblock_t *sb)856 { 857 return sb->uuid;861 void ext4_superblock_get_uuid(ext4_superblock_t *sb, uuid_t *uuid) 862 { 863 uuid_decode(sb->uuid, uuid); 858 864 } 859 865 … … 861 867 * 862 868 * @param sb Superblock 863 * @param uuid Pointer to UUID array864 * 865 */ 866 void ext4_superblock_set_uuid(ext4_superblock_t *sb, const uint8_t *uuid)867 { 868 memcpy(sb->uuid, uuid, sizeof(sb->uuid));869 * @param uuid Pointer to UUID 870 * 871 */ 872 void ext4_superblock_set_uuid(ext4_superblock_t *sb, uuid_t *uuid) 873 { 874 uuid_encode(uuid, sb->uuid); 869 875 } 870 876 … … 1347 1353 } 1348 1354 1355 /* Check if n is a power of p */ 1356 static bool is_power_of(uint32_t n, unsigned p) 1357 { 1358 if (p == 1 && n != p) 1359 return false; 1360 1361 while (n != p) { 1362 if (n < p) 1363 return false; 1364 else if ((n % p) != 0) 1365 return false; 1366 1367 n /= p; 1368 } 1369 1370 return true; 1371 } 1372 1373 /** Get the number of blocks used by superblock + gdt + reserved gdt backups 1374 * 1375 * @param sb Superblock 1376 * @param idx Block group index 1377 * 1378 * @return Number of blocks 1379 */ 1380 uint32_t ext4_superblock_get_group_backup_blocks(ext4_superblock_t *sb, 1381 uint32_t idx) 1382 { 1383 uint32_t r = 0; 1384 bool has_backups = false; 1385 1386 /* First step: determine if the block group contains the backups */ 1387 1388 if (idx <= 1) 1389 has_backups = true; 1390 else { 1391 if (ext4_superblock_has_feature_compatible(sb, 1392 EXT4_FEATURE_COMPAT_SPARSE_SUPER2)) { 1393 uint32_t g1, g2; 1394 1395 ext4_superblock_get_backup_groups_sparse2(sb, 1396 &g1, &g2); 1397 1398 if (idx == g1 || idx == g2) 1399 has_backups = true; 1400 } else if (!ext4_superblock_has_feature_read_only(sb, 1401 EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) { 1402 /* 1403 * Very old fs were all block groups have 1404 * superblock and block descriptors backups. 1405 */ 1406 has_backups = true; 1407 } else { 1408 if ((idx & 1) && (is_power_of(idx, 3) || 1409 is_power_of(idx, 5) || is_power_of(idx, 7))) 1410 has_backups = true; 1411 } 1412 } 1413 1414 if (has_backups) { 1415 uint32_t bg_count; 1416 uint32_t bg_desc_sz; 1417 uint32_t gdt_table; /* Size of the GDT in blocks */ 1418 uint32_t block_size = ext4_superblock_get_block_size(sb); 1419 1420 /* 1421 * Now we know that this block group has backups, 1422 * we have to compute how many blocks are reserved 1423 * for them 1424 */ 1425 1426 if (idx == 0 && block_size == 1024) { 1427 /* 1428 * Special case for first group were the boot block 1429 * resides 1430 */ 1431 r++; 1432 } 1433 1434 /* This accounts for the superblock */ 1435 r++; 1436 1437 /* Add the number of blocks used for the GDT */ 1438 bg_count = ext4_superblock_get_block_group_count(sb); 1439 bg_desc_sz = ext4_superblock_get_desc_size(sb); 1440 gdt_table = ROUND_UP(bg_count * bg_desc_sz, block_size) / 1441 block_size; 1442 1443 r += gdt_table; 1444 1445 /* And now the number of reserved GDT blocks */ 1446 r += ext4_superblock_get_reserved_gdt_blocks(sb); 1447 } 1448 1449 return r; 1450 } 1451 1452 1453 /** Create superblock for new file system. 1454 * 1455 * @param dev_bsize Device block size 1456 * @param dev_bcnt Device number of blocks 1457 * @param rsb Place to store pointer to newly allocated superblock 1458 * @return EOK on success or error code 1459 */ 1460 errno_t ext4_superblock_create(size_t dev_bsize, uint64_t dev_bcnt, 1461 ext4_superblock_t **rsb) 1462 { 1463 ext4_superblock_t *sb; 1464 uuid_t uuid; 1465 uint32_t cur_ts; 1466 uint64_t first_block; 1467 uint64_t fs_blocks; 1468 uint32_t blocks_count; 1469 uint32_t free_blocks; 1470 uint32_t inodes_count; 1471 uint64_t blocks_group; 1472 uint64_t inodes_group; 1473 uint32_t inodes_block; 1474 uint32_t inode_table_blocks; 1475 uint32_t res_blocks; 1476 uint32_t ngroups; 1477 uint32_t idx; 1478 size_t fs_bsize; 1479 errno_t rc; 1480 struct timespec ts; 1481 1482 sb = calloc(1, sizeof(ext4_superblock_t)); 1483 if (sb == NULL) 1484 return ENOMEM; 1485 1486 rc = uuid_generate(&uuid); 1487 if (rc != EOK) 1488 goto error; 1489 1490 /* Current UNIX time */ 1491 getrealtime(&ts); // XXX ISO C does not say what the epoch is 1492 cur_ts = ts.tv_sec; 1493 1494 fs_bsize = 1024; 1495 first_block = 1; /* 1 for 1k block size, 0 otherwise */ 1496 1497 if (fs_bsize % dev_bsize == 0) { 1498 /* Small device blocks */ 1499 fs_blocks = dev_bcnt / (fs_bsize / dev_bsize); 1500 } else { 1501 /* Large device blocks */ 1502 fs_blocks = dev_bcnt * (dev_bsize / fs_bsize); 1503 } 1504 1505 /* FS blocks per group */ 1506 blocks_group = 8 * fs_bsize; 1507 1508 /* Inodes per group */ 1509 inodes_block = fs_bsize / EXT4_REV0_INODE_SIZE; 1510 inodes_group = min((fs_blocks - first_block) / 8, 1511 blocks_group / 4); 1512 if (inodes_group < 16) 1513 inodes_group = 16; 1514 1515 /* Align up to multiple of inodes_block */ 1516 if (inodes_group % inodes_block != 0) 1517 inodes_group += inodes_block - inodes_group % inodes_block; 1518 inode_table_blocks = inodes_group / inodes_block; 1519 1520 /* Number of groups */ 1521 ngroups = ((fs_blocks - first_block) + blocks_group - 1) / blocks_group; 1522 1523 /* Count of all blocks in groups */ 1524 blocks_count = fs_blocks - first_block; 1525 1526 /* Count of all inodes */ 1527 inodes_count = ngroups * inodes_group; 1528 1529 /* Count of blocks reserved for superuser */ 1530 res_blocks = (blocks_count + 19) / 20; 1531 1532 free_blocks = blocks_count; 1533 1534 ext4_superblock_set_magic(sb, EXT4_SUPERBLOCK_MAGIC); 1535 ext4_superblock_set_inodes_count(sb, inodes_count); 1536 ext4_superblock_set_blocks_count(sb, blocks_count); 1537 ext4_superblock_set_reserved_blocks_count(sb, res_blocks); 1538 ext4_superblock_set_free_blocks_count(sb, free_blocks); 1539 ext4_superblock_set_free_inodes_count(sb, inodes_count); 1540 ext4_superblock_set_first_data_block(sb, first_block); 1541 /* Block size will be 1024 bytes */ 1542 ext4_superblock_set_log_block_size(sb, 0); 1543 /* Fragment size should be equal to block size */ 1544 ext4_superblock_set_log_frag_size(sb, 0); 1545 ext4_superblock_set_blocks_per_group(sb, blocks_group); 1546 /* Should be the same as blocks per group. */ 1547 ext4_superblock_set_frags_per_group(sb, blocks_group); 1548 ext4_superblock_set_inodes_per_group(sb, inodes_group); 1549 ext4_superblock_set_mount_time(sb, 0); 1550 ext4_superblock_set_write_time(sb, cur_ts); 1551 ext4_superblock_set_mount_count(sb, 0); 1552 ext4_superblock_set_max_mount_count(sb, (uint16_t)-1); 1553 ext4_superblock_set_state(sb, EXT4_SUPERBLOCK_STATE_VALID_FS); 1554 ext4_superblock_set_errors(sb, EXT4_SUPERBLOCK_ERRORS_CONTINUE); 1555 ext4_superblock_set_minor_rev_level(sb, 0); // XXX 1556 ext4_superblock_set_last_check_time(sb, cur_ts); 1557 ext4_superblock_set_check_interval(sb, 0); 1558 ext4_superblock_set_creator_os(sb, EXT4_SUPERBLOCK_OS_LINUX); 1559 ext4_superblock_set_rev_level(sb, EXT4_GOOD_OLD_REV); 1560 ext4_superblock_set_def_resuid(sb, 0); 1561 ext4_superblock_set_def_resgid(sb, 0); 1562 #if 0 1563 /* Dynamic rev */ 1564 ext4_superblock_set_first_inode(sb, EXT4_REV0_FIRST_INO); 1565 ext4_superblock_set_inode_size(sb, EXT4_REV0_INODE_SIZE); 1566 ext4_superblock_set_block_group_index(sb, 0); // XXX 1567 ext4_superblock_set_features_compatible(sb, 0); 1568 ext4_superblock_set_features_incompatible(sb, 0); 1569 ext4_superblock_set_features_read_only(sb, 0); 1570 1571 ext4_superblock_set_uuid(sb, &uuid); 1572 /* 16-byte Latin-1 string padded with null characters */ 1573 ext4_superblock_set_volume_name(sb, "HelenOS-Ext4\0\0\0\0"); 1574 /* 64-byte Latin-1 string padded with null characters */ 1575 ext4_superblock_set_last_mounted(sb, 1576 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 1577 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); 1578 sb->algorithm_usage_bitmap = 0; 1579 1580 /* Journalling */ 1581 ext4_superblock_set_desc_size(sb, EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE); 1582 #endif 1583 1584 /* Compute free blocks */ 1585 free_blocks = blocks_count; 1586 for (idx = 0; idx < ngroups; idx++) { 1587 free_blocks -= ext4_superblock_get_group_backup_blocks(sb, idx); 1588 /* One for block bitmap, one for inode bitamp */ 1589 free_blocks -= 2; 1590 free_blocks -= inode_table_blocks; 1591 } 1592 1593 ext4_superblock_set_free_blocks_count(sb, free_blocks); 1594 1595 *rsb = sb; 1596 return EOK; 1597 error: 1598 free(sb); 1599 return rc; 1600 } 1601 1349 1602 /** 1350 1603 * @}
Note:
See TracChangeset
for help on using the changeset viewer.