讨论下Linux下SCSI栈的IO错误处理策略
讨论下Linux下SCSI栈的IO错误处理策略
(一)尽快报错 or 尽力重试?
先讨论一个问题:如果上级交给的任务暂时无法完成,那么我们应该:
(策略1)应该尽快向上报错(abort),等待上级做出下一步的指令。
(策略2)暂不报告失败,而是带着未完成的任务,去修复和重试。
(二)Linux的SCSI对错误的处理策略
目前Linux的SCSI栈,默认的策略是暂时不要向上报错,而是修复和重试。希望能对上级屏蔽底层错误,返回一个重试后的成功的结果。
如果SCSI设备驱动完整的注册了各个修复函数(scsi_en_XX_reset ),
那么底层回错的结果就是, 从下向上,逐级修复, 最后把堆积的IO再提交一遍。
如果SCSI设备驱动没有注册scsi_en_XX_reset函数,那么就没有相关修复处理。
static void scsi_unjam_host(struct Scsi_Host *shost)
{
略 。。。
if (!scsi_eh_get_sense(&eh_work_q, &eh_done_q))
scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q);
略 。。。
scsi_eh_flush_done_q(&eh_done_q);
}
void scsi_eh_ready_devs(struct Scsi_Host *shost,
struct list_head *work_q,
struct list_head *done_q)
{
if (!scsi_eh_stu(shost, work_q, done_q))
if (!scsi_eh_bus_device_reset(shost, work_q, done_q))
if (!scsi_eh_target_reset(shost, work_q, done_q))
if (!scsi_eh_bus_reset(shost, work_q, done_q))
if (!scsi_eh_host_reset(shost, work_q, done_q))
scsi_eh_offline_sdevs(work_q,done_q);
}
这段代码看的我心惊胆战。
这个反复重试的策略,对单机系统是合理的,但是对分布式系统不合理。
本来分布式系统可以选择这个盘,也可以选择那个盘,但肯定不会选择故障的盘。早点让上级知道,能更快的把后续读写任务切到其他盘。然后故障盘再执行硬件修复(比如Smart查询,坏道扫描,硬盘上下电)就从容了。再说,如果遇到硬件故障,简单的重试大概率还是失败。
(三)学习结论:
(策略1)如果是集中式的单控系统,读写任务迁移困难,那么遇到困难先别急着abort,还是尽量重试吧。
(策略2)如果是分布式系统,读写任务可以迁移,那么应该尽快abort,因为分布式系统的可靠性从来不是构筑在单设备可靠性之上,而是用冗余来弥补单设备可靠性的不足。如果底层早点报错,那么上层就能早点切换。
##############################
相关函数序列如下:
(1)SCSI层的提交,然后等待硬盘执行完毕后返回中断
scsi_queue_rq
=> scsi_dispatch_cmd
==> Scsi_Host->hostt->queuecommand
==> scsi_cmnd->scsi_done
scsi_execute_req
=> scsi_execute
==> __scsi_execute
===> blk_execute_rq
(2)硬盘返回处理:返回成功 or 返回失败 or 不按时返回
(2.1)中断前半部-硬中断回调
handle_level_irq
_base_interrupt
mpt_callbacks
_scsih_io_done
scsi_cmnd->scsi_done
scsi_mq_done
blk_mq_complete_request
blk_mq_complete_request_remote
blk_mq_trigger_softirq
raise_softirq_irqoff
// 放到软中断中去处理:BLOCK_SOFTIRQ
(2.2)中断后半部-软中断回调
do_softirq
do_softirq_own_stack
_do_softirq
softirq_action->action
// subsys_initcall(blk_softirq_init)
// BLOCK_SOFTIRQ <---> blk_done_softirq
blk_done_softirq
request_queue->softirq_done_fn
scsi_softirq_done
scsi_decide_disposition
// SCSI操作完成
(A)scsi_finish_command
scsi_io_completion
scsi_end_request
blk_update_request
req_bio_endio
bio_endio
bio->bi_end_io
end_bio_bh_io_sync
blk_finish_request
request->end_io
// blk_end_sync_rq
scsi_run_queue
(B) scsi_queue_insert
_scsi_queue_insert
blk_requeue_request
elv_requeue_request
kblockd_schedule_work
(C) scsi_eh_scmd_add
(2.3)返回错误的处理
我再强调下结论,分布式系统要尽快返回结果。
先abort,然后再修复底层故障。
不要一边Hung住未完成的IO,一边来修复底层故障!
scsi_error_handler //while循环任务
(A)eh_strategy_handler //自定义处理策略
# ata_scsi_error
(B)scsi_unjam_host //SCSI默认处理策略
scsi_eh_ready_devs
scsi_eh_bus_device_reset
scsi_eh_target_reset
scsi_eh_bus_reset
scsi_eh_host_reset
scsi_eh_flush_done_q
(3)超时检查
blk_mq_check_expired
blk_mq_rq_timed_out
request->q->mq_ops->timeout
scsi_timeout
scsi_times_out
scsi_eh_scmd_add
scsi_eh_wakeup
Scsi_Host->ehandler
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?