Skip to content

Commit 90f097b

Browse files
committed
ext4: refactor the inline directory conversion and new directory codepaths
There was a lot of common code in the codepaths used to convert an inline directory and to creaet a new directory. To address this, rename ext4_init_dot_dotdot() to ext4_init_dirblock() and then move common code into that function. This reduces the lines of code count in fs/ext4/inline.c and fs/ext4/namei.c, as well as reducing the size of their object files. Signed-off-by: Theodore Ts'o <tytso@mit.edu> Link: https://patch.msgid.link/20250712181249.434530-3-tytso@mit.edu Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent a35454e commit 90f097b

File tree

3 files changed

+48
-77
lines changed

3 files changed

+48
-77
lines changed

fs/ext4/ext4.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3612,6 +3612,7 @@ extern loff_t ext4_llseek(struct file *file, loff_t offset, int origin);
36123612
extern int ext4_get_max_inline_size(struct inode *inode);
36133613
extern int ext4_find_inline_data_nolock(struct inode *inode);
36143614
extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode);
3615+
extern void ext4_update_final_de(void *de_buf, int old_size, int new_size);
36153616

36163617
int ext4_readpage_inline(struct inode *inode, struct folio *folio);
36173618
extern int ext4_try_to_write_inline_data(struct address_space *mapping,
@@ -3671,10 +3672,10 @@ static inline int ext4_has_inline_data(struct inode *inode)
36713672
extern const struct inode_operations ext4_dir_inode_operations;
36723673
extern const struct inode_operations ext4_special_inode_operations;
36733674
extern struct dentry *ext4_get_parent(struct dentry *child);
3674-
extern struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
3675-
struct ext4_dir_entry_2 *de,
3676-
int blocksize, int csum_size,
3677-
unsigned int parent_ino, int dotdot_real_len);
3675+
extern int ext4_init_dirblock(handle_t *handle, struct inode *inode,
3676+
struct buffer_head *dir_block,
3677+
unsigned int parent_ino, void *inline_buf,
3678+
int inline_size);
36783679
extern void ext4_initialize_dirent_tail(struct buffer_head *bh,
36793680
unsigned int blocksize);
36803681
extern int ext4_handle_dirty_dirblock(handle_t *handle, struct inode *inode,

fs/ext4/inline.c

Lines changed: 12 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,7 @@ static void *ext4_get_inline_xattr_pos(struct inode *inode,
997997
}
998998

999999
/* Set the final de to cover the whole block. */
1000-
static void ext4_update_final_de(void *de_buf, int old_size, int new_size)
1000+
void ext4_update_final_de(void *de_buf, int old_size, int new_size)
10011001
{
10021002
struct ext4_dir_entry_2 *de, *prev_de;
10031003
void *limit;
@@ -1061,51 +1061,6 @@ static void ext4_restore_inline_data(handle_t *handle, struct inode *inode,
10611061
ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
10621062
}
10631063

1064-
static int ext4_finish_convert_inline_dir(handle_t *handle,
1065-
struct inode *inode,
1066-
struct buffer_head *dir_block,
1067-
void *buf,
1068-
int inline_size)
1069-
{
1070-
int err, csum_size = 0, header_size = 0;
1071-
struct ext4_dir_entry_2 *de;
1072-
void *target = dir_block->b_data;
1073-
1074-
/*
1075-
* First create "." and ".." and then copy the dir information
1076-
* back to the block.
1077-
*/
1078-
de = target;
1079-
de = ext4_init_dot_dotdot(inode, de,
1080-
inode->i_sb->s_blocksize, csum_size,
1081-
le32_to_cpu(((struct ext4_dir_entry_2 *)buf)->inode), 1);
1082-
header_size = (void *)de - target;
1083-
1084-
memcpy((void *)de, buf + EXT4_INLINE_DOTDOT_SIZE,
1085-
inline_size - EXT4_INLINE_DOTDOT_SIZE);
1086-
1087-
if (ext4_has_feature_metadata_csum(inode->i_sb))
1088-
csum_size = sizeof(struct ext4_dir_entry_tail);
1089-
1090-
inode->i_size = inode->i_sb->s_blocksize;
1091-
i_size_write(inode, inode->i_sb->s_blocksize);
1092-
EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
1093-
ext4_update_final_de(dir_block->b_data,
1094-
inline_size - EXT4_INLINE_DOTDOT_SIZE + header_size,
1095-
inode->i_sb->s_blocksize - csum_size);
1096-
1097-
if (csum_size)
1098-
ext4_initialize_dirent_tail(dir_block,
1099-
inode->i_sb->s_blocksize);
1100-
set_buffer_uptodate(dir_block);
1101-
unlock_buffer(dir_block);
1102-
err = ext4_handle_dirty_dirblock(handle, inode, dir_block);
1103-
if (err)
1104-
return err;
1105-
set_buffer_verified(dir_block);
1106-
return ext4_mark_inode_dirty(handle, inode);
1107-
}
1108-
11091064
static int ext4_convert_inline_data_nolock(handle_t *handle,
11101065
struct inode *inode,
11111066
struct ext4_iloc *iloc)
@@ -1177,8 +1132,17 @@ static int ext4_convert_inline_data_nolock(handle_t *handle,
11771132
error = ext4_handle_dirty_metadata(handle,
11781133
inode, data_bh);
11791134
} else {
1180-
error = ext4_finish_convert_inline_dir(handle, inode, data_bh,
1181-
buf, inline_size);
1135+
unlock_buffer(data_bh);
1136+
inode->i_size = inode->i_sb->s_blocksize;
1137+
i_size_write(inode, inode->i_sb->s_blocksize);
1138+
EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
1139+
1140+
error = ext4_init_dirblock(handle, inode, data_bh,
1141+
le32_to_cpu(((struct ext4_dir_entry_2 *)buf)->inode),
1142+
buf + EXT4_INLINE_DOTDOT_SIZE,
1143+
inline_size - EXT4_INLINE_DOTDOT_SIZE);
1144+
if (!error)
1145+
error = ext4_mark_inode_dirty(handle, inode);
11821146
}
11831147

11841148
out_restore:

fs/ext4/namei.c

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2915,11 +2915,17 @@ static int ext4_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
29152915
return err;
29162916
}
29172917

2918-
struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
2919-
struct ext4_dir_entry_2 *de,
2920-
int blocksize, int csum_size,
2921-
unsigned int parent_ino, int dotdot_real_len)
2918+
int ext4_init_dirblock(handle_t *handle, struct inode *inode,
2919+
struct buffer_head *bh, unsigned int parent_ino,
2920+
void *inline_buf, int inline_size)
29222921
{
2922+
struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *) bh->b_data;
2923+
size_t blocksize = bh->b_size;
2924+
int csum_size = 0, header_size;
2925+
2926+
if (ext4_has_feature_metadata_csum(inode->i_sb))
2927+
csum_size = sizeof(struct ext4_dir_entry_tail);
2928+
29232929
de->inode = cpu_to_le32(inode->i_ino);
29242930
de->name_len = 1;
29252931
de->rec_len = ext4_rec_len_to_disk(ext4_dir_rec_len(de->name_len, NULL),
@@ -2930,18 +2936,29 @@ struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
29302936
de = ext4_next_entry(de, blocksize);
29312937
de->inode = cpu_to_le32(parent_ino);
29322938
de->name_len = 2;
2933-
if (!dotdot_real_len)
2934-
de->rec_len = ext4_rec_len_to_disk(blocksize -
2935-
(csum_size + ext4_dir_rec_len(1, NULL)),
2936-
blocksize);
2937-
else
2939+
memcpy(de->name, "..", 3);
2940+
ext4_set_de_type(inode->i_sb, de, S_IFDIR);
2941+
if (inline_buf) {
29382942
de->rec_len = ext4_rec_len_to_disk(
29392943
ext4_dir_rec_len(de->name_len, NULL),
29402944
blocksize);
2941-
memcpy(de->name, "..", 3);
2942-
ext4_set_de_type(inode->i_sb, de, S_IFDIR);
2945+
de = ext4_next_entry(de, blocksize);
2946+
header_size = (char *)de - bh->b_data;
2947+
memcpy((void *)de, inline_buf, inline_size);
2948+
ext4_update_final_de(bh->b_data, inline_size + header_size,
2949+
blocksize - csum_size);
2950+
} else {
2951+
de->rec_len = ext4_rec_len_to_disk(blocksize -
2952+
(csum_size + ext4_dir_rec_len(1, NULL)),
2953+
blocksize);
2954+
}
29432955

2944-
return ext4_next_entry(de, blocksize);
2956+
if (csum_size)
2957+
ext4_initialize_dirent_tail(bh, blocksize);
2958+
BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata");
2959+
set_buffer_uptodate(bh);
2960+
set_buffer_verified(bh);
2961+
return ext4_handle_dirty_dirblock(handle, inode, bh);
29452962
}
29462963

