0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

mmap系統(tǒng)調(diào)用和vmalloc獲取地址空間

Linux閱碼場 ? 來源:工程師曾玲 ? 2019-02-02 16:13 ? 次閱讀

mmap()系統(tǒng)調(diào)用是在用戶進程與內(nèi)核之間共享內(nèi)存區(qū)域的常用方法。我們最近有個程序,需要應(yīng)用進程能夠讀取內(nèi)核驅(qū)動獲取的數(shù)據(jù),經(jīng)過簡單的調(diào)研,決定采用mmap方式。實現(xiàn)起來不難,在驅(qū)動中注冊一個字符設(shè)備,實現(xiàn)該設(shè)備的mmap()方法即可。但這其中有一點小曲折。

在實現(xiàn)設(shè)備的mmap()方法時,需要將物理內(nèi)存映射到應(yīng)用程序通過mmap()系統(tǒng)調(diào)用傳下來的vma中。vma代表的是進程的一段虛擬地址空間。在第一版里,考慮的不全面,利用alloc_pages()將整個內(nèi)存段申請為一段連續(xù)的物理地址空間。然后通過remap_pfn_range()函數(shù)將這段連續(xù)的物理內(nèi)存映射到vma中。經(jīng)過長時間的測試,沒有發(fā)現(xiàn)問題。直到今天,在部署一個老集群時,遇到了問題。這個集群中有很多老機器,內(nèi)存只有十多個G,而且長時間運行后產(chǎn)生了大量的內(nèi)存碎片。從而導致,我們無法獲得足夠的連續(xù)物理內(nèi)存。沒辦法,只好重新調(diào)整驅(qū)動中分配內(nèi)存的方式,改用vmalloc獲取地址空間。

在kernel里,通常有3種申請內(nèi)存的方式:vmalloc, kmalloc, alloc_pages。kmalloc與alloc_pages類似,均是申請連續(xù)的地址空間。而vmalloc則可以申請一段不連續(xù)的物理地址空間,并將其映射到連續(xù)的線性地址上。每次vmalloc之后,內(nèi)核會創(chuàng)建一個vm_struct,用以映射分配到的不連續(xù)的內(nèi)存區(qū)域。vm_struct類似vma,但是又不是一回事。vma是將物理內(nèi)存映射到進程的虛擬地址空間。而vm_struct是將物理內(nèi)存映射到內(nèi)核的線性地址空間。

既然vmalloc拿到的不是連續(xù)的物理內(nèi)存,那么將這些內(nèi)存映射到vma時,就不能直接利用remap_pfn_range()了。

此時可以采用兩種方法,一種是實現(xiàn)vm_operations_struct的fault()方法,用以在缺頁時再映射需要的頁。此方法操作起來較為麻煩。

另一種方法是直接使用remap_vmalloc_range()函數(shù)。該函數(shù)的原型為:

int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,unsigned long pgoff)

其中參數(shù)vma是mmap使用調(diào)用傳下來的,addr即為vmalloc()所分配內(nèi)存的起始地址。而pgoff則為mmap()系統(tǒng)調(diào)用里的偏移參數(shù),可以通過vma->vm_pgoff獲得。該函數(shù)成功執(zhí)行后,返回值為0。如果返回值為負數(shù),則說明出錯了。通常是由于所傳的參數(shù)不正確。

需要注意的是,需要映射到用戶空間的內(nèi)存段,不能直接利用vmalloc()分配,而應(yīng)該使用vmalloc_user()函數(shù)。該函數(shù)除了分配內(nèi)存之外,還會將相應(yīng)的vm_struct結(jié)構(gòu)標記為VM_USERMAP。否則,remap_vmalloc_range將返回錯誤。

在這個項目中碰到的教訓是,永遠不要假設(shè)系統(tǒng)中一定會有超過一個頁的連續(xù)物理內(nèi)存。

不過較新的內(nèi)核具有compact機制,可以整理內(nèi)存碎片。但是,目前至少有一大部分機器不支持,或未開啟此機制。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 內(nèi)核
    +關(guān)注

    關(guān)注

    3

    文章

    1336

    瀏覽量

    40084
  • 內(nèi)存
    +關(guān)注

    關(guān)注

    8

    文章

    2903

    瀏覽量

    73541
  • malloc
    +關(guān)注

    關(guān)注

    0

    文章

    52

    瀏覽量

    54

