国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Linux內存管理--高端內存映射與非連續內存分配

系統 Linux
返回頁框線性地址的頁分配函數對于高端內存是無效的,因為高端內存不會自動的映射到某個線性地址。內核可以采用三種方式來使用高端物理內存:永久內核映射,臨時內核映射和非連續內存分配。

對于32位的機器來說,高于896的物理內存在內核中屬于高端內存,并沒有對內存做一一的映射,系統保留了128M的線性地址空間來臨時映射這些高于896M的高端物理內存,該線性地址為3G+768m~4G。返回頁框線性地址的頁分配函數對于高端內存是無效的,因為高端內存不會自動的映射到某個線性地址。例如__get_free_pages(GFP_HIGH_MEM,0)函數分配高端內存頁框時,返回的是NULL;內核可以采用三種方式來使用高端物理內存:***內核映射,臨時內核映射和非連續內存分配。建立***內核映射可能會阻塞當前進程的執行,這發生在沒有高端內存沒有空閑的頁表項來做映射的情況下,因此在中斷等不能阻塞的代碼中不要使用***內核映射。臨時內核映射不會發生阻塞的情況,但必須保證沒有其他的內核路徑在使用同樣的臨時內核映射。


一、***內存映射

***內核映射使用的是內核主頁表中的一個專門的頁表,其地址存放在pkmap_page_table中,頁表的頁表項由宏LAST_PKMAP產生,頁表中包含512或者1024項。

該頁表映射的線性地址從PKMAP_BASE開始,pkmap_count數組包含了LAST_PKMAP個計數器,pkmap_page_table頁表中的每項都有對應一個計數值:

計數器為0:對應的頁表項是空閑可用的。

計數器為1:對應的頁表項沒有映射任何高端內存,但是它不能夠使用,因為自從***一次使用以來,其相應的TLB尚未被刷新。

計數器為n:有多個內核成分使用該頁表項所對應的頁框。

