尝试IO请求的QoS(Quality of Service)限流(目前实现的QoS策略有wbt, io-latency cgroup, io-cost cgroup三种) ![]() 图10. blk-mq中IO提交流程
1.如果是fua/flush请求,则将request插入到flush队列,并调用blk_mq_run_hw_queue 启动请求派发 2.如果当前线程正在做IO plug且块设备是硬件单队列的(nr_hw_queues=1),则将request插入到当前线程的plug list 3.如果配置了调度器,则调用blk_mq_sched_insert_request将请求插入调度器队列(如果没有实现insert_requests接口,则插入到当前cpu的软件队列中) 4.如果是硬件多队列块设备上的同步IO请求,则调用blk_mq_try_issue_directly尝试将request直接派发到块设备驱动 5.其他情况,则调用blk_mq_sched_insert_request插入request(同case 3) IO的派发(dispatch) blk-mq中通过调用blk_mq_run_hw_queue派发IO请求到块设备驱动,MQ框架中存在很多的点会触发IO请求往块设备驱动派发,主要如下: ![]() blk_mq_run_hw_queue: 启动硬件队列派发IO请求,可以是同步/异步的执行的。如果队列不在静默状态(quiesced)且有IO请求pending,则启动派发:
![]() 图11. blk-mq启动硬件队列派发IO请求的流程 无论是同步还是异步的派发模式,最终都会调用__blk_mq_run_hw_queue派发IO请求,这个函数先检查执行的上下文,然后调用blk_mq_sched_dispatch_requests派发IO请求到块设备驱动,这个函数的主要流程如下: ![]() 图12. blk-mq派发IO请求的流程
上述4种情况都会调用blk_mq_dispatch_rq_list 将IO请求派发到块设备驱动,这个函数使用块设备驱动实现的几个接口完成派发逻辑: ![]() IO的完成(complete) 下面以UFS+scsi-mq驱动为例,讲解IO完成处理的过程,主要流程如图13所示: ![]() 图13. ufs+scsi-mq驱动中一个IO的完成流程
|