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

Changed files
+77 -43
Documentation
filesystems
ext4
fs
+14 -6
Documentation/filesystems/ext4/super.rst
··· 328 328 - s_checksum_type 329 329 - Metadata checksum algorithm type. The only valid value is 1 (crc32c). 330 330 * - 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. 334 338 * - 0x178 335 339 - __le64 336 340 - s_kbytes_written ··· 470 466 - s_last_error_time_hi 471 467 - Upper 8 bits of the s_last_error_time field. 472 468 * - 0x27A 473 - - __u8 474 - - s_pad[2] 475 - - Zero padding. 469 + - \_\_u8 470 + - s\_first\_error\_errcode 471 + - 472 + * - 0x27B 473 + - \_\_u8 474 + - s\_last\_error\_errcode 475 + - 476 476 * - 0x27C 477 477 - __le16 478 478 - s_encoding
+2 -3
fs/ext4/block_validity.c
··· 351 351 { 352 352 __le32 *bref = p; 353 353 unsigned int blk; 354 + journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; 354 355 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) 358 357 return 0; 359 358 360 359 while (bref < p+max) {
+52 -23
fs/ext4/inode.c
··· 386 386 unsigned int line, 387 387 struct ext4_map_blocks *map) 388 388 { 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) 392 392 return 0; 393 + 393 394 if (!ext4_inode_block_valid(inode, map->m_pblk, map->m_len)) { 394 395 ext4_error_inode(inode, func, line, map->m_pblk, 395 396 "lblock %lu mapped to illegal pblock %llu " ··· 4725 4724 inode_set_iversion_queried(inode, val); 4726 4725 } 4727 4726 4728 - static const char *check_igot_inode(struct inode *inode, ext4_iget_flags flags) 4729 - 4727 + static int check_igot_inode(struct inode *inode, ext4_iget_flags flags, 4728 + const char *function, unsigned int line) 4730 4729 { 4730 + const char *err_str; 4731 + 4731 4732 if (flags & EXT4_IGET_EA_INODE) { 4732 - if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) 4733 - return "missing EA_INODE flag"; 4733 + if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) { 4734 + err_str = "missing EA_INODE flag"; 4735 + goto error; 4736 + } 4734 4737 if (ext4_test_inode_state(inode, EXT4_STATE_XATTR) || 4735 - EXT4_I(inode)->i_file_acl) 4736 - return "ea_inode with extended attributes"; 4738 + EXT4_I(inode)->i_file_acl) { 4739 + err_str = "ea_inode with extended attributes"; 4740 + goto error; 4741 + } 4737 4742 } else { 4738 - if ((EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) 4739 - return "unexpected EA_INODE flag"; 4743 + if ((EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) { 4744 + /* 4745 + * open_by_handle_at() could provide an old inode number 4746 + * that has since been reused for an ea_inode; this does 4747 + * not indicate filesystem corruption 4748 + */ 4749 + if (flags & EXT4_IGET_HANDLE) 4750 + return -ESTALE; 4751 + err_str = "unexpected EA_INODE flag"; 4752 + goto error; 4753 + } 4740 4754 } 4741 - if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD)) 4742 - return "unexpected bad inode w/o EXT4_IGET_BAD"; 4743 - return NULL; 4755 + if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD)) { 4756 + err_str = "unexpected bad inode w/o EXT4_IGET_BAD"; 4757 + goto error; 4758 + } 4759 + return 0; 4760 + 4761 + error: 4762 + ext4_error_inode(inode, function, line, 0, err_str); 4763 + return -EFSCORRUPTED; 4744 4764 } 4745 4765 4746 4766 struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, ··· 4773 4751 struct ext4_inode_info *ei; 4774 4752 struct ext4_super_block *es = EXT4_SB(sb)->s_es; 4775 4753 struct inode *inode; 4776 - const char *err_str; 4777 4754 journal_t *journal = EXT4_SB(sb)->s_journal; 4778 4755 long ret; 4779 4756 loff_t size; ··· 4801 4780 if (!inode) 4802 4781 return ERR_PTR(-ENOMEM); 4803 4782 if (!(inode->i_state & I_NEW)) { 4804 - if ((err_str = check_igot_inode(inode, flags)) != NULL) { 4805 - ext4_error_inode(inode, function, line, 0, err_str); 4783 + ret = check_igot_inode(inode, flags, function, line); 4784 + if (ret) { 4806 4785 iput(inode); 4807 - return ERR_PTR(-EFSCORRUPTED); 4786 + return ERR_PTR(ret); 4808 4787 } 4809 4788 return inode; 4810 4789 } ··· 5086 5065 ret = -EFSCORRUPTED; 5087 5066 goto bad_inode; 5088 5067 } 5089 - if ((err_str = check_igot_inode(inode, flags)) != NULL) { 5090 - ext4_error_inode(inode, function, line, 0, err_str); 5091 - ret = -EFSCORRUPTED; 5092 - goto bad_inode; 5068 + ret = check_igot_inode(inode, flags, function, line); 5069 + /* 5070 + * -ESTALE here means there is nothing inherently wrong with the inode, 5071 + * it's just not an inode we can return for an fhandle lookup. 5072 + */ 5073 + if (ret == -ESTALE) { 5074 + brelse(iloc.bh); 5075 + unlock_new_inode(inode); 5076 + iput(inode); 5077 + return ERR_PTR(-ESTALE); 5093 5078 } 5094 - 5079 + if (ret) 5080 + goto bad_inode; 5095 5081 brelse(iloc.bh); 5082 + 5096 5083 unlock_new_inode(inode); 5097 5084 return inode; 5098 5085
+8 -10
fs/ext4/mballoc.c
··· 3037 3037 unsigned char blocksize_bits = min_t(unsigned char, 3038 3038 sb->s_blocksize_bits, 3039 3039 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); 3044 3042 3045 3043 group--; 3046 3044 if (group == 0) ··· 3046 3048 " 2^0 2^1 2^2 2^3 2^4 2^5 2^6 " 3047 3049 " 2^7 2^8 2^9 2^10 2^11 2^12 2^13 ]\n"); 3048 3050 3049 - i = (blocksize_bits + 2) * sizeof(sg.info.bb_counters[0]) + 3051 + i = (blocksize_bits + 2) * sizeof(sg->bb_counters[0]) + 3050 3052 sizeof(struct ext4_group_info); 3051 3053 3052 3054 grinfo = ext4_get_group_info(sb, group); ··· 3066 3068 * We care only about free space counters in the group info and 3067 3069 * these are safe to access even after the buddy has been unloaded 3068 3070 */ 3069 - memcpy(&sg, grinfo, i); 3070 - seq_printf(seq, "#%-5u: %-5u %-5u %-5u [", group, sg.info.bb_free, 3071 - sg.info.bb_fragments, sg.info.bb_first_free); 3071 + memcpy(sg, grinfo, i); 3072 + seq_printf(seq, "#%-5u: %-5u %-5u %-5u [", group, sg->bb_free, 3073 + sg->bb_fragments, sg->bb_first_free); 3072 3074 for (i = 0; i <= 13; i++) 3073 3075 seq_printf(seq, " %-5u", i <= blocksize_bits + 1 ? 3074 - sg.info.bb_counters[i] : 0); 3076 + sg->bb_counters[i] : 0); 3075 3077 seq_puts(seq, " ]"); 3076 - if (EXT4_MB_GRP_BBITMAP_CORRUPT(&sg.info)) 3078 + if (EXT4_MB_GRP_BBITMAP_CORRUPT(sg)) 3077 3079 seq_puts(seq, " Block bitmap corrupted!"); 3078 3080 seq_putc(seq, '\n'); 3079 3081 return 0;
+1 -1
fs/ext4/namei.c
··· 1971 1971 * split it in half by count; each resulting block will have at least 1972 1972 * half the space free. 1973 1973 */ 1974 - if (i > 0) 1974 + if (i >= 0) 1975 1975 split = count - move; 1976 1976 else 1977 1977 split = count/2;