Linux Barrier IO

来源:互联网 发布:天猫淘宝棉拖鞋 编辑:程序博客网 时间:2024/04/30 19:46
IO顺序是一个比较综合的问题,它涉及的层次比较多,从VFS page cache到I/O调度算法,从IO子系统到存储外设。而Linux Barrier IO就是其中重要的一部分。可能很多人认为,在做了文件写操作后,调用fsync就能保证数据可靠地写入磁盘。大多数情况下,确实如此。


但是,由于磁盘设备自带缓存的存在,fsync这些同步操作,并不能保证存储设备把数据写入非易失性介质。如果此时存储设备发生掉电或者硬件错误,此时存储缓存中的数据将会丢失。


另外,fsync只能保证bio提交后,request_queue能马上unplug。但是这并不能保证IO的顺序。比如,在电梯算法中,一般的文件数据bio是以sorted的顺序插入调度队列。也就是说,该request并不能保证被插入到设备请求队列的队尾。比如在AS调度算法中,如果该request的sector号离当前磁头较远,AS可能会把后来的request先dispatch到设备的请求队列。这无疑会破坏IO的处理顺序。


这对于像日志文件系统中的日志这样的数据,其后果可能是非常严重的。因为日志文件系统中,数据的写入和日志的写入存在先后顺序。如果顺序发生错乱,则可能破坏文件系统。因此必须要有一种方式,来指示写入的数据是否真的按照既定的顺序写入到外部存储的非易失性介质,比便文件系统根据写入情况来进行下一步的操作。


要保证这个顺序,必须要加入处理顺序的逻辑。这个逻辑需要和IO调度器协调配合,不仅要处理插入,排出的顺序,还要处理requeue等的顺序。从逻辑上讲,这部分功能应该不属于sync的范畴。所以才需要Barrier IO。这个还是在简单block device的情况下,如果设备做了软raid,有多路径,情况更加复杂。因此有必要用专门的逻辑来实现这个功能。


Barrier IO的目的是使其之前的IO在其之前写入存储介质,之后的IO需要等到其写入完成后才能得到执行。为了实现这个要求,最多需要执行2次flush(刷新)操作。


注意,这里所说的flush,指的是刷新存储设备的缓存。但并不是所有存储设备都支持flush操作,所以不是所有设备都支持Barrier IO。支持根据这个要求,需要在初始化磁盘设备的请求队列时,显式的表明该设备支持Barrier IO的类型并实现prepare flush 方法,参见“Linux Barrier IO”。


第一次flush是把Barrier IO之前的所有数据刷新,当刷新成功,也就是这些数据被存储设备告知确实写入其介质后,提交Barrier IO所在的请求。然后执行第二次刷新,这次刷新的是Barrier IO所携带的数据。当然,如果Barrier IO没有携带任何数据,则第二次刷新可以省略。此外,如果存储设备支持FUA,则可以在提交Barrier IO所携带的数据时,使用FUA命令。这样可以直接知道Barrier IO所携带的数据是否写入成功,从而省略掉第二次刷新。


通过对Barrier IO的处理过程,我们可以看到,其中最核心的是两次刷新操作和中间的Barrier IO。为了表示这两次刷新操作以及该Barrier IO,在Linux Barrier IO的实现中,引入了3个辅助request: pre_flush_rq, bar_rq, post_flush_rq. 它们包含在磁盘设备的request_queue中。每当通用块层接收到上面发下来的Barrier IO请求,就会把该请求拷贝到bar_rq,并把这3个请求依次加入请求队列,形成flush->barrier->flush请求序列。这样,在处理请求时,便能实现Barrier IO所要求的功能。
0 0
原创粉丝点击