程序员论文总结与思路分享

Linux文件操作源码分析记录(写、修改、关闭、删除文件)

2020-02-04  本文已影响0人  CPinging

上一篇文章我们follow了一下Linux 0.11版本打开与读文件操作,本篇文章我们对写文件进行一个详细的叙述。

上一篇文章链接在此:https://www.jianshu.com/p/f79f27817a28

基础篇

image.png

文件系统用来存储文件内容、文件属性、和目录。这些类型的数据如何存储在磁盘块上的呢?unix/linux使用了一个简单的方法。

它将磁盘块分为三个部分:

  1. 超级块,文件系统中第一个块被称为超级块。这个块存放文件系统本身的结构信息。比如,超级块记录了每个区域的大小,超级块也存放未被使用的磁盘块的信息。
  2. inode表。超级块的下一个部分就是i-节点表,每个文件都有一些属性,如文件的大小、文件所有者、和创建时间等,这些性质被记录在一个称为i-节点的结构中。所有i-节点都有相同的大小,并且i-节点表是这些结构的一个列表,文件系统中每个文件在该表中都有一个i-节点。
  3. 数据区。文件系统的第3个部分是数据区。文件的内容保存在这个区域。磁盘上所有块的大小都一样。如果文件包含了超过一个块的内容,则文件内容会存放在多个磁盘块中。一个较大的文件很容易分布上千个独立的磁盘块中.

写文件操作

由于所研究的操作系统为Linux 0.11 所以我们的文件所存储的大小是有限的,并且操作系统只能以数据块(1 KB)为单位,将缓冲区中的缓冲块(1 KB)的数据同步到外设上。

简单来说:进程空间的数据先要写入缓冲区中,然后操作系统在适当的条件下,将缓冲区中的数据同步到外设上。“这就需要在同步之前,缓冲块与外设上要写入的逻辑块进行一对一绑定,确定外设上的写入位置,以此保证用户空间写入缓冲块的数据,能够准确地同步到指定逻辑块中。”

那么我们如何确定文件的写入位置呢?

具体来说,系统将首先调用write()之后调用sys_write()最后调用file_write()函数。

其中file_write()中有create_block()函数,用于创建新的数据块。

image.png

在create_block()函数中包括_bmap()函数,这个函数之前也出现过,而当时第三个参数传入的为0,这里传入1,代表新建一个块:

image.png

具体的创建工作是在new_block()函数中进行的,内容包括两部分:

1)将新建数据块对应的逻辑块位图置1。

2)在缓冲区中为新建的数据块申请缓冲块,用以承载写入的内容。

image.png

回到file_write()函数:

image.png

之后我们需要将主存中的数据复制到缓冲块


image.png image.png

至此我们已经将数据写入到缓冲区中,之后我们需要将数据从缓冲区转移到外设:

数据从缓冲区同步到硬盘有两种方法。

①一种是updata定期同步;②另一种是因缓冲区使用达到极限,操作系统强行同步。

而这里为了性能考虑,系统并不会立即将数据写入底层。I/O代价实在是非常大的。

那么对于第一种:update定期同步需要一个常驻内存的update进程,该进程会调用pause()函数,并映射到sys_pause()函数,使该进程被设置为可中断等待状态。每隔一段时间,操作系统就将updata进程唤醒。它执行后,调用sync()函数,将缓冲区中的数据同步到外设上。

即:update进程——>pause()——>sys_pause()——>sync()——>sys_sync()

sys_sync()函数先将改动过的文件i节点写入缓冲区(其余内容已经在缓冲区中了),之后,遍历整个缓冲区,只要发现其中缓冲块内容被改动过(b_dirt被置1),就全部同步到外设上。

image.png

这里我们需要详细的看一下sync_inodes()函数是如何将inode写入缓冲区的。

image.png

当inode改过,则调用write_inode()函数:

image.png image.png

最后我们需要回到最初的函数中,当sync_inodes()同步完成后,我们将缓冲区中的数据更新,如果发现该数据内容被改写(b_dirt置1了,于是我们就将缓冲区同步到外设中即可)

image.png

第二种可能,倘若一次性写入大量的数据,那么我们缓冲区肯定无法容下如此庞大的数据量,于是等不到update被唤醒我们就需要同步操作,此时需要getblk()函数发挥作用了:

当在缓冲区中找到的空闲块都已经无法继续写入信息(b_dirt都是1)时,就说明需要腾空间了。

image.png

修改文件操作

image.png

由于写文件是从末尾追加,而无法修改中间数据。那我们应该如何修改数据呢?

这就需要我们使用sys_lseek()函数了:

image.png

之后根据偏移量进行修改即可:

image.png

文件改为 hello,Linuxworld。

关闭文件操作

“close()函数最终映射到sys_close()系统调用函数去执行。将当前进程的task_struct中的filp[20]与file_table[64]解除关系。”

image.png

根据前文我们知道,filp[]为用户进程中的数组,而file_table[]为内核中的登记数组。

image.png

删除文件操作

“删除文件与5.7节中关闭文件有所不同:关闭文件只是解除当前进程与hello.txt文件在file_table[64]中指定挂接点的关系,而删除操作的效果表现为所有进程都无法访问到hello.txt这个文件。”

其调用sys_unlink()函数:

1 获取文件inode
2 检查inode属性
3 检查权限保证可以删除

image.png image.png

而iput函数用于清除inode上的所有信息:

此时对应truncate():

image.png

用于将一级、多级索引释放:

即调用:

memset(inode,0,sizeof(*inode));//将i节点表中hello.txt文件i节点的表项清零

清0后,即使磁盘上仍然保存数据,但是没有任何手段能访问到了。

上一篇下一篇

猜你喜欢

热点阅读