Linux存储系统概述

Linux存储系统包括两个部分:第一部分是站在用户的角度提供读/写的接口,数据以流为表现形式;第二部分是站在存储设备的角度提供读/写接口,数据以块为表现形式。文件系统位于两者中间起到承上启下的作用。

例如,应用程序通过系统调用发出一个写请求,最终的目的是要把数据写到磁盘上,文件系统来负责定位这个写请求的位置并将其转换成块设备需要的块,然后把这个请求发送到设备上。内存在这个过程中扮演了一个磁盘缓存的角色,把上下两个部分隔离成异步运行的两个过程,对上半部分来说,让数据一直留在内存中是最好的方式,因为没有办法预料到之后还会不会修改,如果需要对同一个位置频繁地进行修改,则与磁盘进行不断地数据同步是没有必要的。至于下半部分,数据从页面缓存(Page Cache)同步到磁盘上,发出的请求包包装成一个request,一个request包含一组bio,每个bio包含需要同步的数据页。而对于磁盘来说,要写上面一个位置,首先需要从物理上把磁头移动到那个轨道上,因此需要一定的I/O请求调用的过程,尽可能合理地安排I/O请求执行顺序,不然磁头频繁地来回移动,会严重影响磁盘性能。

用户应用程序访问并使用内核所提供的各种服务的途径即是系统调用。在内核和用户应用程序相交的地方,内核提供了一组系统调用接口,通过这组接口,应用程序可以访问系统硬件和各种操作系统资源。用户可以通过文件系统相关的系统调用请求系统打开文件、关闭文件或读/写文件。主要就是read、write、open和mmap等。

1)mmap

提及mmap,不可避免会涉及进程的地址空间。以32位Linux为例,CPU能访问4GB的虚拟地址空间为0x0-0xFFFFFFFF,其中低3GB的地址(0x0-0xC0000000)是应用层的地址空间,高地址的1GB(0xC0000000-0xFFFFFFFF)是留给Kernel的。Kernel中所有的线程共享这1GB的地址空间,而每个进程可以有自己独立的3GB的虚拟地址空间,互不干扰。进程的地址范围分成不同的内存区域,包括代码段(TEXT)、数据段(DATA)、未初始化的全局变量段(Block Started by Symbol,BSS)、堆(Heap)、栈(Stack)等。

进程地址空间里的内存区域块通常被称为VMA(Virtual Memory Area),它描述了一个连续空间上的独立区间,拥有一致的属性。一个进程地址空间内的各个内存区域是不允许发生地址重叠的。

如果映射的文件名为[anon],则表示匿名的内存映射,指动态生成的内容所占用的内存。例如,堆不存在相对应的磁盘路径,所以它的映射就称为匿名的内存映射(注意一下最后一个[anon]区域,它的地址在内核地址空间,这是VDSO(Virtual Dynamic Shared Object)技术的应用,相当于将一个内核动态库共享给应用进程);[stack]表示栈内存。一般属性为“r-x”(只读并可执行的)的是程序的代码段,而具有可写属性的可能是数据段、未初始化的全局变量段、堆、栈等。

当一个进程运行的时候,其用到文件的代码段、数据段等都是映射到内存地址区域的。这个功能是通过系统调用mmap()来完成的。

 

  • mmap()将文件(由文件句柄fd所指定)从偏移offset的位置开始的长度为length的一个块映射到内存区域中,从而把文件的某一段映射到进程的地址空间,这样程序就可以通过访问内存的方式去访问文件了。 
  • 参数addr是输入的参考虚拟地址,通常指定为NULL,这样内核会自动生成一个合理的虚拟地址。
  • 参数prot为映射的属性,可以是PROT_EXEC(可执行的)、PROT_READ(可读的)、PROT_WRITE(可写的)、PROT_NONE(无)或是它们“比特或”的结果。
  • 参数flags指定映射的一些操作,如MAP_SHARED(共享映射,进程间通过这种映射可以共享文件信息,但只有调用msync()或munmap()后才能保障文件的回写完成)或MAP_PRIVATE(私有映射,对映射内存的写操作基于写时复制实现,也就是说不会写回到真正的文件中,其他进程无法共享)。更多的flags参数介绍读者可以参考mmap2()的manual帮助。
  • 如果fd指向的句柄为一个设备文件,则可以把设备的物理块映射到内存中,这需要在相应的设备驱动中实现xxx_mmap()接口。典型的例子就是利用/dev/mem可以将一些MMU能访问的物理地址映射为应用层虚拟地址,从而可以在应用层直接访问某些物理地址,实现一些简单的驱动开发。
  • 如果flags中包含MAP_ANONYMOUS,则表示这是一个匿名映射,不映射到任何文件中,这时参数fd和offset不起作用,mmap()返回一块初始化为0的匿名映射内存区域块。应用层Glibc库的malloc()函数分配虚拟内存的时候,小于128KB的用brk()系统调用增长堆的大小,而大于等于128KB的直接用MAP_ANONYMOUS的方式映射一个匿名地址空间。开发人员可以用这种方法预先创建一个大的虚拟地址空间,然后在应用层实现自己的内存管理。

与read/write相比,使用mmap的方式对文件进行访问,带来的一个显著好处就是可以减少一次用户空间到内核空间的复制,在某些场景下,如访问音频、视频等大文件,可以带来性能的提升。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值