Skip to content

Commit 5aaaedb

Browse files
committed
Merge tag 'ext4_for_linus-6.15-rc2' of git://git.kernel.org/pub/scm/linux/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
2 parents 051ea72 + 94824ac commit 5aaaedb

File tree

5 files changed

+77
-43
lines changed

5 files changed

+77
-43
lines changed

Documentation/filesystems/ext4/super.rst

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,13 @@ The ext4 superblock is laid out as follows in
328328
- s_checksum_type
329329
- Metadata checksum algorithm type. The only valid value is 1 (crc32c).
330330
* - 0x176
331-
- __le16
332-
- s_reserved_pad
333-
-
331+
- \_\_u8
332+
- s\_encryption\_level
333+
- Versioning level for encryption.
334+
* - 0x177
335+
- \_\_u8
336+
- s\_reserved\_pad
337+
- Padding to next 32bits.
334338
* - 0x178
335339
- __le64
336340
- s_kbytes_written
@@ -466,9 +470,13 @@ The ext4 superblock is laid out as follows in
466470
- s_last_error_time_hi
467471
- Upper 8 bits of the s_last_error_time field.
468472
* - 0x27A
469-
- __u8
470-
- s_pad[2]
471-
- Zero padding.
473+
- \_\_u8
474+
- s\_first\_error\_errcode
475+
-
476+
* - 0x27B
477+
- \_\_u8
478+
- s\_last\_error\_errcode
479+
-
472480
* - 0x27C
473481
- __le16
474482
- s_encoding

fs/ext4/block_validity.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,10 +351,9 @@ int ext4_check_blockref(const char *function, unsigned int line,
351351
{
352352
__le32 *bref = p;
353353
unsigned int blk;
354+
journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
354355

355-
if (ext4_has_feature_journal(inode->i_sb) &&
356-
(inode->i_ino ==
357-
le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum)))
356+
if (journal && inode == journal->j_inode)
358357
return 0;
359358

360359
while (bref < p+max) {

fs/ext4/inode.c

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -386,10 +386,11 @@ static int __check_block_validity(struct inode *inode, const char *func,
386386
unsigned int line,
387387
struct ext4_map_blocks *map)
388388
{
389-
if (ext4_has_feature_journal(inode->i_sb) &&
390-
(inode->i_ino ==
391-
le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_journal_inum)))
389+
journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
390+
391+
if (journal && inode == journal->j_inode)
392392
return 0;
393+
393394
if (!ext4_inode_block_valid(inode, map->m_pblk, map->m_len)) {
394395
ext4_error_inode(inode, func, line, map->m_pblk,
395396
"lblock %lu mapped to illegal pblock %llu "
@@ -4724,22 +4725,43 @@ static inline void ext4_inode_set_iversion_queried(struct inode *inode, u64 val)
47244725
inode_set_iversion_queried(inode, val);
47254726
}
47264727

4727-
static const char *check_igot_inode(struct inode *inode, ext4_iget_flags flags)
4728-
4728+
static int check_igot_inode(struct inode *inode, ext4_iget_flags flags,
4729+
const char *function, unsigned int line)
47294730
{
4731+
const char *err_str;
4732+
47304733
if (flags & EXT4_IGET_EA_INODE) {
4731-
if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL))
4732-
return "missing EA_INODE flag";
4734+
if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) {
4735+
err_str = "missing EA_INODE flag";
4736+
goto error;
4737+
}
47334738
if (ext4_test_inode_state(inode, EXT4_STATE_XATTR) ||
4734-
EXT4_I(inode)->i_file_acl)
4735-
return "ea_inode with extended attributes";
4739+
EXT4_I(inode)->i_file_acl) {
4740+
err_str = "ea_inode with extended attributes";
4741+
goto error;
4742+
}
47364743
} else {
4737-
if ((EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL))
4738-
return "unexpected EA_INODE flag";
4744+
if ((EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) {
4745+
/*
4746+
* open_by_handle_at() could provide an old inode number
4747+
* that has since been reused for an ea_inode; this does
4748+
* not indicate filesystem corruption
4749+
*/
4750+
if (flags & EXT4_IGET_HANDLE)
4751+
return -ESTALE;
4752+
err_str = "unexpected EA_INODE flag";
4753+
goto error;
4754+
}
4755+
}
4756+
if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD)) {
4757+
err_str = "unexpected bad inode w/o EXT4_IGET_BAD";
4758+
goto error;
47394759
}
4740-
if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD))
4741-
return "unexpected bad inode w/o EXT4_IGET_BAD";
4742-
return NULL;
4760+
return 0;
4761+
4762+
error:
4763+
ext4_error_inode(inode, function, line, 0, err_str);
4764+
return -EFSCORRUPTED;
47434765
}
47444766

