趣谈Linux操作系统
刘超
网易杭州研究院云计算技术部首席架构师
立即订阅
19393 人已学习
课程目录
已完结 72 讲
0/4登录后,你可以任选4讲全文学习。
入门准备篇 (3讲)
开篇词 | 为什么要学习Linux操作系统?
免费
01 | 入学测验:你究竟对Linux操作系统了解多少?
02 | 学习路径:爬过这六个陡坡,你就能对Linux了如指掌
核心原理篇:第一部分 Linux操作系统综述 (3讲)
03 | 你可以把Linux内核当成一家软件外包公司的老板
04 | 快速上手几个Linux命令:每家公司都有自己的黑话
05 | 学会几个系统调用:咱们公司能接哪些类型的项目?
核心原理篇:第二部分 系统初始化 (4讲)
06 | x86架构:有了开放的架构,才能打造开放的营商环境
07 | 从BIOS到bootloader:创业伊始,有活儿老板自己上
08 | 内核初始化:生意做大了就得成立公司
09 | 系统调用:公司成立好了就要开始接项目
核心原理篇:第三部分 进程管理 (10讲)
10 | 进程:公司接这么多项目,如何管?
11 | 线程:如何让复杂的项目并行执行?
12 | 进程数据结构(上):项目多了就需要项目管理系统
13 | 进程数据结构(中):项目多了就需要项目管理系统
14 | 进程数据结构(下):项目多了就需要项目管理系统
15 | 调度(上):如何制定项目管理流程?
16 | 调度(中):主动调度是如何发生的?
17 | 调度(下):抢占式调度是如何发生的?
18 | 进程的创建:如何发起一个新项目?
19 | 线程的创建:如何执行一个新子项目?
核心原理篇:第四部分 内存管理 (7讲)
20 | 内存管理(上):为客户保密,规划进程内存空间布局
21 | 内存管理(下):为客户保密,项目组独享会议室封闭开发
22 | 进程空间管理:项目组还可以自行布置会议室
23 | 物理内存管理(上):会议室管理员如何分配会议室?
24 | 物理内存管理(下):会议室管理员如何分配会议室?
25 | 用户态内存映射:如何找到正确的会议室?
26 | 内核态内存映射:如何找到正确的会议室?
核心原理篇:第五部分 文件系统 (4讲)
27 | 文件系统:项目成果要归档,我们就需要档案库
28 | 硬盘文件系统:如何最合理地组织档案库的文档?
29 | 虚拟文件系统:文件多了就需要档案管理系统
30 | 文件缓存:常用文档应该放在触手可得的地方
核心原理篇:第六部分 输入输出系统 (5讲)
31 | 输入与输出:如何建立售前售后生态体系?
32 | 字符设备(上):如何建立直销模式?
33 | 字符设备(下):如何建立直销模式?
34 | 块设备(上):如何建立代理商销售模式?
35 | 块设备(下):如何建立代理商销售模式?
核心原理篇:第七部分 进程间通信 (7讲)
36 | 进程间通信:遇到大项目需要项目组之间的合作才行
37 | 信号(上):项目组A完成了,如何及时通知项目组B?
38 | 信号(下):项目组A完成了,如何及时通知项目组B?
39 | 管道:项目组A完成了,如何交接给项目组B?
40 | IPC(上):不同项目组之间抢资源,如何协调?
41 | IPC(中):不同项目组之间抢资源,如何协调?
42 | IPC(下):不同项目组之间抢资源,如何协调?
核心原理篇:第八部分 网络系统 (7讲)
43 预习 | Socket通信之网络协议基本原理
43 | Socket通信:遇上特大项目,要学会和其他公司合作
44 | Socket内核数据结构:如何成立特大项目合作部?
45 | 发送网络包(上):如何表达我们想让合作伙伴做什么?
46 | 发送网络包(下):如何表达我们想让合作伙伴做什么?
47 | 接收网络包(上):如何搞明白合作伙伴让我们做什么?
48 | 接收网络包(下):如何搞明白合作伙伴让我们做什么?
核心原理篇:第九部分 虚拟化 (7讲)
49 | 虚拟机:如何成立子公司,让公司变集团?
50 | 计算虚拟化之CPU(上):如何复用集团的人力资源?
51 | 计算虚拟化之CPU(下):如何复用集团的人力资源?
52 | 计算虚拟化之内存:如何建立独立的办公室?
53 | 存储虚拟化(上):如何建立自己保管的单独档案库?
54 | 存储虚拟化(下):如何建立自己保管的单独档案库?
55 | 网络虚拟化:如何成立独立的合作部?
核心原理篇:第十部分 容器化 (4讲)
56 | 容器:大公司为保持创新,鼓励内部创业
57 | Namespace技术:内部创业公司应该独立运营
58 | CGroup技术:内部创业公司应该独立核算成本
59 | 数据中心操作系统:上市敲钟
实战串讲篇 (9讲)
60 | 搭建操作系统实验环境(上):授人以鱼不如授人以渔
61 | 搭建操作系统实验环境(下):授人以鱼不如授人以渔
62 | 知识串讲:用一个创业故事串起操作系统原理(一)
63 | 知识串讲:用一个创业故事串起操作系统原理(二)
64 | 知识串讲:用一个创业故事串起操作系统原理(三)
65 | 知识串讲:用一个创业故事串起操作系统原理(四)
66 | 知识串讲:用一个创业故事串起操作系统原理(五)
67 | 期末测试:这些操作系统问题,你真的掌握了吗?
结束语 | 永远别轻视任何技术,也永远别轻视自己
免费
专栏加餐 (2讲)
学习攻略(一):学好操作系统,需要掌握哪些前置知识?
“趣谈Linux操作系统”食用指南
免费
趣谈Linux操作系统
登录|注册

