Ignore:
File:
1 edited

Legend:

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

    r24df0de6 r38542dc  
    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);
     
    6891        block_t *bitmap_block;
    6992        rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, 0);
    70         if (rc != EOK) {
    71                 ext4_filesystem_put_block_group_ref(bg_ref);
    72                 return rc;
    73         }
     93        if (rc != EOK)
     94                return rc;
    7495       
    7596        /* Modify bitmap */
     
    109130       
    110131        /* Release block group reference */
    111         return ext4_filesystem_put_block_group_ref(bg_ref);
     132        rc = ext4_filesystem_put_block_group_ref(bg_ref);
     133        if (rc != EOK)
     134                return rc;
     135       
     136        return EOK;
    112137}
    113138
    114 static int ext4_balloc_free_blocks_internal(ext4_inode_ref_t *inode_ref,
     139/** Free continuous set of blocks.
     140 *
     141 * @param inode_ref Inode, where the blocks are allocated
     142 * @param first     First block to release
     143 * @param count     Number of blocks to release
     144 *
     145 */
     146int ext4_balloc_free_blocks(ext4_inode_ref_t *inode_ref,
    115147    uint32_t first, uint32_t count)
    116148{
    117149        ext4_filesystem_t *fs = inode_ref->fs;
    118150        ext4_superblock_t *sb = fs->superblock;
    119 
     151       
    120152        /* 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 
     153        uint32_t block_group_first =
     154            ext4_balloc_get_bgid_of_block(sb, first);
     155        uint32_t block_group_last =
     156            ext4_balloc_get_bgid_of_block(sb, first + count - 1);
     157       
    126158        assert(block_group_first == block_group_last);
    127 
     159       
    128160        /* Load block group reference */
    129161        ext4_block_group_ref_t *bg_ref;
     
    131163        if (rc != EOK)
    132164                return rc;
    133 
     165       
    134166        uint32_t index_in_group_first =
    135167            ext4_filesystem_blockaddr2_index_in_group(sb, first);
    136 
     168       
    137169        /* Load block with bitmap */
    138170        uint32_t bitmap_block_addr =
    139171            ext4_block_group_get_block_bitmap(bg_ref->block_group, sb);
    140 
     172       
    141173        block_t *bitmap_block;
    142174        rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, 0);
    143         if (rc != EOK) {
    144                 ext4_filesystem_put_block_group_ref(bg_ref);
    145                 return rc;
    146         }
    147 
     175        if (rc != EOK)
     176                return rc;
     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 */
    184         return ext4_filesystem_put_block_group_ref(bg_ref);
    185 }
    186 
    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 
     214        rc = ext4_filesystem_put_block_group_ref(bg_ref);
     215        if (rc != EOK)
     216                return rc;
     217       
    227218        return EOK;
    228219}
     
    240231    ext4_block_group_ref_t *bg_ref)
    241232{
    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;
     233        uint32_t block_group_count = ext4_superblock_get_block_group_count(sb);
     234        uint32_t inode_table_first_block =
     235            ext4_block_group_get_inode_table_first_block(bg_ref->block_group, sb);
     236        uint16_t inode_table_item_size = ext4_superblock_get_inode_size(sb);
     237        uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
     238        uint32_t block_size = ext4_superblock_get_block_size(sb);
     239        uint32_t inode_table_bytes;
     240       
     241        if (bg_ref->index < block_group_count - 1) {
     242                inode_table_bytes = inodes_per_group * inode_table_item_size;
     243        } else {
     244                /* Last block group could be smaller */
     245                uint32_t inodes_count_total = ext4_superblock_get_inodes_count(sb);
     246                inode_table_bytes =
     247                    (inodes_count_total - ((block_group_count - 1) * inodes_per_group)) *
     248                    inode_table_item_size;
     249        }
     250       
     251        uint32_t inode_table_blocks = inode_table_bytes / block_size;
     252       
     253        if (inode_table_bytes % block_size)
     254                inode_table_blocks++;
     255       
     256        return inode_table_first_block + inode_table_blocks;
    280257}
    281258
     
    287264 *
    288265 */
    289 static int ext4_balloc_find_goal(ext4_inode_ref_t *inode_ref, uint32_t *goal)
     266static uint32_t ext4_balloc_find_goal(ext4_inode_ref_t *inode_ref)
    290267{
    291         *goal = 0;
     268        uint32_t goal = 0;
     269       
    292270        ext4_superblock_t *sb = inode_ref->fs->superblock;
    293 
     271       
    294272        uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
    295273        uint32_t block_size = ext4_superblock_get_block_size(sb);
    296274        uint32_t inode_block_count = inode_size / block_size;
    297 
     275       
    298276        if (inode_size % block_size != 0)
    299277                inode_block_count++;
    300 
     278       
    301279        /* If inode has some blocks, get last block address + 1 */
    302280        if (inode_block_count > 0) {
    303281                int rc = ext4_filesystem_get_inode_data_block_index(inode_ref,
    304                     inode_block_count - 1, goal);
     282                    inode_block_count - 1, &goal);
    305283                if (rc != EOK)
    306                         return rc;
    307 
     284                        return 0;
     285               
    308286                if (goal != 0) {
    309                         (*goal)++;
    310                         return EOK;
     287                        goal++;
     288                        return goal;
    311289                }
     290               
    312291                /* If goal == 0, sparse file -> continue */
    313292        }
    314 
     293       
    315294        /* Identify block group of inode */
    316295        uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
    317296        uint32_t block_group = (inode_ref->index - 1) / inodes_per_group;
    318 
     297        block_size = ext4_superblock_get_block_size(sb);
     298       
    319299        /* Load block group reference */
    320300        ext4_block_group_ref_t *bg_ref;
     
    322302            block_group, &bg_ref);
    323303        if (rc != EOK)
    324                 return rc;
    325 
    326         *goal = ext4_balloc_get_first_data_block_in_group(sb, bg_ref);
    327 
    328         return ext4_filesystem_put_block_group_ref(bg_ref);
     304                return 0;
     305       
     306        /* Compute indexes */
     307        uint32_t block_group_count = ext4_superblock_get_block_group_count(sb);
     308        uint32_t inode_table_first_block =
     309            ext4_block_group_get_inode_table_first_block(bg_ref->block_group, sb);
     310        uint16_t inode_table_item_size = ext4_superblock_get_inode_size(sb);
     311        uint32_t inode_table_bytes;
     312       
     313        /* Check for last block group */
     314        if (block_group < block_group_count - 1) {
     315                inode_table_bytes = inodes_per_group * inode_table_item_size;
     316        } else {
     317                /* Last block group could be smaller */
     318                uint32_t inodes_count_total = ext4_superblock_get_inodes_count(sb);
     319                inode_table_bytes =
     320                    (inodes_count_total - ((block_group_count - 1) * inodes_per_group)) *
     321                    inode_table_item_size;
     322        }
     323       
     324        uint32_t inode_table_blocks = inode_table_bytes / block_size;
     325       
     326        if (inode_table_bytes % block_size)
     327                inode_table_blocks++;
     328       
     329        goal = inode_table_first_block + inode_table_blocks;
     330       
     331        ext4_filesystem_put_block_group_ref(bg_ref);
     332       
     333        return goal;
    329334}
    330335
     
    344349        block_t *bitmap_block;
    345350        uint32_t rel_block_idx = 0;
    346         uint32_t free_blocks;
    347         uint32_t goal;
    348351       
    349352        /* Find GOAL */
    350         int rc = ext4_balloc_find_goal(inode_ref, &goal);
    351         if (rc != EOK)
    352                 return rc;
    353 
     353        uint32_t goal = ext4_balloc_find_goal(inode_ref);
     354        if (goal == 0) {
     355                /* no goal found => partition is full */
     356                return ENOSPC;
     357        }
     358       
    354359        ext4_superblock_t *sb = inode_ref->fs->superblock;
    355360       
    356361        /* Load block group number for goal and relative index */
    357         uint32_t block_group = ext4_filesystem_blockaddr2group(sb, goal);
     362        uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, goal);
    358363        uint32_t index_in_group =
    359364            ext4_filesystem_blockaddr2_index_in_group(sb, goal);
     
    361366        /* Load block group reference */
    362367        ext4_block_group_ref_t *bg_ref;
    363         rc = ext4_filesystem_get_block_group_ref(inode_ref->fs,
     368        int rc = ext4_filesystem_get_block_group_ref(inode_ref->fs,
    364369            block_group, &bg_ref);
    365370        if (rc != EOK)
    366371                return rc;
    367 
    368         free_blocks =
    369             ext4_block_group_get_free_blocks_count(bg_ref->block_group, sb);
    370         if (free_blocks == 0) {
    371                 /* This group has no free blocks */
    372                 goto goal_failed;
    373         }
    374372       
    375373        /* Compute indexes */
     
    469467       
    470468        /* No free block found yet */
    471         rc = block_put(bitmap_block);
    472         if (rc != EOK) {
    473                 ext4_filesystem_put_block_group_ref(bg_ref);
    474                 return rc;
    475         }
    476 
    477 goal_failed:
    478 
    479         rc = ext4_filesystem_put_block_group_ref(bg_ref);
    480         if (rc != EOK)
    481                 return rc;
     469        block_put(bitmap_block);
     470        ext4_filesystem_put_block_group_ref(bg_ref);
    482471       
    483472        /* Try other block groups */
     
    492481                if (rc != EOK)
    493482                        return rc;
    494 
    495                 free_blocks =
    496                      ext4_block_group_get_free_blocks_count(bg_ref->block_group, sb);
    497                 if (free_blocks == 0) {
    498                         /* This group has no free blocks */
    499                         goto next_group;
    500                 }
    501 
     483               
    502484                /* Load block with bitmap */
    503485                bitmap_block_addr =
     
    530512                        bitmap_block->dirty = true;
    531513                        rc = block_put(bitmap_block);
    532                         if (rc != EOK) {
    533                                 ext4_filesystem_put_block_group_ref(bg_ref);
     514                        if (rc != EOK)
    534515                                return rc;
    535                         }
    536516                       
    537517                        allocated_block =
     
    548528                        bitmap_block->dirty = true;
    549529                        rc = block_put(bitmap_block);
    550                         if (rc != EOK) {
    551                                 ext4_filesystem_put_block_group_ref(bg_ref);
     530                        if (rc != EOK)
    552531                                return rc;
    553                         }
    554532                       
    555533                        allocated_block =
     
    560538                }
    561539               
    562                 rc = block_put(bitmap_block);
    563                 if (rc != EOK) {
    564                         ext4_filesystem_put_block_group_ref(bg_ref);
    565                         return rc;
    566                 }
    567 
    568 next_group:
    569                 rc = ext4_filesystem_put_block_group_ref(bg_ref);
    570                 if (rc != EOK)
    571                         return rc;
     540                block_put(bitmap_block);
     541                ext4_filesystem_put_block_group_ref(bg_ref);
    572542               
    573543                /* Goto next group */
     
    604574        bg_ref->dirty = true;
    605575       
    606         rc = ext4_filesystem_put_block_group_ref(bg_ref);
     576        ext4_filesystem_put_block_group_ref(bg_ref);
    607577       
    608578        *fblock = allocated_block;
    609         return rc;
     579        return EOK;
    610580}
    611581
     
    622592    bool *free)
    623593{
    624         int rc;
     594        int rc = EOK;
    625595       
    626596        ext4_filesystem_t *fs = inode_ref->fs;
     
    628598       
    629599        /* Compute indexes */
    630         uint32_t block_group = ext4_filesystem_blockaddr2group(sb, fblock);
     600        uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, fblock);
    631601        uint32_t index_in_group =
    632602            ext4_filesystem_blockaddr2_index_in_group(sb, fblock);
     
    643613        block_t *bitmap_block;
    644614        rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, 0);
    645         if (rc != EOK) {
    646                 ext4_filesystem_put_block_group_ref(bg_ref);
    647                 return rc;
    648         }
     615        if (rc != EOK)
     616                return rc;
    649617       
    650618        /* Check if block is free */
Note: See TracChangeset for help on using the changeset viewer.