Merge tag 'ext4_for_linus-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4

Pull ext4 updates from Ted Ts'o:
 "Many cleanups and bug fixes in ext4, especially for the fast commit
  feature.

  Also some performance improvements; in particular, improving IOPS and
  throughput on fast devices running Async Direct I/O by up to 20% by
  optimizing jbd2_transaction_committed()"

* tag 'ext4_for_linus-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (40 commits)
  ext4: make sure the first directory block is not a hole
  ext4: check dot and dotdot of dx_root before making dir indexed
  ext4: sanity check for NULL pointer after ext4_force_shutdown
  jbd2: increase maximum transaction size
  jbd2: drop pointless shrinker batch initialization
  jbd2: avoid infinite transaction commit loop
  jbd2: precompute number of transaction descriptor blocks
  jbd2: make jbd2_journal_get_max_txn_bufs() internal
  jbd2: avoid mount failed when commit block is partial submitted
  ext4: avoid writing unitialized memory to disk in EA inodes
  ext4: don't track ranges in fast_commit if inode has inlined data
  ext4: fix possible tid_t sequence overflows
  ext4: use ext4_update_inode_fsync_trans() helper in inode creation
  ext4: add missing MODULE_DESCRIPTION()
  jbd2: add missing MODULE_DESCRIPTION()
  ext4: use memtostr_pad() for s_volume_name
  jbd2: speed up jbd2_transaction_committed()
  ext4: make ext4_da_map_blocks() buffer_head unaware
  ext4: make ext4_insert_delayed_block() insert multi-blocks
  ext4: factor out a helper to check the cluster allocation state
  ...
This commit is contained in:
Linus Torvalds
2024-07-18 17:03:42 -07:00
20 changed files with 458 additions and 254 deletions

View File

@@ -151,10 +151,11 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode,
return bh;
}
if (!bh && (type == INDEX || type == DIRENT_HTREE)) {
/* The first directory block must not be a hole. */
if (!bh && (type == INDEX || type == DIRENT_HTREE || block == 0)) {
ext4_error_inode(inode, func, line, block,
"Directory hole found for htree %s block",
(type == INDEX) ? "index" : "leaf");
"Directory hole found for htree %s block %u",
(type == INDEX) ? "index" : "leaf", block);
return ERR_PTR(-EFSCORRUPTED);
}
if (!bh)
@@ -2172,6 +2173,52 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,
return err ? err : err2;
}
static bool ext4_check_dx_root(struct inode *dir, struct dx_root *root)
{
struct fake_dirent *fde;
const char *error_msg;
unsigned int rlen;
unsigned int blocksize = dir->i_sb->s_blocksize;
char *blockend = (char *)root + dir->i_sb->s_blocksize;
fde = &root->dot;
if (unlikely(fde->name_len != 1)) {
error_msg = "invalid name_len for '.'";
goto corrupted;
}
if (unlikely(strncmp(root->dot_name, ".", fde->name_len))) {
error_msg = "invalid name for '.'";
goto corrupted;
}
rlen = ext4_rec_len_from_disk(fde->rec_len, blocksize);
if (unlikely((char *)fde + rlen >= blockend)) {
error_msg = "invalid rec_len for '.'";
goto corrupted;
}
fde = &root->dotdot;
if (unlikely(fde->name_len != 2)) {
error_msg = "invalid name_len for '..'";
goto corrupted;
}
if (unlikely(strncmp(root->dotdot_name, "..", fde->name_len))) {
error_msg = "invalid name for '..'";
goto corrupted;
}
rlen = ext4_rec_len_from_disk(fde->rec_len, blocksize);
if (unlikely((char *)fde + rlen >= blockend)) {
error_msg = "invalid rec_len for '..'";
goto corrupted;
}
return true;
corrupted:
EXT4_ERROR_INODE(dir, "Corrupt dir, %s, running e2fsck is recommended",
error_msg);
return false;
}
/*
* This converts a one block unindexed directory to a 3 block indexed
* directory, and adds the dentry to the indexed directory.
@@ -2206,17 +2253,17 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname,
brelse(bh);
return retval;
}
root = (struct dx_root *) bh->b_data;
if (!ext4_check_dx_root(dir, root)) {
brelse(bh);
return -EFSCORRUPTED;
}
/* The 0th block becomes the root, move the dirents out */
fde = &root->dotdot;
de = (struct ext4_dir_entry_2 *)((char *)fde +
ext4_rec_len_from_disk(fde->rec_len, blocksize));
if ((char *) de >= (((char *) root) + blocksize)) {
EXT4_ERROR_INODE(dir, "invalid rec_len for '..'");
brelse(bh);
return -EFSCORRUPTED;
}
len = ((char *) root) + (blocksize - csum_size) - (char *) de;
/* Allocate new block for the 0th block's dirents */
@@ -3038,10 +3085,7 @@ bool ext4_empty_dir(struct inode *inode)
EXT4_ERROR_INODE(inode, "invalid size");
return false;
}
/* The first directory block must not be a hole,
* so treat it as DIRENT_HTREE
*/
bh = ext4_read_dirblock(inode, 0, DIRENT_HTREE);
bh = ext4_read_dirblock(inode, 0, EITHER);
if (IS_ERR(bh))
return false;
@@ -3483,10 +3527,7 @@ static struct buffer_head *ext4_get_first_dir_block(handle_t *handle,
struct ext4_dir_entry_2 *de;
unsigned int offset;
/* The first directory block must not be a hole, so
* treat it as DIRENT_HTREE
*/
bh = ext4_read_dirblock(inode, 0, DIRENT_HTREE);
bh = ext4_read_dirblock(inode, 0, EITHER);
if (IS_ERR(bh)) {
*retval = PTR_ERR(bh);
return NULL;