Commit c067da87 authored by Sweet Tea Dorminy's avatar Sweet Tea Dorminy Committed by David Sterba
Browse files

btrfs: add filesystems state details to error messages



When a filesystem goes read-only due to an error, multiple errors tend
to be reported, some of which are knock-on failures. Logging fs_states,
in btrfs_handle_fs_error() and btrfs_printk() helps distinguish the
first error from subsequent messages which may only exist due to an
error state.

Under the new format, most initial errors will look like:
`BTRFS: error (device loop0) in ...`
while subsequent errors will begin with:
`error (device loop0: state E) in ...`

An initial transaction abort error will look like
`error (device loop0: state A) in ...`
and subsequent messages will contain
`(device loop0: state EA) in ...`

In addition to the error states we can also print other states that are
temporary, like remounting, device replace, or indicate a global state
that may affect functionality.

Now implemented:

E - filesystem error detected
A - transaction aborted
L - log tree errors

M - remounting in progress
R - device replace in progress
C - data checksums not verified (mounted with ignoredatacsums)

Signed-off-by: default avatarSweet Tea Dorminy <sweettea-kernel@dorminy.me>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent b2d9f2dc
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -149,6 +149,8 @@ enum {

	/* Indicates there was an error cleaning up a log tree. */
	BTRFS_FS_STATE_LOG_CLEANUP_ERROR,

	BTRFS_FS_STATE_COUNT
};

#define BTRFS_BACKREF_REV_MAX		256
+60 −8
Original line number Diff line number Diff line
@@ -66,6 +66,52 @@ static struct file_system_type btrfs_root_fs_type;

static int btrfs_remount(struct super_block *sb, int *flags, char *data);

#ifdef CONFIG_PRINTK

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

/*
 * Characters to print to indicate error conditions or uncommon filesystem sate.
 * 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',
	[BTRFS_FS_STATE_DEV_REPLACING]		= 'R',
	[BTRFS_FS_STATE_DUMMY_FS_INFO]		= 0,
	[BTRFS_FS_STATE_NO_CSUMS]		= 'C',
	[BTRFS_FS_STATE_LOG_CLEANUP_ERROR]	= 'L',
};

static void btrfs_state_to_string(const struct btrfs_fs_info *info, char *buf)
{
	unsigned int bit;
	bool states_printed = false;
	unsigned long fs_state = READ_ONCE(info->fs_state);
	char *curr = buf;

	memcpy(curr, STATE_STRING_PREFACE, sizeof(STATE_STRING_PREFACE));
	curr += sizeof(STATE_STRING_PREFACE) - 1;

	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]) {
			*curr++ = fs_state_chars[bit];
			states_printed = true;
		}
	}

	/* If no states were printed, reset the buffer */
	if (!states_printed)
		curr = buf;

	*curr++ = 0;
}
#endif

/*
 * Generally the error codes correspond to their respective errors, but there
 * are a few special cases.
@@ -128,6 +174,7 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function
{
	struct super_block *sb = fs_info->sb;
#ifdef CONFIG_PRINTK
	char statestr[STATE_STRING_BUF_LEN];
	const char *errstr;
#endif

@@ -140,6 +187,7 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function

#ifdef CONFIG_PRINTK
	errstr = btrfs_decode_error(errno);
	btrfs_state_to_string(fs_info, statestr);
	if (fmt) {
		struct va_format vaf;
		va_list args;
@@ -148,12 +196,12 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function
		vaf.fmt = fmt;
		vaf.va = &args;

		pr_crit("BTRFS: error (device %s) in %s:%d: errno=%d %s (%pV)\n",
			sb->s_id, function, line, errno, errstr, &vaf);
		pr_crit("BTRFS: error (device %s%s) in %s:%d: errno=%d %s (%pV)\n",
			sb->s_id, statestr, function, line, errno, errstr, &vaf);
		va_end(args);
	} else {
		pr_crit("BTRFS: error (device %s) in %s:%d: errno=%d %s\n",
			sb->s_id, function, line, errno, errstr);
		pr_crit("BTRFS: error (device %s%s) in %s:%d: errno=%d %s\n",
			sb->s_id, statestr, function, line, errno, errstr);
	}
#endif

@@ -240,12 +288,16 @@ void __cold btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, .
	vaf.va = &args;

	if (__ratelimit(ratelimit)) {
		if (fs_info)
			printk("%sBTRFS %s (device %s): %pV\n", lvl, type,
				fs_info->sb->s_id, &vaf);
		else
		if (fs_info) {
			char statestr[STATE_STRING_BUF_LEN];

			btrfs_state_to_string(fs_info, statestr);
			printk("%sBTRFS %s (device %s%s): %pV\n", lvl, type,
				fs_info->sb->s_id, statestr, &vaf);
		} else {
			printk("%sBTRFS %s: %pV\n", lvl, type, &vaf);
		}
	}

	va_end(args);
}