在Linux驱动程序中,正确的错误处理对于系统的稳定性和可靠性至关重要。以下是Linux驱动程序中错误处理的主要方法和最佳实践:
Linux内核使用负的错误码来表示错误:
#include <linux/errno.h>
int example_function(void)
{
if (error_condition) {
return -EINVAL; // 无效参数
}
return 0; // 成功
}
常用错误码:
- -EINVAL
- 无效参数
- -ENOMEM
- 内存不足
- -ENODEV
- 设备不存在
- -EIO
- I/O错误
- -EBUSY
- 设备或资源忙
对于返回指针的函数,使用ERR_PTR()和IS_ERR():
struct device *init_device(void)
{
if (error_condition) {
return ERR_PTR(-ENODEV);
}
return &my_device;
}
// 调用处
struct device *dev = init_device();
if (IS_ERR(dev)) {
int err = PTR_ERR(dev);
printk(KERN_ERR "Failed to init device: %d\n", err);
return err;
}
int probe(struct platform_device *pdev)
{
struct my_device *dev;
int ret;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
dev->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dev->regs))
return PTR_ERR(dev->regs);
dev->irq = platform_get_irq(pdev, 0);
if (dev->irq < 0)
return dev->irq;
ret = devm_request_irq(&pdev->dev, dev->irq, my_interrupt,
IRQF_SHARED, dev_name(&pdev->dev), dev);
if (ret)
return ret;
// ... 其他初始化代码
return 0;
}
对于复杂的错误处理,可以使用goto:
int complex_init(void)
{
int ret;
void *resource1 = NULL;
void *resource2 = NULL;
resource1 = allocate_resource1();
if (!resource1) {
ret = -ENOMEM;
goto err_alloc1;
}
resource2 = allocate_resource2();
if (!resource2) {
ret = -ENOMEM;
goto err_alloc2;
}
// 初始化成功
return 0;
err_alloc2:
release_resource1(resource1);
err_alloc1:
return ret;
}
使用printk记录错误信息:
printk(KERN_ERR "Driver error: operation failed with code %d\n", error_code);
不同日志级别:
- KERN_EMERG
- 紧急情况
- KERN_ALERT
- 需要立即行动
- KERN_CRIT
- 关键条件
- KERN_ERR
- 错误条件
- KERN_WARNING
- 警告条件
- KERN_NOTICE
- 正常但重要的情况
- KERN_INFO
- 信息性消息
- KERN_DEBUG
- 调试级消息
通过ioctl或read/write等接口向用户空间报告错误:
ssize_t my_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
if (error_condition) {
return -EFAULT; // 会转换为用户空间的errno
}
// ...
}
对于严重错误,可以触发oops或panic:
if (critical_error) {
BUG(); // 触发oops
// 或
panic("Critical driver failure"); // 使系统崩溃
}
WARN_ON(condition); // 如果condition为真,打印警告栈跟踪但继续执行
WARN_ON_ONCE(condition); // 只警告一次
通过遵循这些错误处理原则,可以编写出更健壮、更可靠的Linux设备驱动程序。