前言
?? 本節來學習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宏