您的位置 首页 汽车

linux内核中的IS_ERR

在看内核源码的时候,经常会遇到IS_ERR,比如在linuxarcharmkernelsys_armc中[plain]viewplaincopyprint?asmlinkageintsys_execv

在看内核源码的时分,经常会遇到IS_ERR,比方在linux/arch/arm/kernel/sys_arm.c中

[plain]view plaincopy

print?

  1. asmlinkageintsys_execve(char__user*filenamei,char__user*__user*argv,
  2. char__user*__user*envp,structpt_regs*regs)
  3. {
  4. interror;
  5. char*filename;
  6. filename=getname(filenamei);
  7. error=PTR_ERR(filename);
  8. if(IS_ERR(filename))
  9. gotoout;
  10. error=do_execve(filename,argv,envp,regs);
  11. putname(filename);
  12. out:
  13. returnerror;
  14. }

IS_ERR宏界说在include/linux/err.h,如下所示:

[plain]view plaincopy

print?

  1. #ifndef_LINUX_ERR_H
  2. #define_LINUX_ERR_H
  3. #include
  4. #include
  5. /*
  6. *Kernelpointershaveredundantinformation,sowecanusea
  7. *schemewherewecanreturneitheranerrorcodeoradentry
  8. *pointerwiththesamereturnvalue.
  9. *
  10. *Thisshouldbeaper-architecturething,toallowdifferent
  11. *errorandpointerdecisions.
  12. */
  13. #defineIS_ERR_VALUE(x)unlikely((x)>(unsignedlong)-1000L)
  14. staticinlinevoid*ERR_PTR(longerror)
  15. {
  16. return(void*)error;
  17. }
  18. staticinlinelongPTR_ERR(constvoid*ptr)
  19. {
  20. return(long)ptr;
  21. }
  22. staticinlinelongIS_ERR(constvoid*ptr)
  23. {
  24. returnIS_ERR_VALUE((unsignedlong)ptr);
  25. }
  26. #endif/*_LINUX_ERR_H*/

下面咱们就来具体分析一下这段代码,看看内核中的奇妙规划思路。

要想了解IS_ERR(),首要了解要内核空间。一切的驱动程序都是运转在内核空间,内核空间尽管很大,但总是有限的,而在这有限的空间中,其最终一个page是专门保存的,也便是说一般人不可能用到内核空间最终一个page的指针。换句话说,你在写设备驱动程序的过程中,涉及到的任何一个指针,必定有三种状况:

  1. 有用指针;
  2. NULL,空指针;
  3. 过错指针,或者说无效指针。

而所谓的过错指针便是指其现已抵达了最终一个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]view plaincopy

print?

  1. #defineMAX_ERRNO4095
  2. #defineIS_ERR_VALUE(x)unlikely((x)>=(unsignedlong)-MAX_ERRNO)

即判别是不是在(0xfffff000,0xffffffff)之间,因而,可以用IS_ERR()来判别内核函数的回来值是不是一个有用的指针。留意这儿用unlikely()的意图!

至于PTR_ERR(), ERR_PTR(),仅仅强制转化以下罢了。现在应该知道为什么我写回来过错码的时分也加个负号如 -ENOSYS这姿态了。而PTR_ERR()仅仅回来过错代码,也便是供给一个信息给调用者,假如你只需要知道是否犯错,而不在乎由于什么而犯错,那你当然不必调用PTR_ERR()了。

而咱们的过错码的值在内存中界说都是这样的(asm-generic/errno-base.h):

[plain]view plaincopy

print?

  1. ……
  2. #defineEPERM1/*Operationnotpermitted*/
  3. #defineENOENT2/*Nosuchfileordirectory*/
  4. #defineESRCH3/*Nosuchprocess*/
  5. #defineEINTR4/*Interruptedsystemcall*/
  6. #defineEIO5/*I/Oerror*/
  7. #defineENXIO6/*Nosuchdeviceoraddress*/
  8. #defineE2BIG7/*Argumentlisttoolong*/
  9. #defineENOEXEC8/*Execformaterror*/
  10. #defineEBADF9/*Badfilenumber*/
  11. #defineECHILD10/*Nochildprocesses*/
  12. #defineEAGAIN11/*Tryagain*/
  13. #defineENOMEM12/*Outofmemory*/
  14. #defineEACCES13/*Permissiondenied*/
  15. #defineEFAULT14/*Badaddress*/
  16. #defineENOTBLK15/*Blockdevicerequired*/
  17. #defineEBUSY16/*Deviceorresourcebusy*/
  18. #defineEEXIST17/*Fileexists*/
  19. #defineEXDEV18/*Cross-devicelink*/
  20. #defineENODEV19/*Nosuchdevice*/
  21. #defineENOTDIR20/*Notadirectory*/
  22. #defineEISDIR21/*Isadirectory*/
  23. #defineEINVAL22/*Invalidargument*/
  24. #defineENFILE23/*Filetableoverflow*/
  25. #defineEMFILE24/*Toomanyopenfiles*/
  26. #defineENOTTY25/*Notatypewriter*/
  27. #defineETXTBSY26/*Textfilebusy*/
  28. #defineEFBIG27/*Filetoolarge*/
  29. #defineENOSPC28/*Nospaceleftondevice*/
  30. #defineESPIPE29/*Illegalseek*/
  31. #defineEROFS30/*Read-onlyfilesystem*/
  32. #defineEMLINK31/*Toomanylinks*/
  33. #defineEPIPE32/*Brokenpipe*/
  34. #defineEDOM33/*Mathargumentoutofdomainoffunc*/
  35. #defineERANGE34/*Mathresultnotrepresentable*/
  36. ……..

假如指针指向了最终一个page,那么阐明实际上这不是一个有用的指针。这个指针里保存的实际上是一种过错代码。而一般很常用的办法便是先用IS_ERR()来判别是否是过错,然后假如是,那么就调用PTR_ERR()来回来这个过错代码。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qiche/319602.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部