else()\r
#Generic example target\r
set(BLOCKDEV_TYPE linux)\r
+ add_definitions(-DCONFIG_EXTENT_FULL=1)\r
add_definitions(-DCONFIG_HAVE_OWN_OFLAGS=0)\r
add_definitions(-DCONFIG_HAVE_OWN_ERRNO=0)\r
add_definitions(-DCONFIG_HAVE_OWN_ASSERT=0)\r
int ext4_fread(ext4_file *f, void *buf, size_t size, size_t *rcnt)
{
uint32_t u;
- uint32_t fblock;
- uint32_t fblock_start;
+ ext4_fsblk_t fblock;
+ ext4_fsblk_t fblock_start;
uint32_t fblock_cnt;
uint32_t sblock;
uint32_t sblock_end;
int ext4_fwrite(ext4_file *f, const void *buf, size_t size, size_t *wcnt)
{
uint32_t u;
- uint32_t fblock;
+ ext4_fsblk_t fblock;
uint32_t sblock;
uint32_t sblock_end;
uint32_t file_blocks;
uint32_t block_size;
- uint32_t fblock_start;
+ ext4_fsblk_t fblock_start;
uint32_t fblock_cnt;
struct ext4_block b;
{
struct ext4_block b;
struct ext4_inode_ref ref;
- uint32_t sblock, fblock;
+ uint32_t sblock;
+ ext4_fsblk_t fblock;
uint32_t block_size;
int r;
* @return Block group index
*/
uint32_t ext4_balloc_get_bgid_of_block(struct ext4_sblock *s,
- uint32_t baddr)
+ uint64_t baddr)
{
- if (ext4_get32(s, first_data_block))
+ if (ext4_get32(s, first_data_block) && baddr)
baddr--;
return baddr / ext4_get32(s, blocks_per_group);
* @param bgid block group index
* @return Block address
*/
-uint32_t ext4_balloc_get_block_of_bgid(struct ext4_sblock *s,
+uint64_t ext4_balloc_get_block_of_bgid(struct ext4_sblock *s,
uint32_t bgid)
{
- uint32_t baddr = 0;
+ uint64_t baddr = 0;
if (ext4_get32(s, first_data_block))
baddr++;
return baddr;
}
-int ext4_balloc_free_block(struct ext4_inode_ref *inode_ref, uint32_t baddr)
+int ext4_balloc_free_block(struct ext4_inode_ref *inode_ref, ext4_fsblk_t baddr)
{
struct ext4_fs *fs = inode_ref->fs;
struct ext4_sblock *sb = &fs->sb;
return rc;
/* Load block with bitmap */
- uint32_t bitmap_block_addr =
+ ext4_fsblk_t bitmap_block_addr =
ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
struct ext4_block bitmap_block;
return ext4_fs_put_block_group_ref(&bg_ref);
}
-int ext4_balloc_free_blocks(struct ext4_inode_ref *inode_ref, uint32_t first,
+int ext4_balloc_free_blocks(struct ext4_inode_ref *inode_ref, ext4_fsblk_t first,
uint32_t count)
{
int rc = EOK;
ext4_fs_baddr2_index_in_group(sb, first);
/* Load block with bitmap */
- uint32_t bitmap_block_addr =
+ ext4_fsblk_t bitmap_block_addr =
ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
struct ext4_block bitmap_block;
return rc;
}
-/**@brief Compute 'goal' for allocation algorithm.
- * @param inode_ref Reference to inode, to allocate block for
- * @param goal
- * @return error code
- */
-static int ext4_balloc_find_goal(struct ext4_inode_ref *inode_ref,
- uint32_t *goal)
-{
- struct ext4_sblock *sb = &inode_ref->fs->sb;
- *goal = 0;
-
- uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
- uint32_t block_size = ext4_sb_get_block_size(sb);
- uint32_t inode_block_count = inode_size / block_size;
-
- if (inode_size % block_size != 0)
- inode_block_count++;
-
- /* If inode has some blocks, get last block address + 1 */
- if (inode_block_count > 0) {
- int rc = ext4_fs_get_inode_data_block_index(
- inode_ref, inode_block_count - 1, goal);
- if (rc != EOK)
- return rc;
-
- if (*goal != 0) {
- (*goal)++;
- return rc;
- }
-
- /* If goal == 0, sparse file -> continue */
- }
-
- /* Identify block group of inode */
-
- uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
- uint32_t block_group = (inode_ref->index - 1) / inodes_per_group;
- block_size = ext4_sb_get_block_size(sb);
-
- /* Load block group reference */
- struct ext4_block_group_ref bg_ref;
- int rc =
- ext4_fs_get_block_group_ref(inode_ref->fs, block_group, &bg_ref);
- if (rc != EOK)
- return rc;
-
- /* Compute indexes */
- uint32_t block_group_count = ext4_block_group_cnt(sb);
- uint32_t inode_table_first_block =
- ext4_bg_get_inode_table_first_block(bg_ref.block_group, sb);
- uint16_t inode_table_item_size = ext4_get16(sb, inode_size);
- uint32_t inode_table_bytes;
-
- /* Check for last block group */
- if (block_group < block_group_count - 1) {
- inode_table_bytes = inodes_per_group * inode_table_item_size;
- } else {
- /* Last block group could be smaller */
- uint32_t inodes_count_total = ext4_get32(sb, inodes_count);
-
- inode_table_bytes =
- (inodes_count_total -
- ((block_group_count - 1) * inodes_per_group)) *
- inode_table_item_size;
- }
-
- uint32_t inode_table_blocks = inode_table_bytes / block_size;
-
- if (inode_table_bytes % block_size)
- inode_table_blocks++;
-
- *goal = inode_table_first_block + inode_table_blocks;
-
- return ext4_fs_put_block_group_ref(&bg_ref);
-}
-
-int ext4_balloc_alloc_block(struct ext4_inode_ref *inode_ref, uint32_t *fblock)
+int ext4_balloc_alloc_block(struct ext4_inode_ref *inode_ref,
+ ext4_fsblk_t goal,
+ ext4_fsblk_t *fblock)
{
- uint32_t allocated_block = 0;
- uint32_t bitmap_block_addr;
+ ext4_fsblk_t allocated_block = 0;
+ ext4_fsblk_t bitmap_block_addr;
uint32_t rel_block_idx = 0;
- uint32_t free_blocks;
- uint32_t goal;
+ uint64_t free_blocks;
struct ext4_block bitmap_block;
-
- int rc = ext4_balloc_find_goal(inode_ref, &goal);
- if (rc != EOK) {
- /* no goal found => partition is full */
- return rc;
- }
+ int rc;
struct ext4_sblock *sb = &inode_ref->fs->sb;
}
/* Compute indexes */
- uint32_t first_in_group = ext4_balloc_get_block_of_bgid(sb, bg_ref.index);
+ ext4_fsblk_t first_in_group = ext4_balloc_get_block_of_bgid(sb, bg_ref.index);
uint32_t first_in_group_index =
ext4_fs_baddr2_index_in_group(sb, first_in_group);
inode_ref->dirty = true;
/* Update block group free blocks count */
- uint32_t bg_free_blocks =
+ uint64_t bg_free_blocks =
ext4_bg_get_free_blocks_count(bg_ref.block_group, sb);
bg_free_blocks--;
ext4_bg_set_free_blocks_count(bg_ref.block_group, sb, bg_free_blocks);
}
int ext4_balloc_try_alloc_block(struct ext4_inode_ref *inode_ref,
- uint32_t baddr, bool *free)
+ ext4_fsblk_t baddr, bool *free)
{
int rc;
return rc;
/* Load block with bitmap */
- uint32_t bitmap_block_addr =
+ ext4_fsblk_t bitmap_block_addr =
ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
struct ext4_block bitmap_block;
* @return Block group index
*/
uint32_t ext4_balloc_get_bgid_of_block(struct ext4_sblock *s,
- uint32_t baddr);
+ ext4_fsblk_t baddr);
/**@brief Compute the starting block address of a block group
* @param sb superblock pointer.
* @param bgid block group index
* @return Block address
*/
-uint32_t ext4_balloc_get_block_of_bgid(struct ext4_sblock *s,
+ext4_fsblk_t ext4_balloc_get_block_of_bgid(struct ext4_sblock *s,
uint32_t bgid);
/**@brief Free block from inode.
* @param inode_ref inode reference
* @param baddr block address
* @return standard error code*/
-int ext4_balloc_free_block(struct ext4_inode_ref *inode_ref, uint32_t baddr);
+int ext4_balloc_free_block(struct ext4_inode_ref *inode_ref, ext4_fsblk_t baddr);
/**@brief Free blocks from inode.
* @param inode_ref inode reference
* @param baddr block address
* @return standard error code*/
-int ext4_balloc_free_blocks(struct ext4_inode_ref *inode_ref, uint32_t first,
+int ext4_balloc_free_blocks(struct ext4_inode_ref *inode_ref, ext4_fsblk_t first,
uint32_t count);
/**@brief Allocate block procedure.
* @param inode_ref inode reference
+ * @param goal
* @param baddr allocated block address
* @return standard error code*/
-int ext4_balloc_alloc_block(struct ext4_inode_ref *inode_ref, uint32_t *baddr);
+int ext4_balloc_alloc_block(struct ext4_inode_ref *inode_ref,
+ ext4_fsblk_t goal,
+ ext4_fsblk_t *baddr);
/**@brief Try allocate selected block.
* @param inode_ref inode reference
* @param free if baddr is not allocated
* @return standard error code*/
int ext4_balloc_try_alloc_block(struct ext4_inode_ref *inode_ref,
- uint32_t baddr, bool *free);
+ ext4_fsblk_t baddr, bool *free);
#endif /* EXT4_BALLOC_H_ */
return rc;
}
- uint32_t next_block_phys_idx;
+ ext4_fsblk_t next_block_phys_idx;
int rc = ext4_fs_get_inode_data_block_index(
it->inode_ref, next_block_idx, &next_block_phys_idx);
if (rc != EOK)
/* Linear algorithm */
uint32_t iblock = 0;
- uint32_t fblock = 0;
+ ext4_fsblk_t fblock = 0;
uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
uint32_t inode_size = ext4_inode_get_size(&fs->sb, parent->inode);
uint32_t total_blocks = inode_size / block_size;
/* Linear algorithm */
uint32_t iblock;
- uint32_t fblock;
+ ext4_fsblk_t fblock;
uint32_t block_size = ext4_sb_get_block_size(sb);
uint32_t inode_size = ext4_inode_get_size(sb, parent->inode);
uint32_t total_blocks = inode_size / block_size;
int ext4_dir_dx_init(struct ext4_inode_ref *dir)
{
/* Load block 0, where will be index root located */
- uint32_t fblock;
+ ext4_fsblk_t fblock;
int rc = ext4_fs_get_inode_data_block_index(dir, 0, &fblock);
if (rc != EOK)
return rc;
indirect_level--;
- uint32_t fblock;
+ ext4_fsblk_t fblock;
int rc = ext4_fs_get_inode_data_block_index(
inode_ref, next_block, &fblock);
if (rc != EOK)
/* Fill new path */
while (num_handles--) {
uint32_t block_idx = ext4_dir_dx_entry_get_block(p->position);
- uint32_t block_addr;
+ ext4_fsblk_t block_addr;
int rc = ext4_fs_get_inode_data_block_index(
inode_ref, block_idx, &block_addr);
const char *name)
{
/* Load direct block 0 (index root) */
- uint32_t root_block_addr;
+ ext4_fsblk_t root_block_addr;
int rc2;
int rc =
ext4_fs_get_inode_data_block_index(inode_ref, 0, &root_block_addr);
/* Load leaf block */
uint32_t leaf_block_idx =
ext4_dir_dx_entry_get_block(dx_block->position);
- uint32_t leaf_block_addr;
+ ext4_fsblk_t leaf_block_addr;
rc = ext4_fs_get_inode_data_block_index(
inode_ref, leaf_block_idx, &leaf_block_addr);
ext4_dir_dx_entry_comparator);
#endif
/* Allocate new block for store the second part of entries */
- uint32_t new_fblock;
+ ext4_fsblk_t new_fblock;
uint32_t new_iblock;
rc = ext4_fs_append_inode_block(inode_ref, &new_fblock, &new_iblock);
if (rc != EOK) {
return ENOSPC;
/* Add new block to directory */
- uint32_t new_fblock;
+ ext4_fsblk_t new_fblock;
uint32_t new_iblock;
int rc = ext4_fs_append_inode_block(inode_ref, &new_fblock,
&new_iblock);
int rc2 = EOK;
/* Get direct block 0 (index root) */
- uint32_t root_block_addr;
+ ext4_fsblk_t root_block_addr;
int rc =
ext4_fs_get_inode_data_block_index(parent, 0, &root_block_addr);
if (rc != EOK)
/* Try to insert to existing data block */
uint32_t leaf_block_idx =
ext4_dir_dx_entry_get_block(dx_block->position);
- uint32_t leaf_block_addr;
+ ext4_fsblk_t leaf_block_addr;
rc = ext4_fs_get_inode_data_block_index(parent, leaf_block_idx,
&leaf_block_addr);
if (rc != EOK)
uint32_t parent_inode)
{
/* Load block 0, where will be index root located */
- uint32_t fblock;
+ ext4_fsblk_t fblock;
int rc = ext4_fs_get_inode_data_block_index(dir, 0, &fblock);
if (rc != EOK)
return rc;
* @return Error code*/
static int
ext4_extent_find_block(struct ext4_inode_ref *inode_ref, uint32_t iblock,
- uint32_t *fblock)
+ ext4_fsblk_t *fblock)
{
int rc;
/* Compute bound defined by i-node size */
*fblock = 0;
} else {
/* Compute requested physical block address */
- uint32_t phys_block;
+ ext4_fsblk_t phys_block;
uint32_t first = ext4_extent_get_first_block(extent);
phys_block = ext4_extent_get_start(extent) + iblock - first;
static int ext4_extent_release_branch(struct ext4_inode_ref *inode_ref,
struct ext4_extent_index *index)
{
- uint32_t fblock = ext4_extent_index_get_leaf(index);
+ ext4_fsblk_t fblock = ext4_extent_index_get_leaf(index);
uint32_t i;
struct ext4_block block;
int rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);
/* First extent maybe released partially */
uint32_t first_iblock = ext4_extent_get_first_block(path_ptr->extent);
- uint32_t first_fblock = ext4_extent_get_start(path_ptr->extent) +
+ ext4_fsblk_t first_fblock = ext4_extent_get_start(path_ptr->extent) +
from - first_iblock;
uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
if (entries == limit) {
/* Full node - allocate block for new one */
- uint32_t fblock;
- int rc = ext4_balloc_alloc_block(inode_ref, &fblock);
+ ext4_fsblk_t goal, fblock;
+ int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
+ if (rc != EOK)
+ return rc;
+
+ rc = ext4_balloc_alloc_block(inode_ref, goal, &fblock);
if (rc != EOK)
return rc;
uint16_t limit = ext4_extent_header_get_max_entries_count(path->header);
if (entries == limit) {
- uint32_t new_fblock;
- int rc = ext4_balloc_alloc_block(inode_ref, &new_fblock);
+ ext4_fsblk_t goal, new_fblock;
+ int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
+ if (rc != EOK)
+ return rc;
+
+ rc = ext4_balloc_alloc_block(inode_ref, goal, &new_fblock);
if (rc != EOK)
return rc;
* @return Error code*/
static int
ext4_extent_append_block(struct ext4_inode_ref *inode_ref, uint32_t *iblock,
- uint32_t *fblock, bool update_size)
+ ext4_fsblk_t *fblock, bool update_size)
{
uint16_t i;
+ ext4_fsblk_t goal;
struct ext4_sblock *sb = &inode_ref->fs->sb;
uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
uint32_t block_size = ext4_sb_get_block_size(sb);
uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
uint16_t block_limit = (1 << 15);
- uint32_t phys_block = 0;
+ ext4_fsblk_t phys_block = 0;
if (block_count < block_limit) {
/* There is space for new block in the extent */
if (block_count == 0) {
+ int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
+ if (rc != EOK)
+ goto finish;
+
/* Existing extent is empty */
- rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
+ rc = ext4_balloc_alloc_block(inode_ref, goal, &phys_block);
if (rc != EOK)
goto finish;
goto finish;
} else {
+ ext4_fsblk_t goal;
+ int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
+ if (rc != EOK)
+ goto finish;
+
/* Existing extent contains some blocks */
phys_block = ext4_extent_get_start(path_ptr->extent);
phys_block +=
/* Append new extent to the tree */
phys_block = 0;
+ rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
+ if (rc != EOK)
+ goto finish;
+
/* Allocate new data block */
- rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
+ rc = ext4_balloc_alloc_block(inode_ref, goal, &phys_block);
if (rc != EOK)
goto finish;
}
int ext4_extent_get_blocks(struct ext4_inode_ref *inode_ref, ext4_fsblk_t iblock,
- uint32_t max_blocks, ext4_fsblk_t *result, bool create,
- uint32_t *blocks_count)
+ ext4_lblk_t max_blocks, ext4_fsblk_t *result, bool create,
+ ext4_lblk_t *blocks_count)
{
uint32_t iblk = iblock;
- uint32_t fblk = 0;
+ ext4_fsblk_t fblk = 0;
int r;
if (blocks_count)
#include "ext4_config.h"
#include "ext4_blockdev.h"
+#include "ext4_fs.h"
#include "ext4_super.h"
#include "ext4_balloc.h"
#include "ext4_debug.h"
}
static int ext4_allocate_single_block(struct ext4_inode_ref *inode_ref,
- ext4_fsblk_t goal __unused,
+ ext4_fsblk_t goal,
ext4_fsblk_t *blockp)
{
- return ext4_balloc_alloc_block(inode_ref, (uint32_t *)blockp);
+ return ext4_balloc_alloc_block(inode_ref, goal, blockp);
}
static ext4_fsblk_t ext4_new_meta_blocks(struct ext4_inode_ref *inode_ref,
ext4_fsblk_t block, uint32_t count,
uint32_t flags __unused)
{
- uint32_t i;
- for (i = 0; i < count; i++)
- ext4_balloc_free_block(inode_ref, (uint32_t)block + i);
+ ext4_balloc_free_blocks(inode_ref, block, count);
}
static size_t ext4_ext_space_block(struct ext4_inode_ref *inode_ref)
return max;
}
-static ext4_fsblk_t ext4_ext_find_goal(struct ext4_extent_path *path,
+static ext4_fsblk_t ext4_ext_find_goal(struct ext4_inode_ref *inode_ref,
+ struct ext4_extent_path *path,
ext4_lblk_t block)
{
if (path) {
}
/* OK. use inode's group */
- return 0;
+ return ext4_fs_inode_to_goal_block(inode_ref);
}
/*
{
ext4_fsblk_t goal, newblock;
- goal = ext4_ext_find_goal(path, to_le32(ex->first_block));
+ goal = ext4_ext_find_goal(inode_ref, path, to_le32(ex->first_block));
newblock = ext4_new_meta_blocks(inode_ref, goal, flags, NULL, err);
return newblock;
}
goal = ext4_idx_pblock(
EXT_FIRST_INDEX(ext_inode_hdr(inode_ref->inode)));
else
- goal = 0;
+ goal = ext4_fs_inode_to_goal_block(inode_ref);
newblock = ext4_new_meta_blocks(inode_ref, goal, flags, NULL, &err);
if (newblock == 0)
allocated = max_blocks;
/* allocate new block */
- goal = ext4_ext_find_goal(path, iblock);
+ goal = ext4_ext_find_goal(inode_ref, path, iblock);
newblock = ext4_new_meta_blocks(inode_ref, goal, 0, &allocated, &err);
if (!newblock)
goto out2;
* @return Error code
*/
static int ext4_block_in_group(struct ext4_sblock *s,
- uint32_t baddr,
+ ext4_fsblk_t baddr,
uint32_t bgid)
{
uint32_t actual_bgid;
uint16_t inode_size = ext4_get16(&bg_ref->fs->sb, inode_size);
uint32_t block_size = ext4_sb_get_block_size(&bg_ref->fs->sb);
uint32_t inodes_per_group = ext4_get32(&bg_ref->fs->sb, inodes_per_group);
- uint32_t bitmap_block_addr =
+ ext4_fsblk_t bitmap_block_addr =
ext4_bg_get_block_bitmap(bg_ref->block_group, &bg_ref->fs->sb);
- uint32_t bitmap_inode_addr =
+ ext4_fsblk_t bitmap_inode_addr =
ext4_bg_get_inode_bitmap(bg_ref->block_group, &bg_ref->fs->sb);
- uint32_t inode_table_addr =
+ ext4_fsblk_t inode_table_addr =
ext4_bg_get_inode_table_first_block(bg_ref->block_group,
&bg_ref->fs->sb);
- uint32_t first_group_addr =
+ ext4_fsblk_t first_group_addr =
ext4_balloc_get_block_of_bgid(&bg_ref->fs->sb, bg_ref->index);
uint32_t dsc_per_block =
static int ext4_fs_init_inode_bitmap(struct ext4_block_group_ref *bg_ref)
{
/* Load bitmap */
- uint32_t bitmap_block_addr =
+ ext4_fsblk_t bitmap_block_addr =
ext4_bg_get_inode_bitmap(bg_ref->block_group, &bg_ref->fs->sb);
struct ext4_block block_bitmap;
uint32_t inodes_per_block = block_size / inode_size;
uint32_t inodes_in_group = ext4_inodes_in_group_cnt(sb, bg_ref->index);
uint32_t table_blocks = inodes_in_group / inodes_per_block;
- uint32_t fblock;
+ ext4_fsblk_t fblock;
if (inodes_in_group % inodes_per_block)
table_blocks++;
/* Compute initialization bounds */
- uint32_t first_block =
+ ext4_fsblk_t first_block =
ext4_bg_get_inode_table_first_block(bg_ref->block_group, sb);
- uint32_t last_block = first_block + table_blocks - 1;
+ ext4_fsblk_t last_block = first_block + table_blocks - 1;
/* Initialization of all itable blocks */
for (fblock = first_block; fblock <= last_block; ++fblock) {
return EOK;
}
-static uint64_t ext4_fs_get_descriptor_block(struct ext4_sblock *s,
+static ext4_fsblk_t ext4_fs_get_descriptor_block(struct ext4_sblock *s,
uint32_t bgid,
uint32_t dsc_per_block)
{
uint32_t byte_offset_in_group = offset_in_group * inode_size;
/* Compute block address */
- uint64_t block_id =
+ ext4_fsblk_t block_id =
inode_table_start + (byte_offset_in_group / block_size);
rc = ext4_block_get(fs->bdev, &ref->block, block_id);
/* Release all indirect (no data) blocks */
/* 1) Single indirect */
- uint32_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0);
+ ext4_fsblk_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0);
if (fblock != 0) {
int rc = ext4_balloc_free_block(inode_ref, fblock);
if (rc != EOK)
if (rc != EOK)
return rc;
- uint32_t ind_block;
+ ext4_fsblk_t ind_block;
for (offset = 0; offset < count; ++offset) {
ind_block = to_le32(((uint32_t *)block.data)[offset]);
if (rc != EOK)
return rc;
- uint32_t ind_block;
+ ext4_fsblk_t ind_block;
for (offset = 0; offset < count; ++offset) {
ind_block = to_le32(((uint32_t *)block.data)[offset]);
return rc;
}
- uint32_t ind_subblk;
+ ext4_fsblk_t ind_subblk;
for (suboff = 0; suboff < count; ++suboff) {
ind_subblk = to_le32(((uint32_t *)subblock.data)[suboff]);
inode_ref->dirty = true;
/* Free block with extended attributes if present */
- uint32_t xattr_block =
+ ext4_fsblk_t xattr_block =
ext4_inode_get_file_acl(inode_ref->inode, &fs->sb);
if (xattr_block) {
int rc = ext4_balloc_free_block(inode_ref, xattr_block);
return EOK;
}
+/**@brief Compute 'goal' for inode index
+ * @param inode_ref Reference to inode, to allocate block for
+ * @return goal
+ */
+ext4_fsblk_t ext4_fs_inode_to_goal_block(struct ext4_inode_ref *inode_ref)
+{
+ uint32_t group_inodes =
+ ext4_get32(&inode_ref->fs->sb, inodes_per_group);
+ return (inode_ref->index - 1) / group_inodes;
+}
+
+/**@brief Compute 'goal' for allocation algorithm (For blockmap).
+ * @param inode_ref Reference to inode, to allocate block for
+ * @param goal
+ * @return error code
+ */
+int ext4_fs_indirect_find_goal(struct ext4_inode_ref *inode_ref,
+ ext4_fsblk_t *goal)
+{
+ struct ext4_sblock *sb = &inode_ref->fs->sb;
+ *goal = 0;
+
+ uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
+ uint32_t block_size = ext4_sb_get_block_size(sb);
+ uint32_t inode_block_count = inode_size / block_size;
+
+ if (inode_size % block_size != 0)
+ inode_block_count++;
+
+ /* If inode has some blocks, get last block address + 1 */
+ if (inode_block_count > 0) {
+ int rc = ext4_fs_get_inode_data_block_index(
+ inode_ref, inode_block_count - 1, goal);
+ if (rc != EOK)
+ return rc;
+
+ if (*goal != 0) {
+ (*goal)++;
+ return rc;
+ }
+
+ /* If goal == 0, sparse file -> continue */
+ }
+
+ /* Identify block group of inode */
+
+ uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
+ uint32_t block_group = (inode_ref->index - 1) / inodes_per_group;
+ block_size = ext4_sb_get_block_size(sb);
+
+ /* Load block group reference */
+ struct ext4_block_group_ref bg_ref;
+ int rc =
+ ext4_fs_get_block_group_ref(inode_ref->fs, block_group, &bg_ref);
+ if (rc != EOK)
+ return rc;
+
+ /* Compute indexes */
+ uint32_t block_group_count = ext4_block_group_cnt(sb);
+ ext4_fsblk_t inode_table_first_block =
+ ext4_bg_get_inode_table_first_block(bg_ref.block_group, sb);
+ uint16_t inode_table_item_size = ext4_get16(sb, inode_size);
+ uint32_t inode_table_bytes;
+
+ /* Check for last block group */
+ if (block_group < block_group_count - 1) {
+ inode_table_bytes = inodes_per_group * inode_table_item_size;
+ } else {
+ /* Last block group could be smaller */
+ uint32_t inodes_count_total = ext4_get32(sb, inodes_count);
+
+ inode_table_bytes =
+ (inodes_count_total -
+ ((block_group_count - 1) * inodes_per_group)) *
+ inode_table_item_size;
+ }
+
+ ext4_fsblk_t inode_table_blocks = inode_table_bytes / block_size;
+
+ if (inode_table_bytes % block_size)
+ inode_table_blocks++;
+
+ *goal = inode_table_first_block + inode_table_blocks;
+
+ return ext4_fs_put_block_group_ref(&bg_ref);
+}
+
static int ext4_fs_get_inode_data_block_idx(struct ext4_inode_ref *inode_ref,
- uint64_t iblock, uint32_t *fblock,
+ uint64_t iblock, ext4_fsblk_t *fblock,
bool extent_create)
{
struct ext4_fs *fs = inode_ref->fs;
return EOK;
}
- uint32_t current_block;
+ ext4_fsblk_t current_block;
(void)extent_create;
#if CONFIG_EXTENT_ENABLE
if (rc != EOK)
return rc;
- current_block = (uint32_t)current_fsblk;
+ current_block = current_fsblk;
*fblock = current_block;
ext4_assert(*fblock);
int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
- uint64_t iblock, uint32_t *fblock)
+ uint64_t iblock, ext4_fsblk_t *fblock)
{
return ext4_fs_get_inode_data_block_idx(inode_ref, iblock, fblock,
false);
}
int ext4_fs_init_inode_data_block_index(struct ext4_inode_ref *inode_ref,
- uint64_t iblock, uint32_t *fblock)
+ uint64_t iblock, ext4_fsblk_t *fblock)
{
return ext4_fs_get_inode_data_block_idx(inode_ref, iblock, fblock,
true);
}
int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
- uint64_t iblock, uint32_t fblock)
+ uint64_t iblock, ext4_fsblk_t fblock)
{
struct ext4_fs *fs = inode_ref->fs;
/* Handle simple case when we are dealing with direct reference */
if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
ext4_inode_set_direct_block(inode_ref->inode, (uint32_t)iblock,
- fblock);
+ (uint32_t)fblock);
inode_ref->dirty = true;
return EOK;
/* Compute offsets for the topmost level */
uint64_t block_offset_in_level =
iblock - fs->inode_block_limits[level - 1];
- uint32_t current_block =
+ ext4_fsblk_t current_block =
ext4_inode_get_indirect_block(inode_ref->inode, level - 1);
uint32_t offset_in_block =
block_offset_in_level / fs->inode_blocks_per_level[level - 1];
- uint32_t new_block_addr;
+ ext4_fsblk_t new_block_addr;
struct ext4_block block;
struct ext4_block new_block;
/* Is needed to allocate indirect block on the i-node level */
if (current_block == 0) {
/* Allocate new indirect block */
- int rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
+ ext4_fsblk_t goal;
+ int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
+ if (rc != EOK)
+ return rc;
+
+ rc = ext4_balloc_alloc_block(inode_ref,
+ goal,
+ &new_block_addr);
if (rc != EOK)
return rc;
/* Update i-node */
ext4_inode_set_indirect_block(inode_ref->inode, level - 1,
- new_block_addr);
+ (uint32_t)new_block_addr);
inode_ref->dirty = true;
/* Load newly allocated block */
to_le32(((uint32_t *)block.data)[offset_in_block]);
if ((level > 1) && (current_block == 0)) {
+ ext4_fsblk_t goal;
+ rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
+ if (rc != EOK) {
+ ext4_block_set(fs->bdev, &block);
+ return rc;
+ }
+
/* Allocate new block */
rc =
- ext4_balloc_alloc_block(inode_ref, &new_block_addr);
+ ext4_balloc_alloc_block(inode_ref, goal, &new_block_addr);
if (rc != EOK) {
ext4_block_set(fs->bdev, &block);
return rc;
/* Write block address to the parent */
((uint32_t *)block.data)[offset_in_block] =
- to_le32(new_block_addr);
+ to_le32((uint32_t)new_block_addr);
block.dirty = true;
current_block = new_block_addr;
}
/* Will be finished, write the fblock address */
if (level == 1) {
((uint32_t *)block.data)[offset_in_block] =
- to_le32(fblock);
+ to_le32((uint32_t)fblock);
block.dirty = true;
}
int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
uint32_t iblock)
{
- uint32_t fblock;
+ ext4_fsblk_t fblock;
struct ext4_fs *fs = inode_ref->fs;
/* Compute offsets for the topmost level */
uint64_t block_offset_in_level =
iblock - fs->inode_block_limits[level - 1];
- uint32_t current_block =
+ ext4_fsblk_t current_block =
ext4_inode_get_indirect_block(inode, level - 1);
uint32_t offset_in_block =
block_offset_in_level / fs->inode_blocks_per_level[level - 1];
}
int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
- uint32_t *fblock, uint32_t *iblock)
+ ext4_fsblk_t *fblock, uint32_t *iblock)
{
#if CONFIG_EXTENT_ENABLE
/* Handle extents separately */
uint32_t new_block_idx = inode_size / block_size;
/* Allocate new physical block */
- uint32_t phys_block;
- int rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
+ ext4_fsblk_t goal, phys_block;
+ int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
+ if (rc != EOK)
+ return rc;
+
+ rc = ext4_balloc_alloc_block(inode_ref, goal, &phys_block);
if (rc != EOK)
return rc;
* @return Relative number of block
*/
static inline uint32_t ext4_fs_baddr2_index_in_group(struct ext4_sblock *s,
- uint32_t baddr)
+ ext4_fsblk_t baddr)
{
if (ext4_get32(s, first_data_block))
baddr--;
* @param bgid Block group
* @return Absolute block address
*/
-static inline uint32_t ext4_fs_index_in_group2_baddr(struct ext4_sblock *s,
+static inline ext4_fsblk_t ext4_fs_index_in_group2_baddr(struct ext4_sblock *s,
uint32_t index,
uint32_t bgid)
{
}
/**@brief TODO: */
-static inline uint64_t ext4_fs_first_bg_block_no(struct ext4_sblock *s,
+static inline ext4_fsblk_t ext4_fs_first_bg_block_no(struct ext4_sblock *s,
uint32_t bgid)
{
return (uint64_t)bgid * ext4_get32(s, blocks_per_group) +
*/
int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref, uint64_t new_size);
+/**@brief Compute 'goal' for inode index
+ * @param inode_ref Reference to inode, to allocate block for
+ * @return goal
+ */
+ext4_fsblk_t ext4_fs_inode_to_goal_block(struct ext4_inode_ref *inode_ref);
+
+/**@brief Compute 'goal' for allocation algorithm (For blockmap).
+ * @param inode_ref Reference to inode, to allocate block for
+ * @param goal
+ * @return error code
+ */
+int ext4_fs_indirect_find_goal(struct ext4_inode_ref *inode_ref,
+ ext4_fsblk_t *goal);
+
/**@brief Get physical block address by logical index of the block.
* @param inode_ref I-node to read block address from
* @param iblock Logical index of block
* @return Error code
*/
int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
- uint64_t iblock, uint32_t *fblock);
+ uint64_t iblock, ext4_fsblk_t *fblock);
/**@brief Initialize a part of unwritten range of the inode.
* @param inode_ref I-node to proceed on.
* @return Error code
*/
int ext4_fs_init_inode_data_block_index(struct ext4_inode_ref *inode_ref,
- uint64_t iblock, uint32_t *fblock);
+ uint64_t iblock, ext4_fsblk_t *fblock);
/**@brief Set physical block address for the block logical address into the
* i-node.
* @return Error code
*/
int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
- uint64_t iblock, uint32_t fblock);
+ uint64_t iblock, ext4_fsblk_t fblock);
/**@brief Release data block from i-node
* @param inode_ref I-node to release block from
* @return Error code
*/
int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
- uint32_t *fblock, uint32_t *iblock);
+ ext4_fsblk_t *fblock, uint32_t *iblock);
/**@brief Increment inode link count.
* @param inode none handle
#include "ext4_block_group.h"
#include "ext4_balloc.h"
#include "ext4_inode.h"
-#include "ext4_extent.h"
#include <string.h>
#include <stdlib.h>
{
int ret = EOK;
- uint64_t xattr_block = 0;
+ ext4_fsblk_t xattr_block = 0;
xattr_block = ext4_inode_get_file_acl(xattr_ref->inode_ref->inode,
&xattr_ref->fs->sb);
if (!xattr_block) {
+ ext4_fsblk_t goal =
+ ext4_fs_inode_to_goal_block(xattr_ref->inode_ref);
+
ret = ext4_balloc_alloc_block(xattr_ref->inode_ref,
- (uint32_t *)&xattr_block);
+ goal,
+ &xattr_block);
if (ret != EOK)
goto Finish;
static void ext4_xattr_try_free_block(struct ext4_xattr_ref *xattr_ref)
{
- uint64_t xattr_block;
+ ext4_fsblk_t xattr_block;
xattr_block = ext4_inode_get_file_acl(xattr_ref->inode_ref->inode,
&xattr_ref->fs->sb);
ext4_inode_set_file_acl(xattr_ref->inode_ref->inode, &xattr_ref->fs->sb,
struct ext4_xattr_ref *ref)
{
int rc;
- uint64_t xattr_block;
+ ext4_fsblk_t xattr_block;
xattr_block = ext4_inode_get_file_acl(inode_ref->inode, &fs->sb);
RB_INIT(&ref->root);
ref->ea_size = 0;