說明:
* linux kernel 裡系統函式的回傳值大都是指標, 其指標返回值會有兩種類型, 1.有效指標, 2.無效指標
* 使用 IS_ERR 來判斷是否有錯誤(無效指標), 有錯誤發生再用 PTR_ERR 把回傳指標轉為錯誤碼.
* linux kernel 利用指標能定址到的最後 4k 記憶體區塊當錯誤判斷, 因為最小的記憶體分頁為 4k.
所以最後一頁邊界等於 ptr_max_addr &= ~0xfff;
* 錯誤碼最大值將不能大於 4k(0xfff).
知道這些前提後, 看一下 include/linux/err.h 裡的宣告。(kernel version: 2.6.29/Android 2.1)
/* * Kernel pointers have redundant information, so we can use a * scheme where we can return either an error code or a dentry * pointer with the same return value. * * This should be a per-architecture thing, to allow different * error and pointer decisions. */ #define MAX_ERRNO 4095 #ifndef __ASSEMBLY__ #define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO) static inline void *ERR_PTR(long error) { return (void *) error; } static inline long PTR_ERR(const void *ptr) { return (long) ptr; } static inline long IS_ERR(const void *ptr) { return IS_ERR_VALUE((unsigned long)ptr); } /** * ERR_CAST - Explicitly cast an error-valued pointer to another pointer type * @ptr: The pointer to cast. * * Explicitly cast an error-valued pointer to another pointer type in such a * way as to make it clear that's what's going on. */ static inline void *ERR_CAST(const void *ptr) { /* cast away the const */ return (void *) ptr; }
可以看到 maximum error number = 4095 (== 0x0fff == 4K == size of minimum page block).
IS_ERR 先將指標先轉型為 unsigned long 然後呼叫 IS_ERR_VALUE, 將 IS_ERR_VALUE 內容展開為:
unlikely( (x) >= -4995 )
因為 -4995 轉換為 32 bit hex 為 0xfffff001, 所以是大於或等於 0xfffff001 即被視為錯誤碼.
ERR_PTR (error to pointer) 與 PTR_ERR (pointer to error) 這兩個都只有做轉型, PTR_ERR 比較常用, 一般用 IS_ERR 確定是錯誤值而不是指標後, 就可以用 PTR_ERR 來取得轉型後的錯誤數值, 範例如下:
dev = MKDEV(MISC_MAJOR, misc->minor); misc->class = class_device_create(misc_class, NULL, dev, misc->dev, "%s", misc->name); if (IS_ERR(misc->class)) { err = PTR_ERR(misc->class); goto out; }
至於錯誤編號的定義, 可以很容易猜出來在 asm/errno.h 裡面. 這部份雖然是依平台不同而定, 但是目前版本裡 (2.6.29) x86 與 arm 都是引入 include/asm-generic/errno.h. 然後再由這個檔案引入 include/asm-generic/errno-base.h, 其中 errno-base.h 包含了一些最基本的定義, 如常見的 -EIO, -EBUSY 等等共有 34 個如下:
#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 */
沒有留言:
張貼留言