导航:首页 > 编程系统 > linuxio资源映射

linuxio资源映射

发布时间:2024-07-21 05:03:09

A. linux关于地址空间和MMAP映射有何特点

Linux采用
虚拟
内存技术,系统中的所有进程之间以虚拟方式共享内存。对每个进程来说,它们好像都可以访问整个系统的所有物理内存。更重要的是,即使单独一个进程,它拥有的地址空间也可以远远大于系统物理内存。
进程地址空间由每个进程中的线性地址区组成,每个进程都有一个32位或64位的平坦(flat)空间,空间的具体大小取决于体系结构。“平坦”指地址空间范围是一个独立的连续区间。通常情况下,每个进程都有唯一的这种平坦空间,而且每个进程的地址空间之间彼此互不相干。两个不同的进程可以在它们各自地址空间的相同地址内存存放不同的数据。但是进程之间也可以选择共享地址空间,我们称这样的进程为线程。
在地址空间中,我们更为关心的是进程有权访问的虚拟内存地址区间,比如08048000~0804c000。这些可被访问的合法地址区间被成为内存区域(memory area),通过内核,进程可以给自己的地址空间动态地添加或减少内存区域。
进程只能访问有效范围内的内存地址。每个内存区域也具有相应进程必须遵循的特定访问属性,如只读、只写、可执行等属性。如果一个进程访问了不在有效范围中的地址,或以不正确的方式访问有效地址,那么内核就会终止该进程,并返回“段错误”信息。
?
内存区域可以包含各种内存对象,如下:
?
可执行文件代码的内存映射,成为代码段(text section)。
?
可执行文件的已初始化全局变量的内存映射,成为数据段(data section)。
?
包含未初始化全局变量的零页(也就是bss段)的内存映射。零页是指页面中的数据全部为0。
?
用于进程用户空间栈的零页的内存映射。
?
每一个诸如C库或动态链接程序等共享库的代码段、数据段和bss也会被载入进程的地址空间。
?
任何内存映射文件。
?
任何共享内存段。
?
任何匿名的内存映射,比如由malloc()分配的内存。
进程地址空间的任何有效地址都只能位于唯一的区域,这些内存区域不能相互覆盖。可以看到,在执行的进程中,每个不同的内存片断都对应一个独立的内存区域:栈、对象代码、全局变量、被映射的文件等等。
内核使用内存描述符表示进程的地址空间。内存描述符由mm_struct结构体表示,定义在文件中,该结构包含了和进程地址空间有关的全部信息。
VMA
内存区域由vm_area_struct结构体描述,定义在文件中,内存区域在内核中也经常被称作虚拟内存区域或者VMA。
VMA标志是一种位标志,它定义在vm_area_struct结构中(该结构中的vm_flags子域)。和物理页的访问权限不同,VMA标志反映了内核处理页面索需要遵守的行为准则,而不是硬件要求。VM_IO标志内存区域中包含对设备I/O空间的映射。该标志通常在设备驱动程序执行 mmap()函数进行I/O空间映射时才被设置,同时该标志也表示该内存区域不能被包含在任何进程的存放转存(core mp)中。VM_RESERVED标志内存区域不能被换出,它也是在设备驱动程序进行映射时被设置。
vm_area_struct结构体中的vm_ops域指向与指定内存区域相关的操作函数表,内核使用表中的方法操作VMA。
mmap()和do_mmap():创建地址区间
内核使用do_mmap()函数创建一个新的线性地址区间。但是说给函数创建一个新VMA并不非常准确,因为如果创建的地址区间和一个已经存在的地址区间相邻,并且它们具有相同的访问权限的话,那么两个区间将合并为一个。如果不能合并,那么就确实需要创建一个新的VMA了。但无论哪种情况,do_mmap()函数都会将一个地址区间加入到进程的地址空间中——无论是扩展已经存在的内存区域还是创建一个新的区域。
do_mmap()函数声明在文件中,原型如下:
unsigned long do_mmap(struct file *file, unsigned long addr,
unsigned long len, unsigned long prot,
unsigned long flag, unsigned long offset)
在用户空间可以通过mmap()函数调用获取内核函数do_mmap()的功能。mmap()系统调用原型如下:
void *mmap2(void *start, size_t length,
int prot, int flags,
int fd, off_t pgoff)
do_munmap()函数从特定的进程地址空间中删除指定地址区间,该函数在文件中声明:
int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
系统调用munmap()给用户空间程序提供了一种从自身地址空间中删除指定地址区间的方法,它和系统调用mmap()的作用相反:
int munmap(void *start, size_t length)
mmap设备操作
对于驱动程序来说,内存映射可以提供给用户程序直接访问设备内存的能力。映射一个设备,意味着使用户空间的一段地址关联到设备内存上。无论何时,只要程序在分配的地址范围内进行读取或者写入,实际上就是对设备的访问。
并不是所有的设备都能进行mmap抽象。例如,串口设备和其他面向流的设备就无法实现这种抽象。mmap的另一个限制是映射都是以 PAGE_SIZE为单位的。内核只能在页表一级处理虚拟地址;因此,被映射的区域必须是PAGE_SIZE的整数倍,而且必须位于起始于 PAGE_SIZE整数倍地址的物理内存内。如果区域的大小不是页大小的整数倍,内核就通过生成一个稍微大一些的区域来容纳它。
mmap方法是file_operations结构中的一员,并且在执行mmap系统调用时就会调用该方法。在调用实际方法之前,内核会完成很多工作,而且该方法的原型与系统调用的原型由很大区别。关于Linux命令的介绍,看看《linux就该这么学》,具体关于这一章地址3w(dot)linuxprobe/chapter-02(dot)html
文件操作声明如下:
int (*mmap) (struct file * filp, struct vm_area_struct *vma);
其中vma参数包含了用于访问设备的虚拟地址区间的信息。大部分工作已经由内核完成了,要实现mmap,驱动程序只要为这一地址范围构造合适的页表即可,如果需要的话,就用一个新的操作集替换vma->vm_ops。
有两种建立页表的方法:使用remap_page_range函数可一次建立所有的页表,或者通过nopage VMA方法每次建立一个页表。
构造用于映射一段物理地址的新页表的工作是由remap_page_range完

