Skip to content

Commit

Permalink
Merge tag 'ext4_for_linus-6.15-rc2' of git://git.kernel.org/pub/scm/l…
Browse files Browse the repository at this point in the history
…inux/kernel/git/tytso/ext4

Pull ext4 fixes from Ted Ts'o:
 "A few more miscellaneous ext4 bug fixes and cleanups including some
  syzbot failures and fixing a stale file handing refeencing an inode
  previously used as a regular file, but which has been deleted and
  reused as an ea_inode would result in ext4 erroneously considering
  this a case of fs corruption"

* tag 'ext4_for_linus-6.15-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  ext4: fix off-by-one error in do_split
  ext4: make block validity check resistent to sb bh corruption
  ext4: avoid -Wflex-array-member-not-at-end warning
  Documentation: ext4: Add fields to ext4_super_block documentation
  ext4: don't treat fhandle lookup of ea_inode as FS corruption
  • Loading branch information
Linus Torvalds committed Apr 13, 2025
2 parents 051ea72 + 94824ac commit 5aaaedb
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 43 deletions.
20 changes: 14 additions & 6 deletions Documentation/filesystems/ext4/super.rst
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,13 @@ The ext4 superblock is laid out as follows in
- s_checksum_type
- Metadata checksum algorithm type. The only valid value is 1 (crc32c).
* - 0x176
- __le16
- s_reserved_pad
-
- \_\_u8
- s\_encryption\_level
- Versioning level for encryption.
* - 0x177
- \_\_u8
- s\_reserved\_pad
- Padding to next 32bits.
* - 0x178
- __le64
- s_kbytes_written
Expand Down Expand Up @@ -466,9 +470,13 @@ The ext4 superblock is laid out as follows in
- s_last_error_time_hi
- Upper 8 bits of the s_last_error_time field.
* - 0x27A
- __u8
- s_pad[2]
- Zero padding.
- \_\_u8
- s\_first\_error\_errcode
-
* - 0x27B
- \_\_u8
- s\_last\_error\_errcode
-
* - 0x27C
- __le16
- s_encoding
Expand Down
5 changes: 2 additions & 3 deletions fs/ext4/block_validity.c
Original file line number Diff line number Diff line change
Expand Up @@ -351,10 +351,9 @@ int ext4_check_blockref(const char *function, unsigned int line,
{
__le32 *bref = p;
unsigned int blk;
journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;

if (ext4_has_feature_journal(inode->i_sb) &&
(inode->i_ino ==
le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum)))
if (journal && inode == journal->j_inode)
return 0;

while (bref < p+max) {
Expand Down
75 changes: 52 additions & 23 deletions fs/ext4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,10 +386,11 @@ static int __check_block_validity(struct inode *inode, const char *func,
unsigned int line,
struct ext4_map_blocks *map)
{
if (ext4_has_feature_journal(inode->i_sb) &&
(inode->i_ino ==
le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum)))
journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;

if (journal && inode == journal->j_inode)
return 0;

if (!ext4_inode_block_valid(inode, map->m_pblk, map->m_len)) {
ext4_error_inode(inode, func, line, map->m_pblk,
"lblock %lu mapped to illegal pblock %llu "
Expand Down Expand Up @@ -4724,22 +4725,43 @@ static inline void ext4_inode_set_iversion_queried(struct inode *inode, u64 val)
inode_set_iversion_queried(inode, val);
}

static const char *check_igot_inode(struct inode *inode, ext4_iget_flags flags)

static int check_igot_inode(struct inode *inode, ext4_iget_flags flags,
const char *function, unsigned int line)
{
const char *err_str;

if (flags & EXT4_IGET_EA_INODE) {
if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL))
return "missing EA_INODE flag";
if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) {
err_str = "missing EA_INODE flag";
goto error;
}
if (ext4_test_inode_state(inode, EXT4_STATE_XATTR) ||
EXT4_I(inode)->i_file_acl)
return "ea_inode with extended attributes";
EXT4_I(inode)->i_file_acl) {
err_str = "ea_inode with extended attributes";
goto error;
}
} else {
if ((EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL))
return "unexpected EA_INODE flag";
if ((EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) {
/*
* open_by_handle_at() could provide an old inode number
* that has since been reused for an ea_inode; this does
* not indicate filesystem corruption
*/
if (flags & EXT4_IGET_HANDLE)
return -ESTALE;
err_str = "unexpected EA_INODE flag";
goto error;
}
}
if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD)) {
err_str = "unexpected bad inode w/o EXT4_IGET_BAD";
goto error;
}
if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD))
return "unexpected bad inode w/o EXT4_IGET_BAD";
return NULL;
return 0;

