我们每天都使用计算机操作文件,对文件进行创建、修改等操作,而文件系统是操作系统中非常重要的一个板块,文件系统(File System)在操作系统中有很多值得探究的点,例如它是如何提高用户读写文件的效率的,如何在我们关机电脑后,重新启动将文件内容重新恢复,如果有多个进程同时对一个文件进行内容的修改操作,那么如何保证每个进程的读写文件操作会互不干扰,笔者在后续都会对这些内容进行探讨,本文旨在从底层介绍文件系统的大致组成与一般的读写流程
所有的操作系统基本都会将文件系统分为硬盘空间与内存空间两部分,硬盘空间中保存的是持久化过后的数据,这部分数据无论计算机发生怎样的进程崩溃都不会被改变,内存空间中保存的是用户最近访问操作过的数据,以xv6操作系统为例,其总体的文件系统布局如下图:
而内存区去保存的所有文件最终都会被持久化到磁盘中,因此disk(磁盘)中,各个内存区域的文件也存储在各自的位置上,下面为disk中的文件分区:
下面对每个分区进行介绍:
boot:存放操作系统启动时的必需指令,不可修改
super block:存放文件系统模块的一些元信息,例如数据块的大小,文件索引节点的数量,log(日志)区域中的数据块数量等
log:存储对于内存区域文件的创建修改等信息,可以结合事务(transaction)完成计算机在崩溃操作后的文件恢复(crash recovery)
inode:在xv6操作系统中为64bit大小,存储了单个文件的属性、权限、数据地址等信息,可以提高文件查找效率,同时在文件被修改后,也可以通过inode找到原本的文件地址进行恢复
bitmap:标记了正在使用的文件信息,存储了inode到文件实际地址的一一映射
data:存储文件的实际内容
以xv6操作系统举例,在用户创建文件并写入字符时,并不会直接将写入的字符存储到指定的文件中,而是要先完成创建这个文件的一些初始化信息,这里以echo 'hi' > x
这条命令举例,我修改了write函数,使其在写入数据时会进行输出操作:
这条echo指令主要可以分为这三个阶段,下面我们对每条指令进行解释:
write 33 每个文件都有文件头,这条指令在文件头中将这个地址空间设置为有数据
write 33 创建inode的文件索引
write 46 将当前创建文件的目录写到数据空间中
write 32 更新inode的数据块大小
write 33 完成其他数据的更新
write 45 将inode文件索引与文件数据块地址映射加入bitmap
write 595 写入“h”
write 595 写入“i”
write 33 更新inode文件索引中的数据块大小
write 595 写入“\n”
write 33 更新inode文件索引的数据块大小
因此,操作系统中的文件在修改时,会实时更新文件的索引与文件的实际数据块,保证后续查找文件以及使用文件的高效进行
在操作系统中,一定会出现多个进程同时对文件进行修改操作的情况,这时主要由锁来完成数据块的安全性保护,由于操作系统在创建文件时,会将文件首先存储在Buffer Cache(缓存)中,因此多进程的并发性主要在缓存区的get/write等方法中进行维护,以xv6操作系统为例:
xv6操作系统的缓存区数据结构定义如下:
在该结构体中,主要维护了一把锁和一个双向链表,在进程每次要获取空闲的缓冲区时都需要获取锁进行查询:
这里主要由两个分支模块,如果缓冲区中有空闲的缓存会直接返回这块缓存区域,反之则会遍历缓冲区的区域,通过LRU原则驱逐最近最少使用的内存区域,refcnt记录了缓存区域被进程使用的个数,如果为零表示没有被使用,那么操作系统会将它更新并返回出去,而这里的所有模块都需要再获取缓冲区的自旋锁(spinlock)后才可以进行
而这里有一个值得思考的点就是acquiresleep(&b->lock)
操作,这个指令的主要作用是让缓冲区进入睡眠锁状态,睡眠锁状态下的缓存区域会让出CPU来提高系统执行的整体效率
以上就是关于文件系统(File System)的总体介绍以及流程讲解了,关于操作系统讨论的话题有很多,以xv6操作系统举例,它的缓冲区共用一把锁,导致每次对缓冲区进行文件操作时都要获取锁才可以执行,效率缓慢,如何提高缓冲区的文件执行效率,系统崩溃后文件又如何恢复,如何提高内存持久化到磁盘的更新等,笔者在后续都会尽力讲解这些问题,希望能对你有所帮助!!!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。