# Day 9 Cache and TLB Flushing Under Linux (一)

如同 Day1 简介的,这份文件是之前工作中有碰过 cache & TLB 相关的项目,但是没来得及好好阅读的文件,趁这个机会好好的研究研究。

文件

Original: Documentation/core-api/cachetlb.rst

========================
Linux 下的快取和 TLB 更新
========================

:作者: David S. Miller <[email protected]>

本文描述了由 Linux 虚拟记忆体子系统使用的快取/TLB 更新的应用程序介面(API)。
它列举了每个介面,描述了它的预期目的,以及使用介面後预期的作用。

下面描述的作用是针对单核处理器的实做,以及在该单核处理器上会发生的状况。
若为 SMP (多核处理器),则只需简单的使某个特定介面在系统所有处理器上发生作用。
不要被这句话吓到,认为 SMP 的快取/TLB 更新一定是很没有效率的,
事实上,这是一个可以进行很多优化的区域。
例如,如果可以证明一个使用者的定址空间从未在某个 cpu 上执行过(见mm_cpumask()),
那麽就不需要在该 cpu 上对这个定址空间进行更新。

首先是 TLB 更新介面,因为它们是最简单的。
在 Linux 下,TLB 被抽象为 cpu 软件分页表所取得的"虚拟 -> 实体记忆体转换"的快取;
这意味着,如果软件分页表发生变化,这个 "TLB" 中就有可能存在过期的转换记录。
因此,当软件分页表发生变化时,核心会在分页表发生 *变化後* 呼叫以下其中一种更新介面:

1) ``void flush_tlb_all(void)``

    最全面的更新。在这个介面执行过後,cpu 可以看到任何以前的分页表变化。

    这通常是在核心分页表被改变时使用的,因为这种转换在本质上是“全域性”的。

2) ``void flush_tlb_mm(struct mm_struct *mm)``

    这个介面更新了整个使用者定址空间。
    在执行後,这个介面必须确保 cpu 能够看见对定址空间 ‘mm’ 的任何分页表修改。
    也就是说,在执行後,TLB 中不会有 ‘mm’ 的分页表项。

    这个介面被用来处理整个地址空间的分页表操作,
    比如在 fork 和 exec 过程中发生的事情。

3) ``void flush_tlb_range(struct vm_area_struct *vma,
   unsigned long start, unsigned long end)``

    这里我们要从 TLB 中更新一个特定范围的使用者虚拟记忆体位址转换。
    在执行後,这个介面必须确保 cpu 可以看见对 ‘start’ 到 ‘end-1’ 范围内的地址空间
    ‘vma->vm_mm’ 的任何分页表修改。也就是说,在运行後,TLB 中
    不会有 ‘mm’ 的分页表项存在 ‘start’ 到 ‘end-1’ 范围内的虚拟地址。

    “vma” 是该区域的备份。这个介面主要是用於 munmap() 类型的操作。

    提供这个介面是希望能够找到一个有效率方法来从 TLB 中删除多个页面大小的转换,
    而不是让核心为每个可能被修改的分页表项使用 flush_tlb_page(见下文)。

4) ``void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)``

    这次我们需要从 TLB 中删除 PAGE_SIZE 大小的转换。
    ‘vma’ 是 Linux 用来纪录程序 mmap 区域的资料结构,
    定址空间可以通过 vma->vm_mm 取得。另外,
    可以通过测试(vma->vm_flags & VM_EXEC)来查看这个区域是否是
    可执行的(因此在 split-tlb 类型中,这个区域可能在 “指令 TLB” 中)。

    在运行後,这个介面必须确保 cpu 可以看见任何先前对使用者虚拟位址 “addr” 
    的定址空间 “vma->vm_mm” 所进行的分页表修改。
    也就是说,在运行後,TLB 中不会有虚拟地址 ‘addr’ 的 ‘vma->vm_mm’ 的分页表项。

    这主要是在错误处理时使用。

5) ``void update_mmu_cache(struct vm_area_struct *vma,
   unsigned long address, pte_t *ptep)``

    在每个分页错误结束时,这个介面被执行以告诉架构相关的程序码,
    在软件分页表中,在定址空间 “vma->vm_mm” 的虚拟位址 “address” 处,
    现在存在一个位址转换。

    可以使用这个资讯用任何方式来进行移植。例如,
    可以使用这个介面来为软件管理的 TLB 预先填充 TLB 转换资讯。
    目前 sparc64 架构就是这麽实作的。

我的理解

这份文件描述的是 Linux 底下,快取和 TLB 的更新操作介面,今天阅读的部分是 TLB 更新的介面,就字面上意思来做理解的话,其实并不算困难,简单的统整一下今天阅读到的内容:

  • struct mm_struct 是用来描述一个 struct task_struct 所有的虚拟记忆体定址空间
  • struct vm_area_struct 则是用来描述 struct mm_struct 中 mmap 的资讯
  1. flush_tlb_all:更新所有的 TLB 内容,通常用於 kernel 做分页表更新後
  2. flush_tlb_mm:更新 TLB 中,使用者程序的所有虚拟记忆体位址的转换,通常用於 fork or exec
  3. flush_tlb_range:更新 TLB 中,使用者程序的虚拟记忆体位址转换的某几个分页表项,通常用於 munmap,相较於一个一个 page 的删除,这是一个较有效率的做法
  4. flush_tlb_page:更新 TLB 中,使用者程序的一个 page 大小的虚拟记忆体位址转位,通常用於 fault handler
  5. update_mmu_cache:在 page fault 处理结束後,用来告知 kernel,哪部分 addr 的转换已更新

难的地方在於,实际找到一个 running example,可以动态的观察和追踪整个过程,并同时了解 struct mm_struct 和 struct vm_area_struct 的详细资讯。

後记

文件写的轻巧简洁,但是真的要每个文件上描述的事情都完全了解,要花的功夫可不少;今天光看了 TLB 部分,就产生了一大堆问题,例如:

  • TLB 是个实际硬体吗?还是软件模拟?若是硬体的话,会在哪里呢?
  • struct mm 的实际使用情形是? struct vm_area_struct 呢?
  • MMU 和 TLB 的关系是什麽? 在实际程序码中,看的到相关的讯息吗?
  • 上述提到的所有 API 都是每个架构自己实作自己的版本吗?... 等等

今天的内容就先到这,接下来的几篇会继续阅读这篇文件,整理并记录所有的疑问,然後试着找到答案!
感谢各位,我们明天见!


<<:  【第四天 - HG 泄漏】

>>:  Consistency and Consensus (3-2) - Lamport Timestamp

虹语岚访仲夏夜-19(专业的小四篇)

如果可以  希望一年只想你一次 可惜  那有一天不想你 如果思念  是你身边空气 可不可以 让我也...

烦请各位 excel 先进帮忙~感恩!!

各位先进大家好,小弟有个Excel问题请各位帮忙!! 表格分页1 是主页, 主要为 料件搜寻、新增页...

[区块链&DAPP介绍 Day6] Solidity 教学 - reference types

昨天看完value types,今天来聊聊 reference types。 solidity 的 ...

所以什麽是MQTT啊?

前言 在某次跟同事的讨论中听到这个名词,"A:你知道mqtt吗? W:痾 我不知道 A:...

Nice day 27 (iphone10s 功能挖掘)-读书辅助器延伸

前言 今天我们就来对昨天的读书辅助装置做个改进,让使用起来更加方便还有顺畅,目前的改善方向应该是对昨...