mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-03 10:10:33 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									a35454ecf8
								
							
						
					
					
						commit
						90f097b140
					
				
					 3 changed files with 48 additions and 77 deletions
				
			
		| 
						 | 
					@ -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_get_max_inline_size(struct inode *inode);
 | 
				
			||||||
extern int ext4_find_inline_data_nolock(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 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);
 | 
					int ext4_readpage_inline(struct inode *inode, struct folio *folio);
 | 
				
			||||||
extern int ext4_try_to_write_inline_data(struct address_space *mapping,
 | 
					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_dir_inode_operations;
 | 
				
			||||||
extern const struct inode_operations ext4_special_inode_operations;
 | 
					extern const struct inode_operations ext4_special_inode_operations;
 | 
				
			||||||
extern struct dentry *ext4_get_parent(struct dentry *child);
 | 
					extern struct dentry *ext4_get_parent(struct dentry *child);
 | 
				
			||||||
extern struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
 | 
					extern int ext4_init_dirblock(handle_t *handle, struct inode *inode,
 | 
				
			||||||
				 struct ext4_dir_entry_2 *de,
 | 
								      struct buffer_head *dir_block,
 | 
				
			||||||
				 int blocksize, int csum_size,
 | 
								      unsigned int parent_ino, void *inline_buf,
 | 
				
			||||||
				 unsigned int parent_ino, int dotdot_real_len);
 | 
								      int inline_size);
 | 
				
			||||||
extern void ext4_initialize_dirent_tail(struct buffer_head *bh,
 | 
					extern void ext4_initialize_dirent_tail(struct buffer_head *bh,
 | 
				
			||||||
					unsigned int blocksize);
 | 
										unsigned int blocksize);
 | 
				
			||||||
extern int ext4_handle_dirty_dirblock(handle_t *handle, struct inode *inode,
 | 
					extern int ext4_handle_dirty_dirblock(handle_t *handle, struct inode *inode,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -997,7 +997,7 @@ static void *ext4_get_inline_xattr_pos(struct inode *inode,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Set the final de to cover the whole block. */
 | 
					/* 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;
 | 
						struct ext4_dir_entry_2 *de, *prev_de;
 | 
				
			||||||
	void *limit;
 | 
						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);
 | 
						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,
 | 
					static int ext4_convert_inline_data_nolock(handle_t *handle,
 | 
				
			||||||
					   struct inode *inode,
 | 
										   struct inode *inode,
 | 
				
			||||||
					   struct ext4_iloc *iloc)
 | 
										   struct ext4_iloc *iloc)
 | 
				
			||||||
| 
						 | 
					@ -1177,8 +1132,17 @@ static int ext4_convert_inline_data_nolock(handle_t *handle,
 | 
				
			||||||
		error = ext4_handle_dirty_metadata(handle,
 | 
							error = ext4_handle_dirty_metadata(handle,
 | 
				
			||||||
						   inode, data_bh);
 | 
											   inode, data_bh);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		error = ext4_finish_convert_inline_dir(handle, inode, data_bh,
 | 
							unlock_buffer(data_bh);
 | 
				
			||||||
						       buf, inline_size);
 | 
							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:
 | 
					out_restore:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2915,11 +2915,17 @@ static int ext4_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
 | 
					int ext4_init_dirblock(handle_t *handle, struct inode *inode,
 | 
				
			||||||
			  struct ext4_dir_entry_2 *de,
 | 
							       struct buffer_head *bh, unsigned int parent_ino,
 | 
				
			||||||
			  int blocksize, int csum_size,
 | 
							       void *inline_buf, int inline_size)
 | 
				
			||||||
			  unsigned int parent_ino, int dotdot_real_len)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						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->inode = cpu_to_le32(inode->i_ino);
 | 
				
			||||||
	de->name_len = 1;
 | 
						de->name_len = 1;
 | 
				
			||||||
	de->rec_len = ext4_rec_len_to_disk(ext4_dir_rec_len(de->name_len, NULL),
 | 
						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 = ext4_next_entry(de, blocksize);
 | 
				
			||||||
	de->inode = cpu_to_le32(parent_ino);
 | 
						de->inode = cpu_to_le32(parent_ino);
 | 
				
			||||||
	de->name_len = 2;
 | 
						de->name_len = 2;
 | 
				
			||||||
	if (!dotdot_real_len)
 | 
						memcpy(de->name, "..", 3);
 | 
				
			||||||
		de->rec_len = ext4_rec_len_to_disk(blocksize -
 | 
						ext4_set_de_type(inode->i_sb, de, S_IFDIR);
 | 
				
			||||||
					(csum_size + ext4_dir_rec_len(1, NULL)),
 | 
						if (inline_buf) {
 | 
				
			||||||
					blocksize);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		de->rec_len = ext4_rec_len_to_disk(
 | 
							de->rec_len = ext4_rec_len_to_disk(
 | 
				
			||||||
					ext4_dir_rec_len(de->name_len, NULL),
 | 
										ext4_dir_rec_len(de->name_len, NULL),
 | 
				
			||||||
					blocksize);
 | 
										blocksize);
 | 
				
			||||||
	memcpy(de->name, "..", 3);
 | 
							de = ext4_next_entry(de, blocksize);
 | 
				
			||||||
	ext4_set_de_type(inode->i_sb, de, S_IFDIR);
 | 
							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,
 | 
					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 buffer_head *dir_block = NULL;
 | 
				
			||||||
	struct ext4_dir_entry_2 *de;
 | 
						struct ext4_dir_entry_2 *de;
 | 
				
			||||||
	ext4_lblk_t block = 0;
 | 
						ext4_lblk_t block = 0;
 | 
				
			||||||
	unsigned int blocksize = dir->i_sb->s_blocksize;
 | 
					 | 
				
			||||||
	int csum_size = 0;
 | 
					 | 
				
			||||||
	int err;
 | 
						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)) {
 | 
						if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
 | 
				
			||||||
		err = ext4_try_create_inline_dir(handle, dir, inode);
 | 
							err = ext4_try_create_inline_dir(handle, dir, inode);
 | 
				
			||||||
		if (err < 0 && err != -ENOSPC)
 | 
							if (err < 0 && err != -ENOSPC)
 | 
				
			||||||
| 
						 | 
					@ -2965,21 +2977,15 @@ int ext4_init_new_dir(handle_t *handle, struct inode *dir,
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						set_nlink(inode, 2);
 | 
				
			||||||
	inode->i_size = 0;
 | 
						inode->i_size = 0;
 | 
				
			||||||
	dir_block = ext4_append(handle, inode, &block);
 | 
						dir_block = ext4_append(handle, inode, &block);
 | 
				
			||||||
	if (IS_ERR(dir_block))
 | 
						if (IS_ERR(dir_block))
 | 
				
			||||||
		return PTR_ERR(dir_block);
 | 
							return PTR_ERR(dir_block);
 | 
				
			||||||
	de = (struct ext4_dir_entry_2 *)dir_block->b_data;
 | 
						de = (struct ext4_dir_entry_2 *)dir_block->b_data;
 | 
				
			||||||
	ext4_init_dot_dotdot(inode, de, blocksize, csum_size, dir->i_ino, 0);
 | 
						err = ext4_init_dirblock(handle, inode, dir_block, dir->i_ino, NULL, 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);
 | 
					 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	set_buffer_verified(dir_block);
 | 
					 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	brelse(dir_block);
 | 
						brelse(dir_block);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue