Linux中IS_ERR()函数的理解

转载 2010年12月06日 20:24:00

转自http://jimmy-lee.blog.hexun.com/6075934_d.html

http://blog.chinaunix.net/u3/97568/showart_1978276.html两位的博客。谢两位分享。

在Linux源码中的fs部分,经常会碰到这样的函数(位于kernel/include/linux/fs.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.
 */
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 (unsigned long)ptr > (unsigned long)-1000L;
}

    下面是本人对于IS_ERR函数的理解,不完全是正确的,如果理解有错误,请告之我.

    在IS_ERR()函数中(unsigned long)-1000L实际上表示的是0xFFFFF000(因为负数在计算机中是原码的补码加一),在linux中虚拟内存空间的分配,0~3G是给用户空间的,而3G~4G是给linux内核的,而0xFFFFF000就位于linux内核的虚拟内存空间范围内,从0xFFFFF000到4G间的大小只有4KB,这实际上也就是一个PAGE_SIZE的大小,这时如果一个指针位于这块4KB的区域,则这个指针也就不可能是一个页面的首地址了,因为这已经不足以分配一个页面了。

    这内核虚拟空间的top 4KB一般是不作为分配空间来使用的。(我没有找到确切的证据是这样的,只是根据后面的分析觉得这块空间保留,其地址范围用来进行错误判断).

    如果传递给IS_ERR()函数的参数是一个页面的首地址指针,那么必然是一个错误指针。
    IS_ERR()也可以用来检测一个错误码,这就是与ERR_PTR()配合使用了,看下面一小段代码:(kernel/fs/namespace.c/sys_mount())

asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
                                               unsigned long flags, void * data)
{
    int retval;
    ....
    char *dir_page;
    ....

    dir_page = getname(dir_name);
     retval = PTR_ERR(dir_page);
     if (IS_ERR(dir_page))
          goto out1;

    ....
}

    getname()返回有可能是一个分配的页面的首地址,也有可能因为内存不足返回ERR_PTR(-ENOMEM);先看返回是页面首地址的情况,接着通过PTR_ERR()将这个指针类型的地址转化成为一个整型,再通过IS_ERR()来判断是否是一个有效的页面首地址,这跟前面分析的一样.
    再接下来看一下,如果返回的是错误码的情况,ENOMEM在kernel/include/asm-*/error.h中定义的值是12,经过ERR_PTR(-ENOMEM)返回则成了指针类型,指向0xFFFFFFF4,就指针而言它是指向虚拟内核空间的top4KB空间,再通过IS_ERR()判断返回的是false。

    在linux中我们看到错误码ERRCODE的值从1~??,这个??不太可能大于4KB的,所以通过ERR_PTR(-ERRCODE),则映射到了虚拟内核空间的top4KB(0xFFFFF000~4G)去了,再通过IS_ERR()即可检测出"is error"!

    综上述,IS_ERR()可以检测页面首地址是否有效,也可以检测出错误码.

 

IS_ERR()有一些妙处。
内核中的函数常常返回指针,问题是如果出错,也希望能够通过返回的指针体现出来。
所幸的是,内核返回的指针一般是指向页面的边界(4K边界),即

ptr & 0xfff == 0


这样ptr的值不可能落在(0xfffff000,0xffffffff)之间,
而一般内核的出错代码也是一个小负数,在-1000到0之间,转变成unsigned long,
正好在(0xfffff000,0xffffffff)之间。因此可以用

(unsigned long)ptr > (unsigned long)-1000L


来判断内核函数的返回值是一个有效的指针,还是一个出错代码。

涉及到的任何一个指针,必然有三种情况,一种是有效指针,一种是NULL,空指针,一种是错误指针,或者说无效指针.而所谓的错误指针就是指其已经到达了最后一个page.比如对于32bit的系统来说,内核空间最高地址0xffffffff,那么最后一个page就是指的 0xfffff000~0xffffffff(假设4k一个page).这段地址是被保留的,如果超过这个地址,则肯定是错误的。
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等等,可以看到,这个值实际上是在-1000~0之间的。

