| // SPDX-License-Identifier: GPL-2.0 | |
| #include "fs.h" | |
| #include "messages.h" | |
| #include "discard.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 + 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_LOG_REPLAY_ABORTED] = 'O', | |
| [BTRFS_FS_STATE_DEV_REPLACING] = 'R', | |
| [BTRFS_FS_STATE_DUMMY_FS_INFO] = 0, | |
| [BTRFS_FS_STATE_NO_DATA_CSUMS] = 'C', | |
| [BTRFS_FS_STATE_SKIP_META_CSUMS] = 'S', | |
| [BTRFS_FS_STATE_LOG_CLEANUP_ERROR] = 'L', | |
| [BTRFS_FS_STATE_EMERGENCY_SHUTDOWN] = 'E', | |
| }; | |
| 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 (unlikely(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) { | |
| 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, error, 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, error, errstr); | |
| } | |
| #endif | |
| /* | |
| * Today we only save the error info to memory. Long term we'll also | |
| * send it down to the disk. | |
| */ | |
| WRITE_ONCE(fs_info->fs_error, error); | |
| /* 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), | |
| }; | |
| __printf(3, 4) __cold | |
| void _btrfs_printk(const struct btrfs_fs_info *fs_info, unsigned int level, const char *fmt, ...) | |
| { | |
| struct va_format vaf; | |
| va_list args; | |
| const char *type = logtypes[level]; | |
| struct ratelimit_state *ratelimit = &printk_limits[level]; | |
| #ifdef CONFIG_PRINTK_INDEX | |
| printk_index_subsys_emit("%sBTRFS %s (device %s): ", NULL, fmt); | |
| #endif | |
| va_start(args, fmt); | |
| vaf.fmt = fmt; | |
| vaf.va = &args; | |
| /* Do not ratelimit if CONFIG_BTRFS_DEBUG is enabled. */ | |
| if (IS_ENABLED(CONFIG_BTRFS_DEBUG) || __ratelimit(ratelimit)) { | |
| if (fs_info) { | |
| char statestr[STATE_STRING_BUF_LEN]; | |
| btrfs_state_to_string(fs_info, statestr); | |
| _printk(KERN_SOH "%dBTRFS %s (device %s%s): %pV\n", level, type, | |
| fs_info->sb->s_id, statestr, &vaf); | |
| } else { | |
| _printk(KERN_SOH "%dBTRFS %s: %pV\n", level, type, &vaf); | |
| } | |
| } | |
| va_end(args); | |
| } | |
| #endif | |
| #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 | |
| /* | |
| * Decode unexpected, fatal errors from the caller, issue an alert, and either | |
| * panic or BUGs, depending on mount options. | |
| */ | |
| __cold | |
| void __btrfs_panic(const struct btrfs_fs_info *fs_info, const char *function, | |
| unsigned int line, int error, 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(error); | |
| 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, error, errstr); | |
| btrfs_crit(fs_info, "panic in %s:%d: %pV (errno=%d %s)", | |
| function, line, &vaf, error, errstr); | |
| va_end(args); | |
| /* Caller calls BUG() */ | |
| } |