Linux内核源码分析之文件系统(1) -- 三思而后行

原创文章,转载请注明: 转载自 SunliyMonkey技术博客
本文链接地址: Linux内核源码分析之文件系统(1) -- 三思而后行

URL: http://blog.csdn.net/sunliymonkey/article/details/48657757

最近开始研究Linux文件系统,希望通过阅读源码,了解文件系统的设计要素、控制逻辑,最终自己能够实现出一个简易的文件系统。
    
经历过内核源码阅读的小伙伴,相信你在最初面对如此庞大的内核源码时,一定会有种“面对茫茫大海,无从下手”的感觉,即便幸运的找到了逻辑入口,却在繁琐的函数跳转中晕头转向,无法把握住整个控制路径上的重难点。代码阅读之后,无法上升到整体设计,提炼出实现者的出发点,对代码逻辑,常常感觉迷惑,无法洞悉代码背后的原理。
Linux内核源码分析之文件系统(1) -- 三思而后行_第1张图片
鉴于此,在研究该部分代码前,我从实现的角度出发,根据文件系统的功能往下进行推敲,提炼出文件系统的重难点,有方向性地阅读代码、印证想法、解决疑问。

挖掘出技术难点,带着问题有方向性的阅读代码,这样能够做到事半功倍,同时对整体结构的理解,更加透彻

1. 文件系统是什么                                                           


首先,我们先来考虑下“文件系统是什么?”,在早期操作系统还未出现文件系统这个概念的时候,如果程序需要存储数据,那么它必须自己实现文件存储、文件管理的代码,程序本身需要与硬盘驱动器打交道。最令人头痛的是,你存储文件的地方可能被其他程序覆盖,导致数据的丢失。


为了解决这个“各自为营,重复创造”的现象,大家提出采用统一的中间层,管理应用程序与硬盘之间的文件交互。这样做的好处就是:
  • 应用程序不再关注文件的存储与管理,能够专注于自身的应用逻辑控制
  • 统一的中间层知道所有文件存储的信息,能够避免文件覆盖现象的出现,进行更有效的数据管理
总结来说:
    文件系统是应用程序与块设备(磁盘等)之间的桥梁,是对文件进行统一管理的中间层。          
         对上: 向上层用户提供读写文件的操作接口
                                         
         对下: 将文件在磁盘上进行存储及有效的管理                                        

Linux内核源码分析之文件系统(1) -- 三思而后行_第2张图片

2. 文件系统涉及什么                                                        


2.1 文件系统挂载                                                                                 


在Linux环境下,磁盘作为一种特殊的文件(Linux系统中一切皆文件),允许用户进行读写操作,但是如果我们想要正常使用,在其上创建文件夹,文件等,则必须经过以下几道工序:

  • 采用某种文件系统格式化磁盘

      mkfs -t ext3 /dev/sdb              

  • 为磁盘创建挂载点

      mkdir /sdb_dir                     

  • 挂载磁盘到指定目录下

      mount /dev/sdb /sdb_dir           

  • 修改/ext/fstab配置文件,设置开机自启

      /dev/sdb /sdb_dir ext3 defaults 0 0


我们可以将上面的步骤大体分为两步:

(1)磁盘格式化  : 写入超块信息,按照特有的数据布局,对磁盘进行格式化

(2)文件目录入口: 在整个系统文件目录上,为其寻一入口,以后由此进入


2.2  技术点初总结                                                                                  

 

从上面的步骤中,我们可以发现磁盘无法直接使用,首先需要经过某种文件系统的格式化,而这个格式化过程,包括注册超块信息,将磁盘划分成数据块进行管理,也就是说:文件是由多个数据块联接在一起进行表示。从这里出发,我们来思考一下,文件系统可能涉及哪些技术点:


  1. 文件存储方式
  • 应用程序直接打交道的是文件,文件是采用何种方式持久化在磁盘上呢?
  • 如果采用数据分块的方式,数据块如何有效组织在一起,表示成一个文件?
  2. 读、写、定位的实现
  • 如何快速定位文件中一个数据块的位置?比如要查看文件某个位置的数据。
  3. 元数据的管理
  • 元数据有哪些?目录树,空闲块的维护?
  4. 数据一致性保证
  • 内存的数据与硬盘上的数据如何来往? 何时将内存中的数据固化到磁盘,以防断电等造成的数据丢失。
