内核宏的解释

Explanation of a macro in kernel

在内核2.4.37中,page.h中有这样一个宏:

struct page *mem_map;
struct page *page;

#define VALID_PAGE(page)  ((page - mem_map) < max_mapnr)

我知道mem_map是一个struct page的数组,page是一个struct,那么page - mem_map是什么意思呢?

嗯,我不确定,但也许指针地址比较?

我的意思是,如果其中之一是一个数组并且它没有被取消引用,那么我想操作将应用于地址。

编辑:(精度)

因此,在这种情况下,我认为此操作用于检查 "page" 是否在地址数组 "mem_map" 的范围内。

我们可以这样表示:Graphic representation


宏的实用性:

所以,"mem_map"是数组开始的地址,假设:0x0...5。 "mem_map"(max_mapnr)数组的大小为:5.

我们想知道"page"地址是否在"mem_map"数组的范围内。

真实案例:

假设"page"在"mem_map"中,2e元素。我们可以假设他的地址是这样的:0x0...7;

现在我们进行操作:((0x0...7 - 0x0...5) < 5)。 我们得到 2。所以 "page" 地址在 mem_map.

错误案例:

否则如果"page"不在数组(0x0...D)中:我们的结果将是8。因此,8不小于"max_mapnr"(5)。所以这个页面不在"mem_map"数组中。


如果地址在数组地址 (0x0...2) 下方: ((0x0...2 - 0x0...2)) 的结果将是一个负值。在那种情况下,他们无法与 "max_mapnr"(unsigned long) 进行比较。

我发现这个主题解释为什么比我好:

Signed/unsigned comparisons

所以对于简历: 你不能在 C 中的负值(有符号)和无符号值之间进行操作,因为他会自动转换它们。换句话说,当你做 (-3 - U_nbr) 时,如果你做 (((unsigned)-3) - U_nbr) 也是一样的。并且在选项中,如果您使用 gcc -Wall 标志编译,并且您不手动转换您的值,您将收到一条编译警告消息。

为了测试,我尝试 运行 此代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
        unsigned long test = 0x0000F;
        unsigned long test2 = 0x0000A;
        unsigned long weird = 0x00002;
        char* pt1 = "This is first test string !";
        char* pt2 = "This is a test string";

        printf("Try to make operation on two unsigned long result must be 5: %lu\n", (test - test2));
        printf("Try to make operation between unsigned long result must be negative, so he will be cast: %lu\n", (weird - test2));
        printf("Let's try the same with real adresses: %lu\n", (pt2 - pt1));
        printf("And this is what happens with negative value: %lu\n", (pt1 - pt2));
        printf("For be sure, this is the lenght of string 1. %lu\n", strlen(pt1));
        return (0);
}

输出是:

Try to make operation on two unsigned long result must be 5: 5
Try to make operation between unsigned long result must be negative, so he will be cast: 18446744073709551608
Let's try the same with real adresses: 28
And this is what happens with negative value: 18446744073709551588
For be sure, this is the lenght of string 1. 27

因此,正如我们所见,负值被转换为 Unsigned long 而 return 是溢出的。如果您与 max_mapnr 进行比较,您会发现他是 "out of range"。


感谢 AnshuMan Gupta "weird case"。

它将计算mem_map数组中相应页面的索引,表示它在mem_map数组中的页数,假设为linux的pfn或页框编号(linux 假定 mem_map 数组从第 0 个 pfn 开始到最大 pfn),将 PHYS_PFN_OFFSET 添加到 pfn 将为您提供内存映射中的实际物理页框。 __page_to_pfn

max_mapnr是最大映射页数或最大页框数的限制。 set_max_mapnr

希望能解开你的疑惑。