linux高端内存管理之临时内核映射
2012-01-05 15:14
218 查看
临时内核映射区属于高端内存中的固定内核映射区中的一部分。当必须创建一个映射而当前的上下文又不能睡眠时,内核提供了临时映射(也就是所谓的原子映射)。有一组保留的映射,他们可以存放新创建的临时映射。内核可以原子地把高端内存中的一个页映射到某个保留的映射中。因此,临时映射可以用在不能睡眠的地方,比如中断处理程序中,因为获取映射时绝不会阻塞。
每个CPU都有他自己的窗口集合,他们用enum km_type数据结构表示。该数据结构中定义的每个符号,如KM_BOUNCE_READ、KM_USER0等标示了窗口的线性地址。
在km_type中的每个符号(除了最后一个)都是固定映射的线性地址的一个下标。enum fixed_addressed数据结构包含符号FIX_KMAP_BEGIN和FIX_KMAP_END;把后者的值赋成下标FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1。在这种方式下,系统中的每个CPU都有KM_TYPE_NR个固定映射的线性地址。
临时内核映射的建立
内核调用kmap_atomic()函数
撤销临时映射
kunmap_atomic(),这个函数减少当前进程的preempt_count;因此,如果在请求临时内核映像之前能抢占内核控制路径,那么在同一个映像被撤销后可以再次抢占。
每个CPU都有他自己的窗口集合,他们用enum km_type数据结构表示。该数据结构中定义的每个符号,如KM_BOUNCE_READ、KM_USER0等标示了窗口的线性地址。
enum km_type { KMAP_D(0) KM_BOUNCE_READ, KMAP_D(1) KM_SKB_SUNRPC_DATA, KMAP_D(2) KM_SKB_DATA_SOFTIRQ, KMAP_D(3) KM_USER0, KMAP_D(4) KM_USER1, KMAP_D(5) KM_BIO_SRC_IRQ, KMAP_D(6) KM_BIO_DST_IRQ, KMAP_D(7) KM_PTE0, KMAP_D(8) KM_PTE1, KMAP_D(9) KM_IRQ0, KMAP_D(10) KM_IRQ1, KMAP_D(11) KM_SOFTIRQ0, KMAP_D(12) KM_SOFTIRQ1, KMAP_D(13) KM_SYNC_ICACHE, KMAP_D(14) KM_SYNC_DCACHE, /* UML specific, for copy_*_user - used in do_op_one_page */ KMAP_D(15) KM_UML_USERCOPY, KMAP_D(16) KM_IRQ_PTE, KMAP_D(17) KM_NMI, KMAP_D(18) KM_NMI_PTE, KMAP_D(19) KM_TYPE_NR };
在km_type中的每个符号(除了最后一个)都是固定映射的线性地址的一个下标。enum fixed_addressed数据结构包含符号FIX_KMAP_BEGIN和FIX_KMAP_END;把后者的值赋成下标FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1。在这种方式下,系统中的每个CPU都有KM_TYPE_NR个固定映射的线性地址。
enum fixed_addresses { …… FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, …… }
临时内核映射的建立
内核调用kmap_atomic()函数
用数学公式来避免混乱,他空间有限且虚拟地址固定,这意味着他映射的内存空间不能被 长时间占用,而不被unmap,在效率上比kmap提升不少,然而他和kmap不是用于统一 场合的, **/ void *kmap_atomic(struct page *page, enum km_type type) { return kmap_atomic_prot(page, type, kmap_prot); }
/* * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because * no global lock is needed and because the kmap code must perform a global TLB * invalidation when the kmap pool wraps. * * However when holding an atomic kmap it is not legal to sleep, so atomic * kmaps are appropriate for short, tight code paths only. */ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot) { enum fixed_addresses idx; unsigned long vaddr; /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ /**原子映射是基于每个cpu的,因此在当前cpu上应用抢占,直到unmap的时候才 开启,这样不会导致原子映射的重入了, */ pagefault_disable(); if (!PageHighMem(page)) return page_address(page); /* 递增type,保证下面公式起作用 */ debug_kmap_atomic(type); /* kernel可以在多个cpu上同时运行不同的task,然而他们共同使用一个内存地址空间, 也就是说,内存空间对于多个cpu看到的是同一个,该函数使用的是地址空间中顶部的 一小段地址空间,也就是临时映射区,内核逻辑将这一小段地址空间分成若干各节 每一节的大小是一个页面的大小,可以映射一个页面,根据公用地址空间的原理 所有的cpu共同使用这些节,因此如何能保证N个cpu调用此函数不会将page映射到 一个地址呢,这就是这个数学公式所起到的作用 */ idx = type + KM_TYPE_NR*smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); /*这里为什么是减法 越靠前的枚举项对应的线性地址越靠后*/ BUG_ON(!pte_none(*(kmap_pte-idx))); /*设置pte*/ set_pte(kmap_pte-idx, mk_pte(page, prot)); return (void *)vaddr; }
#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
撤销临时映射
kunmap_atomic(),这个函数减少当前进程的preempt_count;因此,如果在请求临时内核映像之前能抢占内核控制路径,那么在同一个映像被撤销后可以再次抢占。
相关文章推荐
- 全面解析Linux 内核 3.10.x - 内存管理 - 高端地址的内核映射
- linux 高端内存页框管理:永久内核映射、临时内核映射以及非连续内存分配
- 高端内存映射之kmap持久内核映射--Linux内存管理(二十)
- linux高端内存管理之永久内核映射
- linux高端内存管理之永久内核映射
- 高端内存管理--持久映射-固定映射 -临时映射
- Linux 内存管理 -- 高端内存的映射方式
- Linux 内存管理 -- 高端内存的映射方式
- [转]LINUX内存管理 - 高端内存的映射方式
- Linux内存管理之高端内存映射 (2008-02-27 15:28)
- Linux 内存管理 -- 高端内存的映射方式
- Linux内存管理之高端内存映射
- Linux内存管理之高端内存映射
- Linux的内存管理主要分为两部分:物理地址到虚拟地址的映射,内核内存分配管理(主要基于slab)。
- Linux 内存管理 -- 高端内存的映射方式
- Linux 内存管理 -- 高端内存的映射方式
- Linux 内存管理 -- 高端内存的映射方式
- Linux 内存管理 -- 高端内存的映射方式
- Linux内存管理之高端内存映射
- [Linux内存管理] linux内存布局的内核实现--用户空间的映射方式