Linux虚拟存储系统

Linux为每一个进程单独维护了一个单独的虚拟地址空间,形式如图所示。

其中内核虚拟存储器包含内核中的代码和数据结构。内核虚拟存储器中的某些区域被映射到所有进程共享的物理页面。例如每个进程共享内核的代码和全局数据结构。

内核虚拟存储器的其他区域包含每个进程都不相同的数据,比如页表,内核在进程上下文中执行代码时用到的栈。

Linux将虚拟存储器组织成一些区域(也叫做段)的集合。一个区域就是已经存在的(已分配的)虚拟存储器的连续片,这些页是以某种方式相关联的。比如说代码段,数据段,堆,共享库段以及用户栈都是不同的区域。每个存在的虚拟页面都保存在某个区域中,而不属于某个区域的虚拟页是不存在的,并且不能被进程使用。

所以在Linux系统中发生缺页异常时,导致控制转移到内核的异常处理程序,这个处理程序将执行以下步骤:

1. 检查虚拟地址A是合法的吗?换句话说就是A是不是在某个区域内?所以缺页异常处理程序首先搜索区域结构的链表,把A和每个区域结构中的vm_start和vm_end做比较。(涉及一点点内核知识,等会上一个图)。

2. 检查存储器访问是否合法?就是说,该进程是否有读,或者写或执行这个区域内页面的权限。如果试图进行访问是不合法的,那么缺页处理程序会触发一个保护异常,从而终止这个进程。

3. 此刻,内核知道了这个缺页是由于对合法的虚拟地址进行合法的访问操作造成的。那个内核就选择牺牲一个页面,如果牺牲的这个页面被修改过,那么就将它交换出去,换入新的页面并更新页表。当缺页处理程序返回的时候,CPU将冲洗启动引起缺页的那个指令,这条指令将再次发送地址A到MMU。这次MMU就能正常的翻译A,而不会产生缺页中断了。

1 存储器映射

Linux通过将虚拟存储器区域与一个磁盘上的对象关联起来,以初始化这个虚拟存储器区域的内容,这个过程就叫做存储器映射。

存储器映射的概念其实来源于一个聪明的发现:如果虚拟存储器系统可以集成到传统的文件系统中,那么就能够提供一种简单而高效的把程序和数据加载到存储器中的方法。

进程这一抽象的概念能够为每个进程提供自己私有的虚拟地址空间,可以避免受其他进程的错误读写。不过有许多进程有同样的只读文本区域,而且许多程序需要访问只读运行时库代码的相同拷贝。比如每个C程序都需要来自标准C库的诸如printf这样的函数。那么如果每个进程都在物理存储器中保持这些常用代码的复制拷贝,那就是一种极大的浪费。所以,我们需要存储器映射给我们提供一种清晰的机制,来控制多个进程如何共享对象。

一个对象可以被映射到虚拟存储器的一个区域,要么作为共享对象,要么作为私有对象。如果一个进程将一个共享对象映射到它的虚拟之地空间的一个区域内,那么这个进程对这个区域的任何写操作,对于那些也把这个共享对象映射到他们虚拟存储器的其他的进程来说也是可见的。而且这些变化会反应在磁盘上的原始对象中。

对一个映射到私有对象的区域做改变的时候,对于其他进程来说是不可见的,并且进程对这个区域所做的任何写操作都不会反应在磁盘上的对象中。

理解fork函数

既然我们理解了虚拟存储器和存储器映射,那么我们就可以知道fork函数是如何创建一个带有自己独立虚拟地址空间的新进程的。

当fork函数被当前进程调用的时候,内核为新进程创建各种数据结构,并分配给新进程一个唯一的PID。为了给这个新进程创建虚拟存储器,它创建了当前进程的mm_struct,区域结构和页表的原样拷贝。它将两个进程中的每个页面都标记为只读,并将两个进程中的每个区域结构都标记为私有的写时拷贝(区域结构就是文本区,数据区,堆区,栈区哪些)。

