Linux TLB 刷新的懒惰模式

我们都知道,在切换页表时会刷新 TLB,这样就可以使用新的地址空间,那什么是 TLB 刷新的懒惰模式呢?

TLB 是什么这里不作多的解释,可以简单理解为,为了加快 MMU 对虚拟地址的转换而增加的缓存,它记录了一个虚拟地址对应的内存页的物理地址。其实就是根据虚拟地址的前 20 位,来建立一个个条目,对应记录通过查找页表来记录的内存页的物理地址。

既然有缓存,那么被缓存的内容改变时,就涉及到缓存的刷新,就是 TLB 的刷新问题,当一个页表结构发生变化时,使用该页表节构的 CPU 就应该刷新自己的 TLB。

显然进程切换时,由于地址空间发生了变化,TLB 应该得到刷新,然而,内核进程只访问内核空间的地址范围,而每个进程的内核空间的地址范围相同,所以如果 CPU 从一个用户进程切换到一个内核进程,由于用户进程和内核进程的内核地址空间部分相同,其实是不用切换页表的,内核进程依然可以使用前一个用户进程的内核部分的地址空间。这样就省去了刷新 TLB 带来的性能损耗。

想像着是挺完美的,但是在 SMP 构架下,这将带来一些问题,例如,在某一核上 CPU0 刚从一用户进程切换到内核进程,该内核进程沿用该用户进程的地址空间,但它只访问内核空间部分,这不会有问题,然而,如果该用户进程在另一个 CPU1 核上被调度,并且在 CPU0 用它的地址空间时,它在 CPU1 上执行完毕,并退出,那么它的地址空间将被销毁,此时,若 CPU0 如果访问它的地址空间是非常危险的,不管是被缓存的地址还是未被缓存的地址都将可能带来意想不到的严重后果。

那么,难道这种美好的事情就要被上面的情况的发生扼杀,而每次都要刷新 TLB,重新加载页表么。显然还是有补救办法的,如果在 CPU0 上的内核进程执行期间,它所引用的用户进程的地址空间没有被调度并执行完毕的情况还是非常多的,这种不刷新 TLB 带来的性能提升还是可以利用一下的,谁让 Linux 是一个精打细算的内核呢。

如何办到这一点,其实很简单,就是当地址空间销毁时,通知一下,当时正在使用这个地址空间的内核进程。所以只需要记录当前地址空间有哪些 CPU 在引用就行了,当地址空间销毁时,发一个 IPI 给其它引用该地址空间的 CPU,让它们重新加载自己的页表结构,就可以了。

这就引入了 TLB 刷新的懒惰模式。

Linux 为每一个 CPU 创建了一个节构,它是一个每 CPU 数据,所以不需要加锁,每个 CPU 只访问自己的节构,它记录了该 CPU 的状态,TLBSTATE_OK 表示非懒惰模式, TLBSTATE_LAZY 表示懒惰模式。它还记录该 CPU 引用的地址空间节构,是一个 mm_struct 类型的节构体指针,它记录了一个进程的地址空间的所有信息,mm_struct 有一个成员 cpu_vm_mask, 是一个默认 32 位的掩码,如果某个 CPU 在使用这个地址空间,则相应位置会被置位,显然,它将支持最多
32 个 CPU。这样情况就简单了,当一个 CPU 从一个用户进程调出,调用一个内核进程时,它会设置自己的进入 TLBSTATE_LAZY 模式,并且把它引用的用户进程的 mm_struct 中相应的位置位,此时并不切换页表节构,即不加载内核空间的页目录,而如果它引用的地址空间的用户进程退出,地址空间被销毁时,销毁的逻辑中会根据 mm_struct 中相应的掩码,知道向哪些 CPU 发送 IPI 消息,此时使用该地址空间的 CPU 都会收到这个消息,消息的响应函数为 smp_invalidate_interrupt,代码如下:

void smp_invalidate_interrupt(struct pt_regs *regs)
{
	unsigned long cpu;

	cpu = get_cpu();

	if (!cpu_isset(cpu, flush_cpumask))
		goto out;
		/*
		 * This was a BUG() but until someone can quote me the
		 * line from the intel manual that guarantees an IPI to
		 * multiple CPUs is retried _only_ on the erroring CPUs
		 * its staying as a return
		 *
		 * BUG();
		 */

	if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) {
		if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) {
			if (flush_va == TLB_FLUSH_ALL)
				local_flush_tlb();
			else
				__flush_tlb_one(flush_va);
		} else
			leave_mm(cpu);
	}
	ack_APIC_irq();
	smp_mb__before_clear_bit();
	cpu_clear(cpu, flush_cpumask);
	smp_mb__after_clear_bit();
out:
	put_cpu_no_resched();
	__get_cpu_var(irq_stat).irq_tlb_count++;
}

它会比较,看自己引用的地址空间是否是正在销毁的地址空间,如果是,那么查看自己是否是懒惰模式,如果是懒惰模式,则调用 leave_mm ,代码如下:

void leave_mm(int cpu)
{
	if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK)
		BUG();
	cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask);
	load_cr3(swapper_pg_dir);
}

它会把自己从地址空间的掩码中清除,然后加载 swapper_pg_dir 页目录,该页目录就是内核空间的页目录,它会引起 TLB 的刷新,它本该在 CPU 调度入该内核进程时被加载的,而此时才加载,所以就被称为懒惰刷新 TLB。

