免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1343 | 回复: 1
打印 上一主题 下一主题

linux高端内存管理之临时内核映射 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-01-05 19:03 |只看该作者 |倒序浏览
linux高端内存管理之临时内核映射









临时内核映射区属于高端内存中的固定内核映射区中的一部分。当必须创建一个映射而当前的上下文又不能睡眠时,内核提供了临时映射(也就是所谓的原子映射)。有一组保留的映射,他们可以存放新创建的临时映射。内核可以原子地把高端内存中的一个页映射到某个保留的映射中。因此,临时映射可以用在不能睡眠的地方,比如中断处理程序中,因为获取映射时绝不会阻塞。


每个CPU都有他自己的窗口集合,他们用enum km_type数据结构表示。该数据结构中定义的每个符号,如KM_BOUNCE_READ、KM_USER0等标示了窗口的线性地址。
  1. view plaincopy to clipboardprint?enum km_type {  
  2. KMAP_D(0)   KM_BOUNCE_READ,  
  3. KMAP_D(1)   KM_SKB_SUNRPC_DATA,  
  4. KMAP_D(2)   KM_SKB_DATA_SOFTIRQ,  
  5. KMAP_D(3)   KM_USER0,  
  6. KMAP_D(4)   KM_USER1,  
  7. KMAP_D(5)   KM_BIO_SRC_IRQ,  
  8. KMAP_D(6)   KM_BIO_DST_IRQ,  
  9. KMAP_D(7)   KM_PTE0,  
  10. KMAP_D(8)   KM_PTE1,  
  11. KMAP_D(9)   KM_IRQ0,  
  12. KMAP_D(10)  KM_IRQ1,  
  13. KMAP_D(11)  KM_SOFTIRQ0,  
  14. KMAP_D(12)  KM_SOFTIRQ1,  
  15. KMAP_D(13)  KM_SYNC_ICACHE,  
  16. KMAP_D(14)  KM_SYNC_DCACHE,  
  17. /* UML specific, for copy_*_user - used in do_op_one_page */  
  18. KMAP_D(15)  KM_UML_USERCOPY,  
  19. KMAP_D(16)  KM_IRQ_PTE,  
  20. KMAP_D(17)  KM_NMI,  
  21. KMAP_D(18)  KM_NMI_PTE,  
  22. KMAP_D(19)  KM_TYPE_NR  
  23. };  
  24. enum km_type {
  25. KMAP_D(0)        KM_BOUNCE_READ,
  26. KMAP_D(1)        KM_SKB_SUNRPC_DATA,
  27. KMAP_D(2)        KM_SKB_DATA_SOFTIRQ,
  28. KMAP_D(3)        KM_USER0,
  29. KMAP_D(4)        KM_USER1,
  30. KMAP_D(5)        KM_BIO_SRC_IRQ,
  31. KMAP_D(6)        KM_BIO_DST_IRQ,
  32. KMAP_D(7)        KM_PTE0,
  33. KMAP_D(8)        KM_PTE1,
  34. KMAP_D(9)        KM_IRQ0,
  35. KMAP_D(10)        KM_IRQ1,
  36. KMAP_D(11)        KM_SOFTIRQ0,
  37. KMAP_D(12)        KM_SOFTIRQ1,
  38. KMAP_D(13)        KM_SYNC_ICACHE,
  39. KMAP_D(14)        KM_SYNC_DCACHE,
  40. /* UML specific, for copy_*_user - used in do_op_one_page */
  41. KMAP_D(15)        KM_UML_USERCOPY,
  42. KMAP_D(16)        KM_IRQ_PTE,
  43. KMAP_D(17)        KM_NMI,
  44. KMAP_D(18)        KM_NMI_PTE,
  45. KMAP_D(19)        KM_TYPE_NR
  46. };
  47. 在km_type中的每个符号(除了最后一个)都是固定映射的线性地址的一个下标。enum fixed_addressed数据结构包含符号FIX_KMAP_BEGIN和FIX_KMAP_END;把后者的值赋成下标FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1。在这种方式下,系统中的每个CPU都有KM_TYPE_NR个固定映射的线性地址。

  48. view plaincopy to clipboardprint?enum fixed_addresses {  
  49.    ……  
  50. FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */  
  51. FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,  
  52.    ……  
  53. }  
  54. enum fixed_addresses {
  55.    ……
  56. FIX_KMAP_BEGIN,        /* reserved pte's for temporary kernel mappings */
  57. FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
  58.    ……
  59. }
复制代码
临时内核映射的建立

