linux核心中的IS_ERR

來源:互聯網
上載者:User

linux核心中的IS_ERR linux核心中的IS_ERR()、PTR_ERR()和ERR_PTR()在看核心源碼的時候,經常會遇到IS_ERR,比如在 linux/arch/arm/kernel/sys_arm.c中[plain]   www.2cto.com  asmlinkage int sys_execve(char __user *filenamei, char __user * __user *argv,                char __user * __user *envp, struct pt_regs *regs)  {      int error;      char * filename;          filename = getname(filenamei);      error = PTR_ERR(filename);      if (IS_ERR(filename))          goto out;      error = do_execve(filename, argv, envp, regs);      putname(filename);  out:      return error;  }  IS_ERR宏定義在include/linux/err.h,如下所示:  www.2cto.com  [plain] #ifndef _LINUX_ERR_H  #define _LINUX_ERR_H    #include <linux/compiler.h>    #include <asm/errno.h>    /*   * 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 IS_ERR_VALUE(x) unlikely((x) > (unsigned long)-1000L)    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);  }    #endif /* _LINUX_ERR_H */  下面我們就來具體分析一下這段代碼,看看核心中的巧妙設計思路。要想明白IS_ERR(),首先理解要核心空間。所有的驅動程式都是運行在核心空間,核心空間雖然很大,但總是有限的,而在這有限的空間中,其最後一個page是專門保留的,也就是說一般人不可能用到核心空間最後一個page的指標。換句話說,你在寫裝置驅動程式的過程中,涉及到的任何一個指標,必然有三種情況:有效指標;NULL,null 指標;錯誤指標,或者說無效指標。而所謂的錯誤指標就是指其已經到達了最後一個page,即核心用最後一頁捕捉錯誤。比如對於32bit的系統來說,核心空間最高地址0xffffffff,那麼最後一個page就是指的0xfffff000~0xffffffff(假設4k一個page),這段地址是被保留的。核心空間為什麼留出最後一個page?我們知道一個page可能是4k,也可能是更多,比如8k,但至少它也是4k,所以留出一個page出來就可以讓我們把核心空間的指標來記錄錯誤了。核心返回的指標一般是指向頁面的邊界(4k邊界),即ptr & 0xfff == 0。如果你發現你的一個指標指向這個範圍中的某個地址,那麼你的代碼肯定出錯了。IS_ERR()就是判斷指標是否有錯,如果指標並不是指向最後一個page,那麼沒有問題;如果指標指向了最後一個page,那麼說明實際上這不是一個有效指標,這個指標裡儲存的實際上是一種錯誤碼。而通常很常用的方法就是先用IS_ERR()來判斷是否是錯誤,然後如果是,那麼就調用PTR_ERR()來返回這個錯誤碼。因此,判斷一個指標是不是有效,可用如下的方式:#define IS_ERR_VALUE(x) unlikely((x) > (unsigned long)-1000L) (unsigned long)-1000L 應該為  (unsigned long)-0x1000L!(因為 -0x1000 才是 0xFFFFF000),這應該是核心的一個bug吧!在2.6.30.4的核心中是這樣定義的:[plain] #define MAX_ERRNO   4095  #define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)  即判斷是不是在(0xfffff000,0xffffffff)之間,因此,可以用IS_ERR()來判斷核心功能的傳回值是不是一個有效指標。注意這裡用unlikely()的用意!至於PTR_ERR(), ERR_PTR(),只是強制轉換以下而已。現在應該知道為什麼我寫返回錯誤碼的時候也加個負號如 -ENOSYS這樣子了。而PTR_ERR()只是返回錯誤碼,也就是提供一個資訊給調用者,如果你只需要知道是否出錯,而不在乎因為什麼而出錯,那你當然不用調用PTR_ERR()了。而我們的錯誤碼的值在記憶體中定義都是這樣的(asm-generic/errno-base.h):[plain] ......  #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 */  ........  如果指標指向了最後一個page,那麼說明實際上這不是一個有效指標。這個指標裡儲存的實際上是一種錯誤碼。而通常很常用的方法就是先用IS_ERR()來判斷是否是錯誤,然後如果是,那麼就調用PTR_ERR()來返回這個錯誤碼。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.