Linux内核中常用的错误处理机制处理返回指针的函数其中指针值可能表示错误码先show一段代码iff --git a/drivers/opt_ide1/opt-ide1-dio.c b/drivers/opt_ide1/opt-ide1-dio.c index 0a8bddcc7f6b..709418a4f69a 100755 --- a/drivers/opt_ide1/opt-ide1-dio.c b/drivers/opt_ide1/opt-ide1-dio.c -261,8 261,7 static irqreturn_t HW_TRI_handler(int irq, void *dev_id) } input_sync(opt_ide1_do-di_inputdev); } - if (!IS_ERR(opt_ide1_do-gpio_out[OPT_TRIGGER_LED])) - gpio_set_value(opt_ide1_do-gpio_out[OPT_TRIGGER_LED], di0_state_tmp); gpio_set_value(opt_ide1_do-gpio_out[OPT_TRIGGER_LED], di0_state_tmp); spin_unlock(opt_ide1_do-spi_lock); return IRQ_HANDLED; -1030,16 1029,14 static int opt_ide1_do_probe(struct platform_device *pdev) for(i 0; i OPT_DO_MAX; i){ //printk([hezhensheng] %s OPT_DO_MAX %d, line %d \n, __FUNCTION__, OPT_DO_MAX, __LINE__); - if(!IS_ERR(opt_ide1_do.gpio_out[i])) - gpio_direction_output(opt_ide1_do.gpio_out[i], 0); gpio_direction_output(opt_ide1_do.gpio_out[i], 0); } gpio_set_value(opt_ide1_do.gpio_out[OPT_HARD_TRIGGER_EN], 0); opt_ide1_do.soft_trig_en 0; opt_ide1_do.external_light_source_mode 0; for(i 0; i OPT_DI_MAX; i){ - if(!IS_ERR(opt_ide1_do.gpio_in[i])) - gpio_direction_input(opt_ide1_do.gpio_in[i]); gpio_direction_input(opt_ide1_do.gpio_in[i]); }同事优化了IS_ERR()函数日常上这份驱动也都没反馈什么问题回来所以对此函数没还真放多少心思留意。先来了解一下基本都是搭配着PTR_ERR函数使用接着去kernel代码查阅一下是否一样,发现确实如此和PTR_ERR搭配着使用;在 Linux 内核编程中很多函数返回的是指针类型如struct file *,void *但失败时不能简单地返回NULL因为NULL可能也是一个合法的返回值例如表示“没有对象”。为了复用指针返回值来传递错误码内核提供了一套编码机制其中IS_ERR()和PTR_ERR()是最常用的辅助函数。 基本用法1. 错误码的编码与解码ERR_PTR(err)将错误码err负值转换为一个特殊的指针值通常是将错误码加上一个固定的偏移量。IS_ERR(ptr)判断一个指针是否代表了一个错误码即是否是通过ERR_PTR编码的。PTR_ERR(ptr)从错误指针中提取出原始的错误码负值。通常我们不需要手动调用ERR_PTR因为内核函数内部会使用它。我们作为调用者主要使用IS_ERR和PTR_ERR。2. 典型使用模式struct my_device *dev some_kernel_function(...); if (IS_ERR(dev)) { int err PTR_ERR(dev); pr_err(Failed to get device: %d\n, err); return err; // 或者进行其他错误处理 } // 正常使用 dev⚠️ 重要注意事项①必须先检查IS_ERR()再解引用或调用PTR_ERR()如果ptr不是错误指针即是一个有效的指针对其调用PTR_ERR会得到一个“伪造”的错误码这个值没有意义且可能引起误导。必须像上面示例那样先if (IS_ERR(ptr))在分支内再使用PTR_ERR。②区分NULL与错误指针NULL是一个有效的指针值表示空它不是错误指针IS_ERR(NULL)返回false。许多内核函数用NULL表示“没有对象”或“未找到”而用错误码表示“发生了严重错误”。因此检查时通常需要if (!ptr) {/* 表示没有对象不是错误 */} else if (IS_ERR(ptr)) {/* 表示真正的错误 */} else { /* 有效指针 */ }③错误码的取值范围有限内核规定错误码负值必须落在[-4095, -1]范围内MAX_ERRNO定义为 4095。所以ERR_PTR编码后的指针值总是落在(void *)(-4095 ... -1)这个特殊范围内。超出此范围的负值不会被识别为错误指针。④类型转换的困惑IS_ERR接受const void *任何指针类型都可以直接传入无需强制转换。PTR_ERR返回long类型通常需要转换为int来使用内核错误码都是int。如果需要将错误指针转换为另一种指针类型例如从void *转为struct foo *可以使用ERR_CAST(ptr)它只是做类型转换等价于(struct foo *)ptr但能更清晰地表达意图。⑤不要在中断上下文或原子上下文中长期持有错误指针错误指针本身只是一个数值但占用了一个指针槽位。虽然它不是一个真实的内存地址但在某些锁或引用计数场景下错误处理路径需要格外小心。 示例常见错误处理模式struct dentry *dentry lookup_one_len(name, parent, len); if (IS_ERR(dentry)) { /* 真正的错误比如 -ENOENT, -EACCES 等 */ return PTR_ERR(dentry); } if (!dentry) { /* 理论上 lookup_one_len 不会返回 NULL但某些函数会 */ return -ENOENT; } /* 正常使用 dentry */ 内核实现简析可选了解IS_ERR(ptr)实际上检查(unsigned long)ptr (unsigned long)-MAX_ERRNO即指针值是否落在内核保留的错误区间。PTR_ERR(ptr)直接返回(long)ptr因为错误指针的数值就是负错误码。 总结函数作用ERR_PTR(err)将错误码转为错误指针IS_ERR(ptr)判断指针是否为错误指针PTR_ERR(ptr)从错误指针中提取错误码记住两件事永远先IS_ERR后PTR_ERR。NULL不是错误指针需要单独处理。掌握这些规则就能正确、安全地处理内核中返回指针的接口避免因错误处理不当而导致的崩溃或逻辑混乱。转载一下:Linux系统调试深入解析IS_ERR函数的使用_dev is err-CSDN博客一、为什么需要IS_ERR在Linux内核开发中内核空间的函数如内存分配、设备驱动接口无法像用户空间那样直接返回-ENOMEM或-EINVAL等错误码因为它们的返回值 类 型通常是指针。为此内核采用了一种巧妙的方式将错误码编码到指针值中而IS_ERR()正是用来检测这种特殊指针的关键工具。二、IS_ERR的原理错误码的编码规则内核将错误码如-ENOMEM转换为指针的形式具体实现依赖于体系结构。例如在x86-64中错误码会被转换为(void *)(-4095UL ~ -1UL)区间的虚拟地址即最高有效位为1的地址。当指针值在 0xFFFFF000~0xFFFFFFFFFFFFFFFF范围时IS_ERR()返回true。核心函数解析 // 判断指针是否为错误码 bool IS_ERR(const void *ptr); // 从错误指针中提取原始错误码 long PTR_ERR(const void *ptr); // 将错误码转换为指针 void *ERR_PTR(long error);三、实际使用场景示例字符设备驱动中的内存分配static int mydev_open(struct inode *inode, struct file *filp) { struct my_device *dev kmalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; // 用户空间可以直接返回错误码 // 内核函数返回指针的错误处理 dev-regs ioremap(DEVICE_BASE, SIZE); if (IS_ERR(dev-regs)) { int err PTR_ERR(dev-regs); kfree(dev); return err; // 将错误传递到用户空间 } return 0; }四、常见错误及调试技巧典型错误案例void *ptr vmalloc(1024); if (IS_ERR(ptr)) { // 错误vmalloc失败时返回NULL而非错误指针 printk(Allocation failed: %ld\n, PTR_ERR(ptr)); return; }✅ 正确做法对可能返回错误指针的函数如devm_clk_get()使用IS_ERR对返回NULL的函数如kmalloc()直接判空。调试技巧打印错误码printk(Error code: %ld\n, PTR_ERR(ptr));使用dump_stack()定位调用路径
阅读完成 · 觉得有帮助?