// SPDX-License-Identifier: GPL-2.0 #include "kerncompat.h" #include #include #include "kernel-lib/bitops.h" #include "kernel-shared/ctree.h" #include "kernel-shared/messages.h" #ifdef CONFIG_PRINTK #define STATE_STRING_PREFACE ": state " #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_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; 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]) { *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 error) { char *errstr = "unknown"; switch (error) { 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; } /* * 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 error, 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 (error == -EROFS && sb_rdonly(sb)) return; #ifdef CONFIG_PRINTK errstr = btrfs_decode_error(error); btrfs_state_to_string(fs_info, statestr); if (fmt) { DECLARE_PV(vaf); va_list args; va_start(args, fmt); PV_ASSIGN(vaf, fmt, args); pr_crit("BTRFS: error (device %s%s) in %s:%d: error=%d %s (" PV_FMT ")\n", sb->s_id, statestr, function, line, error, errstr, PV_VAL(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, error, errstr); } #endif /* * We don't have fs_info::fs_state yet, and the rest of this is more * kernel related cleanup, so for now comment it out. */ #if 0 /* * 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); #endif 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"; DECLARE_PV(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; } PV_ASSIGN(vaf, fmt, 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_FMT "\n", lvl, type, fs_info->sb->s_id, statestr, PV_VAL(vaf)); } else { _printk("%sBTRFS %s: " PV_FMT "\n", lvl, type, PV_VAL(vaf)); } } va_end(args); } #endif #ifdef CONFIG_BTRFS_ASSERT void __cold btrfs_assertfail(const char *expr, const char *file, int line) { pr_err("assertion failed: %s, in %s:%d\n", expr, file, line); BUG(); } #endif #if BITS_PER_LONG == 32 && defined(__KERNEL__) 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. * * MODIFIED: * - We don't have btrfs_test_opt() yet, kill that and s_id. */ __cold void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function, unsigned int line, int error, const char *fmt, ...) { const char *errstr; DECLARE_PV(vaf); va_list args; #if 0 char *s_id = ""; if (fs_info) s_id = fs_info->sb->s_id; #endif va_start(args, fmt); PV_ASSIGN(vaf, fmt, args); errstr = btrfs_decode_error(error); #if 0 if (fs_info && (btrfs_test_opt(fs_info, PANIC_ON_FATAL_ERROR))) panic(KERN_CRIT "BTRFS panic (device %s) in %s:%d: " PV_FMT " (error=%d %s)\n", s_id, function, line, PV_VAL(vaf), error, errstr); #endif btrfs_crit(fs_info, "panic in %s:%d: " PV_FMT " (error=%d %s)", function, line, PV_VAL(vaf), error, errstr); va_end(args); /* Caller calls BUG() */ }