47454767
struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
@@ -4751,7 +4773,6 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
47514773
struct ext4_inode_info *ei;
47524774
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
47534775
struct inode *inode;
4754-
const char *err_str;
47554776
journal_t *journal = EXT4_SB(sb)->s_journal;
47564777
long ret;
47574778
loff_t size;
@@ -4780,10 +4801,10 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
47804801
if (!inode)
47814802
return ERR_PTR(-ENOMEM);
47824803
if (!(inode->i_state & I_NEW)) {
4783-
if ((err_str = check_igot_inode(inode, flags)) != NULL) {
4784-
ext4_error_inode(inode, function, line, 0, err_str);
4804+
ret = check_igot_inode(inode, flags, function, line);
4805+
if (ret) {
47854806
iput(inode);
4786-
return ERR_PTR(-EFSCORRUPTED);
4807+
return ERR_PTR(ret);
47874808
}
47884809
return inode;
47894810
}
@@ -5065,13 +5086,21 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
50655086
ret = -EFSCORRUPTED;
50665087
goto bad_inode;
50675088
}
5068-
if ((err_str = check_igot_inode(inode, flags)) != NULL) {
5069-
ext4_error_inode(inode, function, line, 0, err_str);
5070-
ret = -EFSCORRUPTED;
5071-
goto bad_inode;
5089+
ret = check_igot_inode(inode, flags, function, line);
5090+
/*
5091+
* -ESTALE here means there is nothing inherently wrong with the inode,
5092+
* it's just not an inode we can return for an fhandle lookup.
5093+
*/
5094+
if (ret == -ESTALE) {
5095+
brelse(iloc.bh);
5096+
unlock_new_inode(inode);
5097+
iput(inode);
5098+
return ERR_PTR(-ESTALE);
50725099
}
5073-
5100+
if (ret)
5101+
goto bad_inode;
50745102
brelse(iloc.bh);
5103+
50755104
unlock_new_inode(inode);
50765105
return inode;
50775106

fs/ext4/mballoc.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3037,18 +3037,16 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
30373037
unsigned char blocksize_bits = min_t(unsigned char,
30383038
sb->s_blocksize_bits,
30393039
EXT4_MAX_BLOCK_LOG_SIZE);
3040-
struct sg {
3041-
struct ext4_group_info info;
3042-
ext4_grpblk_t counters[EXT4_MAX_BLOCK_LOG_SIZE + 2];
3043-
} sg;
3040+
DEFINE_RAW_FLEX(struct ext4_group_info, sg, bb_counters,
3041+
EXT4_MAX_BLOCK_LOG_SIZE + 2);
30443042

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

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

30543052
grinfo = ext4_get_group_info(sb, group);
@@ -3068,14 +3066,14 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
30683066
* We care only about free space counters in the group info and
30693067
* these are safe to access even after the buddy has been unloaded
30703068
*/
3071-
memcpy(&sg, grinfo, i);
3072-
seq_printf(seq, "#%-5u: %-5u %-5u %-5u [", group, sg.info.bb_free,
3073-
sg.info.bb_fragments, sg.info.bb_first_free);
3069+
memcpy(sg, grinfo, i);
3070+
seq_printf(seq, "#%-5u: %-5u %-5u %-5u [", group, sg->bb_free,
3071+
sg->bb_fragments, sg->bb_first_free);
30743072
for (i = 0; i <= 13; i++)
30753073
seq_printf(seq, " %-5u", i <= blocksize_bits + 1 ?
3076-
sg.info.bb_counters[i] : 0);
3074+
sg->bb_counters[i] : 0);
30773075
seq_puts(seq, " ]");
3078-
if (EXT4_MB_GRP_BBITMAP_CORRUPT(&sg.info))
3076+
if (EXT4_MB_GRP_BBITMAP_CORRUPT(sg))
30793077
seq_puts(seq, " Block bitmap corrupted!");
30803078
seq_putc(seq, '\n');
30813079
return 0;

fs/ext4/namei.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1971,7 +1971,7 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
19711971
* split it in half by count; each resulting block will have at least
19721972
* half the space free.
19731973
*/
1974-
if (i > 0)
1974+
if (i >= 0)
19751975
split = count - move;
19761976
else
19771977
split = count/2;

0 commit comments

Comments
 (0)