时间: 2024-08-09 14:47:02

Linux TLB 刷新的懒惰模式的相关文章

linux lvs集群nat模式(比上一篇的lvs nat实用)

这是一篇以apcache服务为例介绍lvs的nat模式配合keepalived实现的方案.实验拓扑图如下所示,虚线上面的大图可以看成是虚线下面"服务器群"的放大版: 本实验共用到4台linux虚拟服务器,其中两台rhel5.6作为主从HA(keepalived)服务器,另外两台rhel4.6模拟Apache服务器--用两台Apache服务器模拟多台Apache服务器. 实验原理是,用Apache服务器为代表模拟实际用到的服务器,用两台Apache模拟多台Apache,所有的Apache

linux运行级别&单用户模式&救援模式

运行级别 init 6 == reboot == shutdwon -r now 重启 init 0 == shutdown -h now 关机 单用户模式 启动后三秒内按任意键--->按e编辑-->按方向键选第2项再按e键-->在最尾部按1-->再按b启动-->过几秒钟进入单用户模式-->用password更改密码并重新启动 救援模式 光盘启动镜像-->选择第三项rescue installed system-->提示是否选择网络-->是否将原系统挂

Linux网卡设置为网桥模式

Linux网卡设置为网桥模式 1.    添加网卡,并修改相关配置文件 1.1虚拟机添加网卡,并配置相关文件 如:eth2为新添加网卡 cd /etc/sysconfig/network-scripts cp ifcfg-eth1 ifcfg-eth2 vi ifcfg-eth2 TYPE=Ethernet BOOTPROTO=none DEFROUTE=yes PEERDNS=yes PEERROUTES=yes IPV4_FAILURE_FATAL=no IPV6INIT=yes IPV6_

linux网卡速率和双工模式的配置

linux网卡速率和双工模式的配置 (2012-09-06 14:39:57) 转载▼ 标签: 科技 网络接口 协商 网卡 工具 it 分类: Linux 改变网络接口的速度和协商方式的工具miitool 和ethtool 通过mii-tool和ethtool工具来调整网卡的速度.双工等,这样能提高网卡的效率: mii-tool 配置网络设备协商方式的工具 mii-tool 介绍 mii-tool - view, manipulate media-independent interface st

转载:Linux的vim三种模式

一般模式:在Linux终端中输入“vim 文件名”就进入了一般模式,但不能输入文字. 编辑模式:在一般模式下按i就会进入编辑模式,此时就可以写程式,按Esc可回到一般模式. 命令模式:在一般模式下按:就会进入命令模式,左下角会有一个冒号出现,此时可以敲入命令并执行. 转载网址:http://anxiongbo.blog.51cto.com/805770/163582 一. VIM高亮 进入vim后,在普通模式下输入如下命令,开启php代码高亮显示 :syntax enable :source $

Linux(CentOS 7)命令行模式安装VMware Tools 详解

本篇文章主要介绍了如何在Linux(CentOS 7)命令行模式安装VMware Tools,具有一定的参考价值,感兴趣的小伙伴们可以参考一下. 本例中为在Linux(以CentOS 7为例)安装VMware Tools. 1.首先启动CentOS 7,在VMware中点击上方"VM",点击"Install VMware Tools..."(如已安装则显示"Reinstall VMware Tools..."). 2.在命令行输入"ls

linux centos 6.0 救援模式

 linux centos 6.0 救援模式   昨天机器我强制把它关机了,今早上班发现系统起不来了.是因为我昨晚没好好对她吗?   废话少说了就好好补她吧!     1.开机引导系统报错: 直接CONtrol-D 继续重启还是很坏!  2.连单用户都进不了,插入第一张光盘赶紧起用linux rescue模式 接在就开始修复fsck 急救! fsck -y /dev/sda1 接在重启reboot. 引导成功进系统! linux centos 6.0 救援模式

清华大学视频课件:基于Linux的C++(自主模式)

基于Linux的C++(自主模式) 课程简介 Linux操作系统开源的特性使得其获得越来越重要的地位,而Linux系统编程也向C++程序设计者提出了更高的要求.本课程由C/C++语言的共性与特性出发,在深入学习程序设计语言的基础上,进一步强调程序设计语言的适用性,并与Linux系统编程紧密结合,通过大力培养学习者的抽象思维能力和计算思维能力,将学习者对语言作为工具的基本认知转化为动手实践能力,完成从具象到抽象再到具象的思维能力转变.课程内容主要涵盖C++程序设计基本概念.数据组织与算法设计.程序

linux TLB表

TLB - translation lookaside buffer 快表,直译为旁路快表缓冲,也可以理解为页表缓冲,地址变换高速缓存. 由于页表存放在主存中,因此程序每次访存至少需要两次:一次访存获取物理地址,第二次访存才获得数据.提高访存性能的关键在于依靠页表的访问局部性.当一个转换的虚拟页号被使用时,它可能在不久的将来再次被使用到,. TLB是一种高速缓存,内存管理硬件使用它来改善虚拟地址到物理地址的转换速度.当前所有的个人桌面,笔记本和服务器处理器都使用TLB来进行虚拟地址到物理地址的映