error:
ext4_error_inode(inode, function, line, 0, err_str);
return -EFSCORRUPTED;
}

struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
Expand All @@ -4751,7 +4773,6 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
struct ext4_inode_info *ei;
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
struct inode *inode;
const char *err_str;
journal_t *journal = EXT4_SB(sb)->s_journal;
long ret;
loff_t size;
Expand Down Expand Up @@ -4780,10 +4801,10 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
if (!inode)
return ERR_PTR(-ENOMEM);
if (!(inode->i_state & I_NEW)) {
if ((err_str = check_igot_inode(inode, flags)) != NULL) {
ext4_error_inode(inode, function, line, 0, err_str);
ret = check_igot_inode(inode, flags, function, line);
if (ret) {
iput(inode);
return ERR_PTR(-EFSCORRUPTED);
return ERR_PTR(ret);
}
return inode;
}
Expand Down Expand Up @@ -5065,13 +5086,21 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
ret = -EFSCORRUPTED;
goto bad_inode;
}
if ((err_str = check_igot_inode(inode, flags)) != NULL) {
ext4_error_inode(inode, function, line, 0, err_str);
ret = -EFSCORRUPTED;
goto bad_inode;
ret = check_igot_inode(inode, flags, function, line);
/*
* -ESTALE here means there is nothing inherently wrong with the inode,
* it's just not an inode we can return for an fhandle lookup.
*/
if (ret == -ESTALE) {
brelse(iloc.bh);
unlock_new_inode(inode);
iput(inode);
return ERR_PTR(-ESTALE);
}

if (ret)
goto bad_inode;
brelse(iloc.bh);

unlock_new_inode(inode);
return inode;

Expand Down
18 changes: 8 additions & 10 deletions fs/ext4/mballoc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3037,18 +3037,16 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
unsigned char blocksize_bits = min_t(unsigned char,
sb->s_blocksize_bits,
EXT4_MAX_BLOCK_LOG_SIZE);
struct sg {
struct ext4_group_info info;
ext4_grpblk_t counters[EXT4_MAX_BLOCK_LOG_SIZE + 2];
} sg;
DEFINE_RAW_FLEX(struct ext4_group_info, sg, bb_counters,
EXT4_MAX_BLOCK_LOG_SIZE + 2);

group--;
if (group == 0)
seq_puts(seq, "#group: free frags first ["
" 2^0 2^1 2^2 2^3 2^4 2^5 2^6 "
" 2^7 2^8 2^9 2^10 2^11 2^12 2^13 ]\n");

i = (blocksize_bits + 2) * sizeof(sg.info.bb_counters[0]) +
i = (blocksize_bits + 2) * sizeof(sg->bb_counters[0]) +
sizeof(struct ext4_group_info);

grinfo = ext4_get_group_info(sb, group);
Expand All @@ -3068,14 +3066,14 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
* We care only about free space counters in the group info and
* these are safe to access even after the buddy has been unloaded
*/
memcpy(&sg, grinfo, i);
seq_printf(seq, "#%-5u: %-5u %-5u %-5u [", group, sg.info.bb_free,
sg.info.bb_fragments, sg.info.bb_first_free);
memcpy(sg, grinfo, i);
seq_printf(seq, "#%-5u: %-5u %-5u %-5u [", group, sg->bb_free,
sg->bb_fragments, sg->bb_first_free);
for (i = 0; i <= 13; i++)
seq_printf(seq, " %-5u", i <= blocksize_bits + 1 ?
sg.info.bb_counters[i] : 0);
sg->bb_counters[i] : 0);
seq_puts(seq, " ]");
if (EXT4_MB_GRP_BBITMAP_CORRUPT(&sg.info))
if (EXT4_MB_GRP_BBITMAP_CORRUPT(sg))
seq_puts(seq, " Block bitmap corrupted!");
seq_putc(seq, '\n');
return 0;
Expand Down
2 changes: 1 addition & 1 deletion fs/ext4/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -1971,7 +1971,7 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
* split it in half by count; each resulting block will have at least
* half the space free.
*/
if (i > 0)
if (i >= 0)
split = count - move;
else
split = count/2;
Expand Down

0 comments on commit 5aaaedb

Please sign in to comment.