B. linux内核 io.h中的outb是哪里的用法

.h文件是函数的说明,你得去定义这个函数的文件里找,一般来说在同名的c或cpp文件里。

C. 楂樻ц兘寮傛io鏈哄埗锛歩o_uring

楂樻ц兘寮傛I/O澶勭悊鏈哄埗锛歩o_uring鐨勯潻鍛芥х獊鐮

闅忕潃Linux 5.10鐗堟湰鐨勯潻鏂帮紝io_uring寮傛IO鎺ュ彛搴旇繍鑰岀敓锛屽畠閫氳繃宸у欑殑鐢ㄦ埛绌洪棿鍐呭瓨鏄犲皠鍜屾棤閿佺幆褰㈤槦鍒楄捐★紝鏋佸ぇ鍦版彁鍗囦簡鏁版嵁澶勭悊鐨勬晥鐜囥俰o_uring浠ュ叾鐙鐗圭殑璁捐★紝灏嗕换鍔℃彁浜や笌缁撴灉杩斿洖鏃犵紳鏁村悎锛屽噺灏戜簡鍐呭瓨鎷疯礉鐨勫紑閿锛屽睍鐜板嚭鍗撹秺鐨勬ц兘銆



io_uring鐨勬牳蹇冩満鍒跺湪浜庡叾鍙屽悜闃熷垪缁撴瀯锛屽寘鎷琒Q锛圫ubmit Queue锛夊拰CQ锛圕ompletion Queue锛夈係Q璐熻矗鎺ユ敹鐢ㄦ埛鐨処O璇锋眰锛岃孋Q鍒欒礋璐i氱煡鐢ㄦ埛璇锋眰鐨勫畬鎴愮姸鎬併傚畠浠閫氳繃鍐呭瓨灞忛殰鎿嶄綔淇濇寔鍚屾ワ紝鏃犻渶閿佹満鍒讹紝浠庤岄伩鍏嶄簡甯歌佺殑绔炴佹潯浠躲



