首页 > 代码库 > IO的生命周期

IO的生命周期

 

 submit_bh

 

       来自cache的数据被封装成bio

 submit_bh -> submit_bio ->submit_bh_wbc->submit_io-> generic_make_request

技术分享

技术分享

make_queue_fn的注册在request queue初始化的时候blk_init_queue->blk_init_allocated_queue

 generic_make_request->blk_queue_bio

blk_queue_bio实现了对bio的合并调度。它调用的函数elv_merge是关键函数,它实现了对请求的调度,IO调度器就是在这里被调用的。

技术分享

IO从块设备层(block IO layer),到发送到块设备驱动(device driver)整个过程经过三类队列:

       1)unplug request queue 属于线程

       2)elevator queue 调度队列,不同的调度器,队列不同

       3)device request queue 派遣队列,dispatch queue。(例如,在deadline_dispatch_requests中实现)

技术分享

技术分享

此时bio(request)还在unplug 队列中。

● blk_queue_bio:

       通过blk_flush_plug_list(也可通过_elv_add_request)将unplug 请求队列中的请求发送到调度队列elevator queue。

技术分享

技术分享

 

来自上层的请求,先尝试合并入unplug 队列,若不能合并,则调用elv_merge合并入调度队列elevator queue。若找不到可合并的请求,则获得一个空请求request,用该bio初始化该request,然后放到unplug队列中。

此时request在调度队列中。

● blk_queue_bio->elv_merge

IO调度器在该函数里调用。

技术分享

技术分享

技术分享

技术分享

此时request在调度队列中。

IO调度器的工作:合并,排序。

排序:使请求按扇区增长的方向有序排列。

CFQ:每个发起IO的进程都有一个队列。

Deadline:有4个队列,分为两类sort_list和fifo_list。每类都有读写两种队列。

       sort_list 按请求起始扇区排序,fifo_list按请求生成的时间排序。

plug和unplug:目的是让请求马上被驱动程序处理。设备处于pluged状态,设备不会被激活。处于unplugged状态,被激活。

● 返回blk_queue_bio,然后

       blk_queue_bio-> add_acct_request-> __elv_add_request

技术分享

此时,request在device request queue(派遣队列)中。

这一步实现具体IO调度器对请求的派遣(发送到派遣队列):

__elv_add_request->elv_drain_elevator->elevator_dispatch_fn

elevator_dispatch_fn将被注册为具体调度器的派遣函数,例如deadline_dispatch_request

技术分享

此时,请求在派遣队列(device request queue)中。

● 返回blk_queue_bio:

       blk_queue_bio-> __blk_run_queue-> __blk_run_queue_uncond->request_fn(scsi_request_fn)-> blk_peek_request->__elv_next_request

request_fn被注册为scsi_request_fn,该函数是驱动程序的入口。

技术分享

技术分享

技术分享

从device request queue中获得一个请求,准备发送到scsi块设备驱动(中间层)

● blk_peek_request中调用q->prep_rq_fn(注册为scsi_prep_fn),将request转化成scsi驱动能够识别scsi command。

技术分享

此时,请求在派遣队列中。

● 回到scsi_request_fn,调用scsi_dispatch_cmd将scsi command发送给scsi host

技术分享

● 在scsi_dispatch_cmd中,调用queuecommand方法,将scsi command挂在自己的队列中,然后启动DMA,将scsi command发送到具体的磁盘。DMA完毕后,DMA控制器中断CPU,告诉CPU DMA结束。并且在中断上下文中,设置DMA结束的中断下半部。DMA中断处理程序返回之后,触发软中断,执行scsi中断下部。

技术分享

技术分享

驱动:scsi中间层(middle level driver) +  scsi host driver。

scsi中间层抽象了scsi总线逻辑;scsi host driver控制scsi总线控制器,实现scsi数据的物理层传输。

queuecommand是这两层之间的桥梁。它将被注册为具体的物理块设备的函数,例如megaraid_queue。

● 在scsi中断下部,调用scsi command结束的回调函数scsi_done:scsi_dispatch_cmd->scsi_done。scsi_done调用blk_complete_request结束请求。

技术分享

技术分享

 

IO的生命周期