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

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
...@@ -149,6 +149,8 @@ enum { ...@@ -149,6 +149,8 @@ enum {
/* Indicates there was an error cleaning up a log tree. */ /* Indicates there was an error cleaning up a log tree. */
BTRFS_FS_STATE_LOG_CLEANUP_ERROR, BTRFS_FS_STATE_LOG_CLEANUP_ERROR,
BTRFS_FS_STATE_COUNT
}; };
#define BTRFS_BACKREF_REV_MAX 256 #define BTRFS_BACKREF_REV_MAX 256
......
...@@ -66,6 +66,52 @@ static struct file_system_type btrfs_root_fs_type; ...@@ -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); 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 * Generally the error codes correspond to their respective errors, but there
* are a few special cases. * are a few special cases.
...@@ -128,6 +174,7 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function ...@@ -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; struct super_block *sb = fs_info->sb;
#ifdef CONFIG_PRINTK #ifdef CONFIG_PRINTK
char statestr[STATE_STRING_BUF_LEN];
const char *errstr; const char *errstr;
#endif #endif
...@@ -140,6 +187,7 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function ...@@ -140,6 +187,7 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function
#ifdef CONFIG_PRINTK #ifdef CONFIG_PRINTK
errstr = btrfs_decode_error(errno); errstr = btrfs_decode_error(errno);
btrfs_state_to_string(fs_info, statestr);
if (fmt) { if (fmt) {
struct va_format vaf; struct va_format vaf;
va_list args; va_list args;
...@@ -148,12 +196,12 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function ...@@ -148,12 +196,12 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function
vaf.fmt = fmt; vaf.fmt = fmt;
vaf.va = &args; vaf.va = &args;
pr_crit("BTRFS: error (device %s) in %s:%d: errno=%d %s (%pV)\n", pr_crit("BTRFS: error (device %s%s) in %s:%d: errno=%d %s (%pV)\n",
sb->s_id, function, line, errno, errstr, &vaf); sb->s_id, statestr, function, line, errno, errstr, &vaf);
va_end(args); va_end(args);
} else { } else {
pr_crit("BTRFS: error (device %s) in %s:%d: errno=%d %s\n", pr_crit("BTRFS: error (device %s%s) in %s:%d: errno=%d %s\n",
sb->s_id, function, line, errno, errstr); sb->s_id, statestr, function, line, errno, errstr);
} }
#endif #endif
...@@ -240,11 +288,15 @@ void __cold btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, . ...@@ -240,11 +288,15 @@ void __cold btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, .
vaf.va = &args; vaf.va = &args;
if (__ratelimit(ratelimit)) { if (__ratelimit(ratelimit)) {
if (fs_info) if (fs_info) {
printk("%sBTRFS %s (device %s): %pV\n", lvl, type, char statestr[STATE_STRING_BUF_LEN];
fs_info->sb->s_id, &vaf);
else 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); printk("%sBTRFS %s: %pV\n", lvl, type, &vaf);
}
} }
va_end(args); va_end(args);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment