Chinaunix首页 | 论坛 | 博客
  • 博客访问: 408763
  • 博文数量: 48
  • 博客积分: 764
  • 博客等级: 上士
  • 技术积分: 1133
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-17 13:29
文章分类

全部博文(48)

文章存档

2014年(5)

2013年(34)

2012年(9)

分类: LINUX

2013-06-30 21:28:56

今天看kernel janitor的补丁时发现了一句代码:

点击(此处)折叠或打开

  1. +    if (!arr->record || !arr->subtree) {
  2.          kfree(arr->record);
  3.          kfree(arr->subtree);
  4.          kfree(arr);
  5.          return ERR_PTR(-ENOMEM);
  6.      }
其他,都不重要,唯独ERR_PTR这句,以前看过,可理解不深(压根就没理解过。),丈二和尚了。
说道底,原理非常简单,就是物尽其用,这是内核的一贯特色。
我们知道内存相关的函数如kmalloc的返回值一般是一个4k对齐的虚拟地址,也有可能是Null。
以32位系统为例,我们知道存储地址值变量类型是unsigned无符号的。
那么这个物尽其用,体现在哪里呢?
地址都是4k对齐那么0XFFFFF000 ~0XFFFFFFFF这4k个地址就没人用了。
当然所有不被4k整除的地址都用不到,而内核就选择了这最后一个page的地址了。
内核用的就是这个范围内的数字。在error_base.h你会看到定义的各种错误量。
把这些错误量前面加个-负号,他们的补码形式正好落在这4k范围内。这就用上了,和原来表示地址也不会冲突。
有了这些值我们就知道具体是什么错误了,比简单返回一个NULL强百倍。

点击(此处)折叠或打开

  1. 20 #define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
  2.  21
  3.  22 static inline void *ERR_PTR(long error)
  4.  23 {
  5.  24 return (void *) error;
  6.  25 }
  7.  26
  8.  27 static inline long PTR_ERR(const void *ptr)
  9.  28 {
  10.  29 return (long) ptr;
  11.  30 }
  12.  31
  13.  32 static inline long IS_ERR(const void *ptr)
  14.  33 {
  15.  34 return IS_ERR_VALUE((unsigned long)ptr);
  16.  35 }
ERR_PTR,PTR_ERR都很简单。解释下IS_ERR:
MAX_ERRNO值是4095对应的负数值-4095,也就是0XFFFFF001.
EPERM值是1对应负数的补码值就是:0XFFFFFFFF.
以此类推,所有err值都大于-4095。就能区分错误码和4k对齐的虚拟地址了,因为内存管理函数返回的虚拟地址的值永不会大于-4095。

阅读(6911) | 评论(2) | 转发(2) |
给主人留下些什么吧!~~

firocu2017-05-01 17:00:40

zpcllinux:\"EPERM值是1对应负数的补码值就是:0XFFFFFFF1\"
EPERM值是1对应负数的补码值是0XFFFFFFFF不是0XFFFFFFF1。

Good catch! Thanks.

回复 | 举报

zpcllinux2016-08-02 16:33:46

\"EPERM值是1对应负数的补码值就是:0XFFFFFFF1\"
EPERM值是1对应负数的补码值是0XFFFFFFFF不是0XFFFFFFF1。