Commit dfa2064b authored by Jan Kara's avatar Jan Kara Committed by Theodore Ts'o

ext4: factor out loop for freeing inode xattr space

Move loop to make enough space in the inode from
ext4_expand_extra_isize_ea() into a separate function to make that
function smaller and better readable and also to avoid delaration of
variables inside a loop block.
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent 6e0cd088
...@@ -1417,6 +1417,63 @@ static int ext4_xattr_move_to_block(handle_t *handle, struct inode *inode, ...@@ -1417,6 +1417,63 @@ static int ext4_xattr_move_to_block(handle_t *handle, struct inode *inode,
return error; return error;
} }
static int ext4_xattr_make_inode_space(handle_t *handle, struct inode *inode,
struct ext4_inode *raw_inode,
int isize_diff, size_t ifree,
size_t bfree, int *total_ino)
{
struct ext4_xattr_ibody_header *header = IHDR(inode, raw_inode);
struct ext4_xattr_entry *small_entry;
struct ext4_xattr_entry *entry;
struct ext4_xattr_entry *last;
unsigned int entry_size; /* EA entry size */
unsigned int total_size; /* EA entry size + value size */
unsigned int min_total_size;
int error;
while (isize_diff > ifree) {
entry = NULL;
small_entry = NULL;
min_total_size = ~0U;
last = IFIRST(header);
/* Find the entry best suited to be pushed into EA block */
for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
total_size =
EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
EXT4_XATTR_LEN(last->e_name_len);
if (total_size <= bfree &&
total_size < min_total_size) {
if (total_size + ifree < isize_diff) {
small_entry = last;
} else {
entry = last;
min_total_size = total_size;
}
}
}
if (entry == NULL) {
if (small_entry == NULL)
return -ENOSPC;
entry = small_entry;
}
entry_size = EXT4_XATTR_LEN(entry->e_name_len);
total_size = entry_size +
EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size));
error = ext4_xattr_move_to_block(handle, inode, raw_inode,
entry);
if (error)
return error;
*total_ino -= entry_size;
ifree += total_size;
bfree -= total_size;
}
return 0;
}
/* /*
* Expand an inode by new_extra_isize bytes when EAs are present. * Expand an inode by new_extra_isize bytes when EAs are present.
* Returns 0 on success or negative error number on failure. * Returns 0 on success or negative error number on failure.
...@@ -1491,66 +1548,26 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, ...@@ -1491,66 +1548,26 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
brelse(bh); brelse(bh);
goto retry; goto retry;
} }
error = -1; error = -ENOSPC;
goto cleanup; goto cleanup;
} }
} else { } else {
bfree = inode->i_sb->s_blocksize; bfree = inode->i_sb->s_blocksize;
} }
while (isize_diff > ifree) { error = ext4_xattr_make_inode_space(handle, inode, raw_inode,
struct ext4_xattr_entry *small_entry = NULL, *entry = NULL; isize_diff, ifree, bfree,
struct ext4_xattr_entry *last; &total_ino);
unsigned int entry_size; /* EA entry size */ if (error) {
unsigned int total_size; /* EA entry size + value size */ if (error == -ENOSPC && !tried_min_extra_isize &&
unsigned int min_total_size = ~0U; s_min_extra_isize) {
tried_min_extra_isize++;
last = IFIRST(header); new_extra_isize = s_min_extra_isize;
/* Find the entry best suited to be pushed into EA block */ brelse(bh);
for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { goto retry;
total_size =
EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
EXT4_XATTR_LEN(last->e_name_len);
if (total_size <= bfree &&
total_size < min_total_size) {
if (total_size + ifree < isize_diff) {
small_entry = last;
} else {
entry = last;
min_total_size = total_size;
}
}
}
if (entry == NULL) {
if (small_entry) {
entry = small_entry;
} else {
if (!tried_min_extra_isize &&
s_min_extra_isize) {
tried_min_extra_isize++;
new_extra_isize = s_min_extra_isize;
brelse(bh);
goto retry;
}
error = -1;
goto cleanup;
}
} }
goto cleanup;
entry_size = EXT4_XATTR_LEN(entry->e_name_len);
total_size = entry_size +
EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size));
error = ext4_xattr_move_to_block(handle, inode, raw_inode,
entry);
if (error)
goto cleanup;
total_ino -= entry_size;
ifree += total_size;
bfree -= total_size;
} }
shift: shift:
/* Adjust the offsets and shift the remaining entries ahead */ /* Adjust the offsets and shift the remaining entries ahead */
ext4_xattr_shift_entries(IFIRST(header), EXT4_I(inode)->i_extra_isize ext4_xattr_shift_entries(IFIRST(header), EXT4_I(inode)->i_extra_isize
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment