- 論壇徽章:
- 0
|
本帖最后由 kirapangzi 于 2013-08-27 17:03 編輯
自二樓指出我理解混淆后,決定深究源碼,找出問題所在。
概括下我的問題:怎樣才能獲取到這樣一段內(nèi)存的page*描述符?——它經(jīng)由memmap啟動參數(shù)保留,然后再ioremap出來獨自管理。
依照源碼所在,分拆開來:
首先,申明環(huán)境與內(nèi)核版本:Fedora 18,3.6.11,X86-64
1,memmap參數(shù)所保留的內(nèi)存,內(nèi)核啟動時,有沒有建立page*結(jié)構(gòu),來描述它?
a,內(nèi)核啟動后,調(diào)用setup_arch->setup_memory_map建立內(nèi)核的e820表,然后parse_early_param->parse_memmap_opt解析memmap=x$y參數(shù),將對應(yīng)的物理地址范圍修改為E820_RESERVED。
b,memblock_x86_fill將e820表中類型為E820_RAM|E820_RESERVED_KERN建立mem_block;
c,paging_init->sparse_memory_present_with_active_regions中,依照上述mem_block中的區(qū)域,填充mem_section全局?jǐn)?shù)組;
d,paging_init->sparse_init->sparse_early_mem_maps_alloc_node中,對當(dāng)前numa nodeid中每個mem_section做page *初始化;
——終于找到重點了,在這個調(diào)用路徑中,下述代碼申請了section中的struct page結(jié)構(gòu)的物理空間,而后以虛擬地址起始為vmemmap(ffffea0000000000)起,通過建立頁表項,映射到這些page結(jié)構(gòu)的物理地址;- unsigned long pnum;
- unsigned long size = sizeof(struct page) * PAGES_PER_SECTION;
- void *vmemmap_buf_start;
- size = ALIGN(size, PMD_SIZE);
- vmemmap_buf_start = __earlyonly_bootmem_alloc(nodeid, size * map_count,
- PMD_SIZE, __pa(MAX_DMA_ADDRESS));
- if (vmemmap_buf_start) {
- vmemmap_buf = vmemmap_buf_start;
- vmemmap_buf_end = vmemmap_buf_start + size * map_count;
- }
復(fù)制代碼 總結(jié):很明顯的,在內(nèi)核最終e820表被設(shè)置為reserved類型的物理地址空間,肯定是沒有建立上述page結(jié)構(gòu)。
一篇不錯的SPARSEMEM介紹文章:http://wangcong.org/blog/archives/2043
2,ioremap時,有沒有涉及到對這段物理地址空間的page*結(jié)構(gòu)操作?
走讀源碼路徑:__ioremap_caller->ioremap_page_range->...->ioremap_pte_range;該函數(shù)中,是針對指定的phys_addr構(gòu)建的pte。
總結(jié):ioremap指定的物理內(nèi)存,在ioremap的整個調(diào)用完成后,內(nèi)核也沒有為這片物理內(nèi)存建立struct page的管理結(jié)構(gòu);而只是建立了virt<->phys這樣的一個轉(zhuǎn)換關(guān)系;
3,如果采用vmalloc_to_page獲取到的page*,到底是何時建立的?
走讀源碼:通過virt_addr walk到pte、pfn后,通過pfn_to_page宏獲取到page *虛擬地址;也就是從前述vmemmap空間中直接線性偏移獲取一個虛擬地址返回;
如果vmalloc_to_page函數(shù)傳入的虛擬地址,內(nèi)核沒有建立page結(jié)構(gòu)的話,此時,page*僅僅只是一個虛擬地址、指針而已,而沒有實際的指向page結(jié)構(gòu);
那為何將這個page *賦值到bio下發(fā)后,底層驅(qū)動反而可以正常工作呢?此處感覺是因為scsi、ata層其實不會去更改page 結(jié)構(gòu)里面的具體數(shù)值,而只是通過page *虛擬地址再次獲取到phys而已;
瀏覽代碼初步驗證:
1,block lld:調(diào)用blk_rq_map_sg->..->sg_set_page;將page*轉(zhuǎn)換為sg->page_link;
2,ata lld/sas lld:調(diào)用dma_map_sg->...->sg_phys;將sg->page_link轉(zhuǎn)換成page*,再獲取到真實的物理地址用作dma;
-------------------------------------------------------------------------------------分割線(下面是舊帖,錯誤的內(nèi)容已經(jīng)刪除)
與X86-64相關(guān)的:
1,當(dāng)系統(tǒng)沒有了Highmem后,vmalloc的作用僅體現(xiàn)在將不連續(xù)的物理區(qū)映射為連續(xù)的virt地址;且是以page為最小單位的;
2,vmalloc、進(jìn)程的空間申請,都是打亂原有virt<->phys,線性映射關(guān)系,重新建立頁表項映射的過程; |
|