`

linux address_space 结构

 
阅读更多

看linux内核很容易被struct address_space 这个结构迷惑,它是代表某个地址空间吗?实际上不是的,它是用于管理文件(struct inode)映射到内存的页面(struct page)的;与之对应,address_space_operations 就是用来操作该文件映射到内存的页面,比如把内存中的修改写回文件、从文件中读入数据到页面缓冲等。
      参考下面这张图,摘自《深入理解linux虚拟内存管理》,对理解linux内存管理颇有帮助

 

http://laokaddk.blog.51cto.com/368606/433769

在阅读Linux2.6的内核内存管理这一部分时,我看到page结构中的一个mapping成员,我感到很迷惑,这个成员的属性太复杂了,我们来看看:
struct address_space *mapping;表示该页所在地址空间描述结构指针,用于内容为文件的页帧
(1)       如果page->mapping等于0,说明该页属于交换告诉缓存swap cache
(2)       如果page->mapping不等于0,但第0位为0,说明该页为匿名也,此时mapping指向一个struct anon_vma结构变量;
(3)       如果page->mapping不等于0,但第0位不为0,则apping指向一个struct address_space地址空间结构变量;
这成员也太麻烦了吧,下面我先看看struct address_space是啥东东:
1、定义:
看linux内核很容易被struct address_space 这个结构迷惑,它是代表某个地址空间吗?实际上不是的,它是用于管理文件(struct inode)映射到内存的页面(struct page)的;与之对应,address_space_operations 就是用来操作该文件映射到内存的页面,比如把内存中的修改写回文件、从文件中读入数据到页面缓冲等。
也就是说address_space结构与文件的对应:一个具体的文件在打开后,内核会在内存中为之建立一个struct inode结构,其中的i_mapping域指向一个address_space结构。这样,一个文件就对应一个address_space结构,一个 address_space与一个偏移量能够确定一个page cache 或swap cache中的一个页面。因此,当要寻址某个数据时,很容易根据给定的文件及数据在文件内的偏移量而找到相应的页面。看下这张图我们就很了解了:

下面先看下address_space结构定义:
struct address_space {
       struct inode           *host;            /* owner: inode, block_device拥有它的节点 */
       struct radix_tree_root    page_tree;       /* radix tree of all pages包含全部页面的radix树 */
       rwlock_t        tree_lock;       /* and rwlock protecting it保护page_tree的自旋锁  */
       unsigned int           i_mmap_writable;/* count VM_SHARED mappings共享映射数 VM_SHARED记数*/
       struct prio_tree_root      i_mmap;         /* tree of private and shared mappings 优先搜索树的树根*/
       struct list_head       i_mmap_nonlinear;/*list VM_NONLINEAR mappings 非线性映射的链表头*/
       spinlock_t              i_mmap_lock; /* protect tree, count, list 保护i_mmap的自旋锁*/
       unsigned int           truncate_count;      /* Cover race condition with truncate 将文件截断的记数*/
       unsigned long         nrpages;  /* number of total pages 页总数*/
       pgoff_t                  writeback_index;/* writeback starts here 回写的起始偏移*/
       struct address_space_operations *a_ops;     /* methods  操作函数表*/
       unsigned long         flags;             /* error bits/gfp mask ,gfp_mask掩码与错误标识 */
       struct backing_dev_info *backing_dev_info; /* device readahead, etc预读信息 */
       spinlock_t              private_lock;   /* for use by the address_space  私有address_space锁*/
       struct list_head       private_list;     /* ditto 私有address_space链表*/
       struct address_space     *assoc_mapping;    /* ditto 相关的缓冲*/
} __attribute__((aligned(sizeof(long))));

2、page cache和swap cache
了解了struct address_space这个东东,我们就知道“一个 address_space与一个偏移量能够确定一个page cache 或swap cache中的一个页面”,那么page cache和swap cache
又是什么东东呢?
page cache是与文件映射对应的,而swap cache是与匿名页对应的。如果一个内存页面不是文件映射,则在换入换出的时候加入到swap cache,如果是文件映射,则不需要交换缓冲。 
原来这两个相同的就是都是address_space,都有相对应的文件操作。:一个被访问文件的物理页面都驻留在page cache或swap cache中,一个页面的所有信息由struct page来描述。struct page中有一个域为指针mapping ,它指向一个struct address_space类型结构。page cache或swap cache中的所有页面就是根据address_space结构以及一个偏移量来区分的。而在这里我可以负责任的告诉大家这个偏移量就是进程线性空间中某个线性地址对应的二级描述符(注意:我这里说的是以SEP4020这个arm结构为例的,它只有二级映射,另外这个二级描述符也是Linux版的,而不是硬件版的描述符)。
一般情况下用户进程调用mmap()时,只是在进程空间内新增了一块相应大小的缓冲区,并设置了相应的访问标识,但并没有建立进程空间到物理页面的映射。因此,第一次访问该空间时,会引发一个缺页异常。、对于共享内存映射情况,缺页异常处理程序首先在swap cache中寻找目标页(符合address_space以及偏移量的物理页),如果找到,则直接返回地址;如果没有找到,则判断该页是否在交换区 (swap area),如果在,则执行一个换入操作;如果上述两种情况都不满足,处理程序将分配新的物理页面,并把它插入到page cache中。进程最终将更新进程页表。注:对于映射普通文件情况(非共享映射),缺页异常处理程序首先会在page cache中根据address_space以及数据偏移量寻找相应的页面。如果没有找到,则说明文件数据还没有读入内存,处理程序会从磁盘读入相应的页面,并返回相应地址,同时,进程页表也会更新。
3、swap cache的补充知识;
当将页面交换到交换文件中时,Linux总是避免页面写,除非必须这样做。当页面已经被交换出内存但是当有进程再次访问时又要将它重新调入内存。只要页面在内存中没有被写过,则交换文件中的拷贝是有效的。
Linux使用swap cache来跟踪这些页面。这个swap cache是一个页表入口链表,每个对应于系统中的物理页面。这是一个对应于交换出页面的页表入口并且描叙页面放置在哪个交换文件中以及在交换文件中的位置。如果swap cache入口为非0值,则表示在交换文件中的这一页没有被修改。如果此页被修改(或者写入)。 则其入口从swap cache中删除。
当Linux需要将一个物理页面交换到交换文件时,它将检查swap cache,如果对应此页面存在有效入口,则不必将这个页面写到交换文件中。这是因为自从上次从交换文件中将其读出来,内存中的这个页面还没有被修改。
swap cache中的入口是已换出页面的页表入口。它们虽被标记为无效但是为Linux提供了页面在哪个交换文件中以及文件中的位置等信息。
保存在交换文件中的dirty页面可能被再次使用到,例如,当应用程序向包含在已交换出物理页面上的虚拟内存区域写入时。对不在物理内存中的虚拟内存页面的访问将引发页面错误。由于处理器不能将此虚拟地址转换成物理地址,处理器将通知操作系统。由于已被交换出去,此时描叙此页面的页表入口被标记成无效。处理器不能处理这种虚拟地址到物理地址的转换,所以它将控制传递给操作系统,同时通知操作系统页面错误的地址与原因。这些信息的格式以及处理器如何将控制传递给操作系统与具体硬件有关。
处理器相关页面错误处理代码将定位描叙包含出错虚拟地址对应的虚拟内存区域的vm_area_struct数据结构。它通过在此进程的vm_area_struct中查找包含出错虚拟地址的位置直到找到为止。这些代码与时间关系重大,进程的vm_area_struct数据结构特意安排成使查找操作时间更少。
执行完这些处理器相关操作并且找到出错虚拟地址的有效内存区域后,页面错处理过程其余部分和前面类似。
通用页面错处理代码为出错虚拟地址寻找页表入口。如果找到的页表入口是一个已换出页面,Linux必须将其交换进入物理内存。已换出页面的页表入口的格式与处理器类型有关,但是所有的处理器将这些页面标记成无效并把定位此页面的必要信息放入页表入口中。Linux利用这些信息以便将页面交换进物理入内存。
此时Linux知道出错虚拟内存地址并且拥有一个包含页面位置信息的页表入口。vm_area_struct数据结构可能包含将此虚拟内存区域交换到物理内存中的子程序:swapin。如果对此虚拟内存区域存在swapin则Linux会使用它。这是已换出系统V共享内存页面的处理过程-因为已换出系统V共享页面和普通的已换出页面有少许不同。如果没有swapin操作,这可能是Linux假定普通页面无须特殊处理。
系统将分配物理页面并将已换出页面读入。关于页面在交换文件中位置信息从页表入口中取出。如果引起页面错误的访问不是写操作则页面被保留在swap cache中并且它的页表入口不再标记为可写。如果页面随后被写入,则将产生另一个页面错误,这时页面被标记为dirty,同时其入口从swap cache中删除。如果页面没有被写并且被要求重新换出,Linux可以免除这次写,因为页面已经存在于交换文件中。
如果引起页面从交换文件中读出的操作是写操作,这个页面将被从swap cache中删除并且其页表入口被标记成dirty且可写。
4、page cache的补充:
说到page cache我们很容易就与buffer cache混淆,
在这里我需要说的是page cache是VFS的一部分,buffer cache是块设备驱动的一部分,或者说page cache是面向用户IO的cache,buffer cache是面向块设备IO的cache,page cache按照文件的逻辑页进行缓冲,buffer cache按照文件的物理块进行缓冲。page cache与buffer cache并不相互独立而是相互融合的,同一文件的cache页即可存在于page cache中,又可存在于buffer cache中,它们在物理内存中只有一份拷贝。文件系统接口就处于page cache和buffer cache之间,它完成page cache的逻辑页与buffer cache的物理块之间的相互转换,再交给统一的块设备IO进行调度处理,文件的逻辑块与物理块的关系就表现为page cache与buffer cache的关系。
Page cache实际上是针对文件系统的,是文件的缓存,在文件层面上的数据会缓存到page cache。文件的逻辑层需要映射到实际的物理磁盘,这种映射关系由文件系统来完成。当page cache的数据需要刷新时,page cache中的数据交给buffer cache,但是这种处理在2.6版本的内核之后就变的很简单了,没有真正意义上的cache操作。

Buffer cache是针对磁盘块的缓存,也就是在没有文件系统的情况下,直接对磁盘进行操作的数据会缓存到buffer cache中,例如,文件系统的元数据都会缓存到buffer cache中。

简单说来,page cache用来缓存文件数据,buffer cache用来缓存磁盘数据。在有文件系统的情况下,对文件操作,那么数据会缓存到page cache,如果直接采用dd等工具对磁盘进行读写,那么数据会缓存到buffer cache。

 

分享到:
评论

相关推荐

    Linux内核分析与应用课件第8章(四)页高速缓存机制及读写.pdf

    Page Cache是通过一系列的数据结构,例如inode、address_space、page,将一个文件映射到页的级别。 在Page Cache中,每个页(page)都有两个字段:mapping和index。mapping字段指向该页所有者的address_space,...

    Linux 内核中Demand paging 与swap 机制的源码分析

    无论哪种形式,内核都将它当作一个文件来处理,并为其创建相应的 `struct address_space` 结构,即 `struct address_space swapper_space`。用户进程的栈和堆内存都可以通过 `swapper_space` 被写入到交换分区中。 ...

    介绍linux cache机制

    address_space中包含了各种操作函数的指针,比如readpage、write_begin、write_end等操作,这些操作由address_space_operations结构定义。find_get_page()函数用于查找特定文件中的特定页面是否已经在页面Cache中;...

    页面缓冲(Page Cache)的管理

    其中最核心的数据结构为`struct address_space`。 ### `struct address_space` 数据结构解析 `struct address_space`用于表示一个文件或设备的逻辑空间,它包括了与文件相关的所有页面缓存信息。该结构体包含了多...

    linux内存的使用与page buffer有什么联系?.docx

    无后备文件的页框在内存不足时会通过交换文件移到磁盘上,而有后备文件的页框则与address_space关联,address_space是文件在内存中的表示,它包含了文件内容对应的Page Buffer。读取文件时,如果address_space中没有...

    linux read函数的系统调用流程

    相关的内核数据结构包括 Dentry、inode、file、file_operations、address_space、address_space_operations 和 bio 等。这些数据结构之间的关系是通过指针来实现的。 Linux read 函数的系统调用流程是一个复杂的...

    Linux_Heap_Internals.pdf

    例如,GLIBC堆管理机制提供了Address Space Layout Randomization (ASLR)机制,用于防止攻击者预测堆中的地址。同时,GLIBC堆管理机制也提供了Data Execution Prevention (DEP)机制,用于防止攻击者执行恶意代码。 ...

    ib_fmr_pool.rar_space

    "af_alg"可能指的是"Address Family ALG",这是Linux内核中的一种机制,用于处理加密、压缩等算法的套接字。在这个上下文中,"af_alg.c"可能包含了处理FMR池管理的函数,如分配、释放FMR,以及与内核进行通信的代码...

    Linux下的内存映射

    2. **文件与`struct address_space`的对应关系**:每打开一个文件,内核都会创建一个`struct inode`结构,其中的`i_mapping`字段指向一个`struct address_space`结构,这使得每个文件都对应一个唯一的`struct ...

    linux 虚拟文件系统数据结构关系

    - `i_mapping`: 指向该`inode`的`address_space`结构。 - `i_ino`: `inode`号,在文件系统内部唯一标识一个`inode`。 - `i_rdev`: 如果是设备文件,则存储设备号。 - `i_hash`: `inode`的哈希值,用于快速查找。 - `...

    Linux内核设计与实现.pdf

    /* thread address space:进程地址空间 0-0xBFFFFFFF for user-thread 0-0xFFFFFFFF for kernel-thread */ ... } ``` task_struct结构中包含了进程的所有信息,如进程状态、flags、信号pending等。操作系统可以...

    wrapfs-aes:在Wrapfs中实现地址空间操作,并在CTR模式下对数据进行AES加密

    此目录中存在的源文件由源代码组成,以添加对address_space operations而不是vm_ops操作)的支持,以及对写入WrapFS文件系统中文件的数据进行128 bit AES-CTR加密。 请从下载适当的源文件供您使用 随附的代码已针对...

    Linux操作系统课程指导:Ch15 Process Address Space (进程地址空间).ppt

    在Linux操作系统中,进程地址空间是每个进程独立拥有的虚拟内存结构,它允许进程访问整个物理内存,即使其大小超过了物理内存的实际容量。这一特性使得每个进程都认为自己独占整个系统资源,形成了所谓的虚拟地址...

    Linux Kernel关键字索引

    address_space_operations - **描述**:定义了一组操作,这些操作可以应用于地址空间。 - **相关头文件**:`include/linux/fs.h` ##### 21. AGPs - **描述**:加速图形端口,一种用于连接显卡的总线标准。 - **...

    清华大学Linux操作系统原理与应用

    1.5.2 Linux内核源代码的结构 13 1.5.3 Linux内核源代码分析工具 14 习题1 15 第2章 内存寻址 17 2.1 内存寻址简介 17 2.1.1 Intel x86 CPU寻址方式的演变 18 2.1.2 IA32寄存器简介 19 2.1.3 物理地址、虚拟地址及...

    Linux操作系统内存管理之磁盘高速缓存机制.pdf

    页高速缓存的核心数据结构是address_space对象,它是一个嵌入在页所有者的索引节点对象中的数据结构。address_space对象还在所有者的页面和对这些页面的操作之间建立起链接关系。每个页描述符都包括两个字段mapping...

    read()函数调用过程剖析

    address_space描述文件的page cache结构以及相关信息,并包含有操作page cache的函数指针。 read()函数调用过程是一个复杂的过程,涉及到多个层次的处理。但是,通过对每个层次的分析,我们可以更好地理解Linux...

    Linux驱动开发庖丁解牛之三 揭开字符设备驱动程序的面纱

    struct address_space *f_mapping; // 地址空间 }; ``` 2. **File Operations (文件操作)** - **定义**:`struct file_operations` 是一个包含多个指向文件操作函数指针的结构体,这些函数定义了如何执行基本...

    linux下的内存映射函数mmap详解及示例代码.doc

    在Linux系统中,每个进程都有一个虚拟地址空间(Virtual Address Space),该地址空间可以被分割成多个虚拟内存区(Virtual Memory Area,VMA),每个VMA都对应虚拟地址空间上的一段连续的区域,VMA是可以被共享和...

    基于Linux的堆栈溢出攻击和防御研究.pdf

    Linux操作系统的堆栈结构使得其容易受到溢出攻击,特别是在使用strcpy()函数时。 Linux操作系统的堆栈结构包括.text、.data、.bss、heap和stack五部分。其中,.text段存放程序的代码,.data段存放已初始化的静态...

Global site tag (gtag.js) - Google Analytics