30 | 文件缓存:常用文档应该放在触手可得的地方

刘超 2019-06-05
上一节,我们讲了文件系统的挂载和文件的打开,并通过打开文件的过程,构建了一个文件管理的整套数据结构体系。其实到这里,我们还没有对文件进行读写,还属于对于元数据的操作。那这一节,我们就重点关注读写。

系统调用层和虚拟文件系统层

文件系统的读写,其实就是调用系统函数 read 和 write。由于读和写的很多逻辑是相似的,这里我们一起来看一下这个过程。
下面的代码就是 read 和 write 的系统调用,在内核里面的定义。
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
struct fd f = fdget_pos(fd);
......
loff_t pos = file_pos_read(f.file);
ret = vfs_read(f.file, buf, count, &pos);
......
}
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
size_t, count)
{
struct fd f = fdget_pos(fd);
......
loff_t pos = file_pos_read(f.file);
ret = vfs_write(f.file, buf, count, &pos);
......
}
对于 read 来讲,里面调用 vfs_read->__vfs_read。对于 write 来讲,里面调用 vfs_write->__vfs_write。
下面是 __vfs_read 和 __vfs_write 的代码。
ssize_t __vfs_read(struct file *file, char __user *buf, size_t count,
loff_t *pos)
{
if (file->f_op->read)
return file->f_op->read(file, buf, count, pos);
else if (file->f_op->read_iter)
return new_sync_read(file, buf, count, pos);
else
return -EINVAL;
}
ssize_t __vfs_write(struct file *file, const char __user *p, size_t count,
loff_t *pos)
{
if (file->f_op->write)
return file->f_op->write(file, p, count, pos);
else if (file->f_op->write_iter)
return new_sync_write(file, p, count, pos);
else
return -EINVAL;
}
上一节,我们讲了,每一个打开的文件,都有一个 struct file 结构。这里面有一个 struct file_operations f_op,用于定义对这个文件做的操作。__vfs_read 会调用相应文件系统的 file_operations 里面的 read 操作,__vfs_write 会调用相应文件系统 file_operations 里的 write 操作。

ext4 文件系统层

