如何以编程方式获取 linux 内核页面大小
Posted
技术标签:
【中文标题】如何以编程方式获取 linux 内核页面大小【英文标题】:How to get linux kernel page size programmatically 【发布时间】:2011-02-03 15:28:05 【问题描述】:我正在为 IA64 开发一个 Linux 模块。我当前的问题是驱动程序使用 PAGE_SIZE 和 PAGE_SHIFT 宏进行 dma 页面分配。我遇到的问题是编译驱动程序的机器不是运行驱动程序所需的机器。因此,如果编译机器上的 PAGE_SIZE 为 2^14K,而目标机器为 2^16K,则驱动程序失败。
我不想把这个问题变成关于在不是运行模块的机器上编译模块的“最佳实践”问题。我理解这方面的问题。我发现人们大多使用 getpagesize() 或 sysconf(_SC_PAGE_SIZE)。这两个选项不在 ia64 内核头文件中,所以我不能使用它们。还有其他方法可以获得运行时 PAGE_SIZE 吗?
我正在查看的选项:
正在读取 /proc 中的某些文件? 系统调用? 让我通过推理计算 PAGE_SIZE 的其他函数(例如 ORDER、getpageshift 等)? 其他?【问题讨论】:
您是说PAGE_SIZE
可针对 IA64 架构进行配置,而不是固定的?我认为 PAGE_SIZE
对于给定的架构是固定的(例如,对于 x86 总是 4096
)。
IA64 确实支持多种页面大小:informit.com/articles/article.aspx?p=29961&seqNum=3
【参考方案1】:
尝试使用getconf
实用程序,它可以让您轻松检索页面大小。
getconf PAGESIZE
【讨论】:
我认为这不能回答 OP 的问题,但这是有用的信息,因为 sysconf(_SC_PAGESIZE) 似乎在 linuxia64 上返回 4K(而 mprotect 在未与 16K 边界对齐的页面上失败)。 我的 x86-64 只返回 4k,但它有 4k、2M 和 1G 页面。【参考方案2】:一种近似的方法是读取/proc/meminfo
并检查Mapped
的大小(我现在的52544 kB),然后检查/proc/vmstat
中的nr_mapped
(我现在的131136)。最后PAGE_SIZE = Mapped/nr_mapped
。有时这会给你一个准确的值(如我引用的当前示例),有时它是近似值但非常接近。
希望这会有所帮助!
【讨论】:
我没有找到Mapped/nr_mapped
甚至接近 getconf PAGESIZE
提供的内容
@MCP 在我的机器上Mapped/nr_mapped = 379512KB/94878 = 4KB
。 getconf PAGESIZE
给出 4096。它们确实匹配。能分享一下你看到的吗?【参考方案3】:
查找页面大小的一种方法是从进程的 smap 中获取它。
例如:
cd /proc/1
grep -i pagesize smaps
KernelPageSize: 4 kB
MMUPageSize: 4 kB
【讨论】:
奇怪地使用了你的技巧,我在 ARM 上看到了4 kB
,但在运行内核的 arch/arm/include/asm/page.h
内部,它是 #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
,显然它 is 1024 字节,当从我的驱动程序,正如定义 page.h
所建议的那样。什么给了?【参考方案4】:
如果您尝试构建内核模块,则至少需要为模块将运行的内核配置的内核头文件。这些将定义您需要的页面大小宏。如果您没有正确配置的头文件,内核将拒绝加载您的模块。
在一台机器上编译模块以在另一台机器上运行并没有错,即使它是不同的架构。您只需要针对正确的内核源代码进行构建。
【讨论】:
这不是内核源的问题。它是关于加载在机器上编译的模块,以运行到另一台机器(两者具有相同的内核版本但配置不同)。我不想针对新配置重新编译,因为 PAGE_SIZE 已更改。我希望从内核中获取该参数作为 API,而不是作为 MACRO(在编译时解决)。 PAGE_SIZE 是非常基本的,并且在构建模块本身时对于模块是必需的..【参考方案5】:这就是我最终所做的:
重新设计我当前的模块以获取一个名为 page_shift 的新模块参数,并使用它来计算PAGE_SIZE (PAGE_SIZE = 1 << PAGE_SHIFT)
创建了一个模块加载器包装器,它使用来自 libc 的 getconf
API 获取当前系统 PAGE_SHIFT
。此包装器获取当前系统页面移位并将其作为模块参数传递。
现在模块正在以不同的 PAGE_SIZE 加载到不同的架构上,没有任何问题。
【讨论】:
菜鸟问题。你能解释一下使用 getconf API 的包装器吗?我的意思是你在 popen() 函数中调用了 getconf 命令还是什么。多一点的光线将非常感激。【参考方案6】:我担心这是不可能的,因为页面大小是内核的一部分。 如果您使用工具链来编译内核模块,则需要了解页面大小。
所以至少在当前的内核架构下是不可能的。
【讨论】:
【参考方案7】:您可以只运行一个测试,只需对具有不同偏移量的文件进行 mmap 映射,然后查看哪个失败。虽然在内核模块中可能很烦人,但也许还有其他类似的测试可以使用。
【讨论】:
以上是关于如何以编程方式获取 linux 内核页面大小的主要内容,如果未能解决你的问题,请参考以下文章
我如何以编程方式确定 Github 目录页面中所有当前存在的目录?