绯荤粺璋冪敤鐨勫叧閿鐜鑺




涓轰簡鐩磋傚湴灞曠ずio_uring鐨勫▉鍔涳紝鎴戜滑閫氳繃瀹炴垬婕旂ず锛氫緥濡傦紝uring_cat绋嬪簭锛屽畠鍒╃敤io_uring灏佽呬簡鏂囦欢鎿嶄綔锛屽疄鐜板湪纾佺洏I/O鏂归潰鐨勬樉钁楁ц兘鎻愬崌銆傚湪瀹為檯娴嬭瘯涓锛屽规瘮寮傛ユā寮忥紙io_uring锛岃揪鍒版儕浜虹殑19.0k IOPS锛夊拰鍚屾ユā寮忥紙8k IOPS锛夛紝io_uring鍦ㄧ佺洏I/O鎬ц兘涓婂崰鎹浜嗘樉钁椾紭鍔裤



姝ゅ栵紝rust_echo_bench鏈嶅姟鍣ㄦ祴璇曡繘涓姝ヨ瘉瀹炰簡io_uring鐨勪紭瓒婃э紝瀹冨湪澶勭悊澶ч噺骞跺彂璇锋眰鏃讹紝灞曠幇鍑哄崜瓒婄殑鍚炲悙閲忓拰鍝嶅簲閫熷害銆傛繁鍏ョ悊瑙io_uring鐨勬牳蹇冪郴缁熻皟鐢ㄦ帴鍙o紝鑳藉熷府鍔╁紑鍙戣呮洿鏈夋晥鍦板埄鐢ㄨ繖涓寮哄ぇ鐨勫伐鍏枫



瀹炶返搴旂敤涓庡︿範璧勬簮


瑕佹繁鍏ユ帉鎻io_uring锛孌PDK鏁欑▼鏄涓涓鏋佸ソ鐨勫︿範璧风偣銆傞氳繃瀹冿紝寮鍙戣呭彲浠ヤ簡瑙e備綍鍒╃敤io_uring杩涜岄珮鏁堢殑缃戠粶鍜孖/O鎿嶄綔锛屼互鍙婂備綍浼樺寲绯荤粺鎬ц兘銆傜珛鍗宠㈤槄锛岃笍涓奿o_uring鐨勯珮鎬ц兘涔嬫梾锛



灏界io_uring鎻愪緵浜嗗己澶х殑鎬ц兘鎻愬崌锛屼絾鍏朵娇鐢ㄤ篃瑕佹眰寮鍙戣呭叿澶囦竴瀹氱殑绯荤粺缂栫▼鐭ヨ瘑鍜屽唴瀛樼$悊鎶宸с傞氳繃缁嗚嚧鐨勪唬鐮佺ず渚嬪拰瀹炶返锛屼綘灏嗚兘澶熼嗙暐io_uring鐨勫唴鍦ㄩ瓍鍔涳紝涓哄簲鐢ㄧ▼搴忓甫鏉ュ墠鎵鏈鏈夌殑閫熷害涓庢晥鐜囥

D. Linux磁盘IO流程

文件IO的分层设计

先看图:

malloc的buf对应application buffer,用户空间;

fwrite是系统提供的最上层接口,也是最常用的接纤哗口。它在用户进程空间开辟一个CLib buffer,将多次小数据量相邻写操作(application buffer)先缓存起来,合并,最终调用write函数一次性写入(或者将大块数据分解多次write调用);

write函数通过调用系统调用接口,将数据从应用层到内核慎巧层,所以write会触发内核态/用户态切换。当数据到达page cache后,内核并不会立即把数据往下传递。而是返回用户空间。数据什么时候写入硬盘,有内核IO调度决定,所以write是一个异步调用;

read调用是先检查page cache里面是否有数据,如果有,就取出来返回用户,如果没有,就同步传递宽竖键下去并等待有数据,再返回用户,所以read是一个同步过程;

