| // 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 |
| |
| #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 |
| |
| 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() */ |
| } |