- 论坛徽章:
- 2
|
在map_new_virtual( ) 里找到空项之后将相应数组元素值设为一,返回到kmap_high()时又将其值加1,所以有一个人使用数组相应元素值为2.
这样安排大概是为了优化对TLB的使用,即尽量延迟删除页映射(及相应TLB项).
- void * kmap_high(struct page * page)
- {
- unsigned long vaddr;
- spin_lock(&kmap_lock);
- vaddr = (unsigned long) page_address(page);
- if (!vaddr)
- vaddr = map_new_virtual(page);
- pkmap_count[(vaddr-PKMAP_BASE) >> PAGE_SHIFT]++;
- spin_unlock(&kmap_lock);
- return (void *) vaddr;
- }
复制代码 if ( !vaddr)只会在第一次映射该page frame时进去.一旦进去了,map_new_virtual会将其在pkmap_count中的对应项设为1,并将映射关系写进hashtable.返回又将对应数组项加1.所以有一个人使用,pkmap_count里的对应值就为2.
如果第二次又有人映射这个page frame,由于page_address可以在hashtable找到映射关系,vaddr是有效值,不会进入if ,pkmap_count里对应项值再加1.
删除映射的时候,仅仅将pkmap_count里对应项值减一.假设只有一个人使用之,本来可以马上解除映射并flush tlb,但这里尽量延迟做这件事.pkmap_count里为1的项都是这种情况.这时,映射依然有效,hashtable中依然有其映射记录,tlb中依然有其映射缓存.映射其它page frame时会跳过这些地址.这样做就是期待同样的page frame再一次被映射,由于hashtable中的记录未被删除,同样的page frame再度被映射时还是会跳过那个if (虽然从逻辑上来看映射已经被解除了),tlb中的项还可以继续用,这就达到了优化作用.
但不可能一直这样等待,总会发生虚拟地址用完的情况,这时就放弃等待,扫描整个pkmap_count,把其中值为1的项置0,删除hasntable中的记录,flush对应的tlb项,此时才算是真正解除了映射.所以,形式上解除映射的kunmap_high还有一个任务是看有没有进程在等待使用虚拟地址,有的话就将其唤醒.当然它们还是会先从pkmap_count中值为0的项开始找起,但最终会发现无可用项,于是调用flush_all_zero_pkmaps( )清除那些pkmap_count值为1的项. |
|