重用page->mapping

翻译自LWN.NET

因为要在struct page这一小段内存中填入最大量的信息,linux kernel中的结构体page是最复杂的结构体之一。struct page中每一个区域都重度过载,开发者们都倾向于:若能避免,绝不对struct page做修改。不过,这并没有阻止JérômeGlisse在2018年Linux存储,文件系统和内存管理峰会的两次全体会议上提出重大更改的建议。建议提供了一些有趣的增益,但是要实现这一目标并不是一件容易的事。

mapping段在struct page中用于描述这个页的来路;对于缓存页面,mapping指向struct address_space来指示这个页面的归属,匿名页面使用mapping来反向映射到struct anon_vma。对于kernel自己用的页面,mapping段可以被slab分配器使用。就像struct page中其他的数据段一样,mapping是一个复杂的区域,可以根据页面在当前的用途提供不同的含义。

Glisse对于这一区域有着自己的设计,但是首先他必须找到清除mapping当前使用方式的办法。大多数时候,与struct page相关的代码都是通过VMA或是struct file找到struct page,在这两种情况下,mapping的信息可以从这两个结构体中获得。在可获得该信息的上下文中,无需将其存储在页面结构本身中;可以通过更改接口来代替它,以将映射信息向下传递到调用链。这样做就允许他清除大多数使用mapping的情况,然后就将mapping段移做他用。

特别是,他正在考虑使用该字段为页面上正在等待的线程接上一个结构体。当前,在线程等待特定页面是通过一组256个共享等待队列完成的,替换掉这些队列,将会加快队列变长的情况下线程的唤醒速度。在一般情况下,没有人在等这个页面时,mapping段将会指向一个结构体:

struct page_mapping{

struct address_space* mapping;

unsigned long flags;

}

本质上,此机制是添加用于访问映射信息的间接层,并添加一些标志以达到良好的效果。但是,当有人需要在该页面上等待时,此结构将被替换为:

struct page_wait {

struct wait_queue_head wq[PAGE_WRITABLE_BITS];

struct wait_queue_entry entry;

struct page_mapping base;

spinlock_t lock;

bool own;

};

完成此替换后,指向page_wait结构的指针的最低有效位设置为标记更改。任何需要旧映射字段的代码都需要注意该更改,并通过另一个间接级别跟随指针以获取该信息。这种情况将一直持续到删除最后一个等待者为止。到那时,将恢复指向page_mapping结构的指针。

休·迪金斯(Hugh Dickins)问格利瑟(Glisse),他正试图用这种改变解决什么问题。 Glisse回答说,重点是要解决共享等待队列的长度,该队列随着时间的推移一直在增长。迪金斯说,只需增加队列,就可以更简单地解决问题。肯特·奥弗斯特里特(Kent Overstreet)表示,也许可以将rhashtables用于此目的。他说,他完全赞成消除mapping字段,但是用其他内容替换该字段将是可耻的。但是,格里斯(Glisse)表示,他的目标不是完全撤离该领域。他真的只是想简化将结构体联系到struct page的过程

马修·威尔科克斯(Matthew Wilcox)建议,也许可以将私有字段用于这种结构附件,但是似乎该字段已经有太多其他用途。克里斯·梅森有力地(幽默地)断言“私人是我的!”。

Dickins说,归纳mapping字段可能会有一些价值,但是使用它来在页面上等待就比较“奇特”了。Glisse回答说,此功能“几乎免费”,几乎不需要代码。但是Dickins坚持认为,mapping说明了任何给定页面的身份。如果将其替换为其他内容,则该页面会丢失该身份信息。他将这种机制描述为添加一些瞬态信息的“奇怪的滥用”。

Rik van Riel询问了该方案如何处理页面查找和truncate操作之间的同步。truction需要mapping,Glisse说,但这是内核中仅有的少数几个地方之一。使事情运转起来只是在那些地方增加对新方案的认识的问题。Dave Chinner说XFS检查一个空mapping值来处理trunction,这将打破新方案。Glisse建议增加一个新的助手,但是Overstreet表示,现在是时候找到一种更好的方法来处理trunction操作的锁定了。

丹·威廉姆斯(Dan Williams)重复了一个问题,为什么确实需要该指针?这次Glisse表示他需要它来进行页面写保护,该主题计划在第二天讨论。他需要在struct page内设置一个指针,而mapping恰好是最容易抓住的指针。Glisse在会议结束时承认大多数开发人员似乎都认为此更改“看起来很丑”。无论如何,他将在不久的将来发布补丁,并查看当时的反应。

通用写保护

不过该小组尚未完成mapping相关的工作,第二天,Glisse在全体会议上主持了关于该主题的另一次会议,他在其中深入研究了这项工作的动机。在许多情况下,名义上可写的内存必须在一段时间内被全局写保护。一种可能的用例是“内核重复内存”,其中内存页在整个系统中都是重复的,以提高性能。在具有多个GPU的系统中,值得在多个页面中复制输入数据的副本,以便每个GPU都可以使用其全部可用带宽访问该数据。另一个是PCIe原子事务-256字节的事务必须等待控制器的确认,这可能是一个缓慢的过程。但是,如果在主机上对存储器进行写保护,则可以使其速度更快。然后,GPU(或其他远程处理器)可以在不使用慢速原子操作的情况下完成其工作。

而且,通常,他希望最大程度地减少对mapping字段的依赖,并在页面结构中开放一些空间以用于其他用途。

