mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-14 15:54:15 +08:00
b831306b3b
Assertions reports are split into two parts, the exact file and location of the condition and then the stack trace printed from btrfs_assertfail(). This means all the stack traces report the same line and this is what's typically reported by various tools, making it harder to distinguish the reports. [403.2467] assertion failed: refcount_read(&block_group->refs) == 1, in fs/btrfs/block-group.c:4259 [403.2479] ------------[ cut here ]------------ [403.2484] kernel BUG at fs/btrfs/messages.c:259! [403.2488] invalid opcode: 0000 [#1] PREEMPT SMP KASAN [403.2493] CPU: 2 PID: 23202 Comm: umount Not tainted 6.2.0-rc4-default+ #67 [403.2499] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552-rebuilt.opensuse.org 04/01/2014 [403.2509] RIP: 0010:btrfs_assertfail+0x19/0x1b [btrfs] ... [403.2595] Call Trace: [403.2598] <TASK> [403.2601] btrfs_free_block_groups.cold+0x52/0xae [btrfs] [403.2608] close_ctree+0x6c2/0x761 [btrfs] [403.2613] ? __wait_for_common+0x2b8/0x360 [403.2618] ? btrfs_cleanup_one_transaction.cold+0x7a/0x7a [btrfs] [403.2626] ? mark_held_locks+0x6b/0x90 [403.2630] ? lockdep_hardirqs_on_prepare+0x13d/0x200 [403.2636] ? __call_rcu_common.constprop.0+0x1ea/0x3d0 [403.2642] ? trace_hardirqs_on+0x2d/0x110 [403.2646] ? __call_rcu_common.constprop.0+0x1ea/0x3d0 [403.2652] generic_shutdown_super+0xb0/0x1c0 [403.2657] kill_anon_super+0x1e/0x40 [403.2662] btrfs_kill_super+0x25/0x30 [btrfs] [403.2668] deactivate_locked_super+0x4c/0xc0 By making btrfs_assertfail a macro we'll get the same line number for the BUG output: [63.5736] assertion failed: 0, in fs/btrfs/super.c:1572 [63.5758] ------------[ cut here ]------------ [63.5782] kernel BUG at fs/btrfs/super.c:1572! [63.5807] invalid opcode: 0000 [#2] PREEMPT SMP KASAN [63.5831] CPU: 0 PID: 859 Comm: mount Tainted: G D 6.3.0-rc7-default+ #2062 [63.5868] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a-rebuilt.opensuse.org 04/01/2014 [63.5905] RIP: 0010:btrfs_mount+0x24/0x30 [btrfs] [63.5964] RSP: 0018:ffff88800e69fcd8 EFLAGS: 00010246 [63.5982] RAX: 000000000000002d RBX: ffff888008fc1400 RCX: 0000000000000000 [63.6004] RDX: 0000000000000000 RSI: ffffffffb90fd868 RDI: ffffffffbcc3ff20 [63.6026] RBP: ffffffffc081b200 R08: 0000000000000001 R09: ffff88800e69fa27 [63.6046] R10: ffffed1001cd3f44 R11: 0000000000000001 R12: ffff888005a3c370 [63.6062] R13: ffffffffc058e830 R14: 0000000000000000 R15: 00000000ffffffff [63.6081] FS: 00007f7b3561f800(0000) GS:ffff88806c600000(0000) knlGS:0000000000000000 [63.6105] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [63.6120] CR2: 00007fff83726e10 CR3: 0000000002a9e000 CR4: 00000000000006b0 [63.6137] Call Trace: [63.6143] <TASK> [63.6148] legacy_get_tree+0x80/0xd0 [63.6158] vfs_get_tree+0x43/0x120 [63.6166] do_new_mount+0x1f3/0x3d0 [63.6176] ? do_add_mount+0x140/0x140 [63.6187] ? cap_capable+0xa4/0xe0 [63.6197] path_mount+0x223/0xc10 This comes at a cost of bloating the final btrfs.ko module due all the inlining, as long as assertions are compiled in. This is a must for debugging builds but this is often enabled on release builds too. Release build: text data bss dec hex filename 1251676 20317 16088 1288081 13a791 pre/btrfs.ko 1260612 29473 16088 1306173 13ee3d post/btrfs.ko DELTA: +8936 CC: Josh Poimboeuf <jpoimboe@kernel.org> Signed-off-by: David Sterba <dsterba@suse.com>
316 lines
8.7 KiB
C
316 lines
8.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include "fs.h"
|
|
#include "messages.h"
|
|
#include "discard.h"
|
|
#include "transaction.h"
|
|
#include "space-info.h"
|
|
#include "super.h"
|
|
|
|
#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 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',
|
|
[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.
|
|
*
|
|
* EUCLEAN: Any sort of corruption that we encounter. The tree-checker for
|
|
* instance will return EUCLEAN if any of the blocks are corrupted in
|
|
* a way that is problematic. We want to reserve EUCLEAN for these
|
|
* sort of corruptions.
|
|
*
|
|
* EROFS: If we check BTRFS_FS_STATE_ERROR and fail out with a return error, we
|
|
* need to use EROFS for this case. We will have no idea of the
|
|
* original failure, that will have been reported at the time we tripped
|
|
* over the error. Each subsequent error that doesn't have any context
|
|
* of the original error should use EROFS when handling BTRFS_FS_STATE_ERROR.
|
|
*/
|
|
const char * __attribute_const__ btrfs_decode_error(int errno)
|
|
{
|
|
char *errstr = "unknown";
|
|
|
|
switch (errno) {
|
|
case -ENOENT: /* -2 */
|
|
errstr = "No such entry";
|
|
break;
|
|
case -EIO: /* -5 */
|
|
errstr = "IO failure";
|
|
break;
|
|
case -ENOMEM: /* -12*/
|
|
errstr = "Out of memory";
|
|
break;
|
|
case -EEXIST: /* -17 */
|
|
errstr = "Object already exists";
|
|
break;
|
|
case -ENOSPC: /* -28 */
|
|
errstr = "No space left";
|
|
break;
|
|
case -EROFS: /* -30 */
|
|
errstr = "Readonly filesystem";
|
|
break;
|
|
case -EOPNOTSUPP: /* -95 */
|
|
errstr = "Operation not supported";
|
|
break;
|
|
case -EUCLEAN: /* -117 */
|
|
errstr = "Filesystem corrupted";
|
|
break;
|
|
case -EDQUOT: /* -122 */
|
|
errstr = "Quota exceeded";
|
|
break;
|
|
}
|
|
|
|
return errstr;
|
|
}
|
|
|
|
/*
|
|
* __btrfs_handle_fs_error decodes expected errors from the caller and
|
|
* invokes the appropriate error response.
|
|
*/
|
|
__cold
|
|
void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function,
|
|
unsigned int line, int errno, const char *fmt, ...)
|
|
{
|
|
struct super_block *sb = fs_info->sb;
|
|
#ifdef CONFIG_PRINTK
|
|
char statestr[STATE_STRING_BUF_LEN];
|
|
const char *errstr;
|
|
#endif
|
|
|
|
#ifdef CONFIG_PRINTK_INDEX
|
|
printk_index_subsys_emit(
|
|
"BTRFS: error (device %s%s) in %s:%d: errno=%d %s", KERN_CRIT, fmt);
|
|
#endif
|
|
|
|
/*
|
|
* Special case: if the error is EROFS, and we're already under
|
|
* SB_RDONLY, then it is safe here.
|
|
*/
|
|
if (errno == -EROFS && sb_rdonly(sb))
|
|
return;
|
|
|
|
#ifdef CONFIG_PRINTK
|
|
errstr = btrfs_decode_error(errno);
|
|
btrfs_state_to_string(fs_info, statestr);
|
|
if (fmt) {
|
|
struct va_format vaf;
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
vaf.fmt = fmt;
|
|
vaf.va = &args;
|
|
|
|
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%s) in %s:%d: errno=%d %s\n",
|
|
sb->s_id, statestr, function, line, errno, errstr);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* 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);
|
|
|
|
/* Don't go through full error handling during mount. */
|
|
if (!(sb->s_flags & SB_BORN))
|
|
return;
|
|
|
|
if (sb_rdonly(sb))
|
|
return;
|
|
|
|
btrfs_discard_stop(fs_info);
|
|
|
|
/* Handle error by forcing the filesystem readonly. */
|
|
btrfs_set_sb_rdonly(sb);
|
|
btrfs_info(fs_info, "forced readonly");
|
|
/*
|
|
* Note that a running device replace operation is not canceled here
|
|
* although there is no way to update the progress. It would add the
|
|
* risk of a deadlock, therefore the canceling is omitted. The only
|
|
* penalty is that some I/O remains active until the procedure
|
|
* completes. The next time when the filesystem is mounted writable
|
|
* again, the device replace operation continues.
|
|
*/
|
|
}
|
|
|
|
#ifdef CONFIG_PRINTK
|
|
static const char * const logtypes[] = {
|
|
"emergency",
|
|
"alert",
|
|
"critical",
|
|
"error",
|
|
"warning",
|
|
"notice",
|
|
"info",
|
|
"debug",
|
|
};
|
|
|
|
/*
|
|
* Use one ratelimit state per log level so that a flood of less important
|
|
* messages doesn't cause more important ones to be dropped.
|
|
*/
|
|
static struct ratelimit_state printk_limits[] = {
|
|
RATELIMIT_STATE_INIT(printk_limits[0], DEFAULT_RATELIMIT_INTERVAL, 100),
|
|
RATELIMIT_STATE_INIT(printk_limits[1], DEFAULT_RATELIMIT_INTERVAL, 100),
|
|
RATELIMIT_STATE_INIT(printk_limits[2], DEFAULT_RATELIMIT_INTERVAL, 100),
|
|
RATELIMIT_STATE_INIT(printk_limits[3], DEFAULT_RATELIMIT_INTERVAL, 100),
|
|
RATELIMIT_STATE_INIT(printk_limits[4], DEFAULT_RATELIMIT_INTERVAL, 100),
|
|
RATELIMIT_STATE_INIT(printk_limits[5], DEFAULT_RATELIMIT_INTERVAL, 100),
|
|
RATELIMIT_STATE_INIT(printk_limits[6], DEFAULT_RATELIMIT_INTERVAL, 100),
|
|
RATELIMIT_STATE_INIT(printk_limits[7], DEFAULT_RATELIMIT_INTERVAL, 100),
|
|
};
|
|
|
|
void __cold _btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
|
|
{
|
|
char lvl[PRINTK_MAX_SINGLE_HEADER_LEN + 1] = "\0";
|
|
struct va_format vaf;
|
|
va_list args;
|
|
int kern_level;
|
|
const char *type = logtypes[4];
|
|
struct ratelimit_state *ratelimit = &printk_limits[4];
|
|
|
|
#ifdef CONFIG_PRINTK_INDEX
|
|
printk_index_subsys_emit("%sBTRFS %s (device %s): ", NULL, fmt);
|
|
#endif
|
|
|
|
va_start(args, fmt);
|
|
|
|
while ((kern_level = printk_get_level(fmt)) != 0) {
|
|
size_t size = printk_skip_level(fmt) - fmt;
|
|
|
|
if (kern_level >= '0' && kern_level <= '7') {
|
|
memcpy(lvl, fmt, size);
|
|
lvl[size] = '\0';
|
|
type = logtypes[kern_level - '0'];
|
|
ratelimit = &printk_limits[kern_level - '0'];
|
|
}
|
|
fmt += size;
|
|
}
|
|
|
|
vaf.fmt = fmt;
|
|
vaf.va = &args;
|
|
|
|
if (__ratelimit(ratelimit)) {
|
|
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);
|
|
}
|
|
#endif
|
|
|
|
void __cold btrfs_print_v0_err(struct btrfs_fs_info *fs_info)
|
|
{
|
|
btrfs_err(fs_info,
|
|
"Unsupported V0 extent filesystem detected. Aborting. Please re-create your filesystem with a newer kernel");
|
|
}
|
|
|
|
#if BITS_PER_LONG == 32
|
|
void __cold btrfs_warn_32bit_limit(struct btrfs_fs_info *fs_info)
|
|
{
|
|
if (!test_and_set_bit(BTRFS_FS_32BIT_WARN, &fs_info->flags)) {
|
|
btrfs_warn(fs_info, "reaching 32bit limit for logical addresses");
|
|
btrfs_warn(fs_info,
|
|
"due to page cache limit on 32bit systems, btrfs can't access metadata at or beyond %lluT",
|
|
BTRFS_32BIT_MAX_FILE_SIZE >> 40);
|
|
btrfs_warn(fs_info,
|
|
"please consider upgrading to 64bit kernel/hardware");
|
|
}
|
|
}
|
|
|
|
void __cold btrfs_err_32bit_limit(struct btrfs_fs_info *fs_info)
|
|
{
|
|
if (!test_and_set_bit(BTRFS_FS_32BIT_ERROR, &fs_info->flags)) {
|
|
btrfs_err(fs_info, "reached 32bit limit for logical addresses");
|
|
btrfs_err(fs_info,
|
|
"due to page cache limit on 32bit systems, metadata beyond %lluT can't be accessed",
|
|
BTRFS_32BIT_MAX_FILE_SIZE >> 40);
|
|
btrfs_err(fs_info,
|
|
"please consider upgrading to 64bit kernel/hardware");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* __btrfs_panic decodes unexpected, fatal errors from the caller, issues an
|
|
* alert, and either panics or BUGs, depending on mount options.
|
|
*/
|
|
__cold
|
|
void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,
|
|
unsigned int line, int errno, const char *fmt, ...)
|
|
{
|
|
char *s_id = "<unknown>";
|
|
const char *errstr;
|
|
struct va_format vaf = { .fmt = fmt };
|
|
va_list args;
|
|
|
|
if (fs_info)
|
|
s_id = fs_info->sb->s_id;
|
|
|
|
va_start(args, fmt);
|
|
vaf.va = &args;
|
|
|
|
errstr = btrfs_decode_error(errno);
|
|
if (fs_info && (btrfs_test_opt(fs_info, PANIC_ON_FATAL_ERROR)))
|
|
panic(KERN_CRIT "BTRFS panic (device %s) in %s:%d: %pV (errno=%d %s)\n",
|
|
s_id, function, line, &vaf, errno, errstr);
|
|
|
|
btrfs_crit(fs_info, "panic in %s:%d: %pV (errno=%d %s)",
|
|
function, line, &vaf, errno, errstr);
|
|
va_end(args);
|
|
/* Caller calls BUG() */
|
|
}
|