From 4bd842820e2740c23908932e264cbf43cb1fdd27 Mon Sep 17 00:00:00 2001 From: gkostka Date: Thu, 24 Oct 2013 00:18:52 +0000 Subject: [PATCH] Bugfix: 1. Directory hash MD4 bugfix. 2. A lot of fixes in directory indexing. 3. Improved inode allocation. --- lwext4/ext4_dir_idx.c | 40 ++++++++++++++++++++++++++++------------ lwext4/ext4_hash.c | 4 ++-- lwext4/ext4_ialloc.c | 20 ++++++++++++++++---- lwext4/ext4_types.h | 2 ++ 4 files changed, 48 insertions(+), 18 deletions(-) diff --git a/lwext4/ext4_dir_idx.c b/lwext4/ext4_dir_idx.c index 408d1eb..4a75a35 100644 --- a/lwext4/ext4_dir_idx.c +++ b/lwext4/ext4_dir_idx.c @@ -351,7 +351,7 @@ static int ext4_dir_dx_get_leaf(struct ext4_hash_info *hinfo, uint16_t entry_space = ext4_sb_get_block_size(&inode_ref->fs->sb) - - sizeof(struct ext4_directory_dx_dot_entry); + sizeof(struct ext4_fake_directory_entry); entry_space = entry_space / sizeof(struct ext4_directory_dx_entry); @@ -606,7 +606,7 @@ static int ext4_dir_dx_split_data(struct ext4_inode_ref *inode_ref, void *entry_buffer_ptr = entry_buffer; while ((void *)dentry < (void *)(old_data_block->data + block_size)) { /* Read only valid entries */ - if (ext4_dir_entry_ll_get_inode(dentry) != 0) { + if (ext4_dir_entry_ll_get_inode(dentry) && dentry->name_length) { uint8_t len = ext4_dir_entry_ll_get_name_length( &inode_ref->fs->sb, dentry); @@ -671,7 +671,7 @@ static int ext4_dir_dx_split_data(struct ext4_inode_ref *inode_ref, uint32_t mid = 0; uint32_t i; for ( i = 0; i < idx; ++i) { - if ((current_size + sort_array[i].rec_len) > (real_size / 2)) { + if ((current_size + sort_array[i].rec_len) > (block_size / 2)) { new_hash = sort_array[i].hash; mid = i; break; @@ -747,9 +747,11 @@ static int ext4_dir_dx_split_data(struct ext4_inode_ref *inode_ref, */ static int ext4_dir_dx_split_index(struct ext4_inode_ref *inode_ref, struct ext4_directory_dx_block *dx_blocks, - struct ext4_directory_dx_block *dx_block) + struct ext4_directory_dx_block *dx_block, + struct ext4_directory_dx_block **new_dx_block) { struct ext4_directory_dx_entry *entries; + if (dx_block == dx_blocks) entries = ((struct ext4_directory_dx_root *) dx_block->block.data)->entries; @@ -801,9 +803,13 @@ static int ext4_dir_dx_split_index(struct ext4_inode_ref *inode_ref, struct ext4_directory_dx_node *new_node = (void *)new_block.data; struct ext4_directory_dx_entry *new_entries = new_node->entries; + memset(&new_node->fake, 0, sizeof(struct ext4_fake_directory_entry)); + uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb); + new_node->fake.entry_length = block_size; + /* Split leaf node */ if (levels > 0) { uint32_t count_left = leaf_count / 2; @@ -849,7 +855,10 @@ static int ext4_dir_dx_split_index(struct ext4_inode_ref *inode_ref, /* Finally insert new entry */ ext4_dir_dx_insert_entry(dx_blocks, hash_right, new_iblock); + dx_blocks[0].block.dirty = true; + dx_blocks[1].block.dirty = true; + new_block.dirty = true; return ext4_block_set(inode_ref->fs->bdev, &new_block); } else { /* Create second level index */ @@ -879,9 +888,14 @@ static int ext4_dir_dx_split_index(struct ext4_inode_ref *inode_ref, /* Add new entry to the path */ dx_block = dx_blocks + 1; - dx_block->position = dx_block->position - entries + new_entries; + dx_block->position = dx_blocks->position - entries + new_entries; dx_block->entries = new_entries; dx_block->block = new_block; + + *new_dx_block = dx_block; + + dx_blocks[0].block.dirty = true; + dx_blocks[1].block.dirty = true; } } @@ -941,24 +955,26 @@ int ext4_dir_dx_add_entry(struct ext4_inode_ref *parent, if (rc != EOK) goto release_index; + /* + * Check if there is needed to split index node + * (and recursively also parent nodes) + */ + rc = ext4_dir_dx_split_index(parent, dx_blocks, dx_block, &dx_block); + if (rc != EOK) + goto release_target_index; + struct ext4_block target_block; rc = ext4_block_get(fs->bdev, &target_block, leaf_block_addr); if (rc != EOK) goto release_index; + /* Check if insert operation passed */ rc = ext4_dir_try_insert_entry(&fs->sb, &target_block, child, name, name_len); if (rc == EOK) goto release_target_index; - /* - * Check if there is needed to split index node - * (and recursively also parent nodes) - */ - rc = ext4_dir_dx_split_index(parent, dx_blocks, dx_block); - if (rc != EOK) - goto release_target_index; /* Split entries to two blocks (includes sorting by hash value) */ struct ext4_block new_block; diff --git a/lwext4/ext4_hash.c b/lwext4/ext4_hash.c index f3cdce5..9e7f8bb 100644 --- a/lwext4/ext4_hash.c +++ b/lwext4/ext4_hash.c @@ -292,8 +292,8 @@ ext2_htree_hash(const char *name, int len, len -= 32; name += 32; } - major = hash[0]; - minor = hash[1]; + major = hash[1]; + minor = hash[2]; break; default: goto error; diff --git a/lwext4/ext4_ialloc.c b/lwext4/ext4_ialloc.c index 587373b..5d85171 100644 --- a/lwext4/ext4_ialloc.c +++ b/lwext4/ext4_ialloc.c @@ -137,13 +137,24 @@ int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir) { struct ext4_sblock *sb = &fs->sb; - uint32_t bgid = 0; + uint32_t bgid = fs->last_inode_bg_id; uint32_t bg_count = ext4_block_group_cnt(sb); uint32_t sb_free_inodes = ext4_get32(sb, free_inodes_count); uint32_t avg_free_inodes = sb_free_inodes / bg_count; + bool rewind = false; /* Try to find free i-node in all block groups */ - while (bgid < bg_count) { + while (bgid <= bg_count) { + + if(bgid == bg_count){ + if(rewind) + break; + bg_count = fs->last_inode_bg_id; + bgid = 0; + rewind = true; + continue; + } + /* Load block group to check */ struct ext4_block_group_ref bg_ref; int rc = ext4_fs_get_block_group_ref(fs, bgid, &bg_ref); @@ -153,12 +164,11 @@ int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir) struct ext4_bgroup *bg = bg_ref.block_group; /* Read necessary values for algorithm */ - uint32_t free_blocks = ext4_bg_get_free_blocks_count(bg, sb); uint32_t free_inodes = ext4_bg_get_free_inodes_count(bg, sb); uint32_t used_dirs = ext4_bg_get_used_dirs_count(bg, sb); /* Check if this block group is good candidate for allocation */ - if ((free_inodes >= avg_free_inodes) && (free_blocks > 0)) { + if (free_inodes >= avg_free_inodes) { /* Load block with bitmap */ uint32_t bitmap_block_addr = ext4_bg_get_inode_bitmap( bg_ref.block_group, sb); @@ -233,6 +243,8 @@ int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir) *index = ext4_ialloc_index_in_group2inode(sb, index_in_group, bgid); + fs->last_inode_bg_id = bgid; + return EOK; } diff --git a/lwext4/ext4_types.h b/lwext4/ext4_types.h index ef1a42e..8ce44da 100644 --- a/lwext4/ext4_types.h +++ b/lwext4/ext4_types.h @@ -235,6 +235,8 @@ struct ext4_fs { uint64_t inode_block_limits[4]; uint64_t inode_blocks_per_level[4]; + + uint32_t last_inode_bg_id; };