Linux内核 文件一致性之主动一致性

        众所周知,Linux内核采用了page cache来缓存文件数据以及元数据。既然采用缓存,就有可能会产生缓存数据与磁盘中的数据不一致的问题,本系列博客中我们重点关注Linux内核如何解决这种不一致。

        一般来说,一个成熟的系统需要提供多种机制来保证数据一致性,其一是用户可控的,即用户能通过特定的接口去控制文件数据的一致性,这是对于文件数据一致性要求比较高的应用需要的语义。另一方面,某些用户或者应用程序对文件数据的一致性要求可能没有那么高,无需在每次写入的时候都调用相应的接口去保证文件缓存数据和磁盘上数据的一致性,此时,操作系统必须能够主动地承担起保证文件一致性的任务。

        下面我们再来讨论下一致性的概念。操作系统中的文件除了数据外(最常见的形式就是字节流),还包含元数据,即文件=数据+元数据,元数据用来描述文件的各种属性,也必须存储在磁盘上。因此,我们说保证文件一致性其实包含了两个方面:数据一致+元数据一致。关于文件数据和元数据在内存中的缓存机制请参考我的另外一篇博客。

        当前Linux下以两种方式实现文件一致性:1. 向用户提供特定接口,用户可通过接口来主动地保证文件一致性;2.系统中存在定期任务(表现形式为内核线程),周期性地同步文件系统中文件脏数据块。这两种方式各有优劣,1可保证文件数据的强一致性,但效率较为低下,每次写入必须等待落实磁盘,2克服了1的低效,但无法保证文件数据的always onsistent。

文件系统一致性接口

       当前Linux主要对用户提供如下接口来保证文件数据一致性(均位于fs/sync.c文件)。

  1. fsync(intfd)
  2. fdatasync(int fd)
  3. sync()

       fsync(fd)将fd代表的文件的脏数据和脏元数据全部刷新至磁盘中。fdatasync(fd)将fd代表的文件的脏数据刷新至磁盘,同时对必要的元数据刷新至磁盘中,这里所说的必要的概念是指:对接下来访问文件有关键作用的信息,如文件大小,而文件修改时间等不属于必要信息。sync()则是对系统中所有的脏的文件数据元数据刷新至磁盘中。本篇博客中我们讲述文件系统的主动一致性也就是详细分析上述三个接口的实现原理。

fsync(int fd)

       fsync的语义是同步fd代表的文件。要实现这种同步,让我们来看看需要有哪些棘手的问题需要解决:

1.   快速定位脏缓存数据。当前Linux以页面为单位组织文件缓存,且将所有的页面组织在radix tree中,那么该问题就变为如何快速定位脏页面?

2.   如何设计一个简单高效的框架来将主动同步和系统中的刷新线程纳入同步框架之中?

       本篇博客中我们不太去关注问题2,待到下一篇中我们会详细思考同步框架的设计。因此下面我们简单描述fsync的实现。追踪它的实现流程如下:

       fsync(int fd)(位于fs/sync.c中)

             ------->do_fsync(fd, 0)(位于fs/sync.c中)

                 ------->vfs_fsync(file, datasync)(位于fs/sync.c中)

                     ------->vfs_fsync_range(file, 0, LLONG_MAX, datasync)(位于fs/sync.c中)

                          ------->filemap_write_and_wait_range(mapping,start, end)(位于mm/filemap.c中)

                             ------->__filemap_fdatawrite_range(mapping,lstart, lend,WB_SYNC_ALL)(位于mm/filemap.c中)

                                 ------->filemap_fdatawait_range(mapping,lstart,lend)(位于mm/filemap.c中)

                                     ------->ext2_fsync(struct file*file, int datasync)(针对ext2文件系统,位于fs/ext2/file.c)

                                       ------->generic_file_fsync(file, datasync)(位于fs/libfs.c中)

