Linux内核中的页面错误

问题描述

阅读Mel Gorman的书Understanding the Linux Virtual Memory Manager之后,我几乎没有疑问。 4.3 Process Address Space Descriptor节说kernel threads never page fault or access the user space portion. The only exception is page faulting within the vmalloc space。以下是我的问题。

  1. kenrel线程永远不会出现页面错误:这是否意味着仅用户空间代码会触发页面错误?如果调用kmalloc()vmalloc(),是否不会出现页面错误?我相信内核必须将这些映射到匿名页面。对此页面执行写操作时,将发生页面错误。我的理解正确吗?

  2. 为什么内核线程无法访问用户空间? copy_to_user()copy_from_user()不这样做吗?

  3. Exception is page faulting within vmalloc space:这是否意味着vmalloc()会触发页面错误,而kmalloc()不会?为什么kmalloc()不会出现页面错误?内核虚拟地址的物理帧不需要保存为页表项吗?

解决方法

我想您会感到困惑,因为您对内核,进程和虚拟内存的开始并不清楚。

  1. kenrel线程从不进行页面错误:这是因为内核空间和用户空间的页面使用不同的分配方法。对于内核空间,我们在初始化时分配页面,但是对于用户空间,我们在运行进程并调用诸如malloc()之类的功能时分配它们,并且在映射之后,当真正使用该虚拟内存时,我们会触发页面错误。

  2. 为什么内核线程无法访问用户空间?当kenrel启动时,进程0将创建进程1和进程2。进程1用于形成用户空间进程树,而进程2用于管理内核线程。这些用户线程总是使用您提到的功能来将数据传输到内核中/从内核传输出去,以实现某些功能,例如打开文件或套接字等。

  3. 异常是vmalloc空间中的页面错误:vmalloc空间不是函数vmalloc(),它是内核内存空间中用于某些动态内存分配的区域,用作异常。

,
  1. 内核线程永不出现页面错误:谈论的页面错误是在驻留虚拟页面或将其从swap恢复时。内核页面不仅可以在kmalloc()上进行页面调度,而且在它们的生命周期内都可以驻留。对于用户空间页面,情况并非如此,其中A)可能是延迟分配的(即,仅作为malloc()上的页面表条目保留,但实际上不会出错,直到memset()或其他取消引用),并且B)可能会交换在内存不足的情况下退出。

  2. 为什么内核线程无法访问用户空间? copy_to_user()或copy_from_user()不会这样做吗?

这是一个很好的问题,有针对特定硬件的答复。过去常常是不鼓励内核线程访问用户空间的情况,正是因为如果访问用户空间中未分页/分页的内存可能会发生页面错误命中(回想一下,在内核空间中不会发生这种情况,如上所述确保)。因此copy_to / from将是正常的memcpy,但包装在页面错误处理程序中。这样,任何潜在的页面错误都将得到透明处理(即将内存分页),并且一切都会好起来。但是肯定存在某些情况,其中,memcpy往返用户内存的错误方法只会奏效-更糟糕的是,它会经常奏效,因为页面错误非常具有RAM驻留性和可用性-因此未处理的错误会导致随机恐慌。因此,始终使用copy_from / to_user的命令。

但是,最近,从安全角度来看,内核/用户内存隔离变得很重要。这是由于许多利用技术(NULL指针取消引用是一种非常常见且功能强大的技术),在这种技术中,伪造的内核对象(或代码)可以在用户空间(从而易于控制)的内存中构造,并可能导致代码执行中的错误。内核。

因此,大多数体系结构都具有页表位,这实际上阻止了内核访问属于用户模式的页。以ARM64为例,此功能称为PAN / PXN(特权访问/从不执行)。

因此,copy_from / to现在不仅可以处理页面错误,还可以在操作之前禁用PAN / PXN,并在操作之后恢复它。

  1. 异常是vmalloc空间中的页面错误:vmalloc()分配了可交换的内存,而kmalloc却没有。不同之处在于实现方式(kmalloc使用GFP_KERNEL)。这也意味着kmalloc更有可能失败(如果没有可用的RAM),但不会发生页面错误(它将返回NULL,这本身就是一个问题。)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...