ext4: save all error info in save_error_info() and drop ext4_set_errno()
Using a separate function, ext4_set_errno() to set the errno is
problematic because it doesn't do the right thing once
s_last_error_errorcode is non-zero.  It's also less racy to set all of
the error information all at once.  (Also, as a bonus, it shrinks code
size slightly.)
Link: https://lore.kernel.org/r/20200329020404.686965-1-tytso@mit.edu
Fixes: 878520ac45 ("ext4: save the error code which triggered...")
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
			
			
This commit is contained in:
		
							parent
							
								
									df41460a21
								
							
						
					
					
						commit
						54d3adbc29
					
				| @ -516,10 +516,9 @@ int ext4_wait_block_bitmap(struct super_block *sb, ext4_group_t block_group, | |||||||
| 	wait_on_buffer(bh); | 	wait_on_buffer(bh); | ||||||
| 	ext4_simulate_fail_bh(sb, bh, EXT4_SIM_BBITMAP_EIO); | 	ext4_simulate_fail_bh(sb, bh, EXT4_SIM_BBITMAP_EIO); | ||||||
| 	if (!buffer_uptodate(bh)) { | 	if (!buffer_uptodate(bh)) { | ||||||
| 		ext4_set_errno(sb, EIO); | 		ext4_error_err(sb, EIO, "Cannot read block bitmap - " | ||||||
| 		ext4_error(sb, "Cannot read block bitmap - " | 			       "block_group = %u, block_bitmap = %llu", | ||||||
| 			   "block_group = %u, block_bitmap = %llu", | 			       block_group, (unsigned long long) bh->b_blocknr); | ||||||
| 			   block_group, (unsigned long long) bh->b_blocknr); |  | ||||||
| 		ext4_mark_group_bitmap_corrupted(sb, block_group, | 		ext4_mark_group_bitmap_corrupted(sb, block_group, | ||||||
| 					EXT4_GROUP_INFO_BBITMAP_CORRUPT); | 					EXT4_GROUP_INFO_BBITMAP_CORRUPT); | ||||||
| 		return -EIO; | 		return -EIO; | ||||||
|  | |||||||
| @ -166,10 +166,8 @@ static int ext4_data_block_valid_rcu(struct ext4_sb_info *sbi, | |||||||
| 
 | 
 | ||||||
| 	if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || | 	if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || | ||||||
| 	    (start_blk + count < start_blk) || | 	    (start_blk + count < start_blk) || | ||||||
| 	    (start_blk + count > ext4_blocks_count(sbi->s_es))) { | 	    (start_blk + count > ext4_blocks_count(sbi->s_es))) | ||||||
| 		sbi->s_es->s_last_error_block = cpu_to_le64(start_blk); |  | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	if (system_blks == NULL) | 	if (system_blks == NULL) | ||||||
| 		return 1; | 		return 1; | ||||||
| @ -181,10 +179,8 @@ static int ext4_data_block_valid_rcu(struct ext4_sb_info *sbi, | |||||||
| 			n = n->rb_left; | 			n = n->rb_left; | ||||||
| 		else if (start_blk >= (entry->start_blk + entry->count)) | 		else if (start_blk >= (entry->start_blk + entry->count)) | ||||||
| 			n = n->rb_right; | 			n = n->rb_right; | ||||||
| 		else { | 		else | ||||||
| 			sbi->s_es->s_last_error_block = cpu_to_le64(start_blk); |  | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return 1; | 	return 1; | ||||||
| } | } | ||||||
| @ -220,10 +216,12 @@ static int ext4_protect_reserved_inode(struct super_block *sb, | |||||||
| 		} else { | 		} else { | ||||||
| 			if (!ext4_data_block_valid_rcu(sbi, system_blks, | 			if (!ext4_data_block_valid_rcu(sbi, system_blks, | ||||||
| 						map.m_pblk, n)) { | 						map.m_pblk, n)) { | ||||||
| 				ext4_error(sb, "blocks %llu-%llu from inode %u " |  | ||||||
| 					   "overlap system zone", map.m_pblk, |  | ||||||
| 					   map.m_pblk + map.m_len - 1, ino); |  | ||||||
| 				err = -EFSCORRUPTED; | 				err = -EFSCORRUPTED; | ||||||
|  | 				__ext4_error(sb, __func__, __LINE__, -err, | ||||||
|  | 					     map.m_pblk, "blocks %llu-%llu " | ||||||
|  | 					     "from inode %u overlap system zone", | ||||||
|  | 					     map.m_pblk, | ||||||
|  | 					     map.m_pblk + map.m_len - 1, ino); | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 			err = add_system_zone(system_blks, map.m_pblk, n); | 			err = add_system_zone(system_blks, map.m_pblk, n); | ||||||
| @ -365,7 +363,6 @@ int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk, | |||||||
| int ext4_check_blockref(const char *function, unsigned int line, | int ext4_check_blockref(const char *function, unsigned int line, | ||||||
| 			struct inode *inode, __le32 *p, unsigned int max) | 			struct inode *inode, __le32 *p, unsigned int max) | ||||||
| { | { | ||||||
| 	struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es; |  | ||||||
| 	__le32 *bref = p; | 	__le32 *bref = p; | ||||||
| 	unsigned int blk; | 	unsigned int blk; | ||||||
| 
 | 
 | ||||||
| @ -379,7 +376,6 @@ int ext4_check_blockref(const char *function, unsigned int line, | |||||||
| 		if (blk && | 		if (blk && | ||||||
| 		    unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb), | 		    unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb), | ||||||
| 						    blk, 1))) { | 						    blk, 1))) { | ||||||
| 			es->s_last_error_block = cpu_to_le64(blk); |  | ||||||
| 			ext4_error_inode(inode, function, line, blk, | 			ext4_error_inode(inode, function, line, blk, | ||||||
| 					 "invalid block"); | 					 "invalid block"); | ||||||
| 			return -EFSCORRUPTED; | 			return -EFSCORRUPTED; | ||||||
|  | |||||||
| @ -2770,21 +2770,20 @@ extern const char *ext4_decode_error(struct super_block *sb, int errno, | |||||||
| extern void ext4_mark_group_bitmap_corrupted(struct super_block *sb, | extern void ext4_mark_group_bitmap_corrupted(struct super_block *sb, | ||||||
| 					     ext4_group_t block_group, | 					     ext4_group_t block_group, | ||||||
| 					     unsigned int flags); | 					     unsigned int flags); | ||||||
| extern void ext4_set_errno(struct super_block *sb, int err); |  | ||||||
| 
 | 
 | ||||||
| extern __printf(4, 5) | extern __printf(6, 7) | ||||||
| void __ext4_error(struct super_block *, const char *, unsigned int, | void __ext4_error(struct super_block *, const char *, unsigned int, int, __u64, | ||||||
| 		  const char *, ...); | 		  const char *, ...); | ||||||
| extern __printf(5, 6) | extern __printf(6, 7) | ||||||
| void __ext4_error_inode(struct inode *, const char *, unsigned int, ext4_fsblk_t, | void __ext4_error_inode(struct inode *, const char *, unsigned int, | ||||||
| 		      const char *, ...); | 			ext4_fsblk_t, int, const char *, ...); | ||||||
| extern __printf(5, 6) | extern __printf(5, 6) | ||||||
| void __ext4_error_file(struct file *, const char *, unsigned int, ext4_fsblk_t, | void __ext4_error_file(struct file *, const char *, unsigned int, ext4_fsblk_t, | ||||||
| 		     const char *, ...); | 		     const char *, ...); | ||||||
| extern void __ext4_std_error(struct super_block *, const char *, | extern void __ext4_std_error(struct super_block *, const char *, | ||||||
| 			     unsigned int, int); | 			     unsigned int, int); | ||||||
| extern __printf(4, 5) | extern __printf(5, 6) | ||||||
| void __ext4_abort(struct super_block *, const char *, unsigned int, | void __ext4_abort(struct super_block *, const char *, unsigned int, int, | ||||||
| 		  const char *, ...); | 		  const char *, ...); | ||||||
| extern __printf(4, 5) | extern __printf(4, 5) | ||||||
| void __ext4_warning(struct super_block *, const char *, unsigned int, | void __ext4_warning(struct super_block *, const char *, unsigned int, | ||||||
| @ -2805,8 +2804,12 @@ void __ext4_grp_locked_error(const char *, unsigned int, | |||||||
| #define EXT4_ERROR_INODE(inode, fmt, a...) \ | #define EXT4_ERROR_INODE(inode, fmt, a...) \ | ||||||
| 	ext4_error_inode((inode), __func__, __LINE__, 0, (fmt), ## a) | 	ext4_error_inode((inode), __func__, __LINE__, 0, (fmt), ## a) | ||||||
| 
 | 
 | ||||||
| #define EXT4_ERROR_INODE_BLOCK(inode, block, fmt, a...)			\ | #define EXT4_ERROR_INODE_ERR(inode, err, fmt, a...)			\ | ||||||
| 	ext4_error_inode((inode), __func__, __LINE__, (block), (fmt), ## a) | 	__ext4_error_inode((inode), __func__, __LINE__, 0, (err), (fmt), ## a) | ||||||
|  | 
 | ||||||
|  | #define ext4_error_inode_block(inode, block, err, fmt, a...)		\ | ||||||
|  | 	__ext4_error_inode((inode), __func__, __LINE__, (block), (err),	\ | ||||||
|  | 			   (fmt), ## a) | ||||||
| 
 | 
 | ||||||
| #define EXT4_ERROR_FILE(file, block, fmt, a...)				\ | #define EXT4_ERROR_FILE(file, block, fmt, a...)				\ | ||||||
| 	ext4_error_file((file), __func__, __LINE__, (block), (fmt), ## a) | 	ext4_error_file((file), __func__, __LINE__, (block), (fmt), ## a) | ||||||
| @ -2814,13 +2817,18 @@ void __ext4_grp_locked_error(const char *, unsigned int, | |||||||
| #ifdef CONFIG_PRINTK | #ifdef CONFIG_PRINTK | ||||||
| 
 | 
 | ||||||
| #define ext4_error_inode(inode, func, line, block, fmt, ...)		\ | #define ext4_error_inode(inode, func, line, block, fmt, ...)		\ | ||||||
| 	__ext4_error_inode(inode, func, line, block, fmt, ##__VA_ARGS__) | 	__ext4_error_inode(inode, func, line, block, 0, fmt, ##__VA_ARGS__) | ||||||
|  | #define ext4_error_inode_err(inode, func, line, block, err, fmt, ...)	\ | ||||||
|  | 	__ext4_error_inode((inode), (func), (line), (block), 		\ | ||||||
|  | 			   (err), (fmt), ##__VA_ARGS__) | ||||||
| #define ext4_error_file(file, func, line, block, fmt, ...)		\ | #define ext4_error_file(file, func, line, block, fmt, ...)		\ | ||||||
| 	__ext4_error_file(file, func, line, block, fmt, ##__VA_ARGS__) | 	__ext4_error_file(file, func, line, block, fmt, ##__VA_ARGS__) | ||||||
| #define ext4_error(sb, fmt, ...)					\ | #define ext4_error(sb, fmt, ...)					\ | ||||||
| 	__ext4_error(sb, __func__, __LINE__, fmt, ##__VA_ARGS__) | 	__ext4_error((sb), __func__, __LINE__, 0, 0, (fmt), ##__VA_ARGS__) | ||||||
| #define ext4_abort(sb, fmt, ...)					\ | #define ext4_error_err(sb, err, fmt, ...)				\ | ||||||
| 	__ext4_abort(sb, __func__, __LINE__, fmt, ##__VA_ARGS__) | 	__ext4_error((sb), __func__, __LINE__, (err), 0, (fmt), ##__VA_ARGS__) | ||||||
|  | #define ext4_abort(sb, err, fmt, ...)					\ | ||||||
|  | 	__ext4_abort((sb), __func__, __LINE__, (err), (fmt), ##__VA_ARGS__) | ||||||
| #define ext4_warning(sb, fmt, ...)					\ | #define ext4_warning(sb, fmt, ...)					\ | ||||||
| 	__ext4_warning(sb, __func__, __LINE__, fmt, ##__VA_ARGS__) | 	__ext4_warning(sb, __func__, __LINE__, fmt, ##__VA_ARGS__) | ||||||
| #define ext4_warning_inode(inode, fmt, ...)				\ | #define ext4_warning_inode(inode, fmt, ...)				\ | ||||||
| @ -2838,7 +2846,12 @@ void __ext4_grp_locked_error(const char *, unsigned int, | |||||||
| #define ext4_error_inode(inode, func, line, block, fmt, ...)		\ | #define ext4_error_inode(inode, func, line, block, fmt, ...)		\ | ||||||
| do {									\ | do {									\ | ||||||
| 	no_printk(fmt, ##__VA_ARGS__);					\ | 	no_printk(fmt, ##__VA_ARGS__);					\ | ||||||
| 	__ext4_error_inode(inode, "", 0, block, " ");			\ | 	__ext4_error_inode(inode, "", 0, block, 0, " ");		\ | ||||||
|  | } while (0) | ||||||
|  | #define ext4_error_inode_err(inode, func, line, block, err, fmt, ...)	\ | ||||||
|  | do {									\ | ||||||
|  | 	no_printk(fmt, ##__VA_ARGS__);					\ | ||||||
|  | 	__ext4_error_inode(inode, "", 0, block, err, " ");		\ | ||||||
| } while (0) | } while (0) | ||||||
| #define ext4_error_file(file, func, line, block, fmt, ...)		\ | #define ext4_error_file(file, func, line, block, fmt, ...)		\ | ||||||
| do {									\ | do {									\ | ||||||
| @ -2848,12 +2861,17 @@ do {									\ | |||||||
| #define ext4_error(sb, fmt, ...)					\ | #define ext4_error(sb, fmt, ...)					\ | ||||||
| do {									\ | do {									\ | ||||||
| 	no_printk(fmt, ##__VA_ARGS__);					\ | 	no_printk(fmt, ##__VA_ARGS__);					\ | ||||||
| 	__ext4_error(sb, "", 0, " ");					\ | 	__ext4_error(sb, "", 0, 0, 0, " ");				\ | ||||||
| } while (0) | } while (0) | ||||||
| #define ext4_abort(sb, fmt, ...)					\ | #define ext4_error_err(sb, err, fmt, ...)				\ | ||||||
| do {									\ | do {									\ | ||||||
| 	no_printk(fmt, ##__VA_ARGS__);					\ | 	no_printk(fmt, ##__VA_ARGS__);					\ | ||||||
| 	__ext4_abort(sb, "", 0, " ");					\ | 	__ext4_error(sb, "", 0, err, 0, " ");				\ | ||||||
|  | } while (0) | ||||||
|  | #define ext4_abort(sb, err, fmt, ...)					\ | ||||||
|  | do {									\ | ||||||
|  | 	no_printk(fmt, ##__VA_ARGS__);					\ | ||||||
|  | 	__ext4_abort(sb, "", 0, err, " ");				\ | ||||||
| } while (0) | } while (0) | ||||||
| #define ext4_warning(sb, fmt, ...)					\ | #define ext4_warning(sb, fmt, ...)					\ | ||||||
| do {									\ | do {									\ | ||||||
|  | |||||||
| @ -80,8 +80,7 @@ static int ext4_journal_check_start(struct super_block *sb) | |||||||
| 	 * take the FS itself readonly cleanly. | 	 * take the FS itself readonly cleanly. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (journal && is_journal_aborted(journal)) { | 	if (journal && is_journal_aborted(journal)) { | ||||||
| 		ext4_set_errno(sb, -journal->j_errno); | 		ext4_abort(sb, -journal->j_errno, "Detected aborted journal"); | ||||||
| 		ext4_abort(sb, "Detected aborted journal"); |  | ||||||
| 		return -EROFS; | 		return -EROFS; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| @ -272,8 +271,7 @@ int __ext4_forget(const char *where, unsigned int line, handle_t *handle, | |||||||
| 	if (err) { | 	if (err) { | ||||||
| 		ext4_journal_abort_handle(where, line, __func__, | 		ext4_journal_abort_handle(where, line, __func__, | ||||||
| 					  bh, handle, err); | 					  bh, handle, err); | ||||||
| 		ext4_set_errno(inode->i_sb, -err); | 		__ext4_abort(inode->i_sb, where, line, -err, | ||||||
| 		__ext4_abort(inode->i_sb, where, line, |  | ||||||
| 			   "error %d when attempting revoke", err); | 			   "error %d when attempting revoke", err); | ||||||
| 	} | 	} | ||||||
| 	BUFFER_TRACE(bh, "exit"); | 	BUFFER_TRACE(bh, "exit"); | ||||||
| @ -343,11 +341,8 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line, | |||||||
| 				struct ext4_super_block *es; | 				struct ext4_super_block *es; | ||||||
| 
 | 
 | ||||||
| 				es = EXT4_SB(inode->i_sb)->s_es; | 				es = EXT4_SB(inode->i_sb)->s_es; | ||||||
| 				es->s_last_error_block = | 				ext4_error_inode_err(inode, where, line, | ||||||
| 					cpu_to_le64(bh->b_blocknr); | 						     bh->b_blocknr, EIO, | ||||||
| 				ext4_set_errno(inode->i_sb, EIO); |  | ||||||
| 				ext4_error_inode(inode, where, line, |  | ||||||
| 						 bh->b_blocknr, |  | ||||||
| 					"IO error syncing itable block"); | 					"IO error syncing itable block"); | ||||||
| 				err = -EIO; | 				err = -EIO; | ||||||
| 			} | 			} | ||||||
|  | |||||||
| @ -349,8 +349,8 @@ static int ext4_valid_extent_idx(struct inode *inode, | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int ext4_valid_extent_entries(struct inode *inode, | static int ext4_valid_extent_entries(struct inode *inode, | ||||||
| 				struct ext4_extent_header *eh, | 				     struct ext4_extent_header *eh, | ||||||
| 				int depth) | 				     ext4_fsblk_t *pblk, int depth) | ||||||
| { | { | ||||||
| 	unsigned short entries; | 	unsigned short entries; | ||||||
| 	if (eh->eh_entries == 0) | 	if (eh->eh_entries == 0) | ||||||
| @ -361,8 +361,6 @@ static int ext4_valid_extent_entries(struct inode *inode, | |||||||
| 	if (depth == 0) { | 	if (depth == 0) { | ||||||
| 		/* leaf entries */ | 		/* leaf entries */ | ||||||
| 		struct ext4_extent *ext = EXT_FIRST_EXTENT(eh); | 		struct ext4_extent *ext = EXT_FIRST_EXTENT(eh); | ||||||
| 		struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es; |  | ||||||
| 		ext4_fsblk_t pblock = 0; |  | ||||||
| 		ext4_lblk_t lblock = 0; | 		ext4_lblk_t lblock = 0; | ||||||
| 		ext4_lblk_t prev = 0; | 		ext4_lblk_t prev = 0; | ||||||
| 		int len = 0; | 		int len = 0; | ||||||
| @ -374,8 +372,7 @@ static int ext4_valid_extent_entries(struct inode *inode, | |||||||
| 			lblock = le32_to_cpu(ext->ee_block); | 			lblock = le32_to_cpu(ext->ee_block); | ||||||
| 			len = ext4_ext_get_actual_len(ext); | 			len = ext4_ext_get_actual_len(ext); | ||||||
| 			if ((lblock <= prev) && prev) { | 			if ((lblock <= prev) && prev) { | ||||||
| 				pblock = ext4_ext_pblock(ext); | 				*pblk = ext4_ext_pblock(ext); | ||||||
| 				es->s_last_error_block = cpu_to_le64(pblock); |  | ||||||
| 				return 0; | 				return 0; | ||||||
| 			} | 			} | ||||||
| 			ext++; | 			ext++; | ||||||
| @ -422,7 +419,7 @@ static int __ext4_ext_check(const char *function, unsigned int line, | |||||||
| 		error_msg = "invalid eh_entries"; | 		error_msg = "invalid eh_entries"; | ||||||
| 		goto corrupted; | 		goto corrupted; | ||||||
| 	} | 	} | ||||||
| 	if (!ext4_valid_extent_entries(inode, eh, depth)) { | 	if (!ext4_valid_extent_entries(inode, eh, &pblk, depth)) { | ||||||
| 		error_msg = "invalid extent entries"; | 		error_msg = "invalid extent entries"; | ||||||
| 		goto corrupted; | 		goto corrupted; | ||||||
| 	} | 	} | ||||||
| @ -440,14 +437,14 @@ static int __ext4_ext_check(const char *function, unsigned int line, | |||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
| corrupted: | corrupted: | ||||||
| 	ext4_set_errno(inode->i_sb, -err); | 	ext4_error_inode_err(inode, function, line, 0, -err, | ||||||
| 	ext4_error_inode(inode, function, line, 0, | 			     "pblk %llu bad header/extent: %s - magic %x, " | ||||||
| 			 "pblk %llu bad header/extent: %s - magic %x, " | 			     "entries %u, max %u(%u), depth %u(%u)", | ||||||
| 			 "entries %u, max %u(%u), depth %u(%u)", | 			     (unsigned long long) pblk, error_msg, | ||||||
| 			 (unsigned long long) pblk, error_msg, | 			     le16_to_cpu(eh->eh_magic), | ||||||
| 			 le16_to_cpu(eh->eh_magic), | 			     le16_to_cpu(eh->eh_entries), | ||||||
| 			 le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max), | 			     le16_to_cpu(eh->eh_max), | ||||||
| 			 max, le16_to_cpu(eh->eh_depth), depth); | 			     max, le16_to_cpu(eh->eh_depth), depth); | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -196,10 +196,9 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||||||
| 	ext4_simulate_fail_bh(sb, bh, EXT4_SIM_IBITMAP_EIO); | 	ext4_simulate_fail_bh(sb, bh, EXT4_SIM_IBITMAP_EIO); | ||||||
| 	if (!buffer_uptodate(bh)) { | 	if (!buffer_uptodate(bh)) { | ||||||
| 		put_bh(bh); | 		put_bh(bh); | ||||||
| 		ext4_set_errno(sb, EIO); | 		ext4_error_err(sb, EIO, "Cannot read inode bitmap - " | ||||||
| 		ext4_error(sb, "Cannot read inode bitmap - " | 			       "block_group = %u, inode_bitmap = %llu", | ||||||
| 			   "block_group = %u, inode_bitmap = %llu", | 			       block_group, bitmap_blk); | ||||||
| 			   block_group, bitmap_blk); |  | ||||||
| 		ext4_mark_group_bitmap_corrupted(sb, block_group, | 		ext4_mark_group_bitmap_corrupted(sb, block_group, | ||||||
| 				EXT4_GROUP_INFO_IBITMAP_CORRUPT); | 				EXT4_GROUP_INFO_IBITMAP_CORRUPT); | ||||||
| 		return ERR_PTR(-EIO); | 		return ERR_PTR(-EIO); | ||||||
| @ -1244,9 +1243,9 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino) | |||||||
| 	inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL); | 	inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL); | ||||||
| 	if (IS_ERR(inode)) { | 	if (IS_ERR(inode)) { | ||||||
| 		err = PTR_ERR(inode); | 		err = PTR_ERR(inode); | ||||||
| 		ext4_set_errno(sb, -err); | 		ext4_error_err(sb, -err, | ||||||
| 		ext4_error(sb, "couldn't read orphan inode %lu (err %d)", | 			       "couldn't read orphan inode %lu (err %d)", | ||||||
| 			   ino, err); | 			       ino, err); | ||||||
| 		return inode; | 		return inode; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1019,7 +1019,7 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode, | |||||||
| 			 * (should be rare). | 			 * (should be rare). | ||||||
| 			 */ | 			 */ | ||||||
| 			if (!bh) { | 			if (!bh) { | ||||||
| 				EXT4_ERROR_INODE_BLOCK(inode, nr, | 				ext4_error_inode_block(inode, nr, EIO, | ||||||
| 						       "Read failure"); | 						       "Read failure"); | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  | |||||||
| @ -98,10 +98,9 @@ int ext4_get_max_inline_size(struct inode *inode) | |||||||
| 
 | 
 | ||||||
| 	error = ext4_get_inode_loc(inode, &iloc); | 	error = ext4_get_inode_loc(inode, &iloc); | ||||||
| 	if (error) { | 	if (error) { | ||||||
| 		ext4_set_errno(inode->i_sb, -error); | 		ext4_error_inode_err(inode, __func__, __LINE__, 0, -error, | ||||||
| 		ext4_error_inode(inode, __func__, __LINE__, 0, | 				     "can't get inode location %lu", | ||||||
| 				 "can't get inode location %lu", | 				     inode->i_ino); | ||||||
| 				 inode->i_ino); |  | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -1762,9 +1761,9 @@ bool empty_inline_dir(struct inode *dir, int *has_inline_data) | |||||||
| 
 | 
 | ||||||
| 	err = ext4_get_inode_loc(dir, &iloc); | 	err = ext4_get_inode_loc(dir, &iloc); | ||||||
| 	if (err) { | 	if (err) { | ||||||
| 		ext4_set_errno(dir->i_sb, -err); | 		EXT4_ERROR_INODE_ERR(dir, -err, | ||||||
| 		EXT4_ERROR_INODE(dir, "error %d getting inode %lu block", | 				     "error %d getting inode %lu block", | ||||||
| 				 err, dir->i_ino); | 				     err, dir->i_ino); | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -269,10 +269,9 @@ void ext4_evict_inode(struct inode *inode) | |||||||
| 	if (inode->i_blocks) { | 	if (inode->i_blocks) { | ||||||
| 		err = ext4_truncate(inode); | 		err = ext4_truncate(inode); | ||||||
| 		if (err) { | 		if (err) { | ||||||
| 			ext4_set_errno(inode->i_sb, -err); | 			ext4_error_err(inode->i_sb, -err, | ||||||
| 			ext4_error(inode->i_sb, | 				       "couldn't truncate inode %lu (err %d)", | ||||||
| 				   "couldn't truncate inode %lu (err %d)", | 				       inode->i_ino, err); | ||||||
| 				   inode->i_ino, err); |  | ||||||
| 			goto stop_handle; | 			goto stop_handle; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -2478,10 +2477,9 @@ update_disksize: | |||||||
| 		up_write(&EXT4_I(inode)->i_data_sem); | 		up_write(&EXT4_I(inode)->i_data_sem); | ||||||
| 		err2 = ext4_mark_inode_dirty(handle, inode); | 		err2 = ext4_mark_inode_dirty(handle, inode); | ||||||
| 		if (err2) { | 		if (err2) { | ||||||
| 			ext4_set_errno(inode->i_sb, -err2); | 			ext4_error_err(inode->i_sb, -err2, | ||||||
| 			ext4_error(inode->i_sb, | 				       "Failed to mark inode %lu dirty", | ||||||
| 				   "Failed to mark inode %lu dirty", | 				       inode->i_ino); | ||||||
| 				   inode->i_ino); |  | ||||||
| 		} | 		} | ||||||
| 		if (!err) | 		if (!err) | ||||||
| 			err = err2; | 			err = err2; | ||||||
| @ -4382,8 +4380,7 @@ make_io: | |||||||
| 		wait_on_buffer(bh); | 		wait_on_buffer(bh); | ||||||
| 		if (!buffer_uptodate(bh)) { | 		if (!buffer_uptodate(bh)) { | ||||||
| 		simulate_eio: | 		simulate_eio: | ||||||
| 			ext4_set_errno(inode->i_sb, EIO); | 			ext4_error_inode_block(inode, block, EIO, | ||||||
| 			EXT4_ERROR_INODE_BLOCK(inode, block, |  | ||||||
| 					       "unable to read itable block"); | 					       "unable to read itable block"); | ||||||
| 			brelse(bh); | 			brelse(bh); | ||||||
| 			return -EIO; | 			return -EIO; | ||||||
| @ -4535,7 +4532,7 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, | |||||||
| 	    (ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))) { | 	    (ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))) { | ||||||
| 		if (flags & EXT4_IGET_HANDLE) | 		if (flags & EXT4_IGET_HANDLE) | ||||||
| 			return ERR_PTR(-ESTALE); | 			return ERR_PTR(-ESTALE); | ||||||
| 		__ext4_error(sb, function, line, | 		__ext4_error(sb, function, line, EFSCORRUPTED, 0, | ||||||
| 			     "inode #%lu: comm %s: iget: illegal inode #", | 			     "inode #%lu: comm %s: iget: illegal inode #", | ||||||
| 			     ino, current->comm); | 			     ino, current->comm); | ||||||
| 		return ERR_PTR(-EFSCORRUPTED); | 		return ERR_PTR(-EFSCORRUPTED); | ||||||
| @ -4598,9 +4595,8 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, | |||||||
| 
 | 
 | ||||||
| 	if (!ext4_inode_csum_verify(inode, raw_inode, ei) || | 	if (!ext4_inode_csum_verify(inode, raw_inode, ei) || | ||||||
| 	    ext4_simulate_fail(sb, EXT4_SIM_INODE_CRC)) { | 	    ext4_simulate_fail(sb, EXT4_SIM_INODE_CRC)) { | ||||||
| 		ext4_set_errno(inode->i_sb, EFSBADCRC); | 		ext4_error_inode_err(inode, function, line, 0, EFSBADCRC, | ||||||
| 		ext4_error_inode(inode, function, line, 0, | 				     "iget: checksum invalid"); | ||||||
| 				 "iget: checksum invalid"); |  | ||||||
| 		ret = -EFSBADCRC; | 		ret = -EFSBADCRC; | ||||||
| 		goto bad_inode; | 		goto bad_inode; | ||||||
| 	} | 	} | ||||||
| @ -5149,9 +5145,8 @@ int ext4_write_inode(struct inode *inode, struct writeback_control *wbc) | |||||||
| 		if (wbc->sync_mode == WB_SYNC_ALL && !wbc->for_sync) | 		if (wbc->sync_mode == WB_SYNC_ALL && !wbc->for_sync) | ||||||
| 			sync_dirty_buffer(iloc.bh); | 			sync_dirty_buffer(iloc.bh); | ||||||
| 		if (buffer_req(iloc.bh) && !buffer_uptodate(iloc.bh)) { | 		if (buffer_req(iloc.bh) && !buffer_uptodate(iloc.bh)) { | ||||||
| 			ext4_set_errno(inode->i_sb, EIO); | 			ext4_error_inode_block(inode, iloc.bh->b_blocknr, EIO, | ||||||
| 			EXT4_ERROR_INODE_BLOCK(inode, iloc.bh->b_blocknr, | 					       "IO error syncing inode"); | ||||||
| 					 "IO error syncing inode"); |  | ||||||
| 			err = -EIO; | 			err = -EIO; | ||||||
| 		} | 		} | ||||||
| 		brelse(iloc.bh); | 		brelse(iloc.bh); | ||||||
|  | |||||||
| @ -3921,9 +3921,9 @@ ext4_mb_discard_group_preallocations(struct super_block *sb, | |||||||
| 	bitmap_bh = ext4_read_block_bitmap(sb, group); | 	bitmap_bh = ext4_read_block_bitmap(sb, group); | ||||||
| 	if (IS_ERR(bitmap_bh)) { | 	if (IS_ERR(bitmap_bh)) { | ||||||
| 		err = PTR_ERR(bitmap_bh); | 		err = PTR_ERR(bitmap_bh); | ||||||
| 		ext4_set_errno(sb, -err); | 		ext4_error_err(sb, -err, | ||||||
| 		ext4_error(sb, "Error %d reading block bitmap for %u", | 			       "Error %d reading block bitmap for %u", | ||||||
| 			   err, group); | 			       err, group); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -4090,18 +4090,16 @@ repeat: | |||||||
| 		err = ext4_mb_load_buddy_gfp(sb, group, &e4b, | 		err = ext4_mb_load_buddy_gfp(sb, group, &e4b, | ||||||
| 					     GFP_NOFS|__GFP_NOFAIL); | 					     GFP_NOFS|__GFP_NOFAIL); | ||||||
| 		if (err) { | 		if (err) { | ||||||
| 			ext4_set_errno(sb, -err); | 			ext4_error_err(sb, -err, "Error %d loading buddy information for %u", | ||||||
| 			ext4_error(sb, "Error %d loading buddy information for %u", | 				       err, group); | ||||||
| 				   err, group); |  | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		bitmap_bh = ext4_read_block_bitmap(sb, group); | 		bitmap_bh = ext4_read_block_bitmap(sb, group); | ||||||
| 		if (IS_ERR(bitmap_bh)) { | 		if (IS_ERR(bitmap_bh)) { | ||||||
| 			err = PTR_ERR(bitmap_bh); | 			err = PTR_ERR(bitmap_bh); | ||||||
| 			ext4_set_errno(sb, -err); | 			ext4_error_err(sb, -err, "Error %d reading block bitmap for %u", | ||||||
| 			ext4_error(sb, "Error %d reading block bitmap for %u", | 				       err, group); | ||||||
| 					err, group); |  | ||||||
| 			ext4_mb_unload_buddy(&e4b); | 			ext4_mb_unload_buddy(&e4b); | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
| @ -4355,9 +4353,8 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb, | |||||||
| 		err = ext4_mb_load_buddy_gfp(sb, group, &e4b, | 		err = ext4_mb_load_buddy_gfp(sb, group, &e4b, | ||||||
| 					     GFP_NOFS|__GFP_NOFAIL); | 					     GFP_NOFS|__GFP_NOFAIL); | ||||||
| 		if (err) { | 		if (err) { | ||||||
| 			ext4_set_errno(sb, -err); | 			ext4_error_err(sb, -err, "Error %d loading buddy information for %u", | ||||||
| 			ext4_error(sb, "Error %d loading buddy information for %u", | 				       err, group); | ||||||
| 				   err, group); |  | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
| 		ext4_lock_group(sb, group); | 		ext4_lock_group(sb, group); | ||||||
|  | |||||||
| @ -175,8 +175,8 @@ static int kmmpd(void *data) | |||||||
| 		 */ | 		 */ | ||||||
| 		if (retval) { | 		if (retval) { | ||||||
| 			if ((failed_writes % 60) == 0) { | 			if ((failed_writes % 60) == 0) { | ||||||
| 				ext4_set_errno(sb, -retval); | 				ext4_error_err(sb, -retval, | ||||||
| 				ext4_error(sb, "Error writing to MMP block"); | 					       "Error writing to MMP block"); | ||||||
| 			} | 			} | ||||||
| 			failed_writes++; | 			failed_writes++; | ||||||
| 		} | 		} | ||||||
| @ -208,9 +208,9 @@ static int kmmpd(void *data) | |||||||
| 
 | 
 | ||||||
| 			retval = read_mmp_block(sb, &bh_check, mmp_block); | 			retval = read_mmp_block(sb, &bh_check, mmp_block); | ||||||
| 			if (retval) { | 			if (retval) { | ||||||
| 				ext4_set_errno(sb, -retval); | 				ext4_error_err(sb, -retval, | ||||||
| 				ext4_error(sb, "error reading MMP data: %d", | 					       "error reading MMP data: %d", | ||||||
| 					   retval); | 					       retval); | ||||||
| 				goto exit_thread; | 				goto exit_thread; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| @ -222,8 +222,7 @@ static int kmmpd(void *data) | |||||||
| 					     "Error while updating MMP info. " | 					     "Error while updating MMP info. " | ||||||
| 					     "The filesystem seems to have been" | 					     "The filesystem seems to have been" | ||||||
| 					     " multiply mounted."); | 					     " multiply mounted."); | ||||||
| 				ext4_set_errno(sb, EBUSY); | 				ext4_error_err(sb, EBUSY, "abort"); | ||||||
| 				ext4_error(sb, "abort"); |  | ||||||
| 				put_bh(bh_check); | 				put_bh(bh_check); | ||||||
| 				retval = -EBUSY; | 				retval = -EBUSY; | ||||||
| 				goto exit_thread; | 				goto exit_thread; | ||||||
|  | |||||||
| @ -422,8 +422,8 @@ repair_branches: | |||||||
| 					   block_len_in_page, 0, &err2); | 					   block_len_in_page, 0, &err2); | ||||||
| 	ext4_double_up_write_data_sem(orig_inode, donor_inode); | 	ext4_double_up_write_data_sem(orig_inode, donor_inode); | ||||||
| 	if (replaced_count != block_len_in_page) { | 	if (replaced_count != block_len_in_page) { | ||||||
| 		EXT4_ERROR_INODE_BLOCK(orig_inode, (sector_t)(orig_blk_offset), | 		ext4_error_inode_block(orig_inode, (sector_t)(orig_blk_offset), | ||||||
| 				       "Unable to copy data block," | 				       EIO, "Unable to copy data block," | ||||||
| 				       " data will be lost."); | 				       " data will be lost."); | ||||||
| 		*err = -EIO; | 		*err = -EIO; | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -160,9 +160,9 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode, | |||||||
| 		    !ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_CRC)) | 		    !ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_CRC)) | ||||||
| 			set_buffer_verified(bh); | 			set_buffer_verified(bh); | ||||||
| 		else { | 		else { | ||||||
| 			ext4_set_errno(inode->i_sb, EFSBADCRC); | 			ext4_error_inode_err(inode, func, line, block, | ||||||
| 			ext4_error_inode(inode, func, line, block, | 					     EFSBADCRC, | ||||||
| 					 "Directory index failed checksum"); | 					     "Directory index failed checksum"); | ||||||
| 			brelse(bh); | 			brelse(bh); | ||||||
| 			return ERR_PTR(-EFSBADCRC); | 			return ERR_PTR(-EFSBADCRC); | ||||||
| 		} | 		} | ||||||
| @ -172,9 +172,9 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode, | |||||||
| 		    !ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_CRC)) | 		    !ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_CRC)) | ||||||
| 			set_buffer_verified(bh); | 			set_buffer_verified(bh); | ||||||
| 		else { | 		else { | ||||||
| 			ext4_set_errno(inode->i_sb, EFSBADCRC); | 			ext4_error_inode_err(inode, func, line, block, | ||||||
| 			ext4_error_inode(inode, func, line, block, | 					     EFSBADCRC, | ||||||
| 					 "Directory block failed checksum"); | 					     "Directory block failed checksum"); | ||||||
| 			brelse(bh); | 			brelse(bh); | ||||||
| 			return ERR_PTR(-EFSBADCRC); | 			return ERR_PTR(-EFSBADCRC); | ||||||
| 		} | 		} | ||||||
| @ -1532,9 +1532,9 @@ restart: | |||||||
| 			goto next; | 			goto next; | ||||||
| 		wait_on_buffer(bh); | 		wait_on_buffer(bh); | ||||||
| 		if (!buffer_uptodate(bh)) { | 		if (!buffer_uptodate(bh)) { | ||||||
| 			ext4_set_errno(sb, EIO); | 			EXT4_ERROR_INODE_ERR(dir, EIO, | ||||||
| 			EXT4_ERROR_INODE(dir, "reading directory lblock %lu", | 					     "reading directory lblock %lu", | ||||||
| 					 (unsigned long) block); | 					     (unsigned long) block); | ||||||
| 			brelse(bh); | 			brelse(bh); | ||||||
| 			ret = ERR_PTR(-EIO); | 			ret = ERR_PTR(-EIO); | ||||||
| 			goto cleanup_and_exit; | 			goto cleanup_and_exit; | ||||||
| @ -1543,9 +1543,9 @@ restart: | |||||||
| 		    !is_dx_internal_node(dir, block, | 		    !is_dx_internal_node(dir, block, | ||||||
| 					 (struct ext4_dir_entry *)bh->b_data) && | 					 (struct ext4_dir_entry *)bh->b_data) && | ||||||
| 		    !ext4_dirblock_csum_verify(dir, bh)) { | 		    !ext4_dirblock_csum_verify(dir, bh)) { | ||||||
| 			ext4_set_errno(sb, EFSBADCRC); | 			EXT4_ERROR_INODE_ERR(dir, EFSBADCRC, | ||||||
| 			EXT4_ERROR_INODE(dir, "checksumming directory " | 					     "checksumming directory " | ||||||
| 					 "block %lu", (unsigned long)block); | 					     "block %lu", (unsigned long)block); | ||||||
| 			brelse(bh); | 			brelse(bh); | ||||||
| 			ret = ERR_PTR(-EFSBADCRC); | 			ret = ERR_PTR(-EFSBADCRC); | ||||||
| 			goto cleanup_and_exit; | 			goto cleanup_and_exit; | ||||||
|  | |||||||
							
								
								
									
										166
									
								
								fs/ext4/super.c
									
									
									
									
									
								
							
							
						
						
									
										166
									
								
								fs/ext4/super.c
									
									
									
									
									
								
							| @ -335,10 +335,12 @@ static time64_t __ext4_get_tstamp(__le32 *lo, __u8 *hi) | |||||||
| #define ext4_get_tstamp(es, tstamp) \ | #define ext4_get_tstamp(es, tstamp) \ | ||||||
| 	__ext4_get_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi) | 	__ext4_get_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi) | ||||||
| 
 | 
 | ||||||
| static void __save_error_info(struct super_block *sb, const char *func, | static void __save_error_info(struct super_block *sb, int error, | ||||||
| 			    unsigned int line) | 			      __u32 ino, __u64 block, | ||||||
|  | 			      const char *func, unsigned int line) | ||||||
| { | { | ||||||
| 	struct ext4_super_block *es = EXT4_SB(sb)->s_es; | 	struct ext4_super_block *es = EXT4_SB(sb)->s_es; | ||||||
|  | 	int err; | ||||||
| 
 | 
 | ||||||
| 	EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; | 	EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; | ||||||
| 	if (bdev_read_only(sb->s_bdev)) | 	if (bdev_read_only(sb->s_bdev)) | ||||||
| @ -347,8 +349,62 @@ static void __save_error_info(struct super_block *sb, const char *func, | |||||||
| 	ext4_update_tstamp(es, s_last_error_time); | 	ext4_update_tstamp(es, s_last_error_time); | ||||||
| 	strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func)); | 	strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func)); | ||||||
| 	es->s_last_error_line = cpu_to_le32(line); | 	es->s_last_error_line = cpu_to_le32(line); | ||||||
| 	if (es->s_last_error_errcode == 0) | 	es->s_last_error_ino = cpu_to_le32(ino); | ||||||
| 		es->s_last_error_errcode = EXT4_ERR_EFSCORRUPTED; | 	es->s_last_error_block = cpu_to_le64(block); | ||||||
|  | 	switch (error) { | ||||||
|  | 	case EIO: | ||||||
|  | 		err = EXT4_ERR_EIO; | ||||||
|  | 		break; | ||||||
|  | 	case ENOMEM: | ||||||
|  | 		err = EXT4_ERR_ENOMEM; | ||||||
|  | 		break; | ||||||
|  | 	case EFSBADCRC: | ||||||
|  | 		err = EXT4_ERR_EFSBADCRC; | ||||||
|  | 		break; | ||||||
|  | 	case 0: | ||||||
|  | 	case EFSCORRUPTED: | ||||||
|  | 		err = EXT4_ERR_EFSCORRUPTED; | ||||||
|  | 		break; | ||||||
|  | 	case ENOSPC: | ||||||
|  | 		err = EXT4_ERR_ENOSPC; | ||||||
|  | 		break; | ||||||
|  | 	case ENOKEY: | ||||||
|  | 		err = EXT4_ERR_ENOKEY; | ||||||
|  | 		break; | ||||||
|  | 	case EROFS: | ||||||
|  | 		err = EXT4_ERR_EROFS; | ||||||
|  | 		break; | ||||||
|  | 	case EFBIG: | ||||||
|  | 		err = EXT4_ERR_EFBIG; | ||||||
|  | 		break; | ||||||
|  | 	case EEXIST: | ||||||
|  | 		err = EXT4_ERR_EEXIST; | ||||||
|  | 		break; | ||||||
|  | 	case ERANGE: | ||||||
|  | 		err = EXT4_ERR_ERANGE; | ||||||
|  | 		break; | ||||||
|  | 	case EOVERFLOW: | ||||||
|  | 		err = EXT4_ERR_EOVERFLOW; | ||||||
|  | 		break; | ||||||
|  | 	case EBUSY: | ||||||
|  | 		err = EXT4_ERR_EBUSY; | ||||||
|  | 		break; | ||||||
|  | 	case ENOTDIR: | ||||||
|  | 		err = EXT4_ERR_ENOTDIR; | ||||||
|  | 		break; | ||||||
|  | 	case ENOTEMPTY: | ||||||
|  | 		err = EXT4_ERR_ENOTEMPTY; | ||||||
|  | 		break; | ||||||
|  | 	case ESHUTDOWN: | ||||||
|  | 		err = EXT4_ERR_ESHUTDOWN; | ||||||
|  | 		break; | ||||||
|  | 	case EFAULT: | ||||||
|  | 		err = EXT4_ERR_EFAULT; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		err = EXT4_ERR_UNKNOWN; | ||||||
|  | 	} | ||||||
|  | 	es->s_last_error_errcode = err; | ||||||
| 	if (!es->s_first_error_time) { | 	if (!es->s_first_error_time) { | ||||||
| 		es->s_first_error_time = es->s_last_error_time; | 		es->s_first_error_time = es->s_last_error_time; | ||||||
| 		es->s_first_error_time_hi = es->s_last_error_time_hi; | 		es->s_first_error_time_hi = es->s_last_error_time_hi; | ||||||
| @ -368,10 +424,11 @@ static void __save_error_info(struct super_block *sb, const char *func, | |||||||
| 	le32_add_cpu(&es->s_error_count, 1); | 	le32_add_cpu(&es->s_error_count, 1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void save_error_info(struct super_block *sb, const char *func, | static void save_error_info(struct super_block *sb, int error, | ||||||
| 			    unsigned int line) | 			    __u32 ino, __u64 block, | ||||||
|  | 			    const char *func, unsigned int line) | ||||||
| { | { | ||||||
| 	__save_error_info(sb, func, line); | 	__save_error_info(sb, error, ino, block, func, line); | ||||||
| 	if (!bdev_read_only(sb->s_bdev)) | 	if (!bdev_read_only(sb->s_bdev)) | ||||||
| 		ext4_commit_super(sb, 1); | 		ext4_commit_super(sb, 1); | ||||||
| } | } | ||||||
| @ -478,7 +535,8 @@ static void ext4_handle_error(struct super_block *sb) | |||||||
| 			     "EXT4-fs error") | 			     "EXT4-fs error") | ||||||
| 
 | 
 | ||||||
| void __ext4_error(struct super_block *sb, const char *function, | void __ext4_error(struct super_block *sb, const char *function, | ||||||
| 		  unsigned int line, const char *fmt, ...) | 		  unsigned int line, int error, __u64 block, | ||||||
|  | 		  const char *fmt, ...) | ||||||
| { | { | ||||||
| 	struct va_format vaf; | 	struct va_format vaf; | ||||||
| 	va_list args; | 	va_list args; | ||||||
| @ -496,24 +554,21 @@ void __ext4_error(struct super_block *sb, const char *function, | |||||||
| 		       sb->s_id, function, line, current->comm, &vaf); | 		       sb->s_id, function, line, current->comm, &vaf); | ||||||
| 		va_end(args); | 		va_end(args); | ||||||
| 	} | 	} | ||||||
| 	save_error_info(sb, function, line); | 	save_error_info(sb, error, 0, block, function, line); | ||||||
| 	ext4_handle_error(sb); | 	ext4_handle_error(sb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void __ext4_error_inode(struct inode *inode, const char *function, | void __ext4_error_inode(struct inode *inode, const char *function, | ||||||
| 			unsigned int line, ext4_fsblk_t block, | 			unsigned int line, ext4_fsblk_t block, int error, | ||||||
| 			const char *fmt, ...) | 			const char *fmt, ...) | ||||||
| { | { | ||||||
| 	va_list args; | 	va_list args; | ||||||
| 	struct va_format vaf; | 	struct va_format vaf; | ||||||
| 	struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es; |  | ||||||
| 
 | 
 | ||||||
| 	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) | 	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	trace_ext4_error(inode->i_sb, function, line); | 	trace_ext4_error(inode->i_sb, function, line); | ||||||
| 	es->s_last_error_ino = cpu_to_le32(inode->i_ino); |  | ||||||
| 	es->s_last_error_block = cpu_to_le64(block); |  | ||||||
| 	if (ext4_error_ratelimit(inode->i_sb)) { | 	if (ext4_error_ratelimit(inode->i_sb)) { | ||||||
| 		va_start(args, fmt); | 		va_start(args, fmt); | ||||||
| 		vaf.fmt = fmt; | 		vaf.fmt = fmt; | ||||||
| @ -530,7 +585,8 @@ void __ext4_error_inode(struct inode *inode, const char *function, | |||||||
| 			       current->comm, &vaf); | 			       current->comm, &vaf); | ||||||
| 		va_end(args); | 		va_end(args); | ||||||
| 	} | 	} | ||||||
| 	save_error_info(inode->i_sb, function, line); | 	save_error_info(inode->i_sb, error, inode->i_ino, block, | ||||||
|  | 			function, line); | ||||||
| 	ext4_handle_error(inode->i_sb); | 	ext4_handle_error(inode->i_sb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -549,7 +605,6 @@ void __ext4_error_file(struct file *file, const char *function, | |||||||
| 
 | 
 | ||||||
| 	trace_ext4_error(inode->i_sb, function, line); | 	trace_ext4_error(inode->i_sb, function, line); | ||||||
| 	es = EXT4_SB(inode->i_sb)->s_es; | 	es = EXT4_SB(inode->i_sb)->s_es; | ||||||
| 	es->s_last_error_ino = cpu_to_le32(inode->i_ino); |  | ||||||
| 	if (ext4_error_ratelimit(inode->i_sb)) { | 	if (ext4_error_ratelimit(inode->i_sb)) { | ||||||
| 		path = file_path(file, pathname, sizeof(pathname)); | 		path = file_path(file, pathname, sizeof(pathname)); | ||||||
| 		if (IS_ERR(path)) | 		if (IS_ERR(path)) | ||||||
| @ -571,7 +626,8 @@ void __ext4_error_file(struct file *file, const char *function, | |||||||
| 			       current->comm, path, &vaf); | 			       current->comm, path, &vaf); | ||||||
| 		va_end(args); | 		va_end(args); | ||||||
| 	} | 	} | ||||||
| 	save_error_info(inode->i_sb, function, line); | 	save_error_info(inode->i_sb, EFSCORRUPTED, inode->i_ino, block, | ||||||
|  | 			function, line); | ||||||
| 	ext4_handle_error(inode->i_sb); | 	ext4_handle_error(inode->i_sb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -615,66 +671,6 @@ const char *ext4_decode_error(struct super_block *sb, int errno, | |||||||
| 	return errstr; | 	return errstr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ext4_set_errno(struct super_block *sb, int err) |  | ||||||
| { |  | ||||||
| 	if (err < 0) |  | ||||||
| 		err = -err; |  | ||||||
| 
 |  | ||||||
| 	switch (err) { |  | ||||||
| 	case EIO: |  | ||||||
| 		err = EXT4_ERR_EIO; |  | ||||||
| 		break; |  | ||||||
| 	case ENOMEM: |  | ||||||
| 		err = EXT4_ERR_ENOMEM; |  | ||||||
| 		break; |  | ||||||
| 	case EFSBADCRC: |  | ||||||
| 		err = EXT4_ERR_EFSBADCRC; |  | ||||||
| 		break; |  | ||||||
| 	case EFSCORRUPTED: |  | ||||||
| 		err = EXT4_ERR_EFSCORRUPTED; |  | ||||||
| 		break; |  | ||||||
| 	case ENOSPC: |  | ||||||
| 		err = EXT4_ERR_ENOSPC; |  | ||||||
| 		break; |  | ||||||
| 	case ENOKEY: |  | ||||||
| 		err = EXT4_ERR_ENOKEY; |  | ||||||
| 		break; |  | ||||||
| 	case EROFS: |  | ||||||
| 		err = EXT4_ERR_EROFS; |  | ||||||
| 		break; |  | ||||||
| 	case EFBIG: |  | ||||||
| 		err = EXT4_ERR_EFBIG; |  | ||||||
| 		break; |  | ||||||
| 	case EEXIST: |  | ||||||
| 		err = EXT4_ERR_EEXIST; |  | ||||||
| 		break; |  | ||||||
| 	case ERANGE: |  | ||||||
| 		err = EXT4_ERR_ERANGE; |  | ||||||
| 		break; |  | ||||||
| 	case EOVERFLOW: |  | ||||||
| 		err = EXT4_ERR_EOVERFLOW; |  | ||||||
| 		break; |  | ||||||
| 	case EBUSY: |  | ||||||
| 		err = EXT4_ERR_EBUSY; |  | ||||||
| 		break; |  | ||||||
| 	case ENOTDIR: |  | ||||||
| 		err = EXT4_ERR_ENOTDIR; |  | ||||||
| 		break; |  | ||||||
| 	case ENOTEMPTY: |  | ||||||
| 		err = EXT4_ERR_ENOTEMPTY; |  | ||||||
| 		break; |  | ||||||
| 	case ESHUTDOWN: |  | ||||||
| 		err = EXT4_ERR_ESHUTDOWN; |  | ||||||
| 		break; |  | ||||||
| 	case EFAULT: |  | ||||||
| 		err = EXT4_ERR_EFAULT; |  | ||||||
| 		break; |  | ||||||
| 	default: |  | ||||||
| 		err = EXT4_ERR_UNKNOWN; |  | ||||||
| 	} |  | ||||||
| 	EXT4_SB(sb)->s_es->s_last_error_errcode = err; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* __ext4_std_error decodes expected errors from journaling functions
 | /* __ext4_std_error decodes expected errors from journaling functions
 | ||||||
|  * automatically and invokes the appropriate error response.  */ |  * automatically and invokes the appropriate error response.  */ | ||||||
| 
 | 
 | ||||||
| @ -699,8 +695,7 @@ void __ext4_std_error(struct super_block *sb, const char *function, | |||||||
| 		       sb->s_id, function, line, errstr); | 		       sb->s_id, function, line, errstr); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ext4_set_errno(sb, -errno); | 	save_error_info(sb, -errno, 0, 0, function, line); | ||||||
| 	save_error_info(sb, function, line); |  | ||||||
| 	ext4_handle_error(sb); | 	ext4_handle_error(sb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -715,7 +710,7 @@ void __ext4_std_error(struct super_block *sb, const char *function, | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| void __ext4_abort(struct super_block *sb, const char *function, | void __ext4_abort(struct super_block *sb, const char *function, | ||||||
| 		unsigned int line, const char *fmt, ...) | 		  unsigned int line, int error, const char *fmt, ...) | ||||||
| { | { | ||||||
| 	struct va_format vaf; | 	struct va_format vaf; | ||||||
| 	va_list args; | 	va_list args; | ||||||
| @ -723,7 +718,7 @@ void __ext4_abort(struct super_block *sb, const char *function, | |||||||
| 	if (unlikely(ext4_forced_shutdown(EXT4_SB(sb)))) | 	if (unlikely(ext4_forced_shutdown(EXT4_SB(sb)))) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	save_error_info(sb, function, line); | 	save_error_info(sb, error, 0, 0, function, line); | ||||||
| 	va_start(args, fmt); | 	va_start(args, fmt); | ||||||
| 	vaf.fmt = fmt; | 	vaf.fmt = fmt; | ||||||
| 	vaf.va = &args; | 	vaf.va = &args; | ||||||
| @ -742,7 +737,6 @@ void __ext4_abort(struct super_block *sb, const char *function, | |||||||
| 		sb->s_flags |= SB_RDONLY; | 		sb->s_flags |= SB_RDONLY; | ||||||
| 		if (EXT4_SB(sb)->s_journal) | 		if (EXT4_SB(sb)->s_journal) | ||||||
| 			jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); | 			jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); | ||||||
| 		save_error_info(sb, function, line); |  | ||||||
| 	} | 	} | ||||||
| 	if (test_opt(sb, ERRORS_PANIC) && !system_going_down()) { | 	if (test_opt(sb, ERRORS_PANIC) && !system_going_down()) { | ||||||
| 		if (EXT4_SB(sb)->s_journal && | 		if (EXT4_SB(sb)->s_journal && | ||||||
| @ -816,15 +810,12 @@ __acquires(bitlock) | |||||||
| { | { | ||||||
| 	struct va_format vaf; | 	struct va_format vaf; | ||||||
| 	va_list args; | 	va_list args; | ||||||
| 	struct ext4_super_block *es = EXT4_SB(sb)->s_es; |  | ||||||
| 
 | 
 | ||||||
| 	if (unlikely(ext4_forced_shutdown(EXT4_SB(sb)))) | 	if (unlikely(ext4_forced_shutdown(EXT4_SB(sb)))) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	trace_ext4_error(sb, function, line); | 	trace_ext4_error(sb, function, line); | ||||||
| 	es->s_last_error_ino = cpu_to_le32(ino); | 	__save_error_info(sb, EFSCORRUPTED, ino, block, function, line); | ||||||
| 	es->s_last_error_block = cpu_to_le64(block); |  | ||||||
| 	__save_error_info(sb, function, line); |  | ||||||
| 
 | 
 | ||||||
| 	if (ext4_error_ratelimit(sb)) { | 	if (ext4_error_ratelimit(sb)) { | ||||||
| 		va_start(args, fmt); | 		va_start(args, fmt); | ||||||
| @ -1037,8 +1028,7 @@ static void ext4_put_super(struct super_block *sb) | |||||||
| 		err = jbd2_journal_destroy(sbi->s_journal); | 		err = jbd2_journal_destroy(sbi->s_journal); | ||||||
| 		sbi->s_journal = NULL; | 		sbi->s_journal = NULL; | ||||||
| 		if ((err < 0) && !aborted) { | 		if ((err < 0) && !aborted) { | ||||||
| 			ext4_set_errno(sb, -err); | 			ext4_abort(sb, -err, "Couldn't clean up the journal"); | ||||||
| 			ext4_abort(sb, "Couldn't clean up the journal"); |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -5452,7 +5442,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) | 	if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) | ||||||
| 		ext4_abort(sb, "Abort forced by user"); | 		ext4_abort(sb, EXT4_ERR_ESHUTDOWN, "Abort forced by user"); | ||||||
| 
 | 
 | ||||||
| 	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | | 	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | | ||||||
| 		(test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0); | 		(test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0); | ||||||
|  | |||||||
| @ -245,7 +245,7 @@ __ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh, | |||||||
| 					 bh->b_data); | 					 bh->b_data); | ||||||
| errout: | errout: | ||||||
| 	if (error) | 	if (error) | ||||||
| 		__ext4_error_inode(inode, function, line, 0, | 		__ext4_error_inode(inode, function, line, 0, -error, | ||||||
| 				   "corrupted xattr block %llu", | 				   "corrupted xattr block %llu", | ||||||
| 				   (unsigned long long) bh->b_blocknr); | 				   (unsigned long long) bh->b_blocknr); | ||||||
| 	else | 	else | ||||||
| @ -269,7 +269,7 @@ __xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header, | |||||||
| 	error = ext4_xattr_check_entries(IFIRST(header), end, IFIRST(header)); | 	error = ext4_xattr_check_entries(IFIRST(header), end, IFIRST(header)); | ||||||
| errout: | errout: | ||||||
| 	if (error) | 	if (error) | ||||||
| 		__ext4_error_inode(inode, function, line, 0, | 		__ext4_error_inode(inode, function, line, 0, -error, | ||||||
| 				   "corrupted in-inode xattr"); | 				   "corrupted in-inode xattr"); | ||||||
| 	return error; | 	return error; | ||||||
| } | } | ||||||
| @ -2880,9 +2880,9 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, | |||||||
| 		if (IS_ERR(bh)) { | 		if (IS_ERR(bh)) { | ||||||
| 			error = PTR_ERR(bh); | 			error = PTR_ERR(bh); | ||||||
| 			if (error == -EIO) { | 			if (error == -EIO) { | ||||||
| 				ext4_set_errno(inode->i_sb, EIO); | 				EXT4_ERROR_INODE_ERR(inode, EIO, | ||||||
| 				EXT4_ERROR_INODE(inode, "block %llu read error", | 						     "block %llu read error", | ||||||
| 						 EXT4_I(inode)->i_file_acl); | 						     EXT4_I(inode)->i_file_acl); | ||||||
| 			} | 			} | ||||||
| 			bh = NULL; | 			bh = NULL; | ||||||
| 			goto cleanup; | 			goto cleanup; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user