SYSCALL_DEFINE1(fdatasync, unsigned int,fd)
{
             return do_fsync(fd, 1);
}
static int do_fsync(unsigned int fd, intdatasync)
{
       struct file*file;
       int ret =-EBADF;
       file =fget(fd);
       if (file) {
       ret =vfs_fsync(file, datasync);
       fput(file);
     
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
第1章 预备知识 1. 1 Linux内核简介 1. 2 Intel X86 CPU系列的寻址方式 1. 3 i386的页式内存管理机制 1. 4 Linux内核源代码中的C语言代码 1.5 Linux内核源代码中的汇编语言代码 第2章 存储管理 2.1 Linux内存管理的基本框架 2.2 地址映射的全过程 2.3 几个重要的数据结构和函数 2.4 越界访问 2.5 用户堆栈的扩展 2.6 物理页面的使用和周转 2.7 物理页面的分配 2.8 页面的定期换出 2. 9 页面的换入 2.10 内核缓冲区的管理 2.11 外部设备存储空间的地址映射 2.12 系统调用brk() 2.13 系统调用mmap() 第3章 中断、异常和系统调用 3.1 X86 CPU对中断的硬件支持 3. 2 中断向量表IDT的初始化 3. 3 中断请求队列的初始化 3. 4 中断的响应和服务 3. 5 软中断与Bottom Half 3.6 页面异常的进入和返回 3. 7 时钟中断 3. 8 系统调用 3. 9 系统调用号与跳转表 第4章 进程与进程调度 4.1 进程四要素 4.2 进程三部曲:创建、执行与消亡 4.3 系统调用fork()、vfork()与clone() 4.4 系统调用execve() 4.5 系统调用exit()与wait4() 4.6 进程的调度与切换 4.7 强制性调度 4.8 系统调用nanosleep()和pause() 4.9 内核中的互斥操作 第5章 文件系统 5.1 概述 5. 2 从路径名到目标节点 5. 3 访问权限与文件安全性 5. 4 文件系统的安装和拆卸 5.5 文件的打开与关闭 5. 6 文件的写与读 5.7 其他文件操作 5. 8 特殊文件系统/proc 第6章 传统的Unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6. 5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量 第7章 基于socket的进程间通信 7.1 系统调用socket() 7.2 函数sys—socket()——创建插口 7.3 函数sys—bind()——指定插口地址 7.4 函数sys—listen()——设定server插口 7.5 函数sys—accept()——接受连接请求 7.6 函数sys—connect()——请求连接 7.7 报文的接收与发送 7.8 插口的关闭 7.9 其他 第8章 设备驱动 8.1 概述 8.2 系统调用mknod() 8.3 可安装模块 8.4 PCI总线 8.5 块设备的驱动 8.6 字符设备驱动概述 8.7 终端设备与汉字信息处理 8.8 控制台的驱动 8.9 通用串行外部总线USB 8.10 系统调用select()以及异步输入/输出 8.11 设备文件系统devfs 第9章 多处理器SMP系统结构 9.1 概述 9.2 SMP结构中的互斥问题 9.3 高速缓存与内存的一致性 9.4 SMP结构中的中断机制 9.5 SMP结构中的进程调度 9.6 SMP系统的引导 第10章 系统引导和初始化 10.1 系统引导过程概述 10.2 系统初始化(第一阶段) 10.3 系统初始化(第二阶段) 10.4 系统初始化(第三阶段) 10.5 系统的关闭和重引导
本PDF电子书包含上下两册,共1576页,带目录,高清非扫描版本。 作者: 毛德操 胡希明 丛书名: Linux内核源代码情景分析 出版社:浙江大学出版社 目录 第1章 预备知识 1.1 Linux内核简介. 1.2 Intel X86 CPU系列的寻址方式 1.3 i386的页式内存管理机制 1.4 Linux内核源代码中的C语言代码 1.5 Linux内核源代码中的汇编语言代码 第2章 存储管理 2.1 Linux内存管理的基本框架 2.2 地址映射的全过程 2.3 几个重要的数据结构和函数 2.4 越界访问 2.5 用户堆栈的扩展 2.6 物理页面的使用和周转 2.7 物理页面的分配 2.8 页面的定期换出 2.9 页面的换入 2.10 内核缓冲区的管理 2.11 外部设备存储空间的地址映射 2.12 系统调用brk() 2.13 系统调用mmap() 第3章 中断、异常和系统调用 3.1 X86 CPU对中断的硬件支持 3.2 中断向量表IDT的初始化 3.3 中断请求队列的初始化 3.4 中断的响应和服务 3.5 软中断与Bottom Half 3.6 页面异常的进入和返回 3.7 时钟中断 3.8 系统调用 3.9 系统调用号与跳转表 第4章 进程与进程调度 4.1 进程四要素 4.2 进程三部曲:创建、执行与消亡 4.3 系统调用fork()、vfork()与clone() 4.4 系统调用execve() 4.5 系统调用exit()与wait4() 4.6 进程的调度与切换 4.7 强制性调度 4.8 系统调用nanosleep()和pause() 4.9 内核中的互斥操作 第5章 文件系统 5.1 概述 5.2 从路径名到目标节点 5.3 访问权限与文件安全性 5.4 文件系统的安装和拆卸 5.5 文件的打开与关闭 5.6 文件的写与读 5.7 其他文件操作 5.8 特殊文件系统/proc 第6章 传统的Unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6.5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量 第7章基于socket的进程间通信 7.1系统调用socket() 7.2函数sys—socket()——创建插口 7.3函数sys—bind()——指定插口地址 7.4函数sys—listen()——设定server插口 7.5函数sys—accept()——接受连接请求 7.6函数sys—connect()——请求连接 7.7报文的接收与发送 7.8插口的关闭 7.9其他 第8章设备驱动 8.1概述 8.2系统调用mknod() 8.3可安装模块 8.4PCI总线 8.5块设备的驱动 8.6字符设备驱动概述 8.7终端设备与汉字信息处理 8.8控制台的驱动 8.9通用串行外部总线USB 8.10系统调用select()以及异步输入/输出 8.11设备文件系统devfs 第9章多处理器SMP系统结构 9.1概述 9.2SMP结构中的互斥问题 9.3高速缓存与内存的一致性 9.4SMP结构中的中断机制 9.5SMP结构中的进程调度 9.6SMP系统的引导 第10章系统引导和初始化 10.1系统引导过程概述 10.2系统初始化(第一阶段) 10.3系统初始化(第二阶段) 10.4系统初始化(第三阶段) 10.5系统的关闭和重引导
Linux内核链表是一个非常基础的数据结构,在Linux内核中被广泛使用。Linux内核链表通过指针连接节点,每个节点都包含下一个节点的指针,从而形成链表。 在多核处理器架构下,由于不同核心的缓存可能不一致,当多个核心同时对链表进行修改时,可能会出现数据不一致的情况。为了解决这个问题,Linux内核采用了一种叫做“cache一致性”的技术,即每次修改链表节点时,都需要将该节点所在的缓存行标记为无效,这样其他核心访问该节点时,就会重新从内存中读取数据,保证数据一致性。 而内存屏障则是保证代码执行顺序的关键技术。在多核处理器架构下,由于不同核心的指令可能乱序执行,因此需要内存屏障来确保指令的执行顺序。内存屏障分为读屏障、写屏障和全屏障三种。 读屏障(rmb)用于确保所有先于读屏障的读操作都完成后,才能执行读屏障之后的操作;写屏障(wmb)用于确保所有先于写屏障的写操作都完成后,才能执行写屏障之后的操作;全屏障(mb)则是同时执行读屏障和写屏障的作用。 在Linux内核链表中,内存屏障被广泛应用。例如,在向链表中添加节点时,需要先将新节点的指针指向下一个节点,再将上一个节点的指针指向新节点。此时就需要使用内存屏障来确保指针的修改顺序正确。具体来说,需要在修改新节点指针之后、修改上一个节点指针之前,加入写屏障;在读取新节点指针之前、读取上一个节点指针之后,加入读屏障。这样就可以确保指针的修改顺序正确,从而避免了数据不一致的情况。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值