对于一个返回指针的函数,我们通常返回NULL表示失败,但是这不能指出那种失败(内存不足?硬件错误还是网络不可达?)
所以返回的时候用ERR_PTR(-ENOME) 等就可以判断,因为这个指针显然不合法
参考 include/iinux/err.h

IS_ERR()说明

感谢fudan_abc的分享,本篇文章选自他的《Linux那些事儿之我是Hub(3)一样的精灵不一样的API》              人的无聊,有时候很难用语言表达.以下关于IS_ERR的文...
  • eleven_yy
  • eleven_yy
  • 2011-09-14 17:28:08
  • 2970

解读PTR_ERR,ERR_PTR,IS_ERR

最近要找工作了,就把内核以及驱动的知识复习了一下。看到了几个宏PTR_ERR,ERR_PTR,IS_ERR(其实是内联函数).还是不太明白,然后就google搜索了一下,搜出来的结果真是不让人满意,看...
  • YAOZHENGUO2006
  • YAOZHENGUO2006
  • 2012-09-11 15:53:21
  • 8383

linux内核中的IS_ERR

linux内核中的IS_ERR()、PTR_ERR()和ERR_PTR()在看内核源码的时候,经常会遇到IS_ERR,比如在 linux/arch/arm/kernel/sys_arm.c中asmli...
  • ce123
  • ce123
  • 2013-01-02 13:14:44
  • 7749

linux内核中的IS_ERR()、PTR_ERR()、ERR_PTR()

linux内核中的IS_ERR()、PTR_ERR()、ERR_PTR() IS_ERR宏定义在include/linux/err.h,如下所示: #define MAX_...
  • ljk0922
  • ljk0922
  • 2015-08-23 21:47:04
  • 876

内核中判断返回指针是否错误的方法:使用IS_ERR或者IS_ERR_OR_NULL

内核中判断返回指针是否错误的方法:使用IS_ERR或者IS_ERR_OR_NULL。 参考include/linux/err.h #define MAX_ERRNO  4095   #ifnd...
  • adaptiver
  • adaptiver
  • 2013-03-11 17:39:49
  • 3915

IS_ERR

 像struct class *cls = class_create();这种语句,其中返回的指针值并不行kmalloc一样这么简单,只判断是否为NULL就可以了,内核是返回其错误值。那么我怎么来判断...
  • xxu0123456789
  • xxu0123456789
  • 2011-04-21 19:34:00
  • 5947

ERR_PTR,PTR_ERR还有IS_ERR函数详解

内核中的函数常常返回指针,问题是如果出错,也希望能够通过返回的指针体现出来。 总体来说,如果内核返回一个指针,那么有三种情况:合法指针,NULL指针和非法指针。 1)合法指针:内核返回的指针...
  • trochiluses
  • trochiluses
  • 2013-07-11 10:24:20
  • 2290

Linux中IS_ERR()函数的理解

转自http://jimmy-lee.blog.hexun.com/6075934_d.html和http://blog.chinaunix.net/u3/97568/showart_1978276....
  • ywf861029
  • ywf861029
  • 2010-12-06 20:24:00
  • 5753

五、1文件系统中的函数PTR_ERR IS_ERR ERR_PTR

最近在使用filp_open打开文件时遇到到一个问题,当打开一个并不存在的文件时,filp_open返回值值为0xfffffffe,而并不是0(NULL),这是因为内核对返回指针的函数做了特殊处理。内...
  • qq_20678703
  • qq_20678703
  • 2016-09-19 11:35:28
  • 144

内核空间 访问 用户空间 flip_open

内核空间 访问  用户空间 flip_open, 简单历程,可以作为调试手段。 本例程每隔一段时间往sdcard目录下的指定文件写入内容 #include #include #includ...
  • liujia2100
  • liujia2100
  • 2013-05-27 20:29:40
  • 3481
收藏助手
不良信息举报
您举报文章:Linux中IS_ERR()函数的理解
举报原因:
原因补充:

(最多只允许输入30个字)