2023925


内存管理

12.7

12.7.1

中断栈

12.7.2 栈上正大光明工作

尽量动态分配,内核栈有限

12.8 高端内存的映射

12.8.1 永久映射

映射page到内核地址空间

void *kmap(struct page *page)

低端内存:返回虚拟地址

高端内存:建立永久映射,并返回地址

kmap可睡眠

永久映射有限,高端内存不需要时候应该解除映射

void kunmap(struct page *page)

12.8.2 临时映射(原子映射)

创建映射且上下文不能睡眠

void *kmap_atomic(struct page*page, enum km_type type)

type描述了临时映射的目的

不会阻塞

禁止内核抢占,每个映射对每个处理器唯一

void kunmap_atomic(void *kvaddr, enum_type type)

12.9 每个CPU的分配

每个CPU的数据存在一个数组里

按当前处理器号决定这个数组的当前元素

unsigned long my_percpu[NR_CPUS];

int cpu;
cpu = get_cpu();
my_percpu[cpu]++; //具体执行的代码
put_cpu();

不存在并发问题

内核抢占问题:

  • 代码被其它处理器抢占,重新调度,CPU变量无效
  • 同一个处理器抢占了两个,造成竞争

get_cpu()时禁止内核抢占,put_cpu()时重新激活处理器

12.10 新的每个CPU接口

2.6内核为了方便操作每个CPU数据,引入percpu

<linux/percpu.h>声明了所有接口操作例程

12.10.1 编译时每个CPU数据

DEFINE_PER_CPU(type, name);

为每个处理器创建类型为type,名字为name的变量实例

在别处声明变量:

DECLARE_PER_CPU(type, name);

get_cpu, put_cpu操作变量

get_cpu_var(name)++;
put_cpu_var(name);

也可以

per_cpu(name, cpu)++;

此方法不会禁止内核抢占,也不会提供锁保护

链接程序将他们创捷在一个唯一的可执行段中.data.percpu

12.10.2 运行时的每个CPU数据

内核实现CPU数据动态分配类似kmalloc

void *alloc_percpu(type);
void *__alloc_percpu(size_t size, size_t align);
void free_percpu(const void *);

alloc_percpu:单字节对齐,按照给定类型的自然边界对齐

__alloc_percpu:指定对齐

返回一个指针,用来引用CPU数据

get_cpu_var(ptr);
put_cpu_var(prt);

12.11 使用每个CPU数据的原因

  1. 减少了数据锁定,不再需要锁(纯粹的编程约定,不存在强制措施)
  2. 大大减少缓存失效,percpu接口缓存对齐(cache align)所有数据

唯一的安全要求:禁止内核抢占(put, get),不能睡眠

12.12 分配函数的选择

  • 常用:kmalloc() GFP_ATOMIC 或 GFP_KERNEL
  • 高端内存:alloc_pages()+kmap()
  • vmalloc():分配大段内存
  • slab:针对创建撤销很多大的数据结构

12.13 小结


文章作者: N1co5in3
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 N1co5in3 !
  目录