29472964
int ext4_init_new_dir(handle_t *handle, struct inode *dir,
@@ -2950,13 +2967,8 @@ int ext4_init_new_dir(handle_t *handle, struct inode *dir,
29502967
struct buffer_head *dir_block = NULL;
29512968
struct ext4_dir_entry_2 *de;
29522969
ext4_lblk_t block = 0;
2953-
unsigned int blocksize = dir->i_sb->s_blocksize;
2954-
int csum_size = 0;
29552970
int err;
29562971

2957-
if (ext4_has_feature_metadata_csum(dir->i_sb))
2958-
csum_size = sizeof(struct ext4_dir_entry_tail);
2959-
29602972
if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
29612973
err = ext4_try_create_inline_dir(handle, dir, inode);
29622974
if (err < 0 && err != -ENOSPC)
@@ -2965,21 +2977,15 @@ int ext4_init_new_dir(handle_t *handle, struct inode *dir,
29652977
goto out;
29662978
}
29672979

2980+
set_nlink(inode, 2);
29682981
inode->i_size = 0;
29692982
dir_block = ext4_append(handle, inode, &block);
29702983
if (IS_ERR(dir_block))
29712984
return PTR_ERR(dir_block);
29722985
de = (struct ext4_dir_entry_2 *)dir_block->b_data;
2973-
ext4_init_dot_dotdot(inode, de, blocksize, csum_size, dir->i_ino, 0);
2974-
set_nlink(inode, 2);
2975-
if (csum_size)
2976-
ext4_initialize_dirent_tail(dir_block, blocksize);
2977-
2978-
BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata");
2979-
err = ext4_handle_dirty_dirblock(handle, inode, dir_block);
2986+
err = ext4_init_dirblock(handle, inode, dir_block, dir->i_ino, NULL, 0);
29802987
if (err)
29812988
goto out;
2982-
set_buffer_verified(dir_block);
29832989
out:
29842990
brelse(dir_block);
29852991
return err;

0 commit comments

Comments
 (0)