4.一樣的精靈,不一樣的API(2)

4.一樣的精靈,不一樣的API(2)

關於內核空間,我只想說,所有的驅動程序都是運行在內核空間的,內核空間雖然很大,但總是有限的。而在這有限的空間中,其最後一個page是專門保留的,也就是說,一般人不可能用到內核空間最後一個page的指針。

換句話說,你在寫設備驅動程序的過程中,涉及的任何一個指針,必然有三種情況:一種是有效指針,一種是NULL(空指針),還有一種是錯誤指針,或者說無效指針。而所謂的錯誤指針就是指其已經到達了最後一個page。比如對於32bit的系統來說,內核空間最高地址0xffffffff,那麼最後一個page就是指的0xfffff000~0xffffffff(假設4KB一個page)。這段地址是被保留的,一般人不得越雷池半步,如果你發現你的一個指針指向這個範圍中的某個地址,那麼恭喜你,你的代碼肯定出錯了。

那麼你是不是很好奇,好端端的內核空間幹嘛要留出最後一個page?這不是明明自己有1000塊錢,非得對自己說只能用900塊。實在不好意思,你說錯了,這裏不僅不是浪費一個page,反而是充分利用資源,把一個東西當兩個東西來用。

看見16行那個"MAX_ERRNO"了嗎?一個宏,定義爲4095,MAX_ERRNO就是最大錯誤號,Linux內核中,出錯有多種可能,因爲有許許多多種錯誤。關於Linux內核中的錯誤,我們看include/asm-generic/errno-base.h文件:

  1. #define EPERM            1      /* Operation not permitted */  
  2. #define ENOENT           2      /* No such file or directory */  
  3. #define ESRCH            3      /* No such process */  
  4. #define EINTR            4      /* Interrupted system call */  
  5. #define EIO              5      /* I/O error */  
  6. #define ENXIO            6      /* No such device or address */  
  7. #define E2BIG            7      /* Argument list too long */  
  8. #define ENOEXEC          8      /* Exec format error */  
  9. #define EBADF            9      /* Bad file number */  
  10. #define ECHILD          10      /* No child processes */  
  11. #define EAGAIN          11      /* Try again */  
  12. #define ENOMEM          12      /* Out of memory */  
  13. #define EACCES          13      /* Permission denied */  
  14. #define EFAULT          14      /* Bad address */  
  15. #define ENOTBLK         15      /* Block device required */  
  16. #define EBUSY           16      /* Device or resource busy */  
  17. #define EEXIST          17      /* File exists */  
  18. #define EXDEV           18      /* Cross-device link */  
  19. #define ENODEV          19      /* No such device */  
  20. #define ENOTDIR         20      /* Not a directory */  
  21. #define EISDIR          21      /* Is a directory */  
  22. #define EINVAL          22      /* Invalid argument */  
  23. #define ENFILE          23      /* File table overflow */  
  24. #define EMFILE          24      /* Too many open files */  
  25. #define ENOTTY          25      /* Not a typewriter */  
  26. #define ETXTBSY         26      /* Text file busy */  
  27. #define EFBIG           27      /* File too large */  
  28. #define ENOSPC          28      /* No space left on device */  
  29. #define ESPIPE          29      /* Illegal seek */  
  30. #define EROFS           30      /* Read-only file system */  
  31. #define EMLINK          31      /* Too many links */  
  32. #define EPIPE           32      /* Broken pipe */  
  33. #define EDOM            33      /* Math argument out of domain of func */  
  34. #define ERANGE          34      /* Math result not representable */  

最常見的幾個是-EBUSY、-EINVAL、-ENODEV、-EPIPE、-EAGAIN、-ENOMEM,我相信只要你使用過Linux就有可能見過這幾個錯誤,因爲它們確實經常出現。

這些是每個體系結構中都有的,另外各個體系結構也都定義了自己的一些錯誤代碼。這些東西當然也都是宏,實際上對應的是一些數字,這些數字就叫做錯誤號。而對於Linux內核來說,不管任何體系結構,錯誤號最多不會超過4095,而4095又正好是比4KB小1,即4096-1。而我們知道一個page可能是4KB,也可能是更多,比如8KB,但至少它也是4KB,所以留出一個page出來就可以讓我們把內核空間的指針來記錄錯誤了。

什麼意思呢?比如我們這裏的IS_ERR(),它就是判斷kthread_run()返回的指針是否有錯,如果指針並不是指向最後一個page,那麼沒有問題,申請成功了,如果指針指向了最後一個page,那麼說明實際上這不是一個有效的指針,這個指針裏保存的實際上是一種錯誤代碼。而通常很常用的方法就是先用IS_ERR()來判斷是否是錯誤,然後如果是,那麼就調用PTR_ERR()來返回這個錯誤代碼。只不過這裏沒有調用PTR_ERR()而已,因爲起決定作用的還是IS_ERR(),而PTR_ERR()只是返回錯誤代碼,也就是提供一個信息給調用者,如果你只需要知道是否出錯,而不在乎因爲什麼而出錯,那你當然不用調用PTR_ERR()了。當然,這裏如果出錯了的話,最終usb_deregister()會被調用,並且usb_hub_init()會返回-1。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章