原文標題:vmalloc與mmap

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    linux內(nèi)核系統(tǒng)調(diào)用之參數(shù)傳遞

    與普通函數(shù)一樣,系統(tǒng)調(diào)用通常需要一些輸入/輸出參數(shù),這些參數(shù)可能包括實際值(即數(shù)字)、用戶模式進程地址空間中的變量地址,甚至包括指向用戶模式
    的頭像 發(fā)表于 12-20 09:32 ?975次閱讀

    拆解mmap內(nèi)存映射的本質(zhì)!

    mmap 內(nèi)存映射里所謂的內(nèi)存其實指的是虛擬內(nèi)存,在調(diào)用 mmap 進行匿名映射的時候(比如進行堆內(nèi)存的分配),是將進程虛擬內(nèi)存空間中的某一段虛擬內(nèi)存區(qū)域與物理內(nèi)存中的匿名內(nèi)存頁進行映
    的頭像 發(fā)表于 01-24 14:30 ?914次閱讀
    拆解<b class='flag-5'>mmap</b>內(nèi)存映射的本質(zhì)!

    Linux的mmap文件內(nèi)存映射機制

    一。mmap系統(tǒng)調(diào)用使得進程之間通過映射同一個普通文件實現(xiàn)共享內(nèi)存。普通文件被映射到進程地址空間后,進程可以像訪問普通內(nèi)存一樣對文件進行訪問
    發(fā)表于 03-08 09:54

    字符設(shè)備驅(qū)動另一種寫法—mmap方法操作LED

    。經(jīng)過自己的研究之后,我發(fā)現(xiàn)還有另外一種寫法,直接在應(yīng)用層操作,省去了內(nèi)核中的地址映射部分,使得用戶可以在應(yīng)用層直接操作LED。 mmap方法是把設(shè)備物理地址直接映射到用戶空間的一種
    發(fā)表于 01-02 17:38

    Linux用戶空間與內(nèi)核空間的區(qū)別?

    對于提供了MMU(存儲管理器,輔助操作系統(tǒng)進行內(nèi)存管理,提供虛實地址轉(zhuǎn)換等硬件支持)的處理器而言,Linux提供了復雜的存儲管理系統(tǒng),使得進程所能訪問的內(nèi)存達到4GB。進程的4GB內(nèi)存空間
    發(fā)表于 06-05 04:35

    labview 中怎么獲取數(shù)值的指針(地址)?調(diào)用dll時要往里面?zhèn)?b class='flag-5'>地址

    labview 中怎么獲取數(shù)值的指針(地址)?調(diào)試一個設(shè)備,調(diào)用dll時要往里面?zhèn)?b class='flag-5'>地址,看了官方.h文件,參考了官方的C#代碼,自己用labview試了試,老是不對,所以想先
    發(fā)表于 03-15 08:59

    linux drivers中的mmap實現(xiàn)

    將設(shè)備驅(qū)動內(nèi)核空間的內(nèi)存映射到用戶空間里,可以通過用戶空間中的mmap系統(tǒng)調(diào)用代替
    發(fā)表于 05-15 10:31 ?1561次閱讀

    Linux的mmap文件內(nèi)存映射機制

    IPC則純粹用于共享目的,當然mmap()實現(xiàn)共享內(nèi)存也是其主要應(yīng)用之一?! ?b class='flag-5'>mmap系統(tǒng)調(diào)用使得進程之間通過映射同一個普通文件實現(xiàn)共享內(nèi)存。普通文件被映射到進程
    發(fā)表于 04-02 14:35 ?396次閱讀

    如何主動調(diào)用獲取flag

    明明有強大的frida工具,可以無需過反調(diào)試,無需IDA去動靜態(tài)調(diào)試,無需獲取RC4密鑰,直接用主動調(diào)用獲取flag,何必走繁瑣的路呢?
    的頭像 發(fā)表于 10-10 09:44 ?3952次閱讀
    如何主動<b class='flag-5'>調(diào)用</b><b class='flag-5'>獲取</b>flag

    PCI總線地址空間系統(tǒng)地址空間的關(guān)系

    于PCI總線統(tǒng)一尋址。每個PCI設(shè)備通過PCI寄存器中的基地址寄存器來指定映射的首地址。PCI地址空間對應(yīng)于計算機系統(tǒng)結(jié)構(gòu)中的PCI總線。
    的頭像 發(fā)表于 01-06 08:30 ?2046次閱讀

    內(nèi)核mmap_sem鎖的危害和相關(guān)優(yōu)化

    mmap_sem鎖是進程為了保護自身虛擬地址空間不受多線程并發(fā)訪問影響而設(shè)計的。
    的頭像 發(fā)表于 02-07 16:01 ?607次閱讀

    Linux內(nèi)核之物理內(nèi)存組織結(jié)構(gòu)

    虛擬內(nèi)存區(qū)域使用起始地址和結(jié)束地址描述,鏈表按起始地址遞增排序。兩系統(tǒng)調(diào)用區(qū)別:mmap指定的偏
    的頭像 發(fā)表于 02-08 09:47 ?847次閱讀

    Linux應(yīng)用開發(fā)之共享內(nèi)存

    mmap() 系統(tǒng)調(diào)用調(diào)用進程的虛擬地址空間中創(chuàng)建一個新的內(nèi)存映射,映射分為兩種。
    的頭像 發(fā)表于 04-06 09:51 ?348次閱讀

    Linux虛擬地址空間和物理地址空間的關(guān)系

    過程,這其實也是MMU的工作原理。 我們知道,在Linux中,每個進程都有自己獨立的地址空間,且互不干擾。每個進程的地址空間又分為用戶空間
    的頭像 發(fā)表于 10-08 11:40 ?915次閱讀
    Linux虛擬<b class='flag-5'>地址</b><b class='flag-5'>空間</b>和物理<b class='flag-5'>地址</b><b class='flag-5'>空間</b>的關(guān)系

    mmap原理詳解

    一句話概括mmap mmap的作用,在應(yīng)用這一層,是讓你把文件的某一段,當作內(nèi)存一樣來訪問。將文件映射到物理內(nèi)存,將進程虛擬空間映射到那塊內(nèi)存。 這樣,進程不僅能像訪問內(nèi)存一樣讀寫文件,多個進程映射
    的頭像 發(fā)表于 11-09 14:59 ?563次閱讀
    <b class='flag-5'>mmap</b>原理詳解