10

A Last Minute Mmu Notifier Change

 3 years ago
source link: https://kernel.taobao.org/2017/09/A-last-minute-MMU-notifier-change/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Sep 1, 2017

A Last Minute Mmu Notifier Change

https://lwn.net/Articles/732952/ 在4.13即将released的最后时刻,新引入了一个内存管理的重要修改,用于修复MMU notifier带来的regression.

内存管理子系统之前做了大量的工作用于正确的配置MMU,使得内核其他部分和用户态都不需要关心MMU管理的细节。但是随后的一些变化使得MMU概念有些不一样,最开始是虚拟化引入用于处理gust内存到host映射的shadow page table,最近也有其他一些设备开始有自己内存映射,类似GPGPU。在内存子系统执行修改之后,这些CPU之外的MMU也需要做出相应的更新。

为此Andrea Arcangeli在2008年2.6.27的合并窗口里面加入了MMU notifier机制,使得其他子系统能够在内存管理子系ç»中加入hook,当一个进程的页表发生修改时会执行hook的callback。

/当页表中address对应页的页表项被移除,同时该页还存在时,下面这个callback会被调用/ void (*invalidate_page)(struct mmu_notifier *mn, struct mm_struct *mm, unsigned long address);

/下面这个callback用于在start和end对应地址范围内存页的映射还存在时通知其他MMU移除这些内存页的映射/ void (*invalidate_range_start)(struct mmu_notifier *mn, struct mm_struct *mm, unsigned long start, unsigned long end);

/当start和end对应地址范围内存页的映射已经都移除时,下面这个callback用于通知其他MMU做些清理工作/ void (*invalidate_range_end)(struct mmu_notifier *mn, struct mm_struct *mm, unsigned long start, unsigned long end);

/当start和end对应地址范围内存页的映射摘除时,下面这个callback会被触发/ void (*invalidate_range)(struct mmu_notifier *mn, struct mm_struct *mm, unsigned long start, unsigned long end);

总共增加了有4个hook点,其中invalidate_range可以在invalidate_range_start和invalidate_range_end之间调用,也可以单独调用。其中invalidate_page是允许睡眠ç,而invalidate_range不允许。

8月份Adam Borowski反馈当使用KVM时4.13-rc内核会触发host系统挂,同时也有其他一些反馈包括一个crash,通过排查发现该问题是由于之前为了修复持有spinlock情况下调用invalidate_page问题而引入的patch导致。最终的修复看起来并不太容易。invalidate_page允许睡眠这个从根本上就会导致各种race,Torvalds为此抱怨MMU notifier机制,并指出这些接口不应该允许睡眠才对。

但实际ä¸如果不允许睡眠,类似支持GPU这种就没法实现。为了清除GPU的页表,需要将命令发送到GPU命令队列,并等待GPU通知页表/tlb以及cache已经清理完毕。

Torvalds最终还是做出来一点让步,并对两种情åµ做了区分,对虚拟地址和mm_struct相关的处理允许睡眠,同时对页表和页相关处理不允许睡眠,因此用于处理虚拟地址并且不会在持有spinlock情况下调用的invalidate_range_start()和invalidate_range_end()是å许睡眠的,invalidate_page和invalidate_range不允许睡眠。同时Torvalds指出invalidate_page从根本上就是设计错误,经过讨论,最好的处理办法就是彻底移除该函数。

Glisse快速的实现了上述想法,并解决了4.13-rc内核的问题,最终赶在4.13内核出release的倒数第三天合并进入内核。invalidate_page最后被彻底移除了,所有外部依赖该函数的模块都需要更新下,否则会失败。

4.13内核的MMU notifier还遗留有一个问题,oom里面用于回收杀死进程内存的代码里面并没有调用这些notifier。这会导致使用了notifier的系统在内存消耗完的时候出现问题。Michal Hocko正在着手修复,最终patch暂时还没有合并。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK