IS_ERR()、PTR_ERR() and ERR_PTR() in Linux Kernel

4311 ワード

カーネル内の関数はポインタを返すことが多く、通常呼び出しエラーが発生するとNULL空のポインタが返されますが、linuxはより優れた処理を行い、返されたポインタで表現することができます.
 
いずれのポインタに対しても、有効なポインタ、NULL、空のポインタ、エラーポインタ、または無効なポインタの3つのケースがあります.エラーポインタとは、32 bitのシステムにとってカーネル空間最高アドレス0 xffffffffが最後のpageに達したことを意味し、最後のpageは0 xfffff 000~0 xffffff(4 Kサイズページを例に)を意味する.このアドレスは保持されていますが、このアドレスを超えると間違いに違いありません.
include/linux/err.hにはこのメカニズムの処理が含まれており,主にIS_を介している.ERR, PTR_ERR, ERR_PTRのいくつかのマクロ.
/*

 * 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

 

#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)

 

/*          ,      -1000~0 ,              */

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);

}

したがって、カーネルに返されるポインタについて、エラーをチェックする方法はif(!retptr)ではなくif(IS_ERR(retptr)または
If( IS_ERR_VALUE(retptr) ).
カーネル内の関数はしばしばポインタを返しますが、問題はエラーが発生した場合でも、返されたポインタで表現したいということです.全体的に、カーネルがポインタを返すと、合法的なポインタ、NULLポインタ、不正なポインタの3つのケースがあります.
1)合法的なポインタ:カーネルが返すポインタは一般的にページの境界(4 K境界)、すなわちptr&0 xfff==0を指す
2)不正ポインタ:ptrの値は(0 xfffff 000,0 xffffffff)の間に落ちることは不可能であり(この区間はカーネルのハイエンドメモリが存在する区間である)、一般的なカーネルのエラーコードも小さな負数であり、-1000から0の間にunsigned longに変換され、ちょうど(0 xfffff 000,0 xffffffff)の間にある.だから使える
(unsigned long)ptr > (unsigned long)-1000L
-1000 L=0 xfffff 000 3)不正なポインタを使用して、エラーの分類を行います.
カーネル関数の戻り値が有効なポインタなのか、エラーコードなのかを判断します. 
    MAX_ERRNOは?4095、MAX_と定義されたマクロERRNOは最大のエラー番号であり、Linuxカーネルでは、エラーが多くの可能性がある.
Linuxカーネルのエラーについてはinclude/asm-generic/errno-baseを見てみましょう.hファイル:
 #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 */

最もよく見られるのは-EBUSY,-EINVAL,-ENODEV,-EPIPE,-EAGAIN,-ENOMEMです.Linuxを使ったことがある限り、これらの間違いを見たことがあります.それは確かによくあるからです.これらは各アーキテクチャにあるものであり、また各アーキテクチャも独自のエラーコードを定義している.これらのものはもちろんマクロで、実際にはいくつかの数字に対応しています.この数字はエラー番号と呼ばれています.Linuxカーネルにとって、どのアーキテクチャにおいても、最も多く、エラー番号は4095を超えない.4095はちょうど4 kより1小さい、すなわち4096が1.一つのpageは4 kかもしれないし、もっと多いかもしれないことを知っています.例えば8 kですが、少なくともそれは4 kなので、pageを残しておくと、カーネル空間のポインタを記録することができます.どういう意味ですか.例えばここのIS_ERR()は、kthread_を判断するrun()が返すポインタが間違っているかどうか、ポインタが最後のpageを指していない場合は問題なく、申請に成功し、ポインタが最後のpageを指している場合は、実際には有効なポインタではないことを示し、このポインタに保存されているのは実際にはエラーコードである.一般的によく使われる方法はISを先に使うことですERR()は、エラーであるか否かを判断し、そうであればPTR_を呼び出すERR()はこのエラーコードを返す.ただPTRは呼び出されていませんERR()ですが、決定的な役割を果たしているのはISですから.ERR()、PTR_ERR()はエラーコードを返すだけです.つまり、呼び出し者に情報を提供します.エラーが発生しているかどうかを知るだけで、何のためにエラーが発生しているのか気にしないでください.PTRを呼び出す必要はありません.ERR()です