文件系统要解决的一个关键问题是怎样防止掉电或系统崩溃造成数据损坏,在此类意外事件中,导致文件系统损坏的根本原因在于写文件不是原子操作,因为写文件涉及的不仅仅是用户数据,还涉及元数据(metadata)包括 Superblock、inode bitmap、inode、data block bitmap等,所以写操作无法一步完成,如果其中任何一个步骤被打断,就会造成数据的不一致或损坏。

举一个简化的例子,我们对一个文件进行写操作,要涉及以下步骤:

  1. 从data block bitmap中分配一个数据块;

  2. 在inode中添加指向数据块的指针;

  3. 把用户数据写入数据块。

  • 如果步骤2完成了,3未完成,结果是数据损坏,因为该文件认为数据块是自己的,但里面的数据其实是垃圾;

  • 如果步骤2完成了,1未完成,结果是元数据不一致,因为该文件已经把数据块据为己有,然而文件系统却还认为该数据块未分配、随后又可能会把该数据块分配给别的文件、造成数据覆盖;

  • 如果步骤1完成了、2未完成,结果就是文件系统分配了一个数据块,但是没有任何文件用到这个数据块,造成空间浪费;

  • 如果步骤3完成了,2未完成,结果就是用户数据写入了硬盘数据块中,但白写了,因为文件不知道这个数据块是自己的。

日志文件系统(Journal File System)就是为解决上述问题而诞生的。

它的原理是在进行写操作之前,把即将进行的各个步骤(称为transaction)事先记录下来,保存在文件系统上单独开辟的一块空间上,这就是所谓的日志(journal),也被称为write-ahead logging,日志保存成功之后才进行真正的写操作、把文件系统的元数据和用户数据写进硬盘(称为checkpoint),这样万一写操作的过程中掉电,下次挂载文件系统之前把保存好的日志重新执行一遍就行了(术语叫做replay),避免了前述的数据损坏场景。

有人问如果保存日志的过程中掉电怎么办?最初始的想法是把一条日志的数据一次性写入硬盘,相当于一个原子操作,然而这并不可行,因为硬盘通常以512字节为单位进行操作,日志数据一超过512字节就不可能一次性写入了。所以实际上是这么做的:给每一条日志设置一个结束符,只有在日志写入成功之后才写结束符,如果一条日志没有对应的结束符就会被视为无效日志,直接丢弃,这样就保证了日志里的数据是完整的。

一条日志在它对应的写操作完成之后就没用了,占用的硬盘空间就可以释放。保存日志的硬盘空间大小是有限的,被循环使用,所以日志也被称为circular log。

至此可以总结一下日志文件系统的工作步骤了:

  1. Journal write : 把transaction写入日志中;

  2. Journal commit : 在一条日志保存好之后,写入结束符;

  3. Checkpoint : 进行真正的写操作,把元数据(metadata)和用户数据(user data)写入文件系统;

  4. Free : 回收日志占用的硬盘空间。

以上方式把用户数据(user data)也记录在日志中,称为Data Journaling,Linux EXT3文件系统就支持这种方式,这种方式存在效率问题:

就是每一个写操作涉及的元数据(metadata)和用户数据(user data)实际上都要在硬盘上写两次,一次写在日志里,一次写在文件系统上。元数据倒也罢了,用户数据通常比较大,拷贝几个GB的电影文件也要乘以2实在是降低了效率。

一个更高效的方式是Metadata Journaling,不把用户数据(user data)记录在日志中,它防止数据损坏的方法是先写入用户数据(user data)、再写日志,即在上述”Journal write”之前先写用户数据,这样就保证了只要日志是有效的,那么它对应的用户数据也是有效的,一旦发生掉电故障,最坏的结果也就是最后一条日志没记完,那么对应的用户数据也会丢,效果与Data Journaling丢弃日志一样,重要的是文件系统的一致性和完整性是有保证的。

Metadata Journaling又叫Ordered Journaling,大多数文件系统都采用这种方式。像Linux EXT3文件系统也是可以选择Data Journaling还是Ordered Journaling的。

参考资料:Crash Consistency: FSCK and Journaling

来源:http://linuxperf.com/?p=153

提高软件的可靠性和效率,是每个 IT 人的使命

GOPS 2019 · 深圳站,4.12-13,不要错过软件工程的第三次革命

点击阅读原文,访问大会官网

