Linux虚拟存储器系统(读书笔记)

April 14th, 2014 by JasonLe's Tech Leave a reply »

之前学了一段时间JOS的Env,对Linux的进程来说,每个进程有个进程控制块PCB。进程的消亡,就是Linux通过控制PCB进行的。

内核虚拟存储器包含内核中的代码和数据结构。内核虚拟存储器的某些区域被映射到所有进程共享的物理页面。例如,每个进程共享内核的代码和全局数据结构。下面这个图和JOS很像。高位属于kernel地址,低位留给user application。

QQ截图20140414203419

 

内核为系统中的每个进程维护一个单独的任务结构(源代码中的task_struct)。任务结构中的元素包含或者指向内核运行该进程所需要的所有信息(例如,PID,指向用户栈的指针、可执行的目标文件的名字以及程序计数器)。

QQ截图20140414203845

task_struct中的一个条目指向mm_struct,它描述了虚拟存储器中的当前状态。其中pgd指向第一级页表(页全局目录)的基址,而mmap指向一个vm_area_struct(区域结构)的链表,其中每个vm_area_structs都描述了当前虚拟地址空间的一个区域(area)。当内核运行这个进程时,它就将pgd存放在CR3控制寄存器中。

在JOS中使用lcr3(physics address)来记录地址。

一个具体区域结构包含下面的字段:

  • vm_start:指向这个区域的起始处。
  • vm_end:指向这个区域的结束处。
  • vm_prot:描述这个区域的内包含的所有页的读写许可权限。
  • vm_flags:描述这个区域内页面是与其他进程共享的,还是这个进程私有的(还描述了其他一些信息)。
  • vm_next:指向链表中下一个区域结构。

共享页面  

共享对象的关键点在于即使对象被映射到了多个共享区域,物理存储器也只需要存放共享对象的一个拷贝。

一个共享对象(注意,物理页面不一定是连续的。)

QQ截图20140414205618

私有对象是使用一种叫做写时拷贝(copy-on-write)的巧妙技术被映射到虚拟存储器中的。对于每个映射私有对象的进程,相应私有区域的页表条目都被标记为只读,并且区域结构被标记为私有的写时拷贝。

QQ截图20140414205641

 

其中有些函数比较重要.
mmap函数要求内核创建一个新的虚拟存储器区域是,最好是从地址start开始的一个区域,并将文件描述符fd指定的对象的一个连续的片(chunk)映射到这个新区域。连续的对象片大小为length字节,从距文件开始处偏移量为offset字节的地方开始。start地址仅仅是一个暗示,通常被定义为NULL。

#include<unistd.h>
#include<sys/mman.h>


void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset) ;
				//返回:若成功时则为指向映射区域的指针,若出错则为MAP_FAILED(-1)

 
我们可以使用这个函数将磁盘文件拷贝到stdout。首先我们要明确stdout 在write中fd=1 ,stderr fd =2

 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <setjmp.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <math.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>


void unix_error(char *msg)                                                                                          
{                                                                                                              
    fprintf(stderr, "%s: %s\n", msg, strerror(errno));                                                         
    exit(0);                                                                                                   
}   
int Open(const char *pathname, int flags, mode_t mode)                                                         
{                                                                                                              
    int rc;                                                                                                    
                                                                                                               
    if ((rc = open(pathname, flags, mode))  < 0)                                                               
    unix_error("Open error");                                                                                  
    return rc;                                                                                                 
}
ssize_t Write(int fd, const void *buf, size_t count)                                                           
{                                                                                                              
    ssize_t rc;                                                                                                
                                                                                                               
    if ((rc = write(fd, buf, count)) < 0)                                                                      
    unix_error("Write error");                                                                                 
    return rc;                                                                                                 
} 
void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)                                                                 
{                                                                                                              
    void *ptr;                                                                                                 
                                                                                                               
    if ((ptr = mmap(addr, len, prot, flags, fd, offset)) == ((void *) -1))                                     
    unix_error("mmap error");                                                                                  
    return(ptr);                                                                                               
}  

void mmapcopy(int fd, int size) 
{
    char *bufp; /* ptr to memory mapped VM area */

    bufp = Mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
    Write(1, bufp, size);
    return;
}


int main(int argc, char **argv) 
{
    struct stat stat;
    int fd;

    if (argc != 2) {
	printf("usage: %s <filename>\n", argv[0]);
	exit(0);
    }

    fd = Open(argv[1], O_RDONLY, 0);
    fstat(fd, &stat);
    mmapcopy(fd, stat.st_size);
    exit(0);
}