Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1071451
  • 博文数量: 277
  • 博客积分: 8313
  • 博客等级: 中将
  • 技术积分: 2976
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-22 11:25
文章分类

全部博文(277)

文章存档

2013年(17)

2012年(66)

2011年(104)

2010年(90)

我的朋友

分类: LINUX

2012-05-16 10:20:11

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

每个CPU都有他自己的窗口集合,他们用enum km_type数据结构表示。该数据结构中定义的每个符号,如KM_BOUNCE_READKM_USER0等标示了窗口的线性地址。

[cpp] view plaincopyprint?

1.        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.      };  

km_type中的每个符号(除了最后一个)都是固定映射的线性地址的一个下标。enum fixed_addressed数据结构包含符号FIX_KMAP_BEGINFIX_KMAP_END;把后者的值赋成下标FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1。在这种方式下,系统中的每个CPU都有KM_TYPE_NR个固定映射的线性地址。

[cpp] view plaincopyprint?

1.        enum fixed_addresses {  

2.           ……  

3.        FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */  

4.        FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,  

5.           ……  

6.        }  

临时内核映射的建立

内核调用kmap_atomic()函数

[cpp] view plaincopyprint?

1.        用数学公式来避免混乱,他空间有限且虚拟地址固定,这意味着他映射的内存空间不能被  

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.        }  

[cpp] view plaincopyprint?

1.        /* 

2.         * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because 

3.         * no global lock is needed and because the kmap code must perform a global TLB 

4.         * invalidation when the kmap pool wraps. 

5.         * 

6.         * However when holding an atomic kmap it is not legal to sleep, so atomic 

7.         * kmaps are appropriate for short, tight code paths only. 

8.         */  

9.        void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)  

10.      {  

11.          enum fixed_addresses idx;  

12.          unsigned long vaddr;  

13.        

14.          /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */  

15.          /**原子映射是基于每个cpu的,因此在当前cpu上应用抢占,直到unmap的时候才 

16.          开启,这样不会导致原子映射的重入了, 

17.          */  

18.          pagefault_disable();  

19.        

20.          if (!PageHighMem(page))  

21.              return page_address(page);  

22.        

23.          /* 递增type,保证下面公式起作用 */  

24.          debug_kmap_atomic(type);  

25.          /* 

26.          kernel可以在多个cpu上同时运行不同的task,然而他们共同使用一个内存地址空间, 

27.          也就是说,内存空间对于多个cpu看到的是同一个,该函数使用的是地址空间中顶部的 

28.          一小段地址空间,也就是临时映射区,内核逻辑将这一小段地址空间分成若干各节 

29.          每一节的大小是一个页面的大小,可以映射一个页面,根据公用地址空间的原理 

30.          所有的cpu共同使用这些节,因此如何能保证Ncpu调用此函数不会将page映射到   一个地址呢,这就是这个数学公式所起到的作用 

31.          */  

32.          idx = type + KM_TYPE_NR*smp_processor_id();  

33.          vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);  

34.          /*这里为什么是减法 

35.          越靠前的枚举项对应的线性地址越靠后*/  

36.          BUG_ON(!pte_none(*(kmap_pte-idx)));  

37.          /*设置pte*/  

38.          set_pte(kmap_pte-idx, mk_pte(page, prot));  

39.        

40.          return (void *)vaddr;  

41.      }  

[cpp] view plaincopyprint?

1.        #define __fix_to_virt(x)    (FIXADDR_TOP - ((x) << PAGE_SHIFT))  

撤销临时映射

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

 

阅读(1166) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~