// 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_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' ,
};
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) {
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 ),
};
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;
/* 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("%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
#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() */
}
Messung V0.5 in Prozent C=93 H=99 G=95
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland