欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
從 Linux 內核訪(fǎng)問(wèn)用戶(hù)空間內存

Linux 內存

在 Linux中,用戶(hù)內存和內核內存是獨立的,在各自的地址空間實(shí)現。地址空間是虛擬的,就是說(shuō)地址是從物理內存中抽象出來(lái)的(通過(guò)一個(gè)簡(jiǎn)短描述的過(guò)程)。由于地址空間是虛擬的,所以可以存在很多。事實(shí)上,內核本身駐留在一個(gè)地址空間中,每個(gè)進(jìn)程駐留在自己的地址空間。這些地址空間由虛擬內存地址組成,允許一些帶有獨立地址空間的進(jìn)程指向一個(gè)相對較小的物理地址空間(在機器的物理內存中)。不僅僅是方便,而且更安全。因為每個(gè)地址空間是獨立且隔離的,因此很安全。

但是與安全性相關(guān)聯(lián)的成本很高。因為每個(gè)進(jìn)程(和內核)會(huì )有相同地址指向不同的物理內存區域,不可能立即共享內存。幸運的是,有一些解決方案。用戶(hù)進(jìn)程可以通過(guò) Portable Operating System Interface for UNIX® (POSIX)共享的內存機制(shmem)共享內存,但有一點(diǎn)要說(shuō)明,每個(gè)進(jìn)程可能有一個(gè)指向相同物理內存區域的不同虛擬地址。

虛擬內存到物理內存的映射通過(guò)頁(yè)表完成,這是在底層軟件中實(shí)現的(見(jiàn)圖1)。硬件本身提供映射,但是內核管理表及其配置。注意這里的顯示,進(jìn)程可能有一個(gè)大的地址空間,但是很少見(jiàn),就是說(shuō)小的地址空間的區域(頁(yè)面)通過(guò)頁(yè)表指向物理內存。這允許進(jìn)程僅為隨時(shí)需要的網(wǎng)頁(yè)指定大的地址空間。


圖 1. 頁(yè)表提供從虛擬地址到物理地址的映射

由于缺乏為進(jìn)程定義內存的能力,底層物理內存被過(guò)度使用。通過(guò)一個(gè)稱(chēng)為 paging(然而,在 Linux 中通常稱(chēng)為 swap)的進(jìn)程,很少使用的頁(yè)面將自動(dòng)移到一個(gè)速度較慢的存儲設備(比如磁盤(pán)),來(lái)容納需要被訪(fǎng)問(wèn)的其它頁(yè)面(見(jiàn)圖 2)。這一行為允許,在將很少使用的頁(yè)面遷移到磁盤(pán)來(lái)提高物理內存使用的同時(shí),計算機中的物理內存為應用程序更容易需要的頁(yè)面提供服務(wù)。注意,一些頁(yè)面可以指向文件,在這種情況下,如果頁(yè)面是臟(dirty)的,數據將被沖洗,如果頁(yè)面是干凈的(clean),直接丟掉。


圖 2. 通過(guò)將很少使用的頁(yè)面遷移到速度慢且便宜的存儲器,交換使物理內存空間得到了更好的利用

關(guān)于作者

MMU-less 架構

不是所有的處理器都有 MMU。因此,uClinux 發(fā)行版(微控制器 Linux)支持操作的一個(gè)地址空間。該架構缺乏 MMU 提供的保護,但是允許 Linux 運行另一類(lèi)處理器。關(guān)于 uClinux 的詳細信息見(jiàn) 參考資料。

選擇一個(gè)頁(yè)面來(lái)交換存儲的過(guò)程被稱(chēng)為一個(gè)頁(yè)面置換算法,可以通過(guò)使用許多算法(至少是最近使用的)來(lái)實(shí)現。該進(jìn)程在請求存儲位置時(shí)發(fā)生,存儲位置的頁(yè)面不在存儲器中(在存儲器管理單元 [MMU] 中無(wú)映射)。這個(gè)事件被稱(chēng)為一個(gè)頁(yè)面錯誤 并被硬件(MMU)刪除,出現頁(yè)面錯誤中斷后該事件由防火墻管理。該棧的詳細說(shuō)明見(jiàn) 圖 3。

Linux 提供一個(gè)有趣的交換實(shí)現,該實(shí)現提供許多有用的特性。Linux交換系統允許創(chuàng )建和使用多個(gè)交換分區和優(yōu)先權,這支持存儲設備上的交換層次結構,這些存儲設備提供不同的性能參數(例如,固態(tài)磁盤(pán) [SSD]上的一級交換和速度較慢的存儲設備上的較大的二級交換)。為 SSD交換附加一個(gè)更高的優(yōu)先級使其可以使用直至耗盡;直到那時(shí),頁(yè)面才能被寫(xiě)入優(yōu)先級較低的交換分區。


圖 3. 地址空間和虛擬 - 物理地址映射的元素

并不是所有的頁(yè)面都適合交換??紤]到響應中斷的內核代碼或者管理頁(yè)表和交換邏輯的代碼,顯然,這些頁(yè)面決不能被換出,因此它們是固定的,或者是永久地駐留在內存中。盡管內核頁(yè)面不需要進(jìn)行交換,然而用戶(hù)頁(yè)面需要,但是它們可以被固定,通過(guò) mlock(或 mlockall)函數來(lái)鎖定頁(yè)面。這就是用戶(hù)空間內存訪(fǎng)問(wèn)函數的目的。如果內核假設一個(gè)用戶(hù)傳遞的地址是有效的且是可訪(fǎng)問(wèn)的,最終可能會(huì )出現內核嚴重錯誤(kernelpanic)(例如,因為用戶(hù)頁(yè)面被換出,而導致內核中的頁(yè)面錯誤)。該應用程序編程接口(API)確保這些邊界情況被妥善處理。


內核 API

現在,讓我們來(lái)研究一下用戶(hù)操作用戶(hù)內存的內核 API。請注意,這涉及內核和用戶(hù)空間接口,而下一部分將研究其他的一些內存 API。用戶(hù)空間內存訪(fǎng)問(wèn)函數在表 1 中列出。


表 1. 用戶(hù)空間內存訪(fǎng)問(wèn) API
函數描述
access_ok 檢查用戶(hù)空間內存指針的有效性
get_user 從用戶(hù)空間獲取一個(gè)簡(jiǎn)單變量
put_user 輸入一個(gè)簡(jiǎn)單變量到用戶(hù)空間
clear_user 清除用戶(hù)空間中的一個(gè)塊,或者將其歸零。
copy_to_user 將一個(gè)數據塊從內核復制到用戶(hù)空間
copy_from_user 將一個(gè)數據塊從用戶(hù)空間復制到內核
strnlen_user 獲取內存空間中字符串緩沖區的大小
strncpy_from_user 從用戶(hù)空間復制一個(gè)字符串到內核

正如您所期望的,這些函數的實(shí)現架構是獨立的。例如在 x86 架構中,您可以使用./linux/arch/x86/lib/usercopy_32.c 和 usercopy_64.c 中的源代碼找到這些函數以及在./linux/arch/x86/include/asm/uaccess.h 中定義的字符串。

當數據移動(dòng)函數的規則涉及到復制調用的類(lèi)型時(shí)(簡(jiǎn)單 VS. 聚集),這些函數的作用如圖 4 所示。


圖 4. 使用 User Space Memory Access API 進(jìn)行數據移動(dòng)

access_ok 函數

您可以使用 access_ok 函數在您想要訪(fǎng)問(wèn)的用戶(hù)空間檢查指針的有效性。調用函數提供指向數據塊的開(kāi)始的指針、塊大小和訪(fǎng)問(wèn)類(lèi)型(無(wú)論這個(gè)區域是用來(lái)讀還是寫(xiě)的)。函數原型定義如下:

access_ok( type, addr, size );            

type 參數可以被指定為 VERIFY_READVERIFY_WRITE。VERIFY_WRITE 也可以識別內存區域是否可讀以及可寫(xiě)(盡管訪(fǎng)問(wèn)仍然會(huì )生成 -EFAULT)。該函數簡(jiǎn)單檢查地址可能是在用戶(hù)空間,而不是內核。

