⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 3.html

📁 介绍linux下文件和设备编程
💻 HTML
📖 第 1 页 / 共 4 页
字号:
mm/swap_file.c 交换分区/文件的操作。<p>mm/page_io.c 读或写一个交换页。<p>mm/swap_state.c swap cache相关操作,加入/删除/查找一个swap cache等。<p>mm/vmscan.c 扫描进程的vm_area,试图换出一些页面(kswapd)。<p>reclaim_page:从inactive_clean_list回收一个页面,放到free_list<p>&nbsp;&nbsp;&nbsp; kclaimd被唤醒后重复调用reclaim_page直到每个区的<p>zone-&gt;free_pages&gt;= zone-&gt;pages_low<p>&nbsp;&nbsp;&nbsp; page_lauder:由__alloc_pages和try_to_free_pages等调用。通常是由于freepages + inactive_clean_list的页太少了。功能:把inactive_dirty_list的页面转移到inactive_clean_list,首先把已经被写回文件或者交换区的页面(by bdflush)放到inactive_clean_list,如果freepages确实短缺,唤醒bdflush,再循环一遍把一定数量的dirty页写回。<p>&nbsp;&nbsp;&nbsp; 关于这几个队列(active_list,inactive_dirty_list,inactive_clean_list)的逻辑,请参照:文档:RFC: design for new VM,可以从lisoleg的文档精华获得。<p>page cache、buffer cache和swap cache<p>&nbsp;&nbsp;&nbsp; page cache:读写文件时文件内容的cache,大小为一个页。不一定在磁盘上连续。<p>&nbsp;&nbsp;&nbsp; buffer cache:读写磁盘块的时候磁盘块内容的cache,buffer cache的内容对应磁盘上一个连续的区域,一个buffer cache大小可能从512(扇区大小)到一个页。<p>&nbsp;&nbsp;&nbsp; swap cache: 是page cache的子集。用于多个进程共享的页面被换出到交换区的情况。<p>page cache 和 buffer cache的关系<p>&nbsp;&nbsp;&nbsp; 本质上是很不同的,buffer cache缓冲磁盘块内容,page cache缓冲文件的一页内容。page cache写回时会使用临时的buffer cache来写磁盘。<p>bdflush: 把dirty的buffer cache写回磁盘。通常只当dirty的buffer太多或者需要更多的buffer而内存开始不足时运行。page_lauder也可能唤醒它。<p>kupdate: 定时运行,把写回期限已经到了的dirty buffer写回磁盘。<p>&nbsp;&nbsp;&nbsp; 2.4的改进:page cache和buffer cache耦合得更好了。在2.2里,磁盘文件的读使用page cache,而写绕过page cache,直接使用buffer cache,因此带来了同步的问题:写完之后必须使用update_vm_cache()更新可能有的page cache。2.4中page cache做了比较大的改进,文件可以通过page cache直接写了,page cache优先使用high memory。而且,2.4引入了新的对象:file address space,它包含用来读写一整页数据的方法。这些方法考虑到了inode的更新、page cache处理和临时buffer的使用。page cache和buffer cache的同步问题就消除了。原来使用inode+offset查找page cache变成通过file address space+offset;原来struct page 中的inode成员被address_space类型的mapping成员取代。这个改进还使得匿名内存的共享成为可能(这个在2.2很难实现,许多讨论过)。<p>虚存系统则从freeBSD借鉴了很多经验,针对2.2的问题作了巨大的调整。<p>&nbsp;&nbsp;&nbsp; 文档:RFC: design for new VM不可不读。<p>&nbsp;&nbsp;&nbsp; 由于时间仓促,新vm的很多细微之处我也还没来得及搞清楚。先大致罗列一下,以后我将进一步完善本文,争取把问题说清楚。另外,等这学期考试过后,我希望能为大家提供一些详细注释过的源代码。<p><p><br><center><A HREF="#Content">[目录]</A></center><hr><br><A NAME="I378" ID="I378"></A><center><b><font size=+2>用户态</font></b></center><br>&nbsp;&nbsp;&nbsp; 用户空间存取内核空间,具体的实现方法要从两个方面考虑,先是用户进程,需要调用mmapp来将自己的一段虚拟空间映射到内核态分配的物理内存;然后内核空间需要重新设置用户进程的这段虚拟内存的页表,使它的物理地址指向对应的物理内存。针对linux内核的几种不同的内存分配方式(kmalloc、vmalloc和ioremap),需要进行不同的处理。<p>一、Linux内存管理概述<p>这里说一下我的理解,主要从数据结构说。<p>1、物理内存都是按顺序分成一页一页的,每页用一个page结构来描述。系统所有的物理页 面的page结<p>构描述就组成了一个数组mem_map。<p>2、进程的虚拟地址空间用task_struct的域mm来描述,它是一个mm_struct结构,这个结构包包含了指向?<p>程页目录的指针(pgd_t * pgd)和指向进程虚拟内存区域的指针(struct vm_area_structt * mmap)<p>3、进程虚拟内存区域具有相同属性的段用结构vm_area_struct描述(简称为VMA)。进程所所有的VMA?<p><br>树组织。<p>4、每个VMA就是一个对象,定义了一组操作,可以通过这组操作来对不同类型的VMA进行不屯 的处理。<p>例如对vmalloc分配的内存的映射就是通过其中的nopage操作实现的。<p>二、mmap处理过程<p>当用户调用mmap的时候,内核进行如下的处理:<p>1、先在进程的虚拟空间查找一块VMA;<p>2、将这块VMA去映射<p>3、如果设备驱动程序或者文件系统的file_operations定义了mmap操作,则调用它<p>4、将这个VMA插入到进程的VMA链中<p>file_operations的中定义的mmap方法原型如下:<br>int (*mmap) (struct file *, struct vm_area_struct *);<p>其中file是虚拟空间映射到的文件结构,vm_area_struct就是步骤1中找到的VMA。<p>三、缺页故障处理过程<p>当访问一个无效的虚拟地址(可能是保护故障,也可能缺页故障等)的时候,就会产生一个个页故障,?<p>统的处理过程如下:<p>1、找到这个虚拟地址所在的VMA;<p>2、如果必要,分配中间页目录表和页表<p>3、如果页表项对应的物理页面不存在,则调用这个VMA的nopage方法,它返回物理页面的paage描述结构<p>(当然这只是其中的一种情况)<p>4、针对上面的情况,将物理页面的地址填充到页表中<p>当页故障处理完后,系统将重新启动引起故障的指令,然后就可以正常访问了<p>下面是VMA的方法:<br>struct vm_operations_struct {<br> void (*open)(struct vm_area_struct * area);<br> void (*close)(struct vm_area_struct * area);<br> struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, innt<p>write_access);<br>};<p>其中缺页函数nopage的address是引起缺页故障的虚拟地址,area是它所在的VMA,write_acccess是存取<p>属性。<p>三、具体实现<p>3.1、对kmalloc分配的内存的映射<p>对kmalloc分配的内存,因为是一段连续的物理内存,所以它可以简单的在mmap例程中设置汉 页表的物<p>理地址,方法是使用函数remap_page_range。它的原型如下:<p>int remap_page_range(unsigned long from, unsigned long phys_addr, unsigned long size,<p>pgprot_t prot)<p>其中from是映射开始的虚拟地址。这个函数为虚拟地址空间from和from+size之间的范围构栽 页表;<p>phys_addr是虚拟地址应该映射到的物理地址;size是被映射区域的大小;prot是保护标志?<p>remap_page_range的处理过程是对from到form+size之间的每一个页面,查找它所在的页目侣己 页表(<p>必要时建立页表),清除页表项旧的内容,重新填写它的物理地址与保护域。<p>remap_page_range可以对多个连续的物理页面进行处理。&lt;&lt;Linux设备驱动程序&gt;&gt;指出,<p>remap_page_range只能给予对保留的页和物理内存之上的物理地址的访问,当对非保留的页页使?<p>remap_page_range时,缺省的nopage处理控制映射被访问的虚地址处的零页。所以在分配内内存后,就?<p>对所分配的内存置保留位,它是通过函数mem_map_reserve实现的,它就是对相应物理页面?<p>PG_reserved标志位。(关于这一点,参见前面的主题为“关于remap_page_range的疑问”档奶致郏?<p>因为remap_page_range有上面的限制,所以可以用另外一种方式,就是采用和vmalloc分配档哪 存同样<p>的方法,对缺页故障进行处理。<p>3.2、对vmalloc分配的内存的映射<p><br>3.2.1、vmalloc分配内存的过程<p>(1)、进行预处理和合法性检查,例如将分配长度进行页面对齐,检查分配长度是否过大?<p>(2)、以GFP_KERNEL为优先级调用kmalloc分配(GFP_KERNEL用在进程上下文中,所以这里里就限制了?<p>中断处理程序中调用vmalloc)描述vmalloc分配的内存的vm_struct结构。<p>(3)、将size加一个页面的长度,使中间形成4K的隔离带,然后在VMALLOC_START和VMALLOOC_END之间<p>编历vmlist链表,寻找一段自由内存区间,将其地址填入vm_struct结构中<p>(4)、返回这个地址<p>vmalloc分配的物理内存并不连续<p>3.2.2、页目录与页表的定义<p>typedef struct { unsigned long pte_low; } pte_t;<br>typedef struct { unsigned long pmd; } pmd_t;<br>typedef struct { unsigned long pgd; } pgd_t;<br>#define pte_val(x) ((x).pte_low)<p>3.2.3、常见例程:<p>(1)、virt_to_phys():内核虚拟地址转化为物理地址<br>#define __pa(x)&nbsp; ((unsigned long)(x)-PAGE_OFFSET)<br>extern inline unsigned long virt_to_phys(volatile void * address)<br>{<br> return __pa(address);<br>}<p>上面转换过程是将虚拟地址减去3G(PAGE_OFFSET=0XC000000),因为内核空间从3G到3G+实实际内存一?<p>映射到物理地址的0到实际内存<p>(2)、phys_to_virt():内核物理地址转化为虚拟地址<br>#define __va(x)&nbsp; ((void *)((unsigned long)(x)+PAGE_OFFSET))<br>extern inline void * phys_to_virt(unsigned long address)<br>{<br> return __va(address);<br>}<br>virt_to_phys()和phys_to_virt()都定义在include\asm-i386\io.h中<p>(3)、#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) &gt;&gt; PAGE_SHIFT))(内核核2.4?<br>&nbsp;&nbsp; #define VALID_PAGE(page) ((page - mem_map) &lt; max_mapnr)(内核2.4)<br>第一个宏根据虚拟地址,将其转换为相应的物理页面的page描述结构,第二个宏判断页面是是不是在有?<p>的物理页面内。(这两个宏处理的虚拟地址必须是内核虚拟地址,例如kmalloc返回的地址#

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -