Linux铁三角 - IO与文件系统(三)文件系统的实现

该文章参考宋宝华老师的视频课程,详细可以去听阅码场宋老师的课程。

文件系统的实现


●  文件系统的一致性:append一个文件的全流程
●  掉电与文件系统一致性
●  fsck
●  文件系统的日志
●  ext4 mount选项
●  文件系统的debug和dump
●  Copy On Write文件系统: btrfs

1、文件系统的一致性:append一个文件的全流程

根据上一章的内容,我们知道在文件系统中存放一个文件的大概流程如下,会先读出 /a 的inode ,再根据它的inode table 中的指针找到 它的data block ,然后读出里面的内容,也就是 b 的inode , 之后在去操作b ,

需要注意的是,改动的实在是太多了,如果在这个改动的过程中,突然掉电了,这就坏了,举个例子,如果在存放b的时候,

1、首先分配好 inode ,更改好了 inode bitmap , 也在 inode table 中填写好了元数据

2、但是正要写 block bitmap的时候,突然断电了,再次开机的时候,很可能 这几个要写的bitmap 要分配给其他文件,最后就造成了文件的不一致性。

硬件不可能原子执行,任何软件的运行,在做数据保护的时候,都不能保证说数据不丢失。只能帮你保证一种,叫一致性。

 举个例子,往一个文件中末尾再加 4k 的大小。 cat 1.txt >> 2.txt 

 如果在这三件事中间,某一个过程断电,都会造成文件系统的不一致性。下面我们模拟一下掉电导致不一致的情况。

2、 掉电与文件系统一致性

dd if=/dev/zero  of=image  bs=1024 count=4096   # 4.2M

mkfs.ext4  -b 4096 image 

调用 dumpe2fs 可以看到九月一个group ,  inode bitmap 是从第18个块开始的,是描述哪一个inode号是占用的,哪些是空闲的。

可以看出来 ff 07 , 说明前 11 个 bit 是被占用了,如果再创建一个文件,它的inode 号应该是 12

 现在我们模拟一下断电导致的不一致性,我们手动修改一下 inode bitmap ,模拟touch 1 的过程中的不完整性,比如 inode bitmap 没有改过来,还是 ff 07 

用 vim -b image 

然后 输入:%!xxd -g 1 

找到第18k的位置,也就是 0x12000 ,将 ff0f  改成 ff07 

然后 输入:%!xxd -r  

保持退出,这个时候 文件系统会认为 12号 inode 编号还是空闲的,这就是文件系统的不一致。

所有的软件手段,都不能保证数据的不丢失,只能保证文件系统的一致性的。(元数据+数据的一致性,或者仅仅是元数据的一致性)

无论你怎么去调整 dirty_expire_centisecs  DIRECT_IO SYNC IO的调整,都不影响丢或者不丢数据,只影响丢了多少数据。

所有的软件修复手段,fsck, 日志, Cow写时拷贝的手段,都是提供文件系统的一致性。

fsck 是早年间经常用的一个手段,现在大家已经基本上不用了,这也是最简单的,它的原理就是,正常的关机,会在文件系统中 mark 一个标记,

一旦你不正常的关机,突然掉电的话,开机的时候就找不到这个标记,它就会把你文件系统的所有的元数据都扫描一遍,然后去比对哪个地方不一致,然后帮你去修复。

之前我们收到修改过的inode bitmap ,就可以用 fsck 来修复过来。

 

现在我们手动修改一下 datablock bitmap ,看一下 fsck 能不能帮我修复过来。

用 dumpe2fs image 看到第2块是 block bitmap

我们看到 第2块的数据是这样的,我们把后面的数据都改成FF,标记成被占用的情况,然后看看 fsck 能否帮我们修复过来。 

修改成下面这样

用dd 查看一下,确实修改成功了。 目前已经将data block bitmap 修改成不一致了。

可以看到 fsck.ext4 是可以修改过来的 

 

fsck 这次修复的原理,就是会查看 inode table 中的是否有指针指向了占用的 block, 如果没有,就会把它修复过来。

 

当然 fsck 比较慢, 目前已经很少用这种原来来搞了,而是借用 日志来完成。

之前我们说到,每次修改文件,其实要做的动作有很多,如果突然掉电,就会造成文件系统的不一致性。

3、日志文件系统  ext3/ext4 

现在的方法更多的是 利用日志 来做。 就是在 修改 inode bitmap 、data block bitmap 、inode table 、data block 之前,

先写一条日志,记录下你要修改的动作,比如是 要修改1、2、3、4 ,然后再去修改,如果这期间有断电导致文件系统的不一致性,

系统再重启的时候,会有一个日志回放,就会先去查看日志,如果日志是完整的,就会根据日志将没做完的动作做完,如果日志是不完整的,直接丢弃日志。

前面举的例子,都是属于元数据一致性的问题,不涉及到 数据一致性的问题。比如下面的例子,在文件末尾,加一个4k的文件,在最后写4k datablock的时候掉电了。这就涉及到数据的一致性了。

要保持元数据 和 数据 的一致性,就要在日志区写入 元数据、数据。

TxB 是开始写日志,TxE 是日志写完,committed的状态。如果根据日志,将数据都更新到硬盘了,就是 checkpointed的状态。

如果这期间有断电导致文件系统的不一致性,系统再重启的时候,会有一个日志回放,就会先去查看日志,如果日志是完整的,就会根据日志将没做完的动作做完,然后释放日志,如果日志是不完整的,直接丢弃日志。

注意这里分为两种,

元数据一致性  ==》 可以保证文件系统是正常的,但是无法保证数据的正确的,因为要写的哪个数据已经找不到了。

数据一致性  ==》 要往日志里写入数据,虽然可以保证数据的一致性,但是 写的速度 效率就会降低50% 

我们在 mount ext4 的时候,其实有三种参数可以选择

data=journal   会将元数据和数据都写进日志

data=writeback  只写元数据,我的日志和数据的写,是不控制顺序的,日志 和 数据都有可能先写完。

data=ordered    只写元数据,先把数据区写完,再去写元数据的日志,有控制顺序的  [ 虽然比 writeback 的性能稍差,打算安全性要好一些]

性能  journal < ordered < writeback 

一致性  journal > ordered > writeback 

在做嵌入式的系统中,可以根据数据的特点,可以更改某些分区的参数,来达到更好的目的。

4、常用的调试工具

比如系统中有一个文件 maic.c ,这是从文件系统中读出来的,

 下面演示一下从 硬盘里的裸扇区中读出来,需要知道这个文件的 block号

 #  debugfs -R 'stat /home/baohua/main.c '  /dev/sda1 

可以看到 这是一个连续的block 号码是  1015373 

 可以用下面比较原始的方法来读。

可以用更原始的方法。 每一个block是4k, 是8个sector ,因为每个sector 是512byte, 所以 1015373 块号对应的是 第 1015373*8 个扇区。

如果要用 /dev/sda 整个磁盘的话,我们就要知道 第一个分区是从哪里开始的,可以用fdisk 查看一下,是 2048 sectors 

可以看出来 ,读出来的就是 main.c  ,后面的乱码是因为 文件没有存到512byte ,  bs=512c 代表512字节。

icheck  可以根据块号 找到它的 inode 

ncheck  可以根据inode 找到它的 文件路径,文件名称。

 

5、写实拷贝文件系统 COW = btrfs

早期的文件系统,没有日志功能,后期才有日志的功能,后期又又了 COW(copy no write)文件系统 : btrfs , 它没有日志。

用COW 来实现文件系统的一致性。这个在嵌入式系统用的比较少。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值