get_user 函數

要從用戶(hù)空間讀取一個(gè)簡(jiǎn)單變量,可以使用 get_user函數,該函數適用于簡(jiǎn)單數據類(lèi)型,比如,charint,但是像結構體這類(lèi)較大的數據類(lèi)型,必須使用 copy_from_user 函數。該原型接受一個(gè)變量(存儲數據)和一個(gè)用戶(hù)空間地址來(lái)進(jìn)行 Read 操作:

get_user( x, ptr );            

get_user 函數將映射到兩個(gè)內部函數其中的一個(gè)。在系統內部,這個(gè)函數決定被訪(fǎng)問(wèn)變量的大?。ǜ鶕峁┑淖兞看鎯Y果)并通過(guò) __get_user_x 形成一個(gè)內部調用。成功時(shí)該函數返回 0,一般情況下,get_userput_user 函數比它們的塊復制副本要快一些,如果是小類(lèi)型被移動(dòng)的話(huà),應該用它們。

put_user 函數

您可以使用 put_user 函數來(lái)將一個(gè)簡(jiǎn)單變量從內核寫(xiě)入用戶(hù)空間。和 get_user 一樣,它接受一個(gè)變量(包含要寫(xiě)的值)和一個(gè)用戶(hù)空間地址作為寫(xiě)目標:

put_user( x, ptr );            

get_user 一樣,put_user 函數被內部映射到 put_user_x 函數,成功時(shí),返回 0,出現錯誤時(shí),返回 -EFAULT。

clear_user 函數

clear_user 函數被用于將用戶(hù)空間的內存塊清零。該函數采用一個(gè)指針(用戶(hù)空間中)和一個(gè)型號進(jìn)行清零,這是以字節定義的:

clear_user( ptr, n );            

在內部,clear_user 函數首先檢查用戶(hù)空間指針是否可寫(xiě)(通過(guò) access_ok),然后調用內部函數(通過(guò)內聯(lián)組裝方式編碼)來(lái)執行 Clear 操作。使用帶有 repeat 前綴的字符串指令將該函數優(yōu)化成一個(gè)非常緊密的循環(huán)。它將返回不可清除的字節數,如果操作成功,則返回 0。

copy_to_user 函數

copy_to_user 函數將數據塊從內核復制到用戶(hù)空間。該函數接受一個(gè)指向用戶(hù)空間緩沖區的指針、一個(gè)指向內存緩沖區的指針、以及一個(gè)以字節定義的長(cháng)度。該函數在成功時(shí),返回 0,否則返回一個(gè)非零數,指出不能發(fā)送的字節數。

copy_to_user( to, from, n );            

檢查了向用戶(hù)緩沖區寫(xiě)入的功能之后(通過(guò) access_ok),內部函數 __copy_to_user 被調用,它反過(guò)來(lái)調用 __copy_from_user_inatomic(在 ./linux/arch/x86/include/asm/uaccess_XX.h 中。其中 XX 是 32 或者 64 ,具體取決于架構。)在確定了是否執行 1、2 或 4 字節復制之后,該函數調用 __copy_to_user_ll,這就是實(shí)際工作進(jìn)行的地方。在損壞的硬件中(在 i486 之前,WP 位在管理模式下不可用),頁(yè)表可以隨時(shí)替換,需要將想要的頁(yè)面固定到內存,使它們在處理時(shí)不被換出。i486 之后,該過(guò)程只不過(guò)是一個(gè)優(yōu)化的副本。

copy_from_user 函數

copy_from_user 函數將數據塊從用戶(hù)空間復制到內核緩沖區。它接受一個(gè)目的緩沖區(在內核空間)、一個(gè)源緩沖區(從用戶(hù)空間)和一個(gè)以字節定義的長(cháng)度。和 copy_to_user 一樣,該函數在成功時(shí),返回 0 ,否則返回一個(gè)非零數,指出不能復制的字節數。

copy_from_user( to, from, n );            

