Changeset aab85d90 in mainline for uspace/lib/ext4/src/superblock.c


Ignore:
Timestamp:
2018-08-27T14:17:14Z (6 years ago)
Author:
Jiri Svoboda <jiri@…>
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)
Message:

Basic Ext4 filesystem creation (can only create Ext2-old, 1K blocks).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/ext4/src/superblock.c

    r8867cf6 raab85d90  
    11/*
     2 * Copyright (c) 2018 Jiri Svoboda
    23 * Copyright (c) 2011 Martin Sucha
    34 * Copyright (c) 2012 Frantisek Princ
     
    3738 */
    3839
     40#include <align.h>
    3941#include <block.h>
    4042#include <byteorder.h>
     
    4244#include <mem.h>
    4345#include <stdlib.h>
     46#include <time.h>
    4447#include "ext4/superblock.h"
    4548
     
    581584void ext4_superblock_set_last_check_time(ext4_superblock_t *sb, uint32_t time)
    582585{
    583         sb->state = host2uint32_t_le(time);
     586        sb->last_check_time = host2uint32_t_le(time);
    584587}
    585588
     
    708711uint32_t ext4_superblock_get_first_inode(ext4_superblock_t *sb)
    709712{
     713        if (ext4_superblock_get_rev_level(sb) == 0)
     714                return EXT4_REV0_FIRST_INO;
     715
    710716        return uint32_t_le2host(sb->first_inode);
    711717}
     
    853859 *
    854860 */
    855 const uint8_t *ext4_superblock_get_uuid(ext4_superblock_t *sb)
    856 {
    857         return sb->uuid;
     861void ext4_superblock_get_uuid(ext4_superblock_t *sb, uuid_t *uuid)
     862{
     863        uuid_decode(sb->uuid, uuid);
    858864}
    859865
     
    861867 *
    862868 * @param sb   Superblock
    863  * @param uuid Pointer to UUID array
    864  *
    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 */
     872void ext4_superblock_set_uuid(ext4_superblock_t *sb, uuid_t *uuid)
     873{
     874        uuid_encode(uuid, sb->uuid);
    869875}
    870876
     
    13471353}
    13481354
     1355/* Check if n is a power of p */
     1356static 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 */
     1380uint32_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 */
     1460errno_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;
     1597error:
     1598        free(sb);
     1599        return rc;
     1600}
     1601
    13491602/**
    13501603 * @}
Note: See TracChangeset for help on using the changeset viewer.