上面我是想到啥,说到啥,整体感觉,有些凌乱,可能会遗漏某些技术点。接下来,从文件系统的基本功能“读写文件”出发,我们来尝试挖掘出一些有用的技术点。

2.3 读写流程分析                                                                              

在这里,我们尝试分析下读写逻辑,整理其控制路径,当然这里只是一个粗糙的版本,毕竟此时我们还未读代码,只是猜想其过程,同时暂且不讨论Page Cache,均采用Direct IO的方式:
    
        Linux内核源码分析之文件系统(1) -- 三思而后行_第3张图片

(1)根据文件路径,查找目录树,获得当前文件目录项

(2)通过文件目录项,可以获得该文件起始块,文件大小,权限等信息

(3)通过文件起始块,文件偏移,以某种方式,得到目标数据块位置 (这里需要研读下如何快速定位某数据块)

(4)读整个目标数据块,数据缓存于内存当中  (是否将整个目标数据块读出来,这里不确定,有待源码印证)

(5)拷贝数据到读请求的buffer当中



         Linux内核源码分析之文件系统(1) -- 三思而后行_第4张图片

(1)根据文件路径,查找目录树,获得当前文件目录项

(2)通过文件目录项,可以获得该文件起始块,文件大小,权限等信息

(3)通过文件大小,如果发现文件偏移超过文件大小,则通过“空闲块管理”获取新的数据块位置。否则,通过文件起始块,文件偏移,以某种方式,得到目标数据块位置;

(4)将数据buffer中的数据写入对应磁盘位置(这里可能使用写buffer,不知如何实现的) 



2.3 技术点总结                                                                                     
  
通过上面的控制逻辑推敲,我们对文件系统想必有更加清晰的认识了,这次,我们再来总结总结,可能涉及的知识点:


正常读写流程
   

  应用读写请求(文件描述符,位置,长度,数据buffer)

  读:文件系统如何填充到buffer当中,在内核态到用户态buffer,是否会有一次拷贝

  写:将buffer当中的数据以IO的方式,发送到下层
 
    目标:
    1. 读写经过的路径:系统调用 --> 文件系统 --> 下层调用接口
    2. 元数据之间的交互:目录树,空闲块的使用
    3. buffer中数据的来龙去脉,能观察到经过了多少次拷贝

磁盘数据固化
  • 数据分布:超级块?目录树?空闲块?数据块? 这些如何记录在案   
  • 数据固化:数据一致性保证,目录树这些在内存中的元数据,何时固化到磁盘上?采用什么方式,保证数据在突然断电的情况下,不会丢失

目录树

  查找文件的入口地址,希望维护快,查找快

  •   数据结构:目录树采用何种数据结构进行维护:BTree?红黑树?
  •   磁盘固化:关机之后, 如何在硬盘上进行存储?
  •   加载方式:运行时,是将所有的目录信息均加载到内存当中,还是按需加载,缓存频繁的目录数据块?

空闲块表

   记录哪些数据块还未被使用            

  •   数据结构:采用何种数据结构进行维护:Bitmap?BTree?红黑树?
        猜测:构造排序二叉树(红黑树啥的),维护关键字<空闲长度,位置>,这样就能快速找到满足长度的一段联系空闲块??
  •   磁盘固化:关机之后, 如何在硬盘上进行存储?
                                                                           

通过上面这些,让我们清楚认识哪些问题需要去注意,能够有方向性的去阅读代码。小伙伴们,让我们带着这些问题,去探索,阅读代码吧!!

当然每个人的关注点可能不一样,在此分享自己源码阅读的方式,希望抛砖引玉,大家相互交流。


你可能感兴趣的:(一一『,linux内核源码,』,一一『,文件系统,』)