Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/ext4/libext4_filesystem.c

    rd1538a1 rfc22069  
    3939#include <errno.h>
    4040#include <malloc.h>
     41#include <ipc/vfs.h>
     42#include <align.h>
     43#include <crypto.h>
    4144#include "libext4.h"
    4245
     
    5255    enum cache_mode cmode)
    5356{
     57        int rc;
     58        ext4_superblock_t *temp_superblock = NULL;
     59
    5460        fs->device = service_id;
    55        
     61
    5662        /* Initialize block library (4096 is size of communication channel) */
    57         int rc = block_init(EXCHANGE_SERIALIZE, fs->device, 4096);
     63        rc = block_init(fs->device, 4096);
    5864        if (rc != EOK)
    59                 return rc;
    60        
     65                goto err;
     66
    6167        /* Read superblock from device to memory */
    62         ext4_superblock_t *temp_superblock;
    6368        rc = ext4_superblock_read_direct(fs->device, &temp_superblock);
    64         if (rc != EOK) {
    65                 block_fini(fs->device);
    66                 return rc;
    67         }
    68        
     69        if (rc != EOK)
     70                goto err_1;
     71
    6972        /* Read block size from superblock and check */
    7073        uint32_t block_size = ext4_superblock_get_block_size(temp_superblock);
    7174        if (block_size > EXT4_MAX_BLOCK_SIZE) {
    72                 block_fini(fs->device);
    73                 return ENOTSUP;
    74         }
    75        
     75                rc = ENOTSUP;
     76                goto err_1;
     77        }
     78
    7679        /* Initialize block caching by libblock */
    7780        rc = block_cache_init(service_id, block_size, 0, cmode);
    78         if (rc != EOK) {
    79                 block_fini(fs->device);
    80                 return rc;
    81         }
    82        
     81        if (rc != EOK)
     82                goto err_1;
     83
    8384        /* Compute limits for indirect block levels */
    8485        uint32_t block_ids_per_block = block_size / sizeof(uint32_t);
     
    9192                    fs->inode_blocks_per_level[i];
    9293        }
    93        
     94
    9495        /* Return loaded superblock */
    9596        fs->superblock = temp_superblock;
    96        
     97
    9798        uint16_t state = ext4_superblock_get_state(fs->superblock);
    98        
     99
    99100        if (((state & EXT4_SUPERBLOCK_STATE_VALID_FS) !=
    100101            EXT4_SUPERBLOCK_STATE_VALID_FS) ||
    101102            ((state & EXT4_SUPERBLOCK_STATE_ERROR_FS) ==
    102103            EXT4_SUPERBLOCK_STATE_ERROR_FS)) {
    103                 block_cache_fini(fs->device);
    104                 block_fini(fs->device);
    105                 return ENOTSUP;
    106         }
    107        
     104                rc = ENOTSUP;
     105                goto err_2;
     106        }
     107
    108108        /* Mark system as mounted */
    109109        ext4_superblock_set_state(fs->superblock, EXT4_SUPERBLOCK_STATE_ERROR_FS);
    110110        rc = ext4_superblock_write_direct(fs->device, fs->superblock);
    111         if (rc != EOK) {
    112                 block_cache_fini(fs->device);
    113                 block_fini(fs->device);
    114                 return rc;
    115         }
    116        
     111        if (rc != EOK)
     112                goto err_2;
     113
    117114        uint16_t mnt_count = ext4_superblock_get_mount_count(fs->superblock);
    118115        ext4_superblock_set_mount_count(fs->superblock, mnt_count + 1);
    119        
     116
    120117        return EOK;
     118
     119err_2:
     120        block_cache_fini(fs->device);
     121err_1:
     122        block_fini(fs->device);
     123err:
     124        if (temp_superblock)
     125                ext4_superblock_release(temp_superblock);
     126        return rc;
    121127}
    122128
     
    136142        /* Release memory space for superblock */
    137143        free(fs->superblock);
    138        
     144
    139145        /* Finish work with block library */
    140146        block_cache_fini(fs->device);
     
    247253}
    248254
     255/** Convert the absolute block number to group number
     256 *
     257 * @param sb    Pointer to the superblock
     258 * @param b     Absolute block number
     259 *
     260 * @return      Group number
     261 */
     262uint32_t ext4_filesystem_blockaddr2group(ext4_superblock_t *sb, uint64_t b)
     263{
     264        uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
     265        uint32_t first_block = ext4_superblock_get_first_data_block(sb);
     266
     267        return (b - first_block) / blocks_per_group;
     268}
     269
    249270/** Initialize block bitmap in block group.
    250271 *
     
    256277static int ext4_filesystem_init_block_bitmap(ext4_block_group_ref_t *bg_ref)
    257278{
     279        uint64_t itb;
     280        uint32_t sz;
     281        uint32_t i;
     282
    258283        /* Load bitmap */
    259         uint32_t bitmap_block_addr = ext4_block_group_get_block_bitmap(
     284        ext4_superblock_t *sb = bg_ref->fs->superblock;
     285        uint64_t bitmap_block_addr = ext4_block_group_get_block_bitmap(
     286            bg_ref->block_group, bg_ref->fs->superblock);
     287        uint64_t bitmap_inode_addr = ext4_block_group_get_inode_bitmap(
    260288            bg_ref->block_group, bg_ref->fs->superblock);
    261289       
     
    269297       
    270298        /* Initialize all bitmap bits to zero */
    271         uint32_t block_size = ext4_superblock_get_block_size(bg_ref->fs->superblock);
     299        uint32_t block_size = ext4_superblock_get_block_size(sb);
    272300        memset(bitmap, 0, block_size);
    273301       
    274         /* Determine first block and first data block in group */
    275         uint32_t first_idx = 0;
    276        
    277         uint32_t first_data = ext4_balloc_get_first_data_block_in_group(
    278             bg_ref->fs->superblock, bg_ref);
    279         uint32_t first_data_idx = ext4_filesystem_blockaddr2_index_in_group(
    280             bg_ref->fs->superblock, first_data);
    281        
     302        /* Determine the number of reserved blocks in the group */
     303        uint32_t reserved_cnt = ext4_filesystem_bg_get_backup_blocks(bg_ref);
     304
    282305        /* Set bits from to first block to first data block - 1 to one (allocated) */
    283         for (uint32_t block = first_idx; block < first_data_idx; ++block)
     306        for (uint32_t block = 0; block < reserved_cnt; ++block)
    284307                ext4_bitmap_set_bit(bitmap, block);
    285        
     308
     309        uint32_t bitmap_block_gid = ext4_filesystem_blockaddr2group(sb,
     310            bitmap_block_addr);
     311        if (bitmap_block_gid == bg_ref->index) {
     312                ext4_bitmap_set_bit(bitmap,
     313                    ext4_filesystem_blockaddr2_index_in_group(sb, bitmap_block_addr));
     314        }
     315
     316        uint32_t bitmap_inode_gid = ext4_filesystem_blockaddr2group(sb,
     317            bitmap_inode_addr);
     318        if (bitmap_inode_gid == bg_ref->index) {
     319                ext4_bitmap_set_bit(bitmap,
     320                    ext4_filesystem_blockaddr2_index_in_group(sb, bitmap_inode_addr));
     321        }
     322
     323        itb = ext4_block_group_get_inode_table_first_block(bg_ref->block_group,
     324            sb);
     325        sz = ext4_filesystem_bg_get_itable_size(sb, bg_ref);
     326
     327        for (i = 0; i < sz; ++i, ++itb) {
     328                uint32_t gid = ext4_filesystem_blockaddr2group(sb, itb);
     329                if (gid == bg_ref->index) {
     330                        ext4_bitmap_set_bit(bitmap,
     331                            ext4_filesystem_blockaddr2_index_in_group(sb, itb));
     332                }
     333        }
     334
    286335        bitmap_block->dirty = true;
    287336       
     
    420469        }
    421470       
    422         /* Inititialize in-memory representation */
     471        /* Initialize in-memory representation */
    423472        newref->block_group = newref->block->data + offset;
    424473        newref->fs = fs;
     
    485534        /* If checksum not supported, 0 will be returned */
    486535        uint16_t crc = 0;
    487        
     536
    488537        /* Compute the checksum only if the filesystem supports it */
    489538        if (ext4_superblock_has_feature_read_only(sb,
     
    498547               
    499548                /* Initialization */
    500                 crc = crc16(~0, sb->uuid, sizeof(sb->uuid));
     549                crc = crc16_ibm(~0, sb->uuid, sizeof(sb->uuid));
    501550               
    502551                /* Include index of block group */
    503                 crc = crc16(crc, (uint8_t *) &le_group, sizeof(le_group));
     552                crc = crc16_ibm(crc, (uint8_t *) &le_group, sizeof(le_group));
    504553               
    505554                /* Compute crc from the first part (stop before checksum field) */
    506                 crc = crc16(crc, (uint8_t *) bg, offset);
     555                crc = crc16_ibm(crc, (uint8_t *) bg, offset);
    507556               
    508557                /* Skip checksum */
     
    513562                    EXT4_FEATURE_INCOMPAT_64BIT)) &&
    514563                    (offset < ext4_superblock_get_desc_size(sb)))
    515                         crc = crc16(crc, ((uint8_t *) bg) + offset,
     564                        crc = crc16_ibm(crc, ((uint8_t *) bg) + offset,
    516565                            ext4_superblock_get_desc_size(sb) - offset);
    517566        }
     
    520569}
    521570
     571/** Get the size of the block group's inode table
     572 *
     573 * @param sb     Pointer to the superblock
     574 * @param bg_ref Pointer to the block group reference
     575 *
     576 * @return       Size of the inode table in blocks.
     577 */
     578uint32_t ext4_filesystem_bg_get_itable_size(ext4_superblock_t *sb,
     579    ext4_block_group_ref_t *bg_ref)
     580{
     581        uint32_t itable_size;
     582        uint32_t block_group_count = ext4_superblock_get_block_group_count(sb);
     583        uint16_t inode_table_item_size = ext4_superblock_get_inode_size(sb);
     584        uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
     585        uint32_t block_size = ext4_superblock_get_block_size(sb);
     586
     587        if (bg_ref->index < block_group_count - 1) {
     588                itable_size = inodes_per_group * inode_table_item_size;
     589        } else {
     590                /* Last block group could be smaller */
     591                uint32_t inodes_count_total = ext4_superblock_get_inodes_count(sb);
     592                itable_size =
     593                    (inodes_count_total - ((block_group_count - 1) * inodes_per_group)) *
     594                    inode_table_item_size;
     595        }
     596
     597        return ROUND_UP(itable_size, block_size) / block_size;
     598}
     599
     600/* Check if n is a power of p */
     601static bool is_power_of(uint32_t n, unsigned p)
     602{
     603        if (p == 1 && n != p)
     604                return false;
     605
     606        while (n != p) {
     607                if (n < p)
     608                        return false;
     609                else if ((n % p) != 0)
     610                        return false;
     611
     612                n /= p;
     613        }
     614
     615        return true;
     616}
     617
     618/** Get the number of blocks used by superblock + gdt + reserved gdt backups
     619 *
     620 * @param bg    Pointer to block group
     621 *
     622 * @return      Number of blocks
     623 */
     624uint32_t ext4_filesystem_bg_get_backup_blocks(ext4_block_group_ref_t *bg)
     625{
     626        uint32_t const idx = bg->index;
     627        uint32_t r = 0;
     628        bool has_backups = false;
     629        ext4_superblock_t *sb = bg->fs->superblock;
     630
     631        /* First step: determine if the block group contains the backups */
     632
     633        if (idx <= 1)
     634                has_backups = true;
     635        else {
     636                if (ext4_superblock_has_feature_compatible(sb,
     637                    EXT4_FEATURE_COMPAT_SPARSE_SUPER2)) {
     638                        uint32_t g1, g2;
     639
     640                        ext4_superblock_get_backup_groups_sparse2(sb,
     641                            &g1, &g2);
     642
     643                        if (idx == g1 || idx == g2)
     644                                has_backups = true;
     645                } else if (!ext4_superblock_has_feature_read_only(sb,
     646                    EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
     647                        /* Very old fs were all block groups have
     648                         * superblock and block descriptors backups.
     649                         */
     650                        has_backups = true;
     651                } else {
     652                        if ((idx & 1) && (is_power_of(idx, 3) ||
     653                            is_power_of(idx, 5) || is_power_of(idx, 7)))
     654                                has_backups = true;
     655                }
     656        }
     657
     658        if (has_backups) {
     659                uint32_t bg_count;
     660                uint32_t bg_desc_sz;
     661                uint32_t gdt_table; /* Size of the GDT in blocks */
     662                uint32_t block_size = ext4_superblock_get_block_size(sb);
     663
     664                /* Now we know that this block group has backups,
     665                 * we have to compute how many blocks are reserved
     666                 * for them
     667                 */
     668
     669                if (idx == 0 && block_size == 1024) {
     670                        /* Special case for first group were the boot block
     671                         * resides
     672                         */
     673                        r++;
     674                }
     675
     676                /* This accounts for the superblock */
     677                r++;
     678
     679                /* Add the number of blocks used for the GDT */
     680                bg_count = ext4_superblock_get_block_group_count(sb);
     681                bg_desc_sz = ext4_superblock_get_desc_size(sb);
     682                gdt_table = ROUND_UP(bg_count * bg_desc_sz, block_size) /
     683                    block_size;
     684
     685                r += gdt_table;
     686
     687                /* And now the number of reserved GDT blocks */
     688                r += ext4_superblock_get_reserved_gdt_blocks(sb);
     689        }
     690
     691        return r;
     692}
     693
    522694/** Put reference to block group.
    523695 *
    524  * @oaram ref Pointer for reference to be put back
     696 * @param ref Pointer for reference to be put back
    525697 *
    526698 * @return Error code
     
    796968                }
    797969               
    798                 block_put(block);
     970                rc = block_put(block);
     971                if (rc != EOK)
     972                        return rc;
     973
    799974                rc = ext4_balloc_free_block(inode_ref, fblock);
    800975                if (rc != EOK)
     
    8401015                                }
    8411016                               
    842                                 block_put(subblock);
     1017                                rc = block_put(subblock);
     1018                                if (rc != EOK) {
     1019                                        block_put(block);
     1020                                        return rc;
     1021                                }
    8431022                        }
    8441023                       
     
    8501029                }
    8511030               
    852                 block_put(block);
     1031                rc = block_put(block);
     1032                if (rc != EOK)
     1033                        return rc;
     1034
    8531035                rc = ext4_balloc_free_block(inode_ref, fblock);
    8541036                if (rc != EOK)
Note: See TracChangeset for help on using the changeset viewer.