nullb driver分析6-blk-mq相关定时器

0.前言

内核版本:4.19
文档目的: 主要以null_dev为例来研究多队列的工作机制, 为了能够凸显多队列的工作流程,只对block层做重点分析说明,对其它代码只做注释性说明。
本文主要介绍跟多队列相关的定时器,这些定时器的出处来源于blk_mq_init_queue函数。
目前对这些定时器的分析还处于混乱状态,可能会有很多错误,建议略过:>

1. 多队列的定时器处理函数

laptop_mode_timer_fn

(1)初始化
laptop_mode_wb_timer定时器是在blk_alloc_queue_node时通过timer_setup(&q->backing_dev_info->laptop_mode_wb_timer,laptop_mode_timer_fn)初始化。laptop_mode_wb_timer内嵌在q->backing_dev_info中, 此定时器主要服务于laptop_mode,定时器回调将唤醒wb线程最终将数据从page cache写入磁盘
(2)调用定时器
laptop_io_completion启动laptop_io_completion定时器
laptop_sync_completion取消laptop_mode_wb_timer定时器
(3)定时器启动/取消时机
在laptop_mode模式或!blk_rq_is_passthrough(req)条件下:
blk_mq_free_request和blk_finish_request会通过调用laptop_io_completion来启动定时器
在在laptop_mode模式下:
ksys_sync通过调用laptop_sync_completion来取消定时器

(4)定时器处理函数

laptop_mode_timer_fn
|--wakeup_flusher_threads_bdi(backing_dev_info, WB_REASON_LAPTOP_TIMER)
    |--__wakeup_flusher_threads_bdi(bdi, reason)
       |--list_for_each_entry_rcu(wb, &bdi->wb_list, bdi_node)
              wb_start_writeback(wb, reason)
               |--wb_wakeup(wb)
                   |--mod_delayed_work(bdi_wq, &wb->dwork, 0)
                       |--wb_workfn(struct work_struct *work)
                           |--do {
                                     wb_do_writeback(wb);
                              } while (!list_empty(&wb->work_list)

wb_init时会调用INIT_DELAYED_WORK(&wb->dwork, wb_workfn)设置wb->dwork的work回调函数为
wb_workfn;

laptop_mode_timer_fn实际就是为了避免数据丢失,将page cache数据写入磁盘的过程。它主要通过唤醒wb->dwork线程来进行处理wb->work_list队列上的所有work

wb_workfn通过wb_do_writeback将page cache数据写入plug队列,并一级级向下分派

blk_rq_timed_out_timer/blk_mq_timeout_work(TODO)

(1) 初始化
blk_alloc_queue_node时通过timer_setup(&q->timeout, blk_rq_timed_out_timer, 0)进行初始化
blk_mq_init_allocated_queue时通过INIT_WORK(&q->timeout_work, blk_mq_timeout_work);

(2) 调用时机
启动q->timeout:

null_queue_rq
|--blk_mq_start_request(bd->rq)
    |--mod_timer(&q->timeout, expiry)
       |--blk_rq_timed_out_timer(struct timer_list *t)
          |--kblockd_schedule_work(&q->timeout_work)
              |--blk_mq_timeout_work(work)

当开始对一个request进行处理时,就会启动一个定时器来检测处理是否超时

blk_mq_requeue_work(TODO)

(1) 初始化
blk_alloc_queue_node时:
INIT_DELAYED_WORK(&q->delay_work, blk_delay_work)进行的初始化
(2) 调用

blk_mq_sched_insert_request
|--if (!(rq->rq_flags & RQF_FLUSH_SEQ) && op_is_flush(rq->cmd_flags))
        blk_insert_flush(rq)
        |--rq->end_io = flush_data_end_io
        |--blk_flush_complete_seq(rq, fq, REQ_FSEQ_ACTIONS & ~policy, 0)
           |--blk_kick_flush(q, fq, cmd_flags)
              |--flush_rq->end_io = flush_end_io
              |--blk_flush_queue_rq(flush_rq, false)
                  |--if (rq->q->mq_ops)
                         blk_mq_add_to_requeue_list(rq, add_front, true)
                         |--blk_mq_kick_requeue_list(q)
                             |--kblockd_mod_delayed_work_on(WORK_CPU_UNBOUND, &q->requeue_work)
                                 |--blk_mq_requeue_work(work)
                                     |--blk_mq_run_hw_queues(q, false)

blk_delay_work(单队列)

flush_end_io
|-- if (queued || fq->flush_queue_delayed)
        blk_run_queue_async(q)
        |--if (likely(!blk_queue_stopped(q) && !blk_queue_dead(q)))
               mod_delayed_work(kblockd_workqueue, &q->delay_work, 0)
                   blk_delay_work
                   |--__blk_run_queue(q)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值