取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《趣谈Linux操作系统》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(13)

  • Zain Lau
    打卡,今年12月冲北邮!

    作者回复: 加油

    2019-06-05
    1
    7
  • 石维康
    查看文件缓存:通过free命令中的buff/cache一栏的信息即可看到文件缓存的用量。
    清除缓存:sync; echo 1 > /proc/sys/vm/drop_caches

    作者回复: 赞

    2019-06-05
    5
  • sugar
    看完了老师讲的文件系统的几节,收获颇丰。但如果想要自己去实践一下,很想知道有没有像wireshark那样的网络抓包工具一样底层的 可以针对文件系统,磁盘物理结构进行监控 分析的工具呢?google了一番没找到...
    2019-06-14
    4
  • why
    - 系统调用层和虚拟文件系统层
        - 调用 read/write 进行读写 → vfs_read/write → __vfs_read/write
        - 打开文件时创建 struct file, 其中有 file_operations, 虚拟文件系统调用 operations 中的 read/write
    - ext4 文件系统层
        - 调用到 generic_file_read/write_iter, 其中判断是否需要使用缓存
        - 缓存, 即内存中一块空间, 可分为两类 I/O
            - 缓存 I/O: 默认模式, 读操作先检测缓存区中是否有, 若无则从文件系统读取并缓存; 写操作直接从用户空间赋值到内核缓存中, 再由 OS 决定或用户调用 sync 写回磁盘
            - 直接 I/O: 程序直接访问磁盘, 不经过缓存
        - 直接 I/O 过程:
            - 读: 若设置了 IOCB_DIRECT, 调用 address_space 的 direct_io 直接读取硬盘( 文件与内存页映射) ; 若使用缓存也要调用 address_sapce 进行文件与内存页的映射
            - 写: 若设置了 IOCB_DIRECT, 调用块设备驱动直接写入磁盘
        - 带缓存写过程
            - 在 while 循环中, 找出写入影响的页, 并依次写入, 完成以下四步
                - 每一页调用 write_begin 做准备
                - 将写入内容从用户态拷贝到内核态
                - 调用 write_end 完成写入
                - 查看脏页 (未写入磁盘的缓存) 是否过多, 是否需要写回磁盘
            - write_begin 做准备
                - ext4 是日志文件系统, 通过日志避免断电数据丢失
                - 文件分为元数据和数据, 其操作日志页分开维护
                    - Journal 模式下: 写入数据前, 元数据及数据日志必须落盘, 安全但性能差
                    - Order 模式下: 只记录元数据日志, 写日志前, 数据必须落盘, 折中
                    - Writeback 模式下: 仅记录元数据日志, 数据不用先落盘
                - write_begin 准备日志, 并得到应该写入的缓存页
                - 内核中缓存以页为单位, 打开文件的 file 结构中用 radix tree 维护文件的缓存页
            - iov_iter_copy_from_user_atomic 拷贝内容, kmap_atomic 将缓存页映射到内核虚拟地址; 将拥护他数据拷贝到内核态; kunmap_aotmic 解映射
            - write_end, 先完成日志写入 并将缓存设置为脏页
            - 调用 balance_dirty_pages_ratelimited 若发先脏页超额, 启动一个线程执行回写.
                - 回写任务 delayed_work 挂在 bdi_wq 队列, 若delay 设为 0, 马上执行回写
                - bdi = backing device info 描述块设备信息, 初始化块设备时回初始化 timer, 到时会执行写回函数
            - 另外其他情况也会回写
                - 用户调用 sync 或内存紧张时, 回调用 wakeup_flusher_threads 刷回脏页
                - 脏页时间超过 timer, 及时回写
        - 带缓存读
            - generic_file_buffered_read 从 page cache 中判断是否由缓存页
                - 若没则从文件系统读取并预读并缓存, 再次查找缓存页
                - 若有, 还需判断是否需要预读, 若需要调用 page_cache_async_readahead
                - 最后调用 copy_page_to_user 从内核拷贝到用户空间
    2019-06-07
    3
  • 玉剑冰锋
    请教老师个问题1.系统默认脏页多长时间或者数量是多少的时候触发事件?2.如果脏页在回写过程中出现故障如何保证数据完整性?3.这里只是提到ext4,其他文件系统跟ext4相比原理一样吗?比如xfs?

    作者回复: vm.dirty_background_bytes = 0
    vm.dirty_background_ratio = 10
    vm.dirty_bytes = 0
    vm.dirty_expire_centisecs = 3000
    vm.dirty_ratio = 30
    vm.dirty_writeback_centisecs = 500

    每个文件系统各自有各自的格式

    2019-06-12
    2
  • 安排
    打卡,每天课程发出后及时看完
    2019-06-05
    2
  • 啦啦啦
    老师,我想问下,在学习mysql实战45讲这个课程里面,讲了数据库也有脏页和干净页,以及如何将脏页刷回磁盘的几个时机,请问这个机制是和本节课讲的操作系统的机制是一回事吗?谢谢老师

    作者回复: 不一样,那是数据库层次的,不是操作系统层次的。

    2019-07-25
    1
  • Geek_54edc1
    free命令查看缓存

    作者回复: 赞

    2019-06-20
    1
  • 周平
    老师讲的很清晰,方便以后查看和复习
    2019-06-10
    1
  • 微秒
    打卡,慢慢看,虽然不是很懂。
    2019-06-06
    1
  • 马媛媛
    请问 ext4的Journal 模式有什么优势呢,有日志逐条落盘的这个开销,为啥write不直接落盘呢?

    作者回复: 写入日志由于是顺序的,写入速度快很多

    2019-06-06
    1
  • williamcai
    脏页在缓存中,如果掉电了,怎么保证回写到硬盘
    2019-10-14
    1
  • 莫名
    “ext4_direct_IO 最终会调用到 __blockdev_direct_IO->do_blockdev_direct_IO,这就跨过了缓存层,直接到了文件系统的设备驱动层。” 觉得这个说法并不准确,绕过缓存,但并没有直接到达设备驱动层,而是通用块层,主要用于io合并之类操作,然后才是设备驱动层。

    作者回复: 是的。赞,谢谢指正

    2019-07-22
收起评论
13
返回
顶部