文件系统是操作系统的重要组成部分,是对文件的组织管理,本文就主要讲述磁盘上的文件是如何存储组织的和文件操作两个部分,废话不多说直接来看。
Linux 里有一句耳熟能详的话,一切皆文件,这也是 UNIX 系统的哲学体现。不论是普通文件,目录,块/字符设备,网络设备套接字等等,对于 Linux 来说都是文件,虽然它们的类型不同,但是 Linux 系统为它们提供了一套统一的接口来统一对待统一操作。
本文不聊那么多种文件,只来说说存储在磁盘上的文件,文件要存储在磁盘上的关键问题是记录各个文件分别用到哪些磁盘块,一般有着以下一些方法。
连续分配,顾名思义,将文件放在连续的物理空间中,如下图所示:
即连续分配就是文件存放在连续的数据块中,两个文件不能共用一个数据块,打个比方说如果一个文件实际利用了 3.5 个数据块,但实际上占用了 4 个数据块。前文也说过,文件系统操作的最小单位就是块,不能够再细分。
连续分配有着如下的优点:
但是缺点也很明显:
采用链表结构文件占用的各个数据块不必连续放置,每个数据块空出一定空间作为指针指向下一块,就如同链表一般,数据块就相当于结点,示意图如下:
这种组织形式的优缺点也很明显,就是数据结构里面讲的链式结构的优缺点,使用链表文件数据块便不必顺序存放,顺序读取比较方便但是随机访问比较麻烦。当某个数据块损坏或丢失便可能导致整个文件的损坏和丢失。
再者块大小一般是 2 的幂次方大小,但是这种方式组织文件每个数据块的大小不再是 2 的幂次方。许多程序会要求 2 的幂次方来读写数据,这就可能会导致额外的开销。
为解决上述问题,提出了一种解决方案,将所有的块指针拿出来组织在一起形成一个表放在内存中,这个表就是文件分配表(FAT, File Allocation Table
)。
如上图所示,文件 A 按先后顺序使用了块 4、0、6、2,文件 B 使用块 5、1、3、10、8。
由于每个磁盘块都会有一项记录所以文件分配表是跟磁盘大小成正比的,磁盘过大时文件分配表便会占用很多的内存,所以这种方案并不适用于大磁盘。
上述的 FAT
是将所有的磁盘块指针集中在一起放在内存中,使得文件使用的磁盘块能够前后连起来,而索引结构则是单独地将每个文件用到的磁盘块地址维护起来。也就是说为每个文件建立一个索引数据结构,里面存放的是文件使用的各个磁盘块地址。这是直接索引的方式,还有一级乃至多级索引,意思是存放的地址指向的并不是数据块,而是索引块,这个索引块里面又来存放数据块或者索引块的地址。
来看看 Linux 操作系统使用的索引结构 inode,inode 包含的信息很多,这里我们只是先说有关寻址的部分,直接来看大致结构图:
注每个块里面应存放了多个地址项,示意图只画出了一个来,关于这个问题操作系统里面有个经典例题,就比如说上图表示的 inode,有 12 个直接索引,1 个一级索引,1 个二级索引,1 个三级索引,再假设每个块 1 KB,一个地址项需要 4 字节来表示,则该 inode 最大能表示多大的文件?
直接索引:
每个索引块能存放 个地址
一级索引:
二级索引:
三级索引:
则支持的最大文件大小为将他们加和起来得到的结果约为 16G。
上述是对文件所使用的磁盘块的管理实现方式,对于磁盘上空闲的块也需要管理,这样当需要为一个新文件分配磁盘块的时候才方便操作,对于空闲空间的管理有着以下一些方法
磁盘上一段连续的未分配区域叫做空闲区,空闲区表属于连续分配的方式,具体做法是建立一张表,记录第一个空闲块的块号和连续空闲块个数。
每个空闲块里面存放一个指针,指向下一个空闲块,用这种方式将空闲块给串起来,将第一个空闲块保存在磁盘的特殊位置,同时也缓存在内存当中。
当创建文件时则从链头取下几块分配给该文件,当删除文件时将该文件占用的磁盘块连接到链头。
上述两种方法都不适合大型文件系统,会导致空闲表过大或者链式结构过长。空闲成组链表法顾名思义,先将空闲块分成一个个组,然后将这些组用链表法串起来。
将组中的组长块(一般第一个)作为“指针”指向下一个组,当然整个块是不可能只存放一个指针的,不然未免也太浪费了些,其实这个块里面还要存放下一个组的空闲块数、组长块号、各空闲块号等信息。
大家应该很熟悉了,就是用一个 bit 来表示一个磁盘块的使用情况,1 代表使用,0 代表空闲。对于 的磁盘, 的块大小,有 个磁盘块,则需要 来表示。
使用位图法会增加 CPU 的计算负担。
来看一个具体的文件系统 EXT2,捋一捋上面所讲的知识点,看看 EXT2 这种文件系统在磁盘上是怎么布局的。
直接先来看总体结构布局图:
MBR/GPT,操作系统引导块:不用多说了吧,见前文详解:[捋一捋磁盘及分区]
超级块:描述整个分区的文件系统信息,inode/数据块的大小、总量、使用量、剩余量,文件系统挂载时间、最近一次写入数据时间、最近一次检验磁盘时间等信息。
块组描述符表:块组描述符表存放的是块组描述符,有多少个块组就有多少个块组描述符。块组描述符存储的是 inode 数组,数据区域的起始位置,inode 和数据块的总量剩余量等信息,块组描述符表在每一个块组中都有一份拷贝
块位图:标记块的使用情况,每一个 bit 表示磁盘块是否空闲可用,只占用 1 块。
inode 位图:标记 inode 的使用情况,每一个 bit 表示 inode 是否空闲可用,只占用 1 块。
inode 数组:存储所有 inode 的地方,inode 几乎包括了一个文件除文件名之外的所有信息,主要包括文件大小,拥有者组的 ID,读写执行权限,时间戳等属性信息,还有就是数据块指针。
数据块:存放具体的文件内容数据
目录也是文件,与普通文件不同的是,它的数据是文件信息,也就是说,目录是包含文件信息的文件。
目录就是一张表,里面存放的是目录项,主要有 3 个属性:文件名、 inode 编号,文件类型。inode 包含了一个文件的绝大部分信息,但是并没有包含文件名,这属性是在目录项这儿指出的。目录项最主要的作用就是将 inode 和文件名给联系起来。
每个目录文件会至少包括两个目录项:当前目录 .
以及父目录 ..
,如下图空文件夹 test 下所包含的目录项:
需要注意的是根目录的父目录还是自己,也就是说根目录的两个目录项 .
和 ..
是一样的。
那路径又是什么呢?我们经常看到如上图 /OS/test
这样的路径表示,仔细看看会发现其实这就是用 '/'
隔开的一个个文件名。
路径有两种,一种是如上面一般最左边是由 '/'
开始的路径,这叫做绝对路径,比如说 /a/b/c.txt,这说明做路径解析时从根目录开始解析,即在根目录下查找 a 目录,a 目录下查找 b 目录,b 目录下查找 c.txt 文件。
另一种是相对路径,相对于当前位置的路径,不以 '/'
开头,比如说 a/b.txt,当前目录下查找 a 目录,a 目录下查找 b.txt 文件。./c.txt 表示在当前目录下查找 c.txt 文件。../d.txt 表示在当前目录的父目录下查找 d.txt 文件。
上面一直在抽象地说查找,下面来具体看看怎们根据路径来找到相应的文件。前面说过单看路径这一串字符的话,会发现其实路径就是被分隔符 '/'
隔开的一个个文件名,有了文件名那就好办了,目录项里面就存储着文件名和 inode 编号的对应关系,所以查找文件就是在目录项中根据文件名找到相应 inode
编号,具体的可以分为以下四步:
inode 存储的是文件本身的信息,对于文件我们经常要不停的操作,所以也得有记录文件操作信息的结构。
这个数据结构就是文件结构体(struct file
),打开一个文件就会产生一个文件结构体,所有的这些文件结构体由内核集中管理组成文件表,文件结构体也就是文件表的表项。文件表是全局的,不是某个进程私有的。
文件结构体主要包含的信息路径,inode 指针,打开次数,文件偏移位置等等。都应该很好理解吧,不详细解释了。
但每个进程操作的文件不应该隔离开吗?对头,*所以每个进程又有一个打开文件描述符表(`struct file fd_array[NR_OPEN_DEFAULT]`),可以看出它是一个指针数组,指向的是文件表项(文件结构体)**。
这个数组的索引便是文件描述符,他是一个数组的索引,所以文件描述符都是非负整数。
这是两个关于文件描述符的函数,dup 的函数原型如下:
int dup(int oldfd);
函数 dup 复制文件描述符 oldfd,返回一个新描述符 newfd,这个 newfd 有以下两个特点:
dup2 与 dup 很相似,函数原型如下:
int dup2(int oldfd, int newfd);
该函数的功能与 dup 相似,只是可以自己决定返回的文件描述符,而不是返回最小可用的文件描述符。
文件指针就是打开文件描述符表的元素,即 fd_array[i]
,指向的是文件表项。
文件流指针是 c语言里面用的,c 语言头文件 stdio.h 中定义了一个 FILE 结构体,名字与 file 结构相同,不要搞混淆了,来看看怎么定义的:
struct _iobuf {
char *_ptr; //文件输入的下一个位置
int _cnt; //当前缓冲区的相对位置
char *_base; //指基础位置(即是文件的其始位置)
int _flag; //文件标志
int _file; //文件的有效性验证,实际上就是文件描述符
int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取
int _bufsiz; //缓冲区大小
char *_tmpfname; //临时文件名
};
typedef struct _iobuf FILE;
上面那个 int _file 实际上就是文件描述符,所以 c 语言的 FILE 结构体其实就是文件描述符的封装。
这下捋清楚有关文件操作的这些名词了吧,弄清楚上面的内容后我们再来看一看关于文件描述符和文件表项需要注意的一些地方:
最后来看一看示意图从头捋一捋:
关于文件我们在内存里面维护了三种数据结构:文件描述符,文件结构体,以及内存中的 inode,这三种结构集合起来就是上面所讲过的各种表,内存中的 inode 基本上和磁盘上的一样,可以看作是磁盘上的 inode 缓存。
当然文件的部分具体数据在内存里面也是有缓存的,操作文件在内存中的缓存和为其维护的结构,再同步到磁盘就是有关文件的系统调用实际干的事情。
同步到磁盘可以看作是写磁盘,有关磁盘的读写操作都是有具体的指令 in 和 out。可以使用内联汇编等方式将这两条指令封装成函数便于调用。
下面来看一些具体的文件操作的大致原理。
创建文件:一个文件对应一个 inode,创建一个文件就要使用一个 inode,所以要在 inode 位图和 inode 数组中申请空闲的 inode。当然创建的还有文件本身,所以也要在块位图中申请数据块。文件肯定也要属于某个目录,所以该目录要增加一个目录项。
打开文件:一般是根据给定的路径和标识打开文件,所以首先要进行路径解析,得到文件的 inode,将其加载到内存中的 inode 缓存中,然后创建文件表项,创建文件描述符。
关闭文件:回收相应文件描述符,文件表项中的文件打开数减一,如果减到 0 的话再删除文件表项,回收缓存中的 inode。
读写文件:大致就是对磁盘的读写,使用上述说的 in 和 out 指令,但是磁盘 I/O 速度很慢,所以都需要一个缓存区中转来减少 I/O 次数。当然还有一些其他技术比如说 DMA,这儿就不展开了。
文件的读写指针定位(lseek):其实就是设置文件表项中的文件偏移属性。
删除文件:基本上就是创建文件的逆操作。
创建目录:为新目录分配 inode,分配块,新目录中添加两个目录项 . 和 .. ,新目录的父目录中添加新目录的目录项。
删除目录:也基本上就是创建目录的逆操作
至于目录的其他操作原理基本也和普通文件类似,或者说对于磁盘上文件的所有操作基本原理都类似。记住 CPU 是不能和磁盘直接交换数据的,直接与 CPU 打交道的是内存,所以要对磁盘上的文件做什么操作都是要先读取到内存,在内存中操作完之后同步到磁盘。
操作系统可能支持多个文件系统,各个文件系统对文件操作管理实现的方式可能不尽相同,而为了统一,在文件系统之上添加一个代理虚拟文件系统,使其对外表现出统一的接口。
进程,虚拟文件系统,文件系统,外存的大致关系如下所示:
虚拟文件对外提供统一的接口供进程调用,这个接口一般是 POSIX 标准的系统调用,比如说 open,write 之类的,各个文件系统提供实际的功能函数进行实际的操作。这就又与前文系统调用联系起来了,可以看看前文将知识串一串:[捋一捋系统调用] Linux 不像 Windows 为每一个分区分配一个字母作为盘符,每一个分区直接摆在那了,Linux 要使用某个分区必须要挂载到某个目录才行。
挂载是一种访问文件系统的方法,实际上就是将某个文件系统和当前目录树中的一个目录联系起来的一个过程。举个例子,我要将一个新分区上的文件系统挂载到 /a 底下,那么 /a 这个目录就会显示新的分区上的信息,之后就可以对其上的文件进行操作。
这个目录原则上应该是空目录,否则这个目录下的东西会被暂时隐藏掉,直到卸载之后才会重新出来。
有关文件系统本文就先说到这,有什么错误还请批评指正,也欢迎大家来同我交流讨论学习进步。
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/zlGeu_Z8av9mE_zjMs8vhA
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。