該函數首先檢查從用戶(hù)空間源緩沖區讀取的能力(通過(guò) access_ok),然后調用 __copy_from_user,最后調用 __copy_from_user_ll。從此開(kāi)始,根據構架,為執行從用戶(hù)緩沖區到內核緩沖區的零拷貝(不可用字節)而進(jìn)行一個(gè)調用。優(yōu)化組裝函數包含管理功能。

strnlen_user 函數

strnlen_user 函數也能像 strnlen 那樣使用,但前提是緩沖區在用戶(hù)空間可用。strnlen_user 函數帶有兩個(gè)參數:用戶(hù)空間緩沖區地址和要檢查的最大長(cháng)度。

strnlen_user( src, n );            

strnlen_user 函數首先通過(guò)調用 access_ok 檢查用戶(hù)緩沖區是否可讀。如果是 strlen 函數被調用,max length 參數則被忽略。

strncpy_from_user 函數

strncpy_from_user 函數將一個(gè)字符串從用戶(hù)空間復制到一個(gè)內核緩沖區,給定一個(gè)用戶(hù)空間源地址和最大長(cháng)度。

strncpy_from_user( dest, src, n );            

由于從用戶(hù)空間復制,該函數首先使用 access_ok 檢查緩沖區是否可讀。和 copy_from_user 一樣,該函數作為一個(gè)優(yōu)化組裝函數(在 ./linux/arch/x86/lib/usercopy_XX.c 中)實(shí)現。


內存映射的其他模式

上面部分探討了在內核和用戶(hù)空間之間移動(dòng)數據的方法(使用內核初始化操作)。Linux 還提供一些其他的方法,用于在內核和用戶(hù)空間中移動(dòng)數據。盡管這些方法未必能夠提供與用戶(hù)空間內存訪(fǎng)問(wèn)函數相同的功能,但是它們在地址空間之間映射內存的功能是相似的。

在用戶(hù)空間,注意,由于用戶(hù)進(jìn)程出現在單獨的地址空間,在它們之間移動(dòng)數據必須經(jīng)過(guò)某種進(jìn)程間通信機制。Linux 提供各種模式(比如,消息隊列),但是最著(zhù)名的是 POSIX 共享內存(shmem)。該機制允許進(jìn)程創(chuàng )建一個(gè)內存區域,然后同一個(gè)或多個(gè)進(jìn)程共享該區域。注意,每個(gè)進(jìn)程可能在其各自的地址空間中映射共享內存區域到不同地址。因此需要相對的尋址偏移(offset addressing)。

mmap 函數允許一個(gè)用戶(hù)空間應用程序在虛擬地址空間中創(chuàng )建一個(gè)映射,該功能在某個(gè)設備驅動(dòng)程序類(lèi)中是常見(jiàn)的,允許將物理設備內存映射到進(jìn)程的虛擬地址空間。在一個(gè)驅動(dòng)程序中,mmap 函數通過(guò) remap_pfn_range 內核函數實(shí)現,它提供設備內存到用戶(hù)地址空間的線(xiàn)性映射。


結束語(yǔ)

本文討論了 Linux 中的內存管理主題,然后討論了使用這些概念的用戶(hù)空間內存訪(fǎng)問(wèn)函數。在用戶(hù)空間和內核空間之間移動(dòng)數據并沒(méi)有表面上看起來(lái)那么簡(jiǎn)單,但是 Linux 包含一個(gè)簡(jiǎn)單的 API 集合,跨平臺為您管理這個(gè)復雜的任務(wù)。


參考資料

學(xué)習

獲得產(chǎn)品和技術(shù)

  • 以最適合您的方式 IBM 產(chǎn)品評估試用版軟件:下載產(chǎn)品試用版,在線(xiàn)試用產(chǎn)品,在云環(huán)境下試用產(chǎn)品,或者在 IBM SOA Sandbox for People 中花費幾個(gè)小時(shí)來(lái)學(xué)習如何高效實(shí)現面向服務(wù)架構。

討論

關(guān)于作者

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
內核代碼不可直接訪(fǎng)問(wèn)用戶(hù)空間數據
Linux內存管理原理
Linux內存管理
內核怎樣管理你的內存
linux內核中內存相關(guān)的操作函數
操作系統與內存管理
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久