HelenOS sources
This source file includes following definitions.
- ext4_ialloc_inode2index_in_group
- ext4_ialloc_index_in_group2inode
- ext4_ialloc_get_bgid_of_inode
- ext4_ialloc_free_inode
- ext4_ialloc_alloc_inode
- ext4_ialloc_alloc_this_inode
#include <errno.h>
#include <stdbool.h>
#include "ext4/bitmap.h"
#include "ext4/block_group.h"
#include "ext4/filesystem.h"
#include "ext4/ialloc.h"
#include "ext4/superblock.h"
static uint32_t ext4_ialloc_inode2index_in_group(ext4_superblock_t *sb,
uint32_t inode)
{
uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
return (inode - 1) % inodes_per_group;
}
static uint32_t ext4_ialloc_index_in_group2inode(ext4_superblock_t *sb,
uint32_t index, uint32_t bgid)
{
uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
return bgid * inodes_per_group + (index + 1);
}
static uint32_t ext4_ialloc_get_bgid_of_inode(ext4_superblock_t *sb,
uint32_t inode)
{
uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
return (inode - 1) / inodes_per_group;
}
errno_t ext4_ialloc_free_inode(ext4_filesystem_t *fs, uint32_t index, bool is_dir)
{
ext4_superblock_t *sb = fs->superblock;
uint32_t block_group = ext4_ialloc_get_bgid_of_inode(sb, index);
ext4_block_group_ref_t *bg_ref;
errno_t rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref);
if (rc != EOK)
return rc;
uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap(
bg_ref->block_group, sb);
block_t *bitmap_block;
rc = block_get(&bitmap_block, fs->device, bitmap_block_addr,
BLOCK_FLAGS_NONE);
if (rc != EOK)
return rc;
uint32_t index_in_group = ext4_ialloc_inode2index_in_group(sb, index);
ext4_bitmap_free_bit(bitmap_block->data, index_in_group);
bitmap_block->dirty = true;
rc = block_put(bitmap_block);
if (rc != EOK) {
ext4_filesystem_put_block_group_ref(bg_ref);
return rc;
}
if (is_dir) {
uint32_t bg_used_dirs = ext4_block_group_get_used_dirs_count(
bg_ref->block_group, sb);
bg_used_dirs--;
ext4_block_group_set_used_dirs_count(bg_ref->block_group, sb,
bg_used_dirs);
}
uint32_t free_inodes = ext4_block_group_get_free_inodes_count(
bg_ref->block_group, sb);
free_inodes++;
ext4_block_group_set_free_inodes_count(bg_ref->block_group, sb,
free_inodes);
bg_ref->dirty = true;
rc = ext4_filesystem_put_block_group_ref(bg_ref);
if (rc != EOK)
return rc;
uint32_t sb_free_inodes =
ext4_superblock_get_free_inodes_count(sb);
sb_free_inodes++;
ext4_superblock_set_free_inodes_count(sb, sb_free_inodes);
return EOK;
}
errno_t ext4_ialloc_alloc_inode(ext4_filesystem_t *fs, uint32_t *index, bool is_dir)
{
int pick_first_free = 0;
ext4_superblock_t *sb = fs->superblock;
uint32_t bgid;
uint32_t sb_free_inodes;
uint32_t avg_free_inodes;
uint32_t const bg_count = ext4_superblock_get_block_group_count(sb);
retry:
bgid = 0;
sb_free_inodes = ext4_superblock_get_free_inodes_count(sb);
avg_free_inodes = sb_free_inodes / bg_count;
while (bgid < bg_count) {
ext4_block_group_ref_t *bg_ref;
errno_t rc = ext4_filesystem_get_block_group_ref(fs, bgid, &bg_ref);
if (rc != EOK)
return rc;
ext4_block_group_t *bg = bg_ref->block_group;
uint32_t free_blocks = ext4_block_group_get_free_blocks_count(bg, sb);
uint32_t free_inodes = ext4_block_group_get_free_inodes_count(bg, sb);
uint32_t used_dirs = ext4_block_group_get_used_dirs_count(bg, sb);
if (((free_inodes >= avg_free_inodes) ||
(bgid == bg_count - 1) || pick_first_free) && (free_blocks > 0)) {
uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap(
bg_ref->block_group, sb);
block_t *bitmap_block;
rc = block_get(&bitmap_block, fs->device, bitmap_block_addr,
BLOCK_FLAGS_NONE);
if (rc != EOK) {
ext4_filesystem_put_block_group_ref(bg_ref);
return rc;
}
uint32_t inodes_in_group = ext4_superblock_get_inodes_in_group(sb, bgid);
uint32_t index_in_group;
rc = ext4_bitmap_find_free_bit_and_set(bitmap_block->data,
0, &index_in_group, inodes_in_group);
if (rc == ENOSPC) {
rc = block_put(bitmap_block);
if (rc != EOK) {
ext4_filesystem_put_block_group_ref(bg_ref);
return rc;
}
rc = ext4_filesystem_put_block_group_ref(bg_ref);
if (rc != EOK)
return rc;
bgid++;
continue;
}
bitmap_block->dirty = true;
rc = block_put(bitmap_block);
if (rc != EOK) {
ext4_filesystem_put_block_group_ref(bg_ref);
return rc;
}
free_inodes--;
ext4_block_group_set_free_inodes_count(bg, sb, free_inodes);
if (is_dir) {
used_dirs++;
ext4_block_group_set_used_dirs_count(bg, sb, used_dirs);
}
if (ext4_block_group_has_flag(bg,
EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
uint32_t unused =
ext4_block_group_get_itable_unused(bg, sb);
uint32_t inodes_in_group =
ext4_superblock_get_inodes_in_group(sb, bgid);
uint32_t free = inodes_in_group - unused;
if (index_in_group >= free) {
unused = inodes_in_group - (index_in_group + 1);
ext4_block_group_set_itable_unused(bg, sb, unused);
}
}
bg_ref->dirty = true;
rc = ext4_filesystem_put_block_group_ref(bg_ref);
if (rc != EOK)
return rc;
sb_free_inodes--;
ext4_superblock_set_free_inodes_count(sb, sb_free_inodes);
*index = ext4_ialloc_index_in_group2inode(sb, index_in_group, bgid);
return EOK;
}
rc = ext4_filesystem_put_block_group_ref(bg_ref);
if (rc != EOK)
return rc;
++bgid;
}
if (pick_first_free == 0) {
pick_first_free = 1;
goto retry;
}
return ENOSPC;
}
errno_t ext4_ialloc_alloc_this_inode(ext4_filesystem_t *fs, uint32_t inode,
bool is_dir)
{
ext4_superblock_t *sb = fs->superblock;
uint32_t bgid = ext4_ialloc_get_bgid_of_inode(sb, inode);
uint32_t sb_free_inodes = ext4_superblock_get_free_inodes_count(sb);
ext4_block_group_ref_t *bg_ref;
errno_t rc = ext4_filesystem_get_block_group_ref(fs, bgid, &bg_ref);
if (rc != EOK)
return rc;
ext4_block_group_t *bg = bg_ref->block_group;
uint32_t free_inodes = ext4_block_group_get_free_inodes_count(bg, sb);
uint32_t used_dirs = ext4_block_group_get_used_dirs_count(bg, sb);
uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap(
bg_ref->block_group, sb);
block_t *bitmap_block;
rc = block_get(&bitmap_block, fs->device, bitmap_block_addr,
BLOCK_FLAGS_NONE);
if (rc != EOK) {
ext4_filesystem_put_block_group_ref(bg_ref);
return rc;
}
uint32_t index_in_group = ext4_ialloc_inode2index_in_group(sb, inode);
ext4_bitmap_set_bit(bitmap_block->data, index_in_group);
bitmap_block->dirty = true;
rc = block_put(bitmap_block);
if (rc != EOK) {
ext4_filesystem_put_block_group_ref(bg_ref);
return rc;
}
free_inodes--;
ext4_block_group_set_free_inodes_count(bg, sb, free_inodes);
if (is_dir) {
used_dirs++;
ext4_block_group_set_used_dirs_count(bg, sb, used_dirs);
}
if (ext4_block_group_has_flag(bg,
EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
uint32_t unused =
ext4_block_group_get_itable_unused(bg, sb);
uint32_t inodes_in_group =
ext4_superblock_get_inodes_in_group(sb, bgid);
uint32_t free = inodes_in_group - unused;
if (index_in_group >= free) {
unused = inodes_in_group - (index_in_group + 1);
ext4_block_group_set_itable_unused(bg, sb, unused);
}
}
bg_ref->dirty = true;
rc = ext4_filesystem_put_block_group_ref(bg_ref);
if (rc != EOK)
return rc;
sb_free_inodes--;
ext4_superblock_set_free_inodes_count(sb, sb_free_inodes);
return EOK;
}
HelenOS homepage, sources at GitHub