要达到这一目的,需要对现在使用mapping的位置以及可能存在的替代方法进行全面的了解。例如,与文件相关的系统调用使用了mapping,但是它们还提供了文件(以及mapping)作为参数,因此它们不需要从struct page中获取mapping。同样,与内存相关的系统调用可以访问正在操作的虚拟内存区域(VMA);可以在此处找到mapping。从用于块I / O的BIO结构获取映射信息可能会有些棘手。Glisse说,他希望BIO与mapping之间的关系不会改变,但是BIO实际上有时可以包含来自多个文件的页面。这个问题可以解决,但是可能需要将mapping信息直接存储在BIO结构中。

移走了大多数mapping的用户后,可以使用指向新结构的指针替换该字段,从而添加一个间接级别。事实证明,内核同页合并(KSM)机制已经做到了。因此,第一步可能是使mapping指向page_attachment结构(不同于前一天显示的page_mapping结构),它将替换KSM机制并使之更加通用。

Boaz Harrosh提出了前一天已经提过的问题,即为什么是mapping而不是private。Glisse回答说,private以“有趣的方式”被使用。知道发生了什么并不总是容易的。删除mapping用户要容易得多。

Dickins同意将mapping作为目标是正确的。但是他建议,如果在很少的地方使用它,为什么不将替换struct放在某个固定位置,而是将它链接到页面结构呢?答案似乎是,永远不清楚一个特定的struct连接到mapping字段结束的时间。但是Dickins坚持认为,将mapping指向始终有用的结构应该是有意义的。他(再次)说,mapping跟踪页面的标识,因此应将其替换为仍能处理该功能的结构。

他继续说道,当初添加anon_vma机制(以允许将匿名页面映射回引用它们的任务)时,对mapping字段的使用被“捏造”以适应它。然后,KSM做了进一步的“捏造”。开发人员一直想避免更改内核中的每个文件系统,因此他们选择了简单的方法。但是,他说,如果Glisse愿意为彻底改变这一领域而做的工作,那么他应该摆脱周围的“特殊性”。

David Howells询问是否可以完全消除address_space结构,而将必需的信息放回inode结构中。Glisse说,他希望看到这种情况发生,但是这样做的前景令人望而生畏。他的计划是先创建自己想要的功能,然后再考虑类似的大型任务。

前路

Glisse制定了他的工作推进计划。它旨在最大限度地提高对更改的信心,然后再依赖它们。第一步是用调用辅助函数替换掉对mapping的所有引用,然后将修改使用mapping的低级函数以将该函数作为参数。此更改将使用Coccinelle之类的工具完成,并且该参数的值一开始将为NULL;该代码将继续使用mapping字段,并且将忽略新参数。

在随后的开发周期中,将更改文件系统以将mapping信息向下传递到需要的位置。内存管理系统调用将看到类似的更改。在此过程中的某个时候,KSM机制将转换为更通用的方法。

这项工作完成后,应该有可能避免在几乎所有情况下使用mapping。但是,对于之后的几个发行版,代码将继续使用mapping,同时检查以确保它与调用堆栈中传递的值匹配。这应该会使我们确信转换已正确完成或者会指出转换尚未完成的地方。一旦可信度达到足够高的水平,就可以采取最后一步,并且不再使用mapping字段。

Harrosh说,很可能在某些地方两个mapping值不匹配。这可能导致bug,或者是由于某种原因而导致实际mapping不是存储在页面结构中的mapping的地方。但是,Glisse计划在实际使用mapping字段的地方进行测试,因此有望有效。

Dickins担心这项工作听起来像是大量的扰动。他说,他将需要更多地了解将带来的好处。他说,这将需要文件系统开发人员“响亮的肯定”。梅森说,使文件之间的页面共享更加容易是“很大的事情”,因此这对他来说是一项重要功能。就像这一连串讨论的一样,要在文件间共享page还需要克服很多挑战,这个主题最终放到了一边,因为文件系统的开发者需要有时间在此做足够的工作。

Dickins还建议,如果真正的目标是对页面进行全局写保护,则新的页面标志可能是解决该问题的更好方法。威廉姆斯则表示,真正的问题是用户空间需要写入页面,而这个页面正由诸如GPU之类的设备独占;正确的做法是后退然后说“不要那样做”,该解决方案可能被认为是向用户空间不良行为屈服。Glisse回答说,无法更改用户空间的程序,它可能是使用了十年的程序,使用的库已经过更新,可以加速GPU的操作。Williams说,解决该问题的方法是,如果应用程序需要更新的性能选项,则要求它们迁移到更新的库。

Josef Bacik说,上述提议的机制解决了他遇到的与mapping有关的问题,因此,他很高兴看到它的应用。Overstreet同意该更改将使许多用例受益。戴夫·汉森(Dave Hansen)表示,其好处可能不仅限于GPU,还包括拥有自己内存的其他设备。Dickins说,他对目标没有其他意见,但他仍然不确定改变映射是否是实现目标的正确方法。但是他感到文件系统人员很高兴有一个愿意做这项工作的傻瓜,并且他们希望内存管理人员不要阻塞它。

威尔科克斯指出,其中一些问题以前已经解决过。 SGI在几年前进行二进制文本复制。这促使约翰内斯·韦纳(Johannes Weiner)观察到,如果该小组已开始交流SGI轶事,那么现在就该总结讨论了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章