ext4: Scan all directory blocks for space when inserting a new entry

Previously, only the last directory block was scanned for available space.
Instead, scan all blocks back to front, and if no sufficient space is
found, eventually append a new block.
Blocks are only appended if the directory does not use extents or the new
block would require insertion of indirect blocks, as the old code does.

Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>
This commit is contained in:
Stefan Brüns 2016-09-06 04:36:44 +02:00 committed by Tom Rini
parent b96c3c7292
commit a321abd54f

View file

@ -370,14 +370,10 @@ int ext4fs_update_parent_dentry(char *filename, int file_type)
{ {
unsigned int *zero_buffer = NULL; unsigned int *zero_buffer = NULL;
char *root_first_block_buffer = NULL; char *root_first_block_buffer = NULL;
int direct_blk_idx; int blk_idx;
long int root_blknr;
long int first_block_no_of_root = 0; long int first_block_no_of_root = 0;
long int previous_blknr = -1;
int totalbytes = 0; int totalbytes = 0;
short int padding_factor = 0;
unsigned int new_entry_byte_reqd; unsigned int new_entry_byte_reqd;
unsigned int last_entry_dirlen;
int sizeof_void_space = 0; int sizeof_void_space = 0;
int templength = 0; int templength = 0;
int inodeno = -1; int inodeno = -1;
@ -389,6 +385,7 @@ int ext4fs_update_parent_dentry(char *filename, int file_type)
uint32_t new_blk_no; uint32_t new_blk_no;
uint32_t new_size; uint32_t new_size;
uint32_t new_blockcnt; uint32_t new_blockcnt;
uint32_t directory_blocks;
zero_buffer = zalloc(fs->blksz); zero_buffer = zalloc(fs->blksz);
if (!zero_buffer) { if (!zero_buffer) {
@ -401,19 +398,18 @@ int ext4fs_update_parent_dentry(char *filename, int file_type)
printf("No Memory\n"); printf("No Memory\n");
return -1; return -1;
} }
new_entry_byte_reqd = ROUND(strlen(filename) +
sizeof(struct ext2_dirent), 4);
restart: restart:
directory_blocks = le32_to_cpu(g_parent_inode->size) >>
LOG2_BLOCK_SIZE(ext4fs_root);
blk_idx = directory_blocks - 1;
restart_read:
/* read the block no allocated to a file */ /* read the block no allocated to a file */
for (direct_blk_idx = 0; direct_blk_idx < INDIRECT_BLOCKS; first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx);
direct_blk_idx++) { if (first_block_no_of_root <= 0)
root_blknr = read_allocated_block(g_parent_inode, goto fail;
direct_blk_idx);
if (root_blknr == 0) {
first_block_no_of_root = previous_blknr;
break;
}
previous_blknr = root_blknr;
}
status = ext4fs_devread((lbaint_t)first_block_no_of_root status = ext4fs_devread((lbaint_t)first_block_no_of_root
* fs->sect_perblk, * fs->sect_perblk,
@ -425,42 +421,33 @@ restart:
goto fail; goto fail;
dir = (struct ext2_dirent *)root_first_block_buffer; dir = (struct ext2_dirent *)root_first_block_buffer;
totalbytes = 0; totalbytes = 0;
while (le16_to_cpu(dir->direntlen) > 0) { while (le16_to_cpu(dir->direntlen) > 0) {
/* unsigned short used_len = ROUND(dir->namelen +
* blocksize-totalbytes because last directory length sizeof(struct ext2_dirent), 4);
* i.e. dir->direntlen is free availble space in the
* block that means it is a last entry of directory
* entry
*/
/* traversing the each directory entry */ /* last entry of block */
if (fs->blksz - totalbytes == le16_to_cpu(dir->direntlen)) { if (fs->blksz - totalbytes == le16_to_cpu(dir->direntlen)) {
if (strlen(filename) % 4 != 0)
padding_factor = 4 - (strlen(filename) % 4);
new_entry_byte_reqd = strlen(filename) + /* check if new entry fits */
sizeof(struct ext2_dirent) + padding_factor; if ((used_len + new_entry_byte_reqd) <=
padding_factor = 0; le16_to_cpu(dir->direntlen)) {
/* dir->direntlen = cpu_to_le16(used_len);
* update last directory entry length to its break;
* length because we are creating new directory } else {
* entry if (blk_idx > 0) {
*/ printf("Block full, trying previous\n");
if (dir->namelen % 4 != 0) blk_idx--;
padding_factor = 4 - (dir->namelen % 4); goto restart_read;
}
last_entry_dirlen = dir->namelen + printf("All blocks full: Allocate new\n");
sizeof(struct ext2_dirent) + padding_factor;
if ((fs->blksz - totalbytes - last_entry_dirlen) <
new_entry_byte_reqd) {
printf("Last Block Full:Allocate new block\n");
if (le32_to_cpu(g_parent_inode->flags) & if (le32_to_cpu(g_parent_inode->flags) &
EXT4_EXTENTS_FL) { EXT4_EXTENTS_FL) {
printf("Directory uses extents\n"); printf("Directory uses extents\n");
goto fail; goto fail;
} }
if (direct_blk_idx == INDIRECT_BLOCKS - 1) { if (directory_blocks >= INDIRECT_BLOCKS) {
printf("Directory exceeds limit\n"); printf("Directory exceeds limit\n");
goto fail; goto fail;
} }
@ -470,7 +457,8 @@ restart:
goto fail; goto fail;
} }
put_ext4((uint64_t)new_blk_no * fs->blksz, zero_buffer, fs->blksz); put_ext4((uint64_t)new_blk_no * fs->blksz, zero_buffer, fs->blksz);
g_parent_inode->b.blocks.dir_blocks[direct_blk_idx] = g_parent_inode->b.blocks.
dir_blocks[directory_blocks] =
cpu_to_le32(new_blk_no); cpu_to_le32(new_blk_no);
new_size = le32_to_cpu(g_parent_inode->size); new_size = le32_to_cpu(g_parent_inode->size);
@ -487,8 +475,6 @@ restart:
goto fail; goto fail;
goto restart; goto restart;
} }
dir->direntlen = cpu_to_le16(last_entry_dirlen);
break;
} }
templength = le16_to_cpu(dir->direntlen); templength = le16_to_cpu(dir->direntlen);