当fork在新进程中返回时,新进程现在的虚拟存储器刚好和调用fork时存在的存你存储器相同。当这两个进程中的任何一个后来进行写操作时,写时拷贝机制就会创建新的页面,因此,也就为每个进程保持了私有地址空间的抽象概念。

理解execve函数

虚拟存储器和存储器映射在将程序加载到存储器到的过程中扮演者重要的角色。假设当前的进程中执行了如下的调用: execve(“a.out”, NULL, NULL);

execve函数在当前的进程中加载并运行包含在可执行目标文件a.out中的程序,用a.out程序有效的替代了当前程序。加载并运行a.out需要以下几个步骤:

  1. 删除已存在的用户区域:删除当前进程虚拟地址的用户部分中的已存在的区域结构。
  2. 映射私有区域:为新程序的文本,数据,bss,和栈区创建新的区域结构。所有这些新的区域都是私有的,写时拷贝的。文本和数据区域被映射为a.out文件中的文本和数据区。bss区域是请求二进制零的,映射到匿名文件,其大小包含在a.out中。栈和堆区域也是请求二进制零的,初始长度为0.
  3. 映射共享区域:如果a.out程序和共享对象(或目标)链接,比如标准C库libc.so,那么这些对象都是动态链接到这个程序的,然后在映射到用户虚拟地址空间中的共享区域内。
  4. 设置程序计数器(PC):exevce做的最后一件事情就是设置当前进程上下文中的程序计数器,使之指向文本区域的入口点。

如何使用mmap函数(用户级存储器映射)

Unix进程可以使用mmap函数来创建新的虚拟存储器区域,并将对象映射到这些区域中。

#include <unistd.h>
#include <sys/mman.h>
void *mmap(void *start, size_t length, int prot, int flag
           int fd, off_t offset);

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

参数prot包含描述新映射的虚拟存储器区域的访问权限位(在相应结构中的vm_prot位)

  • PROT_EXEC:这个区域内的页面由可以被CPU执行的指令组成。
  • PROT_READ:这个区域内的页面可读。
  • PROT_WRITE:这个区域内的页面可写。
  • PROT_NONE:这个区域内的页面不能被访问。

参数flag由描述被映射对象类型的位组成。如果设置了MAP_ANON标记为,那么被映射的对象就是一个匿名对象,而相应的虚拟页面是请求二进制零的。MAP_PRIVATE表示被映射的对象是一个私有的,写时拷贝的对象。而MAP_SHARED表示是一个共享的对象。

可以写一个C程序,使用mmap函数将一个任意大小的磁盘文件拷贝到stdout。

int main(int argc, char **argv)
{
  struct stat stat;
  int fd;
  if(argc != 2)
  {
    printf("Usage Wrong");
    exit(0);
  }
  fd = Open(argv[1], O_RDONLY, 0);
  fstat(fd, &stat);
  char * bufp;
  bufp = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE,
              fd, 0);
  Write(1, bufp, stat.st_size);
  exit(0);
}

转载于:https://www.cnblogs.com/nathan-1988/archive/2012/07/18/2598422.html

