当前位置:嗨网首页>书籍在线阅读

20-write()行为

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

2.3.6 write()行为

当write()调用返回时,内核已经把数据从提供的缓冲区中拷贝到内核缓冲区中,但不保证数据已经写到目的地。实际上,write调用执行非常快,因此不可能保证数据已经写到目的地。处理器和硬盘之间的性能差异使得这种情况非常明显。

相反,当用户空间发起write()系统调用时,Linux内核会做几项检查,然后直接把数据拷贝到缓冲区中。然后,在后台,内核收集所有这样的“脏”缓冲区(即存储的数据比磁盘上的数据新),进行排序优化,然后把这些缓冲区写到磁盘上(这个过程称为回写writeback)。通过这种方式,write()可以频繁调用并立即返回。这种方式还支持内核把写操作推迟到系统空闲时期,批处理很多写操作。

延迟写并没有改变POSIX语义。举个例子,假设要对一份刚写到缓冲区但还没写到磁盘的数据执行读操作,请求响应时会直接读取缓冲区的数据,而不是读取磁盘上的“陈旧”数据。这种方式进一步提高了效率,因为对于这个读请求,是从内存缓冲区而不是从硬盘中读的。如期望的那样,读写请求相互交织,而结果也和预期一致——当然,前提是在数据写到磁盘之前,系统没有崩溃!虽然应用可能认为写操作已经成功了,在系统崩溃情况下,数据却没有写入到磁盘。

延迟写的另一个问题在于无法强制“顺序写(write ordering)”。虽然应用可能会考虑对写请求进行排序,按特定顺序写入磁盘;而内核主要是出于性能考虑,按照合适的方式对写请求重新排序。只有当系统出现崩溃时,延迟写才会有问题,因为最终所有的缓冲区都会写回,而且文件的最终状态和预期的一致。实际上绝大多数应用并不关心写顺序。数据库是少数几个关心顺序的,它们希望写操作有序,确保数据库不会处于不一致状态。

延迟写的最后一个问题是对某些I/O错误的提示信息不准确。在回写时产生的任何I/O错误,比如物理磁盘驱动出错,都不能报告给发起写请求的进程。实际上,内核内“脏”缓冲区和进程无关。多个进程可能会“弄脏”(即更新)同一片缓冲区中的数据,进程可能在数据仅被写到缓冲区尚未写到磁盘的时候就退出了。进程操作失败,如何“事后”与之通信呢?

对于这些潜在问题,内核试图最小化延迟写带来的风险。为了保证数据按时写入,内核设置了“最大缓存时效”(maximum buffer age),并在超出给定时效前将所有脏缓存的数据写入磁盘。用户可以用过/proc/sys/vm/dirty_expire_centisecs来配置这个值,该值单位是厘秒(0.01秒)。

Linux系统也支持强制文件缓存写回,甚至是将所有的写操作同步。这些主题将在2.4节中详细探讨。

在本章后续部分,2.11节将深入探讨Linux内核缓存回写子系统。