mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
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 consider this a case of fs corrupotion. -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEK2m5VNv+CHkogTfJ8vlZVpUNgaMFAmf7r3YACgkQ8vlZVpUN gaPl9QgApwE5BAQdO6miW0sDMPj5b4sMc25aG4OPlfKhFqiIJB0Ub4zC2n0OFnaf HXk8P5oVeepH9ciTnYFF30X20Ythzjwmd9j5eyq2wsfYASQUjfcvmR9WovbqZtGQ 3Zerd9QFp7SvZa+K4sADBhEb/7HAnxDGfiqSQptY6WQTwD+it1bnuhmzG0m6AH4m R1ItREDx7D2QrudDToFBd8XQ+FgRETZ8Qrs7PqIznw/dBNMdHRnAiw2eiyuoPU/S T8cmCxii3Z9sJ6LtohKYuWOmOmdxg951V5ZcekVRuaFSljSUsRsIplO7OlaMvQDs 9vGVKiiZLdU2B0Wd90IeQUdJmP4xPg== =I8qx -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
5aaaedb0cb
@ -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
|
||||
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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 "
|
||||
@ -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_test_inode_state(inode, EXT4_STATE_XATTR) ||
|
||||
EXT4_I(inode)->i_file_acl)
|
||||
return "ea_inode with extended attributes";
|
||||
} 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)) {
|
||||
err_str = "missing EA_INODE flag";
|
||||
goto error;
|
||||
}
|
||||
if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD))
|
||||
return "unexpected bad inode w/o EXT4_IGET_BAD";
|
||||
return NULL;
|
||||
if (ext4_test_inode_state(inode, EXT4_STATE_XATTR) ||
|
||||
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)) {
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
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,
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
|
@ -3037,10 +3037,8 @@ 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)
|
||||
@ -3048,7 +3046,7 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
|
||||
" 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);
|
||||
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user