Linux虚拟存储系统相关推荐

  1. linux虚拟网卡名不是eth0,linux不能启动虚拟网卡eth0

    最近,在做linux虚拟机上做实验时,发现不能启动linux的网卡, 当我用ifconfig命令时,只有如下的信息出现: lo        Link encap:Local Loopback ine ...

  2. linux服务器lvs,Linux的企业-LVS(Linux虚拟服务器)及FULLNAT设置

    一.Linux Virtual Server (linux虚拟服务) lvs工作于IOS七层模型的传输层,通过对TCP.UDP.SCTP.IPsec ESP.AH这些工作在四层的协议的支持,根据目标地 ...

  3. 德国虚拟主机 linux,细说Linux虚拟主机的搭建及配置

    我们知道Linux操作系统是目前在服务器上应用广泛的操作系统.前面我们刚介绍了<Ubuntu虚拟机:如何选择虚拟化软件>,现在来提及Linux系统下的虚拟主机.在Linux操作系统下的虚拟 ...

  4. 网络设备中的linux,理解linux虚拟网络设备veth

    原标题:理解linux虚拟网络设备veth 前面介绍了linux network namespace,接着介绍一下如何让一个独立的网络命名空间和主机的网络互通,这里我们需要用到linux虚拟网络设备v ...

  5. linux虚拟文件系统浅析

    linux虚拟文件系统浅析 虚拟文件系统(VFS) 在我看来, "虚拟"二字主要有两层含义: 1, 在同一个目录结构中, 可以挂载着若干种不同的文件系统. VFS隐藏了它们的实现细 ...

  6. linux虚拟网络设备--eth, tap/tun, veth-pair(九)

    Linux 虚拟网络的背后都是由一个个的虚拟设备构成的.虚拟化技术没出现之前,计算机网络系统都只包含物理的网卡设备,通过网卡适配器,线缆介质,连接外部网络,构成庞大的 Internet. 然而,随着虚 ...

  7. linux 虚拟网络设备详解(四)

    Linux 抽象网络设备简介 和磁盘设备类似,Linux 用户想要使用网络功能,不能通过直接操作硬件完成,而需要直接或间接的操作一个 Linux 为我们抽象出来的设备,既通用的 Linux 网络设备来 ...

  8. RHEV平台中如何在 RED HAT ENTERPRISE LINUX 虚拟机上安装 GUEST 代理和驱动

    使用 Red Hat Enterprise Virtualization Agent 软件仓库所提供的 rhevm-guest-agent 软件包可以在 Red Hat Enterprise Linu ...

  9. linux redis 3.0.7,linux虚拟机上安装配置redis3.0.7

    linux shell 的 linux虚拟机上安装配置redis3.0.7 我们给大家列出详细的图文步骤教给大家在linux虚拟机上安装redis以及相关的配置流程. 将redis-3.0.7.tar ...

  10. [转+总结]Linux虚拟系统安装VMware Tools总结

    [转+总结]Linux虚拟系统安装VMware Tools总结 转自中国网络 一.VMware Tools安装手记(For Linux Guest OS) 为什么要装 VMware Tools? 因为 ...

最新文章

  1. Dialog 带白色的边的处理方法
  2. Bioinformatics|基于知识图谱嵌入的药物靶标发现
  3. 智领先机 惠普推出家庭信息中心HIC
  4. NeHe教程Qt实现——lesson07
  5. 如何下载github项目中的某一部分
  6. java获得服务器路径的几中方法
  7. weblogic9修改线程数设置
  8. 【转】从哈希存储到Bloom Filter
  9. Python3网络爬虫开发实战,Cookies 池的搭建,破解反爬虫!
  10. sublime press key “escape” can't type anything
  11. 将base64格式的图片下载到本地
  12. 计算机网络实验报告3-tcp,计算机网络实验报告3 TCP
  13. adadelta算法_机器学习中的优化算法(3)-AdaGrad, Adadelta(附Python示例)
  14. spring中@Autowired注解的原理
  15. 一些用JAVA实现的小题目
  16. javascript查看详情与收起详情
  17. 【分库分表ShardingSphere】
  18. python设置颜色深浅_海伯恩例外,因为颜色深浅
  19. windows10 1050ti vs2015 openc3.2 cuda8.0配置自己的darknetyolov3
  20. python pandas read_excel 参数详解 to_excel 读写Excel

热门文章

  1. 【转】mysql数据库中实现内连接、左连接、右连接
  2. [unity]网游中实现资源动态加载
  3. Mysql + keepalived 实现双主热备读写分离【转】
  4. hadoop核心框架简介
  5. 【笔记】vim如何删除重复行
  6. Luogu2680 [NOIP2015 提高组] 运输计划
  7. CF1041A Heist
  8. Code[VS]1302 小矮人
  9. elementui中下拉菜单需要传入多个参数的处理
  10. FastDFS的安装讲解