forked from Minki/linux
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: Sweet Tea Dorminy <sweettea-kernel@dorminy.me> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
b2d9f2dc01
commit
c067da8781
@ -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
|
||||
|
@ -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,11 +288,15 @@ 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);
|
||||
|
Loading…
Reference in New Issue
Block a user