源碼分析:

  1. void fastcall *kmap_high(struct page *page) 
  2. unsigned long vaddr; 
  3.  
  4.  
  5. spin_lock(&kmap_lock); 
  6. //page->virtual記錄了頁框對應的線性地址 
  7. vaddr = (unsigned long)page_address(page); 
  8. //若頁框未被映射過,分配新的空閑頁表項 
  9. if (!vaddr) 
  10. vaddr = map_new_virtual(page); 
  11. //若是剛分配到了空閑頁表項的話,在map_new_virtual()中其count 
  12. //值被設置為了1,在這里再次++ 
  13. pkmap_count[PKMAP_NR(vaddr)]++; 
  14. BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 2); 
  15. spin_unlock(&kmap_lock); 
  16. return (void*) vaddr; 
  17. static inline unsigned long map_new_virtual(struct page *page) 
  18. unsigned long vaddr; 
  19. int count; 
  20.  
  21.  
  22. start: 
  23. count = LAST_PKMAP; 
  24. //尋找一個空的頁表項 
  25. for (;;) { 
  26. //從上一次找到的空閑頁表項的位置開始尋找 
  27. last_pkmap_nr = (last_pkmap_nr + 1) & LAST_PKMAP_MASK; 
  28. if (!last_pkmap_nr) { 
  29. flush_all_zero_pkmaps(); 
  30. count = LAST_PKMAP; 
  31. //找到一個未用的空閑頁表項 
  32. if (!pkmap_count[last_pkmap_nr]) 
  33. break;  /* Found a usable entry */ 
  34. //count變為0的話,意味著當前沒有空閑的頁表項 
  35. if (--count) 
  36. continue
  37. //沒有找到空閑的頁表項,將當前進程加入到等待隊列,進行調度,直到 
  38. //有空閑的頁表項或者該頁面被別人映射 
  39. DECLARE_WAITQUEUE(wait, current); 
  40.  
  41.  
  42. __set_current_state(TASK_UNINTERRUPTIBLE); 
  43. add_wait_queue(&pkmap_map_wait, &wait); 
  44. spin_unlock(&kmap_lock); 
  45. schedule(); 
  46. remove_wait_queue(&pkmap_map_wait, &wait); 
  47. spin_lock(&kmap_lock); 
  48. //有可能在該進程睡眠期間,有其它進程對該頁面做了內存映射 
  49. if (page_address(page)) 
  50. return (unsigned long)page_address(page); 
  51.  
  52.  
  53. /* Re-start */ 
  54. goto start; 
  55. //得到對應頁表項對應的線性地址 
  56. vaddr = PKMAP_ADDR(last_pkmap_nr); 
  57. //設置對應的頁表項 
  58. set_pte_at(&init_mm, vaddr, 
  59.   &(pkmap_page_table[last_pkmap_nr]), mk_pte(page, kmap_prot)); 
  60. //設置***內存映射數組的值 
  61. pkmap_count[last_pkmap_nr] = 1; 
  62. //將page->virtual的值設為vaddr,ok 
  63. set_page_address(page, (void *)vaddr); 
  64.  
  65.  
  66. return vaddr; 

二、臨時內核映射

臨時內核映射比較簡單,在內核中,為每個cpu都保存了一組頁表項,每個頁表項由一個特定的內核成分使用,需要注意的是,不同的內核控制路徑不應該同時使用一個頁表項,這樣的話,會使后一個內核控制路徑將前一個內核控制路徑設置頁表項給沖掉。

建立臨時內核映射使用kmap_atomic()函數。

  1. void *__kmap_atomic(struct page *page, enum km_type type) 
  2. enum fixed_addresses idx; 
  3. unsigned long vaddr; 
  4.  
  5.  
  6. //禁止內核搶占,以預防不同內核控制路徑使用同一頁表項 
  7. inc_preempt_count(); 
  8. //非高端內存,不用進行高端內存映射 
  9. if (!PageHighMem(page)) 
  10. return page_address(page); 
  11. //得到使用的頁表項的下表索引 
  12. idx = type + KM_TYPE_NR*smp_processor_id(); 
  13. //得到相關頁表項的線性地址 
  14. vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); 
  15. //設置對應的頁表項 
  16. set_pte(kmap_pte-idx, mk_pte(page, kmap_prot)); 
  17. local_flush_tlb_one((unsigned long)vaddr); 
  18.  
  19.  
  20. return (void*) vaddr; 

三、非連續內存分配

下圖顯示了如何使用高于0xc0000000線性地址的線性地址空間:

  1. 內存區的開始部分包含的是對前896MB的RAM進行映射的線性地址,直接映射的物理內存的末尾的線性地址保存在high_memory變量中。
  2. 內存區的結尾位置包含的是固定映射的線性地址。
  3. 從PKMAP_BASE開始,是用于高端內存***映射的線性地址。
  4. 其余的線性地址用于非連續內存區,在物理內存映射和***個內存區間有一個8M的安全區,用于捕捉對內存的越界訪問,同樣道理,插入其它4KB大小的內存區來隔離非連續內存區。

非連續內存區描述符數據結構:

  1. struct vm_struct { 
  2. void     *addr;//內存區***個內存單元的線性地址 
  3. unsigned long    size;//內存區的大小加上4K,4K是用來檢查越界的內存 
  4. unsigned long     flags;//非連續內存的類型,VM_ALLOC表示使用vmalloc分配的內存,VM_MAP表示使用vmap分配的內存, 
  5.      //VM_IOREMAP表示用ioremap()分配的內存 
  6. struct page  **pages;//非連續內存的的物理頁數組 
  7. unsigned int     nr_pages;//非連續內存的物理頁的個數 
  8. unsigned long    phys_addr; 
  9. struct vm_struct    *next;//用來將各個非連續內存描述符串聯起來 
  10. }; 

1、分配非連續的內存區

分配函數主要是vmalloc(),vmap(),vmalloc()會去調用__vmalloc_node()函數:

  1. void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot, 
  2. int node) 
  3. struct vm_struct *area; 
  4. //size要對其為4K的整數倍,因為非連續內存區域是將各個物理頁進行映射 
  5. size = PAGE_ALIGN(size); 
  6. if (!size || (size >> PAGE_SHIFT) > num_physpages) 
  7. return NULL; 
  8. //找到一塊空閑的線性地址區域,用來映射該非連續內存 
  9. area = get_vm_area_node(size, VM_ALLOC, node); 
  10. if (!area) 
  11. return NULL; 
  12.  
  13.  
  14. return __vmalloc_area_node(area, gfp_mask, prot, node); 
  15.  
  16.  
  17. void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask, 
  18. pgprot_t prot, int node) 
  19. struct page **pages; 
  20. unsigned int nr_pages, array_size, i; 
  21. //計算要映射的物理頁數 
  22. nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT; 
  23. //計算vm_struct中pages數組的數組元素個數 
  24. array_size = (nr_pages * sizeof(struct page *)); 
  25. //記錄下物理頁面的數目 
  26. area->nr_pages = nr_pages; 
  27. //為vm_struct中的pages數組分配內存 
  28. if (array_size > PAGE_SIZE) { 
  29. pages = __vmalloc_node(array_size, gfp_mask, PAGE_KERNEL, node); 
  30. area->flags |= VM_VPAGES; 
  31. else 
  32. pages = kmalloc_node(array_size, (gfp_mask & ~__GFP_HIGHMEM), node); 
  33. area->pages = pages; 
  34. if (!area->pages) { 
  35. remove_vm_area(area->addr); 
  36. kfree(area); 
  37. return NULL; 
  38. memset(area->pages, 0, array_size); 
  39. //為非連續內存進行頁面的分配,每次分配一個頁面,將其頁框指針記錄在pages數組中 
  40. for (i = 0; i < area->nr_pages; i++) { 
  41. if (node < 0) 
  42. area->pages[i] = alloc_page(gfp_mask); 
  43. else 
  44. area->pages[i] = alloc_pages_node(node, gfp_mask, 0); 
  45. if (unlikely(!area->pages[i])) { 
  46. /* Successfully allocated i pages, free them in __vunmap() */ 
  47. area->nr_pages = i; 
  48. goto fail; 
  49. //將各個物理頁框映射到分配好的空閑線性區里面去 
  50. if (map_vm_area(area, prot, &pages)) 
  51. goto fail; 
  52. return area->addr; 
  53.  
  54.  
  55. fail: 
  56. vfree(area->addr); 
  57. return NULL; 

__vmalloc_node()并不觸及當前進程的頁表,因此當內核態進程訪問非連續內存區時,會發生缺頁異常,因為對應的進程的相應地址對應的頁表項為空。當缺頁異常發生時,異常處理程序會到內核主頁表(init_mm.pgd頁全局目錄)中去查看是否有對應的頁表項,有的話,就會修改當前進程的頁表項,并繼續進程的執行。

2、釋放非連續的內存區

  1. void vfree(void *addr) 
  2. BUG_ON(in_interrupt()); 
  3. __vunmap(addr, 1); 
  4. void __vunmap(void *addr, int deallocate_pages) 
  5. struct vm_struct *area; 
  6.  
  7.  
  8. if (!addr) 
  9. return
  10. //釋放的地址應該是4k的整數倍 
  11. if ((PAGE_SIZE-1) & (unsigned long)addr) { 
  12. printk(KERN_ERR "Trying to vfree() bad address (%p)\n", addr); 
  13. WARN_ON(1); 
  14. return
  15. //移除對應的vm_area數據描述符,解除對各個物理頁面的頁面映射項 
  16. area = remove_vm_area(addr); 
  17. if (unlikely(!area)) { 
  18. printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n"
  19. addr); 
  20. WARN_ON(1); 
  21. return
  22.  
  23.  
  24. debug_check_no_locks_freed(addr, area->size); 
  25. //需要向伙伴系統歸還非連續的物理頁 
  26. if (deallocate_pages) { 
  27. int i; 
  28. //將各個物理頁面歸還給伙伴系統 
  29. for (i = 0; i < area->nr_pages; i++) { 
  30. BUG_ON(!area->pages[i]); 
  31. __free_page(area->pages[i]); 
  32.  
  33.  
  34. if (area->flags & VM_VPAGES) 
  35. vfree(area->pages); 
  36. else 
  37. kfree(area->pages); 
  38.  
  39.  
  40. kfree(area); 
  41. return

與vmalloc()一樣,該函數修改的是主內核頁全局目錄和它的頁表表項,內核永遠不會回收頁全局,頁上級,頁中間目錄,也不會回收頁表,而進程的頁表會指向這些表項。這樣的話,假設一個內核進程訪問已經釋放的非連續內存,最終就會訪問到已經被清空的頁表表項,從而引發缺頁異常,這就是一個錯誤。

責任編輯:奔跑的冰淇淋 來源: ChinaUnix博客
相關推薦

2009-10-19 09:45:06

linux內存存管理

2023-10-18 13:31:00

Linux內存

2018-05-18 09:07:43

Linux內核內存

2013-10-12 11:15:09

Linux運維內存管理

2013-10-11 17:32:18

Linux運維內存管理

2011-12-20 10:43:21

Java

2025-06-09 04:00:00

2009-06-03 15:52:34

堆內存棧內存Java內存分配

2021-07-14 10:00:32

Python內存測量

2018-07-23 09:26:08

iOS內存優化

2024-11-07 09:37:46

2009-06-16 11:11:07

Java內存管理Java內存泄漏

2021-10-15 08:51:09

Linux內存 Kmalloc

2023-09-05 09:36:19

2021-04-27 13:56:49

內存.映射地址

2025-07-01 02:25:00

2022-03-07 10:54:34

內存Linux

2022-08-08 08:31:00

Linux內存管理

2013-03-28 09:55:37

Java對象

2017-05-18 16:30:29

Linux內存管理
點贊
收藏

51CTO技術棧公眾號

亚洲欧洲国产精品久久| 久久久久久久综合| 国产福利影院在线观看| 精品日韩一区二区| **女人18毛片一区二区| 麻豆av免费在线| 5566中文字幕一区二区电影| 国产精品传媒精东影业在线| 少妇激情一区二区三区| 夜夜嗨av一区二区三区四区| 国产欧美精品| 青青视频在线观| 欧美在线视频免费观看| 欧美国产精品v| 亚洲天堂1区| 亚洲欧美久久234| 在线不卡欧美精品一区二区三区| 欧美日韩国产免费观看视频| 天堂在线资源视频| 不卡毛片在线看| 国产91丝袜在线18| 美女91在线看| 神马影院午夜我不卡影院| 色屁屁一区二区| 欧美日韩精品一区二区视频| 人妻夜夜添夜夜无码av | 亚洲国产成人精品视频| 第一区第二区在线| 少妇高潮毛片色欲ava片| 中文字幕亚洲精品| 国产美女主播视频一区| 欧美理论电影| 日本中文不卡| 8x8x8国产精品| 亚洲第一区色| 久久久资源网| 超碰97人人人人人蜜桃| 欧美视频专区一二在线观看| 99久久夜色精品国产亚洲1000部| 偷偷要色偷偷| 国产精品亚洲美女av网站| 亚洲大片一区二区三区| 中文字幕日韩欧美精品高清在线| 无圣光视频在线观看| 96sao精品视频在线观看| 第一福利永久视频精品 | 日本人妻伦在线中文字幕| 欧美激情综合| 最近免费中文字幕中文高清百度| 久久久中精品2020中文| 一区二区三区日韩| 亚洲视屏一区| 成年人国产在线观看| 浮妇高潮喷白浆视频| 欧美一区二区三区免费观看| 欧美日韩午夜剧场| 蜜臀a∨国产成人精品| 天天综合在线观看| 国产导航在线| 久久久一本精品99久久精品| 亚洲美女视频网| 国产欧美日韩精品在线| 日韩一区欧美| 俺来俺也去www色在线观看| 亚洲国产精品久久久久婷蜜芽| 国产精品福利在线观看| 日韩精品专区在线影院观看| 久久综合久久99| 偷偷www综合久久久久久久| 69av成人| 男男做性免费视频网| 久久av二区| 久久中文字幕在线视频| 一本一道波多野结衣一区二区| 久久精品久久精品| 亚洲素人在线| av资源网在线播放| 黄色成人av| 亚洲免费一在线| 亚洲福利av在线| a视频免费看| 国产视频在线视频| 日韩video| 国产精品电影| 91在线免费网站| 未来日记在线观看| 狠久久av成人天堂| 欧美华人在线视频| 精品乱码一区二区三区| 亚洲一区二区三区在线观看视频 | 91高清视频在线| 91麻豆精品国产91久久久| 日本伊人精品一区二区三区介绍 | 国产专区中文字幕| 欧美性bbwbbwbbwhd| 国内精品久久久久久久| 制服丝袜激情欧洲亚洲| 日本一区二区在线不卡| 亚洲一区二区免费看| 亚洲精品在线播放| 在线欧美三级| 97国产在线| 免费超爽大片黄| 国产伦精品一区二区三毛| 高清一区二区三区四区五区| 亚洲国产精品成人av| 岛国av在线不卡| 久久久久久久av麻豆果冻| 噜噜噜91成人网| 日本不卡二三区| 日本伊人久久| 性欧美18~19sex高清播放| 亚洲字幕成人中文在线观看| 日韩精品视频一区二区在线观看| 麻豆av福利av久久av| 国产97在线|日韩| 久久中文字幕在线| 日韩精品极品视频免费观看| 欧美日韩一区二区三区免费看 | 国产欧美123| 国产久一道中文一区| 538国产精品一区二区在线| 亚洲色图校园春色| 欧美一级二级在线观看| 疯狂欧美牲乱大交777| 国产精品国产三级国产aⅴ中文| 狠狠网亚洲精品| 国产精品视频| 在线精品国产| 日韩影视高清在线观看| 精品亚洲a∨一区二区三区18| sm性调教片在线观看| 五月天婷婷在线视频| 午夜视频在线观看韩国| 狠狠躁狠狠躁视频专区| 日本中文字幕网址| 特大黑人娇小亚洲女mp4| 图片区小说区区亚洲五月| 国产亚洲精品自在久久| 91欧美激情另类亚洲| 国产精品伦子伦免费视频| 91av视频在线播放| 欧美激情乱人伦一区| zzjj国产精品一区二区| 国产亚洲一区二区在线| 亚洲欧美精品suv| 亚洲国产精品va在线| 精品国产91乱码一区二区三区| 欧美一区二区美女| 91精品国产综合久久婷婷香蕉| 欧美亚洲一区三区| 狠狠综合久久av一区二区小说| 亚洲图片自拍偷拍| 亚洲一区日韩精品中文字幕| 亚洲免费观看高清完整版在线 | 亚洲人成伊人成综合网小说| 久久久综合视频| 久久男人中文字幕资源站| 国产一区在线观看麻豆| 国产精品一区二区无线| 国产不卡视频在线播放| av电影一区二区| 久久精品夜色噜噜亚洲aⅴ| 91一区一区三区| 97久久精品人人爽人人爽蜜臀| 99精品桃花视频在线观看| 95精品视频在线| 日本一区二区三区四区在线视频| 国产精品蜜臀在线观看| 亚洲精品国产第一综合99久久| 一区二区三区免费网站| 五月天一区二区| 在线中文字幕不卡| 欧美日韩在线播| 日韩午夜三级在线| 亚洲美女性生活视频| 在线免费观看羞羞视频一区二区| 亚洲欧美日韩精品久久亚洲区| 国产亚洲精品久久久优势| 日韩在线中文字| 国产综合在线视频| 欧美亚洲另类制服自拍| 国产主播精品在线| 韩国成人av| 异国色恋浪漫潭| 精品视频一区二区在线| 写真福利片hd在线观看| 国产精品久久久久一区二区国产| chinese偷拍一区二区三区| 里番在线播放| 小说区图片区亚洲| 国产精品入口久久| 精品1区2区3区4区| 国模无码大尺度一区二区三区| 91免费观看视频在线| 一区二区高清在线| 在线91免费看| 久久精品最新地址| 国产在线观看不卡| 亚洲资源在线网|