我有一个支持 eMMC 的 Linux 3.10 开发设备 (Android),我试图更好地理解 Linux 何时实际从 eMMC 而不是页面缓存读取。具体来说,我对 ELF 加载过程感兴趣,我无法解释以下结果。
我已经在 init 运行的文件系统上放置了一个 ELF 文件,并且不会退出。 ELF 文件数据驻留在块 0x22d930-0x22da78 中,我修改了内核以记录对这些块的任何 eMMC 读取访问。在启动过程中,日志显示从 eMMC 读取了整个 ELF 文件。
mmc read block: 0x22d930, num_blocks: 0x20
mmc read block: 0x22d9f0, num_blocks: 0x88
mmc read block: 0x22d950, num_blocks: 0xa0
这对我来说很有意义,因为我希望当 init 第一个 fork/execve 是我的 ELF (0x20 + 0x88 + 0xa0 = 0x22da78 - 0x22d930) 时,从 eMMC 读取完整的 ELF。
当我删除页面缓存并终止进程时,我感到困惑。当我终止进程时,init 配置为通过另一个 fork/execve 自动重新启动该进程。通过删除页面缓存,我希望再次从 eMMC 读取完整的 ELF。但是,在发出以下命令后,我只看到部分 eMMC 读取访问。
echo 3 > /proc/sys/vm/drop_caches && kill -9 <pid>
mmc read block: 0x22d960, num_blocks: 0x10
mmc read block: 0x22d988, num_blocks: 0x8
mmc read block: 0x22d9a0, num_blocks: 0x8
mmc read block: 0x22d9c0, num_blocks: 0x40
mmc read block: 0x22da40, num_blocks: x018
mmc read block: 0x22da60, num_blocks: 0x18
我的进程已使用新的 pid 成功重新启动,但我不明白为什么 Linux 没有从磁盘重新读取完整的 ELF? Linux 甚至不重新读取 ELF 标头,我知道这是 execve 读取的第一个文件。
来自我的原始进程的原始文件映射的部分是否仍在某些缓存/RAM 中?以下命令仅显示我的过程。
lsof | grep <ELF name>
我将不胜感激任何帮助解释这种行为以及我认为的逻辑有问题的地方。
答案1
问题似乎是 init 重新启动进程和页面缓存被删除之间的时间安排。kill -9 <pid> && echo 3 > /proc/sys/vm/drop_caches
正确的顺序似乎如下所示,而不是发出。
stop <service>
echo 3 > /proc/sys/vm/drop_caches
start <service>
一旦服务停止,文件映射就不再锁定在页面缓存中,现在可以删除。这会迫使 Linux 在服务再次启动时从磁盘重新读取 ELF。