Ignore:
File:
1 edited

Legend:

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

    r24df0de6 rd579acc  
    3939#include "libext4.h"
    4040
     41/** Compute number of block group from block address.
     42 *
     43 * @param sb         Superblock pointer.
     44 * @param block_addr Absolute address of block.
     45 *
     46 * @return Block group index
     47 *
     48 */
     49static uint32_t ext4_balloc_get_bgid_of_block(ext4_superblock_t *sb,
     50    uint32_t block_addr)
     51{
     52        uint32_t blocks_per_group =
     53            ext4_superblock_get_blocks_per_group(sb);
     54        uint32_t first_block =
     55            ext4_superblock_get_first_data_block(sb);
     56       
     57        /* First block == 0 or 1 */
     58        if (first_block == 0)
     59                return block_addr / blocks_per_group;
     60        else
     61                return (block_addr - 1) / blocks_per_group;
     62}
     63
    4164/** Free block.
    4265 *
     
    5376       
    5477        /* Compute indexes */
    55         uint32_t block_group = ext4_filesystem_blockaddr2group(sb, block_addr);
     78        uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, block_addr);
    5679        uint32_t index_in_group =
    5780            ext4_filesystem_blockaddr2_index_in_group(sb, block_addr);
     
    112135}
    113136
    114 static int ext4_balloc_free_blocks_internal(ext4_inode_ref_t *inode_ref,
     137/** Free continuous set of blocks.
     138 *
     139 * @param inode_ref Inode, where the blocks are allocated
     140 * @param first     First block to release
     141 * @param count     Number of blocks to release
     142 *
     143 */
     144int ext4_balloc_free_blocks(ext4_inode_ref_t *inode_ref,
    115145    uint32_t first, uint32_t count)
    116146{
    117147        ext4_filesystem_t *fs = inode_ref->fs;
    118148        ext4_superblock_t *sb = fs->superblock;
    119 
     149       
    120150        /* Compute indexes */
    121         uint32_t block_group_first = ext4_filesystem_blockaddr2group(sb,
    122             first);
    123         uint32_t block_group_last = ext4_filesystem_blockaddr2group(sb,
    124             first + count - 1);
    125 
     151        uint32_t block_group_first =
     152            ext4_balloc_get_bgid_of_block(sb, first);
     153        uint32_t block_group_last =
     154            ext4_balloc_get_bgid_of_block(sb, first + count - 1);
     155       
    126156        assert(block_group_first == block_group_last);
    127 
     157       
    128158        /* Load block group reference */
    129159        ext4_block_group_ref_t *bg_ref;
     
    131161        if (rc != EOK)
    132162                return rc;
    133 
     163       
    134164        uint32_t index_in_group_first =
    135165            ext4_filesystem_blockaddr2_index_in_group(sb, first);
    136 
     166       
    137167        /* Load block with bitmap */
    138168        uint32_t bitmap_block_addr =
    139169            ext4_block_group_get_block_bitmap(bg_ref->block_group, sb);
    140 
     170       
    141171        block_t *bitmap_block;
    142172        rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, 0);
     
    145175                return rc;
    146176        }
    147 
     177       
    148178        /* Modify bitmap */
    149179        ext4_bitmap_free_bits(bitmap_block->data, index_in_group_first, count);
    150180        bitmap_block->dirty = true;
    151 
     181       
    152182        /* Release block with bitmap */
    153183        rc = block_put(bitmap_block);
     
    157187                return rc;
    158188        }
    159 
     189       
    160190        uint32_t block_size = ext4_superblock_get_block_size(sb);
    161 
     191       
    162192        /* Update superblock free blocks count */
    163193        uint32_t sb_free_blocks =
     
    165195        sb_free_blocks += count;
    166196        ext4_superblock_set_free_blocks_count(sb, sb_free_blocks);
    167 
     197       
    168198        /* Update inode blocks count */
    169199        uint64_t ino_blocks =
     
    172202        ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks);
    173203        inode_ref->dirty = true;
    174 
     204       
    175205        /* Update block group free blocks count */
    176206        uint32_t free_blocks =
     
    180210            sb, free_blocks);
    181211        bg_ref->dirty = true;
    182 
     212       
    183213        /* Release block group reference */
    184214        return ext4_filesystem_put_block_group_ref(bg_ref);
    185215}
    186216
    187 /** Free continuous set of blocks.
    188  *
    189  * @param inode_ref Inode, where the blocks are allocated
    190  * @param first     First block to release
    191  * @param count     Number of blocks to release
    192  *
    193  */
    194 int ext4_balloc_free_blocks(ext4_inode_ref_t *inode_ref,
    195     uint32_t first, uint32_t count)
    196 {
    197         int r;
    198         uint32_t gid;
    199         uint64_t limit;
    200         ext4_filesystem_t *fs = inode_ref->fs;
    201         ext4_superblock_t *sb = fs->superblock;
    202 
    203         while (count) {
    204                 gid = ext4_filesystem_blockaddr2group(sb, first);
    205                 limit = ext4_filesystem_index_in_group2blockaddr(sb, 0,
    206                     gid + 1);
    207 
    208                 if ((first + count) >= limit) {
    209                         /* This extent spans over 2 or more block groups,
    210                          * we'll break it into smaller parts.
    211                          */
    212                         uint32_t s = limit - first;
    213 
    214                         r = ext4_balloc_free_blocks_internal(inode_ref,
    215                             first, s);
    216                         if (r != EOK)
    217                                 return r;
    218 
    219                         first = limit;
    220                         count -= s;
    221                 } else {
    222                         return ext4_balloc_free_blocks_internal(inode_ref,
    223                             first, count);
    224                 }
    225         }
    226 
    227         return EOK;
    228 }
    229 
    230217/** Compute first block for data in block group.
    231218 *
     
    240227    ext4_block_group_ref_t *bg_ref)
    241228{
    242         uint32_t r;
    243         uint64_t itable = ext4_block_group_get_inode_table_first_block(
    244             bg_ref->block_group, sb);
    245         uint32_t itable_sz = ext4_filesystem_bg_get_itable_size(sb, bg_ref);
    246 
    247         if (!ext4_superblock_has_feature_incompatible(sb,
    248             EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
    249                 /* If we are not using FLEX_BG, the first data block
    250                  * is always after the inode table.
    251                  */
    252                 r = itable + itable_sz;
    253                 return ext4_filesystem_blockaddr2_index_in_group(sb, r);
    254         }
    255 
    256         uint64_t bbmap = ext4_block_group_get_block_bitmap(bg_ref->block_group,
    257             sb);
    258         uint64_t ibmap = ext4_block_group_get_inode_bitmap(bg_ref->block_group,
    259             sb);
    260 
    261         r = ext4_filesystem_index_in_group2blockaddr(sb, 0, bg_ref->index);
    262         r += ext4_filesystem_bg_get_backup_blocks(bg_ref);
    263 
    264         if (ext4_filesystem_blockaddr2group(sb, bbmap) != bg_ref->index)
    265                 bbmap = -1; /* Invalid */
    266 
    267         if (ext4_filesystem_blockaddr2group(sb, ibmap) != bg_ref->index)
    268                 ibmap = -1;
    269 
    270         while (1) {
    271                 if (r == bbmap || r == ibmap)
    272                         r++;
    273                 else if (r >= itable && r < (itable + itable_sz))
    274                         r = itable + itable_sz;
    275                 else
    276                         break;
    277         }
    278 
    279         return r;
     229        uint32_t block_group_count = ext4_superblock_get_block_group_count(sb);
     230        uint32_t inode_table_first_block =
     231            ext4_block_group_get_inode_table_first_block(bg_ref->block_group, sb);
     232        uint16_t inode_table_item_size = ext4_superblock_get_inode_size(sb);
     233        uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
     234        uint32_t block_size = ext4_superblock_get_block_size(sb);
     235        uint32_t inode_table_bytes;
     236       
     237        if (bg_ref->index < block_group_count - 1) {
     238                inode_table_bytes = inodes_per_group * inode_table_item_size;
     239        } else {
     240                /* Last block group could be smaller */
     241                uint32_t inodes_count_total = ext4_superblock_get_inodes_count(sb);
     242                inode_table_bytes =
     243                    (inodes_count_total - ((block_group_count - 1) * inodes_per_group)) *
     244                    inode_table_item_size;
     245        }
     246       
     247        uint32_t inode_table_blocks = inode_table_bytes / block_size;
     248       
     249        if (inode_table_bytes % block_size)
     250                inode_table_blocks++;
     251       
     252        return inode_table_first_block + inode_table_blocks;
    280253}
    281254
     
    291264        *goal = 0;
    292265        ext4_superblock_t *sb = inode_ref->fs->superblock;
    293 
     266       
    294267        uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
    295268        uint32_t block_size = ext4_superblock_get_block_size(sb);
    296269        uint32_t inode_block_count = inode_size / block_size;
    297 
     270       
    298271        if (inode_size % block_size != 0)
    299272                inode_block_count++;
    300 
     273       
    301274        /* If inode has some blocks, get last block address + 1 */
    302275        if (inode_block_count > 0) {
     
    305278                if (rc != EOK)
    306279                        return rc;
    307 
     280               
    308281                if (goal != 0) {
    309282                        (*goal)++;
    310283                        return EOK;
    311284                }
     285               
    312286                /* If goal == 0, sparse file -> continue */
    313287        }
    314 
     288       
    315289        /* Identify block group of inode */
    316290        uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
    317291        uint32_t block_group = (inode_ref->index - 1) / inodes_per_group;
    318 
     292        block_size = ext4_superblock_get_block_size(sb);
     293       
    319294        /* Load block group reference */
    320295        ext4_block_group_ref_t *bg_ref;
     
    323298        if (rc != EOK)
    324299                return rc;
    325 
    326         *goal = ext4_balloc_get_first_data_block_in_group(sb, bg_ref);
    327 
     300       
     301        /* Compute indexes */
     302        uint32_t block_group_count = ext4_superblock_get_block_group_count(sb);
     303        uint32_t inode_table_first_block =
     304            ext4_block_group_get_inode_table_first_block(bg_ref->block_group, sb);
     305        uint16_t inode_table_item_size = ext4_superblock_get_inode_size(sb);
     306        uint32_t inode_table_bytes;
     307       
     308        /* Check for last block group */
     309        if (block_group < block_group_count - 1) {
     310                inode_table_bytes = inodes_per_group * inode_table_item_size;
     311        } else {
     312                /* Last block group could be smaller */
     313                uint32_t inodes_count_total = ext4_superblock_get_inodes_count(sb);
     314                inode_table_bytes =
     315                    (inodes_count_total - ((block_group_count - 1) * inodes_per_group)) *
     316                    inode_table_item_size;
     317        }
     318       
     319        uint32_t inode_table_blocks = inode_table_bytes / block_size;
     320       
     321        if (inode_table_bytes % block_size)
     322                inode_table_blocks++;
     323       
     324        *goal = inode_table_first_block + inode_table_blocks;
     325       
    328326        return ext4_filesystem_put_block_group_ref(bg_ref);
    329327}
     
    355353       
    356354        /* Load block group number for goal and relative index */
    357         uint32_t block_group = ext4_filesystem_blockaddr2group(sb, goal);
     355        uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, goal);
    358356        uint32_t index_in_group =
    359357            ext4_filesystem_blockaddr2_index_in_group(sb, goal);
     
    628626       
    629627        /* Compute indexes */
    630         uint32_t block_group = ext4_filesystem_blockaddr2group(sb, fblock);
     628        uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, fblock);
    631629        uint32_t index_in_group =
    632630            ext4_filesystem_blockaddr2_index_in_group(sb, fblock);
Note: See TracChangeset for help on using the changeset viewer.