]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ext4: refactor the inline directory conversion and new directory codepaths
authorTheodore Ts'o <tytso@mit.edu>
Sat, 12 Jul 2025 18:12:49 +0000 (14:12 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 18 Jul 2025 03:25:21 +0000 (23:25 -0400)
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>
fs/ext4/ext4.h
fs/ext4/inline.c
fs/ext4/namei.c

index 9ac0a7d4fa0cd7b54ff9966310f6ddf4d8d69d09..d377e02c9767acab7c560c4581b6394bb8e9c5d1 100644 (file)
@@ -3612,6 +3612,7 @@ extern loff_t ext4_llseek(struct file *file, loff_t offset, int origin);
 extern int ext4_get_max_inline_size(struct inode *inode);
 extern int ext4_find_inline_data_nolock(struct inode *inode);
 extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode);
+extern void ext4_update_final_de(void *de_buf, int old_size, int new_size);
 
 int ext4_readpage_inline(struct inode *inode, struct folio *folio);
 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)
 extern const struct inode_operations ext4_dir_inode_operations;
 extern const struct inode_operations ext4_special_inode_operations;
 extern struct dentry *ext4_get_parent(struct dentry *child);
-extern struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
-                                struct ext4_dir_entry_2 *de,
-                                int blocksize, int csum_size,
-                                unsigned int parent_ino, int dotdot_real_len);
+extern int ext4_init_dirblock(handle_t *handle, struct inode *inode,
+                             struct buffer_head *dir_block,
+                             unsigned int parent_ino, void *inline_buf,
+                             int inline_size);
 extern void ext4_initialize_dirent_tail(struct buffer_head *bh,
                                        unsigned int blocksize);
 extern int ext4_handle_dirty_dirblock(handle_t *handle, struct inode *inode,
index 77e8b7707650e551b04f79e487b4479ca760b543..640133adef380f3d29a978cab2bb3e6d285e17c9 100644 (file)
@@ -997,7 +997,7 @@ static void *ext4_get_inline_xattr_pos(struct inode *inode,
 }
 
 /* Set the final de to cover the whole block. */
-static void ext4_update_final_de(void *de_buf, int old_size, int new_size)
+void ext4_update_final_de(void *de_buf, int old_size, int new_size)
 {
        struct ext4_dir_entry_2 *de, *prev_de;
        void *limit;
@@ -1061,51 +1061,6 @@ static void ext4_restore_inline_data(handle_t *handle, struct inode *inode,
        ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
 }
 
-static int ext4_finish_convert_inline_dir(handle_t *handle,
-                                         struct inode *inode,
-                                         struct buffer_head *dir_block,
-                                         void *buf,
-                                         int inline_size)
-{
-       int err, csum_size = 0, header_size = 0;
-       struct ext4_dir_entry_2 *de;
-       void *target = dir_block->b_data;
-
-       /*
-        * First create "." and ".." and then copy the dir information
-        * back to the block.
-        */
-       de = target;
-       de = ext4_init_dot_dotdot(inode, de,
-               inode->i_sb->s_blocksize, csum_size,
-               le32_to_cpu(((struct ext4_dir_entry_2 *)buf)->inode), 1);
-       header_size = (void *)de - target;
-
-       memcpy((void *)de, buf + EXT4_INLINE_DOTDOT_SIZE,
-               inline_size - EXT4_INLINE_DOTDOT_SIZE);
-
-       if (ext4_has_feature_metadata_csum(inode->i_sb))
-               csum_size = sizeof(struct ext4_dir_entry_tail);
-
-       inode->i_size = inode->i_sb->s_blocksize;
-       i_size_write(inode, inode->i_sb->s_blocksize);
-       EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
-       ext4_update_final_de(dir_block->b_data,
-                       inline_size - EXT4_INLINE_DOTDOT_SIZE + header_size,
-                       inode->i_sb->s_blocksize - csum_size);
-
-       if (csum_size)
-               ext4_initialize_dirent_tail(dir_block,
-                                           inode->i_sb->s_blocksize);
-       set_buffer_uptodate(dir_block);
-       unlock_buffer(dir_block);
-       err = ext4_handle_dirty_dirblock(handle, inode, dir_block);
-       if (err)
-               return err;
-       set_buffer_verified(dir_block);
-       return ext4_mark_inode_dirty(handle, inode);
-}
-
 static int ext4_convert_inline_data_nolock(handle_t *handle,
                                           struct inode *inode,
                                           struct ext4_iloc *iloc)
@@ -1177,8 +1132,17 @@ static int ext4_convert_inline_data_nolock(handle_t *handle,
                error = ext4_handle_dirty_metadata(handle,
                                                   inode, data_bh);
        } else {
-               error = ext4_finish_convert_inline_dir(handle, inode, data_bh,
-                                                      buf, inline_size);
+               unlock_buffer(data_bh);
+               inode->i_size = inode->i_sb->s_blocksize;
+               i_size_write(inode, inode->i_sb->s_blocksize);
+               EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
+
+               error = ext4_init_dirblock(handle, inode, data_bh,
+                         le32_to_cpu(((struct ext4_dir_entry_2 *)buf)->inode),
+                         buf + EXT4_INLINE_DOTDOT_SIZE,
+                         inline_size - EXT4_INLINE_DOTDOT_SIZE);
+               if (!error)
+                       error = ext4_mark_inode_dirty(handle, inode);
        }
 
 out_restore:
index 9913a94b6a6d360bb2f778e4c030840e1526c495..d83f91b623174b85f168e5ab3553cadd7075303b 100644 (file)
@@ -2915,11 +2915,17 @@ err_unlock_inode:
        return err;
 }
 
-struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
-                         struct ext4_dir_entry_2 *de,
-                         int blocksize, int csum_size,
-                         unsigned int parent_ino, int dotdot_real_len)
+int ext4_init_dirblock(handle_t *handle, struct inode *inode,
+                      struct buffer_head *bh, unsigned int parent_ino,
+                      void *inline_buf, int inline_size)
 {
+       struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *) bh->b_data;
+       size_t                  blocksize = bh->b_size;
+       int                     csum_size = 0, header_size;
+
+       if (ext4_has_feature_metadata_csum(inode->i_sb))
+               csum_size = sizeof(struct ext4_dir_entry_tail);
+
        de->inode = cpu_to_le32(inode->i_ino);
        de->name_len = 1;
        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,
        de = ext4_next_entry(de, blocksize);
        de->inode = cpu_to_le32(parent_ino);
        de->name_len = 2;
