前言
本节来学习Linux错误码,因为内核中的函数常常返回指针,如果出错,也希望能够通过返回的指针体现出来。
嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程,未来预计四个月将高强度更新本专栏,喜欢的可以关注本博主并订阅本专栏,一起讨论一起学习。现在关注就是老粉啦!
行文目录
- 前言
- 内核返回的指针
- IS_ERR()
- IS_ERR_OR_NULL()
- PTR_ERR()
- ERR_PTR()
- 使用案例
- 附录:Linux错误码大全
- 参考资料
内核返回的指针
在介绍之前,我们需要理解一下内核空间最大的错误码。对于一个64位的系统而言,内核空间占用(0x0000000000000000 ~ 0xffffffffffffffff)的虚拟地址。其中Linux采用分页机制管理内存,而CPU访问的是线性地址需要通过页表转化成物理地址。所以内核就约定留出最后一页4k(fffffffffffff000 ~ 0xffffffffffffffff)用来记录内核空间的错误指针。
因此所谓的错误指针已经指向了内核空间的最后一页
指针一般有三种:合法指针、错误指针、NULL指针。
合法指针:内核返回的指针一般是指向页面的边界,即ptr & 0xfff == 0
非法指针:不指向任何有效内存地址
错误指针:错误指针是指指向无效、未定义或未分配内存的指针
IS_ERR()
将传入的值与(unsigned long)-MAX_ERRNO
的值进行比较,在Linux中,定义了MAX_ERRNO
的定义为4095,其含义就是最大错误号。
-4096的二进制是补码,其值为0xfffff001,即大于等于0xfffff001的指针为非法指针。而这一部分正好是Linux内核的最后一页,存储的错误码,对应的值就是错误类型。
IS_ERR()
的结果:
有效指针、空指针返回false
错误指针返回true
IS_ERR_OR_NULL()
和IS_ERR()的区别在于其NULL也返回true
有效指针返回false
错误指针、空指针返回true
PTR_ERR()
将传入的void *类型指针强转为long类型,并返回。用于将错误指针转为long类型值,从而返回出错误类型
ERR_PTR()
将传入的long类型强转为void *类型指针,并返回
使用案例
imx6uirq.class = class_create(THIS_MODULE, IMX6UIRQ_NAME);
if (IS_ERR(imx6uirq.class)) {return PTR_ERR(imx6uirq.class);
}imx6uirq.device = device_create(imx6uirq.class, NULL, imx6uirq.devid, NULL, IMX6UIRQ_NAME);
if (IS_ERR(imx6uirq.device)) {return PTR_ERR(imx6uirq.device);
}
现在我们利用class_create()函数和device_create()函数创建了相应的设备节点,返回的是一个指针,我们需要对指针的合法性进行判断,因此就会使用IS_ERR()函数判断,如果是无效的就会调用PTR_ERR()函数将错误码返回。
附录:Linux错误码大全
注意: 返回错误码的时候一般加个负号,如-EIO
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
参考资料
[1] ERR_PTR,PTR_ERR还有IS_ERR函数详解
[2] 如何理解Linux内核IS_ERR、ERR_PTR、PTR_ERR
[3] linux内核中的IS_ERR()、PTR_ERR()、ERR_PTR()
[4] 内核IS_ERR、PTR_ERR、ERR_PTR宏