内核里常用宏BUG_ON/WARN_ON/WARN_ONCE

一、背景

内核代码里经常能看到一些用于检查一些条件的宏,如BUG_ON,WARN_ON等,这些宏除了直观的说明条件应该或者不应该被满足以外,还能方便我们进行规范的打印,让代码更加简洁,也同时满足的一些基本的要求,如在内核代码里进行打印时不建议直接使用printk,需要使用dev_printk或者至少得用pr_xx这样的打印宏。你若使用printk来进行打印输出的时候,如果用./scripts/checkpatch.pl来扫描你的改动的patch的话,如果发现是直接使用printk的话,checkpatch.pl的检查脚本会报出一个警告的。

这篇博客里,我们一次介绍一下这些基本的宏。

二、BUG/BUG_ON宏

我们搜索BUG_ON宏可以搜到,它是分为可以是ARCH代码来实现,也可以不用ARCH代码用公共的代码来实现:

如上图可以看到BUG_ON就是判断入参的条件,如果入参的条件是true,就调用BUG宏来触发panic。

CONFIG_BUG默认情况下就是打开的:

在没有定义arch的BUG_ON函数时,就用公共代码的BUG_ON实现。

可以看到是有有些arch下实现自己的BUG_ON的,搜索HAVE_ARCH_BUG_ON就可以搜到:

如mips平台的BUG_ON实现:

三、WARN_ON,WARN_ON_ONCE,WARN_ONCE宏

3.1 WARN_ON的实现

WARN_ON的下面的定义也是被包在一般都开的CONFIG_BUG宏里的:

常见的arm64平台和x86平台也都是用的上图里的定义。

我们进一步看__WARN宏的实现,__WARN宏根据有没有定义__WARN_FLAGS的情况,

来进行的定义:

而__WARN_FLAGS在x86和arm64平台都有相关定义:

我们追一下arm64平台的也就是上图里的__BUG_FLAGS是如何实现的,如上图看到__BUG_FLAGS使用了ASM_BUG_FLAGS,ASM_BUG_FLAGS定义如下:

可以看到上面图里红色框出的部分,也就是用了brk汇编指令,传入的是BUG_BRK_IMM,定义及如下:

3.2 WARN_ON_ONCE和WARN_ONCE的区别

WARN_ON_ONCE和WARN_ONCE在内核代码里大量使用,它们俩是有区别的,虽然区别并不复杂,但是却很有用,且容易被忽视。

WARN_ON_ONCE的定义如下:

它是无法输入自定义的字符串的。

而WARN_ONCE则不同,可以输入自定义的字符串:

这个区别很关键,有时候就需要定义自己的日志内容。

3.3 WARN_ONCE如何确保只打印一次

接着上面分析的WARN_ONCE宏来看一下WARN_ONCE宏所调用的DO_ONCE_LITE_IF宏是如何实现的:

如上图可以看到DO_ONCE_LITE_IF宏使用了__ONCE_LITE_IF宏来判断是否已经打印了一次。

而__ONCE_LITE_IF宏声明了一个static的bool类型的变量,这样就可以保留之前是否已经打印一次的状态了。

3.4 如何清楚打印了一次的标记

可以从上面 3.3 的分析里可以看到,在声明用于判断是否打印一次的变量时,用得是__section(".data.once")的段,这个为什么要用这个段呢,因为这个段可以让系统针对这些WARN_ONCE的标记的变量统一进行一些批处理。

下图里的clear_warn_once_set函数就是对该.data.once段的所有标记位进行清除:

而clear_warn_once_set被集成进clear_warn_once_fops后,

最后暴露出debugfs的用户态可以进行控制的节点:

有关的可以清楚WARN_ONCE标记的命令如下:

bash 复制代码
echo 1 > /sys/kernel/debug/clear_warn_once
相关推荐
志栋智能4 小时前
运维超自动化的版本控制与回滚机制
运维·自动化
中云DDoS CC防护蔡蔡4 小时前
DDOS和CC攻击谁更可怕
运维·服务器·经验分享·网络安全·ddos
Ruiery4 小时前
Linux 6.6内核内存管理深度解析(十六):mmap — 用户态“申请内存“的真相
linux·运维·服务器
ClickHouseDB4 小时前
ClickHouse Cloud 与 Snowflake 实时性价比对比:CostBench 测试中的 412 倍差距来
运维·数据库·系统架构
欧米欧5 小时前
Linux系统篇(七),环境变量的底层溯源,核心获取机制与安全应用
linux·运维·服务器
Ruiery5 小时前
Linux 6.6内核内存管理深度解析(十八):KASLR 内核地址空间随机化
linux·运维·服务器·安全
todoitbo5 小时前
群晖NAS部署JmalCloud:Docker安装、文件管理、博客与公网访问完整教程
运维·docker·容器
时间售卖铺5 小时前
触发器与函数实战:MySQL高效编程秘诀
运维·数据库·mysql·云原生
qetfw6 小时前
UOS MariaDB 数据库:安装、最小权限与备份验证
linux·数据库·mariadb·uos
前端精髓6 小时前
调用大模型API
运维·服务器·microsoft