内核调用kmap_atomic()函数
  1. view plaincopy to clipboardprint?用数学公式来避免混乱,他空间有限且虚拟地址固定,这意味着他映射的内存空间不能被  
  2. 长时间占用,而不被unmap,在效率上比kmap提升不少,然而他和kmap不是用于统一  
  3. 场合的,  
  4. **/  
  5. void *kmap_atomic(struct page *page, enum km_type type)  
  6. {  
  7.     return kmap_atomic_prot(page, type, kmap_prot);  
  8. }  
  9. 用数学公式来避免混乱,他空间有限且虚拟地址固定,这意味着他映射的内存空间不能被
  10. 长时间占用,而不被unmap,在效率上比kmap提升不少,然而他和kmap不是用于统一
  11. 场合的,
  12. **/
  13. void *kmap_atomic(struct page *page, enum km_type type)
  14. {
  15.         return kmap_atomic_prot(page, type, kmap_prot);
  16. }view plaincopy to clipboardprint?/*
  17. * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because
  18. * no global lock is needed and because the kmap code must perform a global TLB
  19. * invalidation when the kmap pool wraps.
  20. *
  21. * However when holding an atomic kmap it is not legal to sleep, so atomic
  22. * kmaps are appropriate for short, tight code paths only.
  23. */  
  24. void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)  
  25. {  
  26.     enum fixed_addresses idx;  
  27.     unsigned long vaddr;  
  28.   
  29.     /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */  
  30.     /**原子映射是基于每个cpu的,因此在当前cpu上应用抢占,直到unmap的时候才
  31.     开启,这样不会导致原子映射的重入了,
  32.     */  
  33.     pagefault_disable();  
  34.   
  35.     if (!PageHighMem(page))  
  36.         return page_address(page);  
  37.   
  38.     /* 递增type,保证下面公式起作用 */  
  39.     debug_kmap_atomic(type);  
  40.     /*
  41.     kernel可以在多个cpu上同时运行不同的task,然而他们共同使用一个内存地址空间,
  42.     也就是说,内存空间对于多个cpu看到的是同一个,该函数使用的是地址空间中顶部的
  43.     一小段地址空间,也就是临时映射区,内核逻辑将这一小段地址空间分成若干各节
  44.     每一节的大小是一个页面的大小,可以映射一个页面,根据公用地址空间的原理
  45.     所有的cpu共同使用这些节,因此如何能保证N个cpu调用此函数不会将page映射到   一个地址呢,这就是这个数学公式所起到的作用
  46.     */  
  47.     idx = type + KM_TYPE_NR*smp_processor_id();  
  48.     vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);  
  49.     /*这里为什么是减法
  50.     越靠前的枚举项对应的线性地址越靠后*/  
  51.     BUG_ON(!pte_none(*(kmap_pte-idx)));  
  52.     /*设置pte*/  
  53.     set_pte(kmap_pte-idx, mk_pte(page, prot));  
  54.   
  55.     return (void *)vaddr;  
  56. }  
  57. /*
  58. * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because
  59. * no global lock is needed and because the kmap code must perform a global TLB
  60. * invalidation when the kmap pool wraps.
  61. *
  62. * However when holding an atomic kmap it is not legal to sleep, so atomic
  63. * kmaps are appropriate for short, tight code paths only.
  64. */
  65. void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
  66. {
  67.         enum fixed_addresses idx;
  68.         unsigned long vaddr;

  69.         /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
  70.         /**原子映射是基于每个cpu的,因此在当前cpu上应用抢占,直到unmap的时候才
  71.         开启,这样不会导致原子映射的重入了,
  72.         */
  73.         pagefault_disable();

  74.         if (!PageHighMem(page))
  75.                 return page_address(page);

  76.         /* 递增type,保证下面公式起作用 */
  77.         debug_kmap_atomic(type);
  78.         /*
  79.         kernel可以在多个cpu上同时运行不同的task,然而他们共同使用一个内存地址空间,
  80.         也就是说,内存空间对于多个cpu看到的是同一个,该函数使用的是地址空间中顶部的
  81.         一小段地址空间,也就是临时映射区,内核逻辑将这一小段地址空间分成若干各节
  82.         每一节的大小是一个页面的大小,可以映射一个页面,根据公用地址空间的原理
  83.         所有的cpu共同使用这些节,因此如何能保证N个cpu调用此函数不会将page映射到        一个地址呢,这就是这个数学公式所起到的作用
  84.         */
  85.         idx = type + KM_TYPE_NR*smp_processor_id();
  86.         vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
  87.         /*这里为什么是减法
  88.         越靠前的枚举项对应的线性地址越靠后*/
  89.         BUG_ON(!pte_none(*(kmap_pte-idx)));
  90.         /*设置pte*/
  91.         set_pte(kmap_pte-idx, mk_pte(page, prot));

  92.         return (void *)vaddr;
  93. }view plaincopy to clipboardprint?#define __fix_to_virt(x)    (FIXADDR_TOP - ((x) << PAGE_SHIFT))  
  94. #define __fix_to_virt(x)        (FIXADDR_TOP - ((x) << PAGE_SHIFT))
复制代码
撤销临时映射

kunmap_atomic(),这个函数减少当前进程的preempt_count;因此,如果在请求临时内核映像之前能抢占内核控制路径,那么在同一个映像被撤销后可以再次抢占。

论坛徽章:
0
2 [报告]
发表于 2012-01-05 19:04 |只看该作者
谢谢分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP