Commit ae3364e5 authored by Filipe Manana's avatar Filipe Manana Committed by David Sterba
Browse files

btrfs: store the error that turned the fs into error state



Currently when we turn the fs into an error state, typically after a
transaction abort, we don't store the error anywhere, we just set a bit
(BTRFS_FS_STATE_ERROR) at struct btrfs_fs_info::fs_state to signal the
error state.

There are cases where it would be useful to have access to the specific
error in order to provide a more meaningful error to users/applications.
This change adds a member to struct btrfs_fs_info to store the error and
removes the BTRFS_FS_STATE_ERROR bit. When there's no error, the new
member (fs_error) has a value of 0, otherwise its value is a negative
errno value.

Followup changes will make use of this new member.

Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 1b6948ac
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3222,7 +3222,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device

	/* check FS state, whether FS is broken. */
	if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_ERROR)
		set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state);
		WRITE_ONCE(fs_info->fs_error, -EUCLEAN);

	/*
	 * In the long term, we'll store the compression type in the super
+8 −4
Original line number Diff line number Diff line
@@ -46,8 +46,6 @@ static_assert(sizeof(struct btrfs_super_block) == BTRFS_SUPER_INFO_SIZE);
 * Runtime (in-memory) states of filesystem
 */
enum {
	/* Global indicator of serious filesystem errors */
	BTRFS_FS_STATE_ERROR,
	/*
	 * Filesystem is being remounted, allow to skip some operations, like
	 * defrag
@@ -686,6 +684,12 @@ struct btrfs_fs_info {
	bool qgroup_rescan_running;
	u8 qgroup_drop_subtree_thres;

	/*
	 * If this is not 0, then it indicates a serious filesystem error has
	 * happened and it contains that error (negative errno value).
	 */
	int fs_error;

	/* Filesystem state */
	unsigned long fs_state;

@@ -962,8 +966,8 @@ static inline void btrfs_wake_unfinished_drop(struct btrfs_fs_info *fs_info)
	clear_and_wake_up_bit(BTRFS_FS_UNFINISHED_DROPS, &fs_info->flags);
}

#define BTRFS_FS_ERROR(fs_info)	(unlikely(test_bit(BTRFS_FS_STATE_ERROR, \
						   &(fs_info)->fs_state)))
#define BTRFS_FS_ERROR(fs_info)	(READ_ONCE((fs_info)->fs_error))

#define BTRFS_FS_LOG_CLEANUP_ERROR(fs_info)				\
	(unlikely(test_bit(BTRFS_FS_STATE_LOG_CLEANUP_ERROR,		\
			   &(fs_info)->fs_state)))
+7 −3
Original line number Diff line number Diff line
@@ -10,14 +10,13 @@
#ifdef CONFIG_PRINTK

#define STATE_STRING_PREFACE	": state "
#define STATE_STRING_BUF_LEN	(sizeof(STATE_STRING_PREFACE) + BTRFS_FS_STATE_COUNT)
#define STATE_STRING_BUF_LEN	(sizeof(STATE_STRING_PREFACE) + BTRFS_FS_STATE_COUNT + 1)

/*
 * Characters to print to indicate error conditions or uncommon filesystem state.
 * RO is not an error.
 */
static const char fs_state_chars[] = {
	[BTRFS_FS_STATE_ERROR]			= 'E',
	[BTRFS_FS_STATE_REMOUNTING]		= 'M',
	[BTRFS_FS_STATE_RO]			= 0,
	[BTRFS_FS_STATE_TRANS_ABORTED]		= 'A',
@@ -37,6 +36,11 @@ static void btrfs_state_to_string(const struct btrfs_fs_info *info, char *buf)
	memcpy(curr, STATE_STRING_PREFACE, sizeof(STATE_STRING_PREFACE));
	curr += sizeof(STATE_STRING_PREFACE) - 1;

	if (BTRFS_FS_ERROR(info)) {
		*curr++ = 'E';
		states_printed = true;
	}

	for_each_set_bit(bit, &fs_state, sizeof(fs_state)) {
		WARN_ON_ONCE(bit >= BTRFS_FS_STATE_COUNT);
		if ((bit < BTRFS_FS_STATE_COUNT) && fs_state_chars[bit]) {
@@ -155,7 +159,7 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function
	 * Today we only save the error info to memory.  Long term we'll also
	 * send it down to the disk.
	 */
	set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state);
	WRITE_ONCE(fs_info->fs_error, errno);

	/* Don't go through full error handling during mount. */
	if (!(sb->s_flags & SB_BORN))