-       if (!dotdot_real_len)
-               de->rec_len = ext4_rec_len_to_disk(blocksize -
-                                       (csum_size + ext4_dir_rec_len(1, NULL)),
-                                       blocksize);
-       else
+       memcpy(de->name, "..", 3);
+       ext4_set_de_type(inode->i_sb, de, S_IFDIR);
+       if (inline_buf) {
                de->rec_len = ext4_rec_len_to_disk(
                                        ext4_dir_rec_len(de->name_len, NULL),
                                        blocksize);
-       memcpy(de->name, "..", 3);
-       ext4_set_de_type(inode->i_sb, de, S_IFDIR);
+               de = ext4_next_entry(de, blocksize);
+               header_size = (char *)de - bh->b_data;
+               memcpy((void *)de, inline_buf, inline_size);
+               ext4_update_final_de(bh->b_data, inline_size + header_size,
+                       blocksize - csum_size);
+       } else {
+               de->rec_len = ext4_rec_len_to_disk(blocksize -
+                                       (csum_size + ext4_dir_rec_len(1, NULL)),
+                                       blocksize);
+       }
 
-       return ext4_next_entry(de, blocksize);
+       if (csum_size)
+               ext4_initialize_dirent_tail(bh, blocksize);
+       BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata");
+       set_buffer_uptodate(bh);
+       set_buffer_verified(bh);
+       return ext4_handle_dirty_dirblock(handle, inode, bh);
 }
 
 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,
        struct buffer_head *dir_block = NULL;
        struct ext4_dir_entry_2 *de;
        ext4_lblk_t block = 0;
-       unsigned int blocksize = dir->i_sb->s_blocksize;
-       int csum_size = 0;
        int err;
 
-       if (ext4_has_feature_metadata_csum(dir->i_sb))
-               csum_size = sizeof(struct ext4_dir_entry_tail);
-
        if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
                err = ext4_try_create_inline_dir(handle, dir, inode);
                if (err < 0 && err != -ENOSPC)
@@ -2965,21 +2977,15 @@ int ext4_init_new_dir(handle_t *handle, struct inode *dir,
                        goto out;
        }
 
+       set_nlink(inode, 2);
        inode->i_size = 0;
        dir_block = ext4_append(handle, inode, &block);
        if (IS_ERR(dir_block))
                return PTR_ERR(dir_block);
        de = (struct ext4_dir_entry_2 *)dir_block->b_data;
-       ext4_init_dot_dotdot(inode, de, blocksize, csum_size, dir->i_ino, 0);
-       set_nlink(inode, 2);
-       if (csum_size)
-               ext4_initialize_dirent_tail(dir_block, blocksize);
-
-       BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata");
-       err = ext4_handle_dirty_dirblock(handle, inode, dir_block);
+       err = ext4_init_dirblock(handle, inode, dir_block, dir->i_ino, NULL, 0);
        if (err)
                goto out;
-       set_buffer_verified(dir_block);
 out:
        brelse(dir_block);
        return err;