内核中设置文件结束符_Linux 日志文件系统原来是这样工作的相关推荐

  1. linux 2行数据为一条记录 该如何操作这一条记录_Linux 日志文件系统原来是这样工作的...

    文件系统要解决的一个关键问题是怎样防止掉电或系统崩溃造成数据损坏,在此类意外事件中,导致文件系统损坏的根本原因在于写文件不是原子操作,因为写文件涉及的不仅仅是用户数据,还涉及元数据(metadata) ...

  2. 什么是Linux系统调用system call?(Linux内核中设置的一组用于实现各种系统功能的子程序)(区别于标准C库函数调用)核心态和用户态的概念、中断的概念、系统调用号、系统调用表

    文章目录 什么是系统调用? 为什么要用系统调用? 系统调用是怎么工作的? 如何使用系统调用? _syscall*()是什么? errno是什么? 调用性能问题 Linux系统调用列表 进程控制 文件系 ...

  3. Linux内核中读写文件数据的方法

    Linux内核中读写文件数据的方法     有时候需要在Linuxkernel--大多是在需要调试的驱动程序--中读写文件数据.在kernel中操作文件没有标准库可用,需要利用kernel的一些函数, ...

  4. 【转】 Linux内核中读写文件数据的方法--不错

    原文网址:http://blog.csdn.net/tommy_wxie/article/details/8193954 Linux内核中读写文件数据的方法     有时候需要在Linuxkernel ...

  5. Linux中文件描述符1,linux内核中的文件描述符(一)--基础知识简介

    原标题:linux内核中的文件描述符(一)--基础知识简介 Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blo ...

  6. 如何在linux内核中读写文件

    在VFS的支持下,用户态进程读写任何类型的文件系统都可以使用read和write着两个系统调用,但是在linux内核中没有这样的系统调用我们如何操作文件呢?我们知道read和write在进入内核态之后 ...

  7. 在linux内核中操作文件的方法--使用get_fs()和set_fs(KERNEL_DS)

    在linux内核中操作文件的方法--使用get_fs()和set_fs(KERNEL_DS) #include <linux/kernel.h> #include <linux/mo ...

  8. linux内核中的文件描述符(一)--基础知识简介

    linux内核中的文件描述符(一)--基础知识简介 Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blog.cs ...

  9. X64驱动:内核中的文件回调

    无论在用户层还是内核层,操作文件的流程基本一致,除了在API函数上的区别(用户层调用用户层API,内核层调用内核API)以外其他基本一致,先讲解一下文件系统执行的流程. 以NTFS文件系统为例:假设我 ...

最新文章

  1. 云计算安全威胁集中营
  2. java文件上传下载服务并发超时,先收藏了
  3. 什么是认证、授权、会话
  4. ❤️《10个超级常用Python方法总结》复制即用丨小白捷径【文末赠书2本】❤️
  5. 利用ipsec配置tcp/ip用于安全连接
  6. 1.4 Padding
  7. python 多个列表_python遍历多个列表生成列表或字典
  8. 点云的无序性_三维点云分类与分割-PointNet
  9. 阿里云实现人脸登录(人脸库 OSS)
  10. matlab步长教程,matlab仿真步长
  11. 驱动人生病毒清除教程
  12. 鲲鹏920的服务器芯片,鲲鹏920芯片是什么芯片
  13. 都说ApiPost香,它到底香在哪里?
  14. OSChina 周二乱弹 —— 基于现代生物化学的长生不老药炼制教程
  15. WIFI手机使用正常电脑使用卡顿解决方案
  16. OpenCV3之——霍夫变换(霍夫线变换和霍夫圆变换)
  17. 怎么区分zh和ch_怎样区分zhchsh与zcs
  18. oracle怎么新开账期,oracle成本核算
  19. 11.投资管理流程与投资者需求
  20. 1-Java的诞生和发展

热门文章

  1. python3.8还是3.7_选择 Python3.6 还是 Python 3.7
  2. vue在created调用点击方法_vue中created、mounted等方法整理
  3. cheked复选框返回值的时候选中
  4. 如何获取iOS设备的IP地址
  5. Struts2的简单认识
  6. jQuery中的动画
  7. iptables中state模块的连接状态
  8. Cisco Easy ***综合配置示例
  9. CentOS 5.5 挂载windows ntfs 文件系统
  10. ubuntu下安装nagios