今天看kernel janitor的补丁时发现了一句代码:
-
+ if (!arr->record || !arr->subtree) {
-
kfree(arr->record);
-
kfree(arr->subtree);
-
kfree(arr);
-
return ERR_PTR(-ENOMEM);
-
}
其他,都不重要,唯独ERR_PTR这句,以前看过,可理解不深(压根就没理解过。),丈二和尚了。
说道底,原理非常简单,就是物尽其用,这是内核的一贯特色。
我们知道内存相关的函数如kmalloc的返回值一般是一个4k对齐的虚拟地址,也有可能是Null。
以32位系统为例,我们知道存储地址值变量类型是unsigned无符号的。
那么这个物尽其用,体现在哪里呢?
地址都是4k对齐那么0XFFFFF000 ~0XFFFFFFFF这4k个地址就没人用了。
当然所有不被4k整除的地址都用不到,而内核就选择了这最后一个page的地址了。
内核用的就是这个范围内的数字。在error_base.h你会看到定义的各种错误量。
把这些错误量前面加个-负号,他们的补码形式正好落在这4k范围内。这就用上了,和原来表示地址也不会冲突。
有了这些值我们就知道具体是什么错误了,比简单返回一个NULL强百倍。
-
20 #define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
-
21
-
22 static inline void *ERR_PTR(long error)
-
23 {
-
24 return (void *) error;
-
25 }
-
26
-
27 static inline long PTR_ERR(const void *ptr)
-
28 {
-
29 return (long) ptr;
-
30 }
-
31
-
32 static inline long IS_ERR(const void *ptr)
-
33 {
-
34 return IS_ERR_VALUE((unsigned long)ptr);
-
35 }
ERR_PTR,PTR_ERR都很简单。解释下IS_ERR:
MAX_ERRNO值是4095对应的负数值-4095,也就是0XFFFFF001.
EPERM值是1对应负数的补码值就是:0XFFFFFFFF.
以此类推,所有err值都大于-4095。就能区分错误码和4k对齐的虚拟地址了,因为内存管理函数返回的虚拟地址的值永不会大于-4095。
阅读(868) | 评论(0) | 转发(0) |