Changeset aab85d90 in mainline


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).

Files:
2 added
12 edited

Legend:

Unmodified
Added
Removed
  • .gitignore

    r8867cf6 raab85d90  
    108108uspace/app/mkbd/mkbd
    109109uspace/app/mkexfat/mkexfat
     110uspace/app/mkext4/mkext4
    110111uspace/app/mkfat/mkfat
    111112uspace/app/mkmfs/mkmfs
  • boot/Makefile.common

    r8867cf6 raab85d90  
    195195        $(USPACE_PATH)/app/mkfat/mkfat \
    196196        $(USPACE_PATH)/app/mkexfat/mkexfat \
     197        $(USPACE_PATH)/app/mkext4/mkext4 \
    197198        $(USPACE_PATH)/app/mkmfs/mkmfs \
    198199        $(USPACE_PATH)/app/nic/nic \
  • uspace/Makefile

    r8867cf6 raab85d90  
    6161        app/mkfat \
    6262        app/mkexfat \
     63        app/mkext4 \
    6364        app/mkmfs \
    6465        app/modplay \
  • uspace/lib/ext4/include/ext4/filesystem.h

    r8867cf6 raab85d90  
    11/*
     2 * Copyright (c) 2018 Jiri Svoboda
    23 * Copyright (c) 2011 Martin Sucha
    34 * Copyright (c) 2012 Frantisek Princ
     
    4041
    4142extern errno_t ext4_filesystem_probe(service_id_t);
     43extern errno_t ext4_filesystem_create(service_id_t);
    4244extern errno_t ext4_filesystem_open(ext4_instance_t *, service_id_t,
    4345    enum cache_mode, aoff64_t *, ext4_filesystem_t **);
     
    6769uint32_t ext4_filesystem_bg_get_backup_blocks(ext4_block_group_ref_t *bg);
    6870uint32_t ext4_filesystem_bg_get_itable_size(ext4_superblock_t *sb,
    69     ext4_block_group_ref_t *bg_ref);
     71    uint32_t);
    7072
    7173#endif
  • uspace/lib/ext4/include/ext4/ialloc.h

    r8867cf6 raab85d90  
    11/*
     2 * Copyright (c) 2018 Jiri Svoboda
    23 * Copyright (c) 2012 Frantisek Princ
    34 * All rights reserved.
     
    3839extern errno_t ext4_ialloc_free_inode(ext4_filesystem_t *, uint32_t, bool);
    3940extern errno_t ext4_ialloc_alloc_inode(ext4_filesystem_t *, uint32_t *, bool);
     41extern errno_t ext4_ialloc_alloc_this_inode(ext4_filesystem_t *, uint32_t,
     42    bool);
     43
    4044
    4145#endif
  • uspace/lib/ext4/include/ext4/superblock.h

    r8867cf6 raab85d90  
    11/*
     2 * Copyright (c) 2018 Jiri Svoboda
    23 * Copyright (c) 2011 Martin Sucha
    34 * Copyright (c) 2012 Frantisek Princ
     
    3738#include <block.h>
    3839#include <stdint.h>
     40#include <uuid.h>
    3941#include "ext4/types.h"
    4042
     
    113115    uint32_t);
    114116
    115 extern const uint8_t *ext4_superblock_get_uuid(ext4_superblock_t *);
    116 extern void ext4_superblock_set_uuid(ext4_superblock_t *, const uint8_t *);
     117extern void ext4_superblock_get_uuid(ext4_superblock_t *, uuid_t *);
     118extern void ext4_superblock_set_uuid(ext4_superblock_t *, uuid_t *);
    117119extern const char *ext4_superblock_get_volume_name(ext4_superblock_t *);
    118120extern void ext4_superblock_set_volume_name(ext4_superblock_t *, const char *);
     
    162164extern uint32_t ext4_superblock_get_inodes_in_group(ext4_superblock_t *,
    163165    uint32_t);
     166extern errno_t ext4_superblock_create(size_t, uint64_t, ext4_superblock_t **);
     167extern uint32_t ext4_superblock_get_group_backup_blocks(ext4_superblock_t *,
     168    uint32_t);
    164169
    165170#endif
  • uspace/lib/ext4/include/ext4/types.h

    r8867cf6 raab85d90  
    11/*
     2 * Copyright (c) 2018 Jiri Svoboda
    23 * Copyright (c) 2011 Martin Sucha
    34 * Copyright (c) 2012 Frantisek Princ
     
    143144
    144145
     146#define EXT4_GOOD_OLD_REV 0
     147#define EXT4_DYNAMIC_REV 1
     148
    145149#define EXT4_SUPERBLOCK_MAGIC   0xEF53
    146150#define EXT4_SUPERBLOCK_SIZE    1024
     
    276280#define EXT4_MAX_BLOCK_SIZE   65536  /* 64 KiB */
    277281#define EXT4_REV0_INODE_SIZE  128
     282#define EXT4_REV0_FIRST_INO   11
    278283
    279284#define EXT4_INODE_BLOCK_SIZE  512
  • uspace/lib/ext4/src/balloc.c

    r8867cf6 raab85d90  
    11/*
     2 * Copyright (c) 2018 Jiri Svoboda
    23 * Copyright (c) 2012 Frantisek Princ
    34 * All rights reserved.
     
    251252        uint64_t itable = ext4_block_group_get_inode_table_first_block(
    252253            bg_ref->block_group, sb);
    253         uint32_t itable_sz = ext4_filesystem_bg_get_itable_size(sb, bg_ref);
     254        uint32_t itable_sz = ext4_filesystem_bg_get_itable_size(sb,
     255            bg_ref->index);
    254256
    255257        if (!ext4_superblock_has_feature_incompatible(sb,
  • uspace/lib/ext4/src/filesystem.c

    r8867cf6 raab85d90  
    11/*
     2 * Copyright (c) 2018 Jiri Svoboda
    23 * Copyright (c) 2011 Martin Sucha
    34 * Copyright (c) 2012 Frantisek Princ
     
    4748#include "ext4/bitmap.h"
    4849#include "ext4/block_group.h"
     50#include "ext4/directory.h"
    4951#include "ext4/extent.h"
    5052#include "ext4/filesystem.h"
     
    5557
    5658static errno_t ext4_filesystem_check_features(ext4_filesystem_t *, bool *);
     59static errno_t ext4_filesystem_init_block_groups(ext4_filesystem_t *);
     60static errno_t ext4_filesystem_alloc_this_inode(ext4_filesystem_t *,
     61    uint32_t, ext4_inode_ref_t **, int);
     62static uint32_t ext4_filesystem_inodes_per_block(ext4_superblock_t *);
    5763
    5864/** Initialize filesystem for opening.
     
    155161        block_cache_fini(fs->device);
    156162        block_fini(fs->device);
     163}
     164
     165/** Create lost+found directory.
     166 *
     167 * @param fs Filesystem
     168 * @return EOK on success or error code
     169 */
     170static errno_t ext4_filesystem_create_lost_found(ext4_filesystem_t *fs,
     171    ext4_inode_ref_t *root_dir_ref)
     172{
     173        errno_t rc;
     174        ext4_inode_ref_t *inode_ref;
     175
     176        rc = ext4_filesystem_alloc_inode(fs, &inode_ref, L_DIRECTORY);
     177        if (rc != EOK)
     178                goto error;
     179
     180        rc = ext4_directory_add_entry(inode_ref, ".", inode_ref);
     181        if (rc != EOK)
     182                goto error;
     183
     184        rc = ext4_directory_add_entry(inode_ref, "..", root_dir_ref);
     185        if (rc != EOK)
     186                goto error;
     187
     188        rc = ext4_directory_add_entry(root_dir_ref, "lost+found", inode_ref);
     189        if (rc != EOK)
     190                goto error;
     191
     192        inode_ref->dirty = true;
     193
     194        uint16_t nlinks = ext4_inode_get_links_count(inode_ref->inode);
     195        ext4_inode_set_links_count(inode_ref->inode, nlinks + 1);
     196
     197        rc = ext4_filesystem_put_inode_ref(inode_ref);
     198        if (rc != EOK)
     199                goto error;
     200
     201error:
     202        return rc;
     203}
     204
     205/** Create root directory.
     206 *
     207 * @param fs Filesystem
     208 * @return EOK on success or error code
     209 */
     210static errno_t ext4_filesystem_create_root_dir(ext4_filesystem_t *fs)
     211{
     212        errno_t rc;
     213        ext4_inode_ref_t *inode_ref;
     214
     215        rc = ext4_filesystem_get_inode_ref(fs, EXT4_INODE_ROOT_INDEX,
     216            &inode_ref);
     217        if (rc != EOK)
     218                goto error;
     219
     220        inode_ref->dirty = true;
     221
     222        rc = ext4_directory_add_entry(inode_ref, ".", inode_ref);
     223        if (rc != EOK)
     224                goto error;
     225
     226        rc = ext4_directory_add_entry(inode_ref, "..", inode_ref);
     227        if (rc != EOK)
     228                goto error;
     229
     230        uint16_t nlinks = ext4_inode_get_links_count(inode_ref->inode);
     231        ext4_inode_set_links_count(inode_ref->inode, nlinks + 1);
     232
     233        rc = ext4_filesystem_create_lost_found(fs, inode_ref);
     234        if (rc != EOK)
     235                goto error;
     236
     237        nlinks = ext4_inode_get_links_count(inode_ref->inode);
     238        ext4_inode_set_links_count(inode_ref->inode, nlinks + 1);
     239
     240        rc = ext4_filesystem_put_inode_ref(inode_ref);
     241        if (rc != EOK)
     242                goto error;
     243
     244error:
     245        return rc;
     246}
     247
     248/** Create new filesystem.
     249 *
     250 * @param service_id Block device where to create new filesystem
     251 */
     252errno_t ext4_filesystem_create(service_id_t service_id)
     253{
     254        errno_t rc;
     255        ext4_superblock_t *superblock = NULL;
     256        ext4_filesystem_t *fs = NULL;
     257        size_t dev_bsize;
     258        aoff64_t dev_nblocks;
     259        ext4_inode_ref_t *inode_ref = NULL;
     260        bool block_inited = false;
     261        bool fs_inited = false;
     262        uint32_t idx;
     263
     264        /* Initialize block library (4096 is size of communication channel) */
     265        rc = block_init(service_id, 4096);
     266        if (rc != EOK)
     267                goto err;
     268
     269        block_inited = true;
     270
     271        /* Get device block size */
     272        rc = block_get_bsize(service_id, &dev_bsize);
     273        if (rc != EOK)
     274                goto err;
     275
     276        /* Get device number of blocks */
     277        rc = block_get_nblocks(service_id, &dev_nblocks);
     278        if (rc != EOK)
     279                goto err;
     280
     281        /* Create superblock */
     282        rc = ext4_superblock_create(dev_bsize, dev_nblocks, &superblock);
     283        if (rc != EOK)
     284                goto err;
     285
     286        /* Write superblock to device */
     287        rc = ext4_superblock_write_direct(service_id, superblock);
     288        if (rc != EOK)
     289                goto err;
     290
     291        block_fini(service_id);
     292        block_inited = false;
     293        ext4_superblock_release(superblock);
     294        superblock = NULL;
     295
     296        fs = calloc(1, sizeof(ext4_filesystem_t));
     297        if (fs == NULL)
     298                goto err;
     299
     300        /* Open file system */
     301        rc = ext4_filesystem_init(fs, service_id, CACHE_MODE_WT);
     302        if (rc != EOK)
     303                goto err;
     304
     305        fs_inited = true;
     306
     307        /* Init block groups */
     308        rc = ext4_filesystem_init_block_groups(fs);
     309        if (rc != EOK)
     310                goto err;
     311
     312        /* Reserved i-nodes */
     313        for (idx = 1; idx < EXT4_REV0_FIRST_INO; idx++) {
     314                if (idx == EXT4_INODE_ROOT_INDEX) {
     315                        rc = ext4_filesystem_alloc_this_inode(fs, idx,
     316                            &inode_ref, L_DIRECTORY);
     317                        if (rc != EOK)
     318                                goto error;
     319
     320                        rc = ext4_filesystem_put_inode_ref(inode_ref);
     321                        if (rc != EOK)
     322                                goto error;
     323                } else {
     324                        /* Allocate inode by allocation algorithm */
     325                        errno_t rc = ext4_ialloc_alloc_this_inode(fs, idx,
     326                            false);
     327                        if (rc != EOK)
     328                                return rc;
     329
     330                        rc = ext4_filesystem_get_inode_ref(fs, idx,
     331                            &inode_ref);
     332                        if (rc != EOK)
     333                                goto error;
     334
     335                        memset(inode_ref->inode, 0, ext4_superblock_get_inode_size(fs->superblock));
     336                        inode_ref->dirty = true;
     337
     338                        rc = ext4_filesystem_put_inode_ref(inode_ref);
     339                        if (rc != EOK)
     340                                goto error;
     341                }
     342        }
     343
     344        /* Create root directory */
     345        rc = ext4_filesystem_create_root_dir(fs);
     346        if (rc != EOK)
     347                goto err;
     348
     349        /* Write superblock to device */
     350        rc = ext4_superblock_write_direct(service_id, fs->superblock);
     351        if (rc != EOK)
     352                goto err;
     353
     354        ext4_filesystem_fini(fs);
     355        free(fs);
     356        return EOK;
     357err:
     358        if (fs_inited)
     359                ext4_filesystem_fini(fs);
     360        if (fs != NULL)
     361                free(fs);
     362        if (superblock != NULL)
     363                ext4_superblock_release(superblock);
     364        if (block_inited)
     365                block_fini(service_id);
     366        return rc;
     367error:
     368        return rc;
    157369}
    158370
     
    373585}
    374586
     587/** Initialize block group structures
     588 */
     589static errno_t ext4_filesystem_init_block_groups(ext4_filesystem_t *fs)
     590{
     591        errno_t rc;
     592        block_t *block;
     593        aoff64_t b;
     594        ext4_block_group_t *bg;
     595        ext4_superblock_t *sb = fs->superblock;
     596        ext4_block_group_ref_t *bg_ref;
     597
     598        uint32_t block_group_count = ext4_superblock_get_block_group_count(sb);
     599        uint32_t block_size = ext4_superblock_get_block_size(sb);
     600        uint32_t desc_size = ext4_superblock_get_desc_size(fs->superblock);
     601        /* Number of descriptors per block */
     602        uint32_t descriptors_per_block =
     603            ext4_superblock_get_block_size(fs->superblock) / desc_size;
     604        /* Block where block group descriptor (and first block group) starts */
     605        aoff64_t block_id =
     606            ext4_superblock_get_first_data_block(fs->superblock) + 1;
     607        /* Number of blocks containing descriptor table */
     608        uint32_t dtable_blocks =
     609            (block_group_count + descriptors_per_block - 1) /
     610            descriptors_per_block;
     611
     612        uint32_t bg_index;
     613        aoff64_t bg_block0;
     614        uint32_t dcnt;
     615        uint32_t i;
     616        uint32_t now;
     617
     618        aoff64_t block_bitmap;
     619        aoff64_t inode_bitmap;
     620        aoff64_t inode_table;
     621        uint32_t free_blocks;
     622        uint32_t free_inodes;
     623        uint32_t used_dirs;
     624        uint32_t reserved;
     625        uint32_t inode_table_blocks;
     626
     627        dcnt = block_group_count;
     628
     629        /* Fill in block descriptors */
     630        b = block_id;
     631        bg_index = 0;
     632        bg_block0 = block_id;
     633        while (dcnt > 0) {
     634                rc = block_get(&block, fs->device, b, BLOCK_FLAGS_NOREAD);
     635                if (rc != EOK)
     636                        return rc;
     637
     638                if (dcnt > descriptors_per_block)
     639                        now = descriptors_per_block;
     640                else
     641                        now = dcnt;
     642
     643                memset(block->data, 0, block_size);
     644
     645                for (i = 0; i < now; i++) {
     646                        bg = (ext4_block_group_t *) (block->data + i *
     647                            desc_size);
     648
     649                        block_bitmap = bg_block0 + dtable_blocks;
     650                        inode_bitmap = block_bitmap + 1;
     651                        inode_table = inode_bitmap + 1;
     652
     653                        free_blocks = ext4_superblock_get_blocks_in_group(sb,
     654                            bg_index);
     655
     656                        free_inodes =
     657                            ext4_filesystem_bg_get_itable_size(sb, bg_index) *
     658                            ext4_filesystem_inodes_per_block(sb);
     659                        used_dirs = 0;
     660
     661                        ext4_block_group_set_block_bitmap(bg, sb, block_bitmap);
     662                        ext4_block_group_set_inode_bitmap(bg, sb, inode_bitmap);
     663                        ext4_block_group_set_inode_table_first_block(bg, sb,
     664                            inode_table);
     665                        ext4_block_group_set_free_blocks_count(bg, sb,
     666                            free_blocks);
     667                        ext4_block_group_set_free_inodes_count(bg, sb,
     668                            free_inodes);
     669                        ext4_block_group_set_used_dirs_count(bg, sb,
     670                            used_dirs);
     671
     672                        /// XX Lazy
     673                        ext4_block_group_set_flag(bg,
     674                            EXT4_BLOCK_GROUP_BLOCK_UNINIT);
     675                        ext4_block_group_set_flag(bg,
     676                            EXT4_BLOCK_GROUP_INODE_UNINIT);
     677
     678                        bg_index++;
     679                        bg_block0 += ext4_superblock_get_blocks_per_group(sb);
     680                }
     681
     682                block->dirty = true;
     683
     684                rc = block_put(block);
     685                if (rc != EOK)
     686                        return rc;
     687
     688                ++b;
     689                dcnt -= now;
     690        }
     691
     692        /* This initializes the bitmaps and inode table */
     693        for (bg_index = 0; bg_index < block_group_count; bg_index++) {
     694                rc = ext4_filesystem_get_block_group_ref(fs, bg_index, &bg_ref);
     695                if (rc != EOK)
     696                        return rc;
     697
     698                /*
     699                 * Adjust number of free blocks
     700                 */
     701                free_blocks = ext4_superblock_get_blocks_in_group(sb, bg_index);
     702                reserved = ext4_filesystem_bg_get_backup_blocks(bg_ref);
     703                inode_table_blocks = ext4_filesystem_bg_get_itable_size(sb,
     704                    bg_ref->index);
     705                /* One for block bitmap one for inode bitmap */
     706                free_blocks = free_blocks - reserved - 2 - inode_table_blocks;
     707
     708                ext4_block_group_set_free_blocks_count(bg_ref->block_group,
     709                    sb, free_blocks);
     710                bg_ref->dirty = true;
     711
     712                rc = ext4_filesystem_put_block_group_ref(bg_ref);
     713                if (rc != EOK)
     714                        return rc;
     715        }
     716
     717        return EOK;
     718}
     719
    375720/** Initialize block bitmap in block group.
    376721 *
     
    392737        uint64_t bitmap_inode_addr = ext4_block_group_get_inode_bitmap(
    393738            bg_ref->block_group, bg_ref->fs->superblock);
     739        uint32_t blocks_group = ext4_superblock_get_blocks_per_group(sb);
     740        uint32_t bg_blocks = ext4_superblock_get_blocks_in_group(sb,
     741            bg_ref->index);
    394742
    395743        block_t *bitmap_block;
     
    428776        itb = ext4_block_group_get_inode_table_first_block(bg_ref->block_group,
    429777            sb);
    430         sz = ext4_filesystem_bg_get_itable_size(sb, bg_ref);
     778        sz = ext4_filesystem_bg_get_itable_size(sb, bg_ref->index);
    431779
    432780        for (i = 0; i < sz; ++i, ++itb) {
     
    438786        }
    439787
     788        /* For last group need to mark blocks which are outside of the FS */
     789        for (uint32_t block = bg_blocks; block < blocks_group; block++) {
     790                ext4_bitmap_set_bit(bitmap, block);
     791        }
     792
    440793        bitmap_block->dirty = true;
    441794
     
    498851        ext4_superblock_t *sb = bg_ref->fs->superblock;
    499852
    500         uint32_t inode_size = ext4_superblock_get_inode_size(sb);
    501853        uint32_t block_size = ext4_superblock_get_block_size(sb);
    502         uint32_t inodes_per_block = block_size / inode_size;
     854        uint32_t inodes_per_block = ext4_filesystem_inodes_per_block(sb);
    503855
    504856        uint32_t inodes_in_group =
     
    612964                    EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
    613965                        rc = ext4_filesystem_init_inode_table(newref);
    614                         if (rc != EOK)
     966                        if (rc != EOK) {
     967                                block_put(newref->block);
     968                                free(newref);
    615969                                return rc;
     970                        }
    616971
    617972                        ext4_block_group_set_flag(newref->block_group,
     
    6761031/** Get the size of the block group's inode table
    6771032 *
    678  * @param sb     Pointer to the superblock
    679  * @param bg_ref Pointer to the block group reference
    680  *
    681  * @return       Size of the inode table in blocks.
     1033 * @param sb       Pointer to the superblock
     1034 * @param bg_index Block group index
     1035 *
     1036 * @return         Size of the inode table in blocks.
    6821037 */
    6831038uint32_t ext4_filesystem_bg_get_itable_size(ext4_superblock_t *sb,
    684     ext4_block_group_ref_t *bg_ref)
     1039    uint32_t bg_index)
    6851040{
    6861041        uint32_t itable_size;
     
    6901045        uint32_t block_size = ext4_superblock_get_block_size(sb);
    6911046
    692         if (bg_ref->index < block_group_count - 1) {
     1047        if (bg_index < block_group_count - 1) {
    6931048                itable_size = inodes_per_group * inode_table_item_size;
    6941049        } else {
     
    7031058}
    7041059
    705 /* Check if n is a power of p */
    706 static bool is_power_of(uint32_t n, unsigned p)
    707 {
    708         if (p == 1 && n != p)
    709                 return false;
    710 
    711         while (n != p) {
    712                 if (n < p)
    713                         return false;
    714                 else if ((n % p) != 0)
    715                         return false;
    716 
    717                 n /= p;
    718         }
    719 
    720         return true;
    721 }
    722 
    7231060/** Get the number of blocks used by superblock + gdt + reserved gdt backups
    7241061 *
     
    7291066uint32_t ext4_filesystem_bg_get_backup_blocks(ext4_block_group_ref_t *bg)
    7301067{
    731         uint32_t const idx = bg->index;
    732         uint32_t r = 0;
    733         bool has_backups = false;
    734         ext4_superblock_t *sb = bg->fs->superblock;
    735 
    736         /* First step: determine if the block group contains the backups */
    737 
    738         if (idx <= 1)
    739                 has_backups = true;
    740         else {
    741                 if (ext4_superblock_has_feature_compatible(sb,
    742                     EXT4_FEATURE_COMPAT_SPARSE_SUPER2)) {
    743                         uint32_t g1, g2;
    744 
    745                         ext4_superblock_get_backup_groups_sparse2(sb,
    746                             &g1, &g2);
    747 
    748                         if (idx == g1 || idx == g2)
    749                                 has_backups = true;
    750                 } else if (!ext4_superblock_has_feature_read_only(sb,
    751                     EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
    752                         /*
    753                          * Very old fs were all block groups have
    754                          * superblock and block descriptors backups.
    755                          */
    756                         has_backups = true;
    757                 } else {
    758                         if ((idx & 1) && (is_power_of(idx, 3) ||
    759                             is_power_of(idx, 5) || is_power_of(idx, 7)))
    760                                 has_backups = true;
    761                 }
    762         }
    763 
    764         if (has_backups) {
    765                 uint32_t bg_count;
    766                 uint32_t bg_desc_sz;
    767                 uint32_t gdt_table; /* Size of the GDT in blocks */
    768                 uint32_t block_size = ext4_superblock_get_block_size(sb);
    769 
    770                 /*
    771                  * Now we know that this block group has backups,
    772                  * we have to compute how many blocks are reserved
    773                  * for them
    774                  */
    775 
    776                 if (idx == 0 && block_size == 1024) {
    777                         /*
    778                          * Special case for first group were the boot block
    779                          * resides
    780                          */
    781                         r++;
    782                 }
    783 
    784                 /* This accounts for the superblock */
    785                 r++;
    786 
    787                 /* Add the number of blocks used for the GDT */
    788                 bg_count = ext4_superblock_get_block_group_count(sb);
    789                 bg_desc_sz = ext4_superblock_get_desc_size(sb);
    790                 gdt_table = ROUND_UP(bg_count * bg_desc_sz, block_size) /
    791                     block_size;
    792 
    793                 r += gdt_table;
    794 
    795                 /* And now the number of reserved GDT blocks */
    796                 r += ext4_superblock_get_reserved_gdt_blocks(sb);
    797         }
    798 
    799         return r;
     1068        return ext4_superblock_get_group_backup_blocks(bg->fs->superblock,
     1069            bg->index);
    8001070}
    8011071
     
    9271197}
    9281198
    929 /** Allocate new i-node in the filesystem.
    930  *
    931  * @param fs        Filesystem to allocated i-node on
     1199/** Initialize newly allocated i-node in the filesystem.
     1200 *
     1201 * @param fs        Filesystem to initialize i-node on
     1202 * @param index     I-node index
    9321203 * @param inode_ref Output pointer to return reference to allocated i-node
    9331204 * @param flags     Flags to be set for newly created i-node
     
    9361207 *
    9371208 */
    938 errno_t ext4_filesystem_alloc_inode(ext4_filesystem_t *fs,
     1209static errno_t ext4_filesystem_init_inode(ext4_filesystem_t *fs, uint32_t index,
    9391210    ext4_inode_ref_t **inode_ref, int flags)
    9401211{
     
    9441215                is_dir = true;
    9451216
    946         /* Allocate inode by allocation algorithm */
    947         uint32_t index;
    948         errno_t rc = ext4_ialloc_alloc_inode(fs, &index, is_dir);
    949         if (rc != EOK)
    950                 return rc;
    951 
    9521217        /* Load i-node from on-disk i-node table */
    953         rc = ext4_filesystem_get_inode_ref(fs, index, inode_ref);
     1218        errno_t rc = ext4_filesystem_get_inode_ref(fs, index, inode_ref);
    9541219        if (rc != EOK) {
    9551220                ext4_ialloc_free_inode(fs, index, is_dir);
     
    10211286}
    10221287
     1288/** Allocate new i-node in the filesystem.
     1289 *
     1290 * @param fs        Filesystem to allocated i-node on
     1291 * @param inode_ref Output pointer to return reference to allocated i-node
     1292 * @param flags     Flags to be set for newly created i-node
     1293 *
     1294 * @return Error code
     1295 *
     1296 */
     1297errno_t ext4_filesystem_alloc_inode(ext4_filesystem_t *fs,
     1298    ext4_inode_ref_t **inode_ref, int flags)
     1299{
     1300        /* Check if newly allocated i-node will be a directory */
     1301        bool is_dir = false;
     1302        if (flags & L_DIRECTORY)
     1303                is_dir = true;
     1304
     1305        /* Allocate inode by allocation algorithm */
     1306        uint32_t index;
     1307        errno_t rc = ext4_ialloc_alloc_inode(fs, &index, is_dir);
     1308        if (rc != EOK)
     1309                return rc;
     1310
     1311        rc = ext4_filesystem_init_inode(fs, index, inode_ref, flags);
     1312        if (rc != EOK) {
     1313                ext4_ialloc_free_inode(fs, index, is_dir);
     1314                return rc;
     1315        }
     1316
     1317        return EOK;
     1318}
     1319
     1320/** Allocate specific i-node in the filesystem.
     1321 *
     1322 * @param fs        Filesystem to allocated i-node on
     1323 * @param index     Index of i-node to allocate
     1324 * @param inode_ref Output pointer to return reference to allocated i-node
     1325 * @param flags     Flags to be set for newly created i-node
     1326 *
     1327 * @return Error code
     1328 *
     1329 */
     1330static errno_t ext4_filesystem_alloc_this_inode(ext4_filesystem_t *fs,
     1331    uint32_t index, ext4_inode_ref_t **inode_ref, int flags)
     1332{
     1333        /* Check if newly allocated i-node will be a directory */
     1334        bool is_dir = false;
     1335        if (flags & L_DIRECTORY)
     1336                is_dir = true;
     1337
     1338        /* Allocate inode by allocation algorithm */
     1339        errno_t rc = ext4_ialloc_alloc_this_inode(fs, index, is_dir);
     1340        if (rc != EOK)
     1341                return rc;
     1342
     1343        rc = ext4_filesystem_init_inode(fs, index, inode_ref, flags);
     1344        if (rc != EOK) {
     1345                ext4_ialloc_free_inode(fs, index, is_dir);
     1346                return rc;
     1347        }
     1348
     1349        return EOK;
     1350}
     1351
    10231352/** Release i-node and mark it as free.
    10241353 *
     
    16742003}
    16752004
     2005/** Get the number of inodes per block.
     2006 *
     2007 * @param sb Superblock
     2008 * @return   Number of inodes per block
     2009 */
     2010static uint32_t ext4_filesystem_inodes_per_block(ext4_superblock_t *sb)
     2011{
     2012        uint32_t inode_size = ext4_superblock_get_inode_size(sb);
     2013        uint32_t block_size = ext4_superblock_get_block_size(sb);
     2014
     2015        return block_size / inode_size;
     2016}
     2017
    16762018/**
    16772019 * @}
  • uspace/lib/ext4/src/ialloc.c

    r8867cf6 raab85d90  
    11/*
     2 * Copyright (c) 2018 Jiri Svoboda
    23 * Copyright (c) 2012 Frantisek Princ
    34 * All rights reserved.
     
    311312}
    312313
     314/** Allocate a specific I-node.
     315 *
     316 * @param fs     Filesystem to allocate i-node on
     317 * @param inode  I-node to allocate
     318 * @param is_dir Flag if allocated i-node will be file or directory
     319 *
     320 * @return Error code
     321 *
     322 */
     323errno_t ext4_ialloc_alloc_this_inode(ext4_filesystem_t *fs, uint32_t inode,
     324    bool is_dir)
     325{
     326        ext4_superblock_t *sb = fs->superblock;
     327
     328        uint32_t bgid = ext4_ialloc_get_bgid_of_inode(sb, inode);
     329        uint32_t sb_free_inodes = ext4_superblock_get_free_inodes_count(sb);
     330
     331        /* Load block group */
     332        ext4_block_group_ref_t *bg_ref;
     333        errno_t rc = ext4_filesystem_get_block_group_ref(fs, bgid, &bg_ref);
     334        if (rc != EOK)
     335                return rc;
     336
     337        ext4_block_group_t *bg = bg_ref->block_group;
     338
     339        /* Read necessary values for algorithm */
     340        uint32_t free_inodes = ext4_block_group_get_free_inodes_count(bg, sb);
     341        uint32_t used_dirs = ext4_block_group_get_used_dirs_count(bg, sb);
     342
     343        /* Load block with bitmap */
     344        uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap(
     345            bg_ref->block_group, sb);
     346
     347        block_t *bitmap_block;
     348        rc = block_get(&bitmap_block, fs->device, bitmap_block_addr,
     349            BLOCK_FLAGS_NONE);
     350        if (rc != EOK) {
     351                ext4_filesystem_put_block_group_ref(bg_ref);
     352                return rc;
     353        }
     354
     355        /* Allocate i-node in the bitmap */
     356        uint32_t index_in_group = ext4_ialloc_inode2index_in_group(sb, inode);
     357        ext4_bitmap_set_bit(bitmap_block->data, index_in_group);
     358
     359        /* Save the bitmap */
     360        bitmap_block->dirty = true;
     361
     362        rc = block_put(bitmap_block);
     363        if (rc != EOK) {
     364                ext4_filesystem_put_block_group_ref(bg_ref);
     365                return rc;
     366        }
     367
     368        /* Modify filesystem counters */
     369        free_inodes--;
     370        ext4_block_group_set_free_inodes_count(bg, sb, free_inodes);
     371
     372        /* Increment used directories counter */
     373        if (is_dir) {
     374                used_dirs++;
     375                ext4_block_group_set_used_dirs_count(bg, sb, used_dirs);
     376        }
     377
     378        /* Decrease unused inodes count */
     379        if (ext4_block_group_has_flag(bg,
     380            EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
     381                uint32_t unused =
     382                    ext4_block_group_get_itable_unused(bg, sb);
     383
     384                uint32_t inodes_in_group =
     385                    ext4_superblock_get_inodes_in_group(sb, bgid);
     386
     387                uint32_t free = inodes_in_group - unused;
     388
     389                if (index_in_group >= free) {
     390                        unused = inodes_in_group - (index_in_group + 1);
     391                        ext4_block_group_set_itable_unused(bg, sb, unused);
     392                }
     393        }
     394
     395        /* Save modified block group */
     396        bg_ref->dirty = true;
     397
     398        rc = ext4_filesystem_put_block_group_ref(bg_ref);
     399        if (rc != EOK)
     400                return rc;
     401
     402        /* Update superblock */
     403        sb_free_inodes--;
     404        ext4_superblock_set_free_inodes_count(sb, sb_free_inodes);
     405
     406        return EOK;
     407}
     408
    313409/**
    314410 * @}
  • 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 * @}
  • uspace/srv/volsrv/mkfs.c

    r8867cf6 raab85d90  
    120120                break;
    121121        case fs_ext4:
     122                cmd = "/app/mkext4";
     123                break;
    122124        case fs_cdfs:
    123125                cmd = NULL;
Note: See TracChangeset for help on using the changeset viewer.