fclose隐含fflush函数,fflush只负责把数据从Clibbuffer拷贝到pagecache中返回,并没有刷新到磁盘上,刷新到磁盘上可以使用fsync函数;

即便fsync仍有可能没写到磁盘上,一是磁盘有缓存,二是即便关闭缓存也可能为了跑分没有真正关闭;

** 一致性
fwrite使用用户进程私有空间,多线程必然需要做同步。write如果写大小小于PIPE_BUF,是原子操作。根据已知信息,内核所做仅限于此,如果两个进程同时写文件,可能出现错乱,需要实测。

** 安全性
从前面的分层设计来看,使用fsync函数可以最大限度保障安全写入,但仍然没有绝对的安全性。

另外一张图

E. 宓屽叆寮廘inux寮鍙戜腑鐨勬枃浠禝/O鏄浠涔

銆銆宓屽叆寮弆inux寮鍙戜腑鐨勬枃浠禝/O灏辨槸瀵瑰栬捐繘琛屾枃浠舵娊璞★紝涔熷氨鏄璁や负涓鍒囧栭儴璁惧囬兘鏄鏂囦欢锛屾墍鏈夊瑰栬剧殑璁块棶閮介氳繃鏂囦欢鏂瑰紡銆傚氫换鍔″氨鏄鐢ㄤ竴涓狢PU鎵ц屽氫釜浠诲姟锛岃繖涓浠诲姟鍙鍋氳繘绋嬫垨绾跨▼銆
銆銆I/O杈撳叆/杈撳嚭(Input/Output),鍒嗕负IO璁惧囧拰IO鎺ュ彛涓や釜閮ㄥ垎銆
銆銆鍦≒OSIX鍏煎圭殑绯荤粺涓婏紝渚嬪侺inux绯荤粺锛孖/O鎿嶄綔鍙浠ユ湁澶氱嶆柟寮忥紝姣斿侱IO(Direct I/O),AIO(Asynchronous I/O 寮傛I/O),Memory-Mapped I/O(鍐呭瓨鏄犺綢/O)绛夛紝涓嶅悓鐨処/O鏂瑰紡鏈変笉鍚岀殑鏂瑰紡鍜屾ц兘锛屽湪涓嶅悓鐨勫簲鐢ㄤ腑鍙浠ユ寜鎯呭喌閫夋嫨涓嶅悓鐨処/O鏂瑰紡銆
銆銆杈撳叆杈撳嚭I/O娴佸彲浠ョ湅鎴愬瑰瓧鑺傛垨鑰呭寘瑁呭悗鐨勫瓧鑺傜殑璇诲彇灏辨槸鎷垮嚭鏉ユ斁杩涘幓鍙岃矾鍒囨崲锛涘疄鐜拌仈鍔ㄦ帶鍒剁郴缁熺殑寮辩數绾胯矾涓庤鎺ц惧囩殑寮虹數绾胯矾涔嬮棿鐨勮浆鎺ャ侀殧绂伙紝浠ラ槻姝㈠己鐢电獪鍏ョ郴缁燂紝淇濋殰绯荤粺鐨勫畨鍏锛

阅读全文

与linuxio资源映射相关的资料

热点内容
手机锁屏后的文件在哪里 浏览:282
枪神纪母猴飞天教程 浏览:516
快捷建立文件夹 浏览:477
exe视频文件没有注册类 浏览:451
unix批量删除文件名前缀 浏览:541
k750s升级bios 浏览:147
学韩语用什么app 浏览:478
110固态硬盘分区win10 浏览:317
怎么恢复系统文件 浏览:358
数据线转换器多少钱 浏览:274
美国队长qq皮肤多少钱 浏览:630
win8word文档在哪 浏览:180
甘肃省人事局文件在哪里 浏览:689
spss安装输入代码 浏览:546
网络语言知乎 浏览:596
iphoneicloud无法显示 浏览:112
ict程序包 浏览:729
java有哪些条件语句 浏览:345
冒险岛120级去哪里升级 浏览:511
手机输入法声音文件 浏览:876

友情链接