Recovering Device Driver翻译

摘要

本文提出了一种新的机制,使应用程序能够在设备驱动程序失败时正确运行。因为设备驱动程序是大多数系统的主要故障部件,减少驱动程序引起的故障大大提高了整体可靠性。早期的工作表明,操作系统可以经受住驱动程序的故障,但是依赖于它们的应用程序却不能。因此,虽然操作系统的可靠性得到了极大的提高,但应用程序的可靠性通常没有得到提高。

为了纠正这种情况,我们引入了一种新的操作系统机制,称为影子驱动程序。影子驱动程序监视设备驱动程序,并从驱动程序故障中透明地恢复。此外,它还承担了恢复过程中出现故障的驱动程序的角色。通过这种方式,使用失败驱动程序的应用程序,以及内核本身,继续按照预期的方式工作。

我们为Linux操作系统实现了影子驱动程序,并在十几个设备驱动程序上测试它们。我们的结果表明,应用程序和操作系统确实可以在各种设备驱动程序失败后存活下来。此外,影子驱动程序的性能开销最小。最后,只需对操作系统内核稍加改动,而无需对现有设备驱动程序进行任何改动,就可以引入它们。

介绍

提高可靠性是商用操作系统面临的最大挑战之一。系统故障在所有领域都很常见,而且代价高昂:在家庭、服务器室和嵌入式系统中,操作系统本身的存在是不可见的。在低端市场,失败会导致用户受挫并失去销量。在高端情况下,由于系统故障停机一小时可能导致数百万美元的损失。

这些系统故障大多数是由操作系统的设备驱动程序引起的。驱动程序失败导致了85%的Windows XP[30]崩溃,而Linux驱动程序的错误率是其他内核代码[14]的7倍。一个失败的驱动程序通常会导致应用程序、操作系统内核或两者都崩溃或停止正常工作。因此,防止驱动引起的故障可以提高系统的整体可靠性。

内核中早期的故障隔离系统旨在防止驱动程序故障破坏内核本身[33]。在这些系统中,内核卸载一个失败的驱动程序,然后从安全的初始状态重新启动它。虽然隔离技术可以减少系统崩溃的频率,但使用失败驱动程序的应用程序仍然可能崩溃。发生这些失败是因为驱动程序在重新启动时丢失了应用程序状态,导致应用程序接收错误的结果。大多数应用程序都没有准备好处理这个问题。相反,它们反映了传统的故障模型:驱动程序和操作系统要么一起故障,要么根本不故障。

本文提出了一种新的机制,称为影子驱动程序,该机制通过在故障恢复过程中对客户端隐藏驱动程序的故障,从而提高系统的整体可靠性。在正常运行期间,影子通过监控内核和驱动程序之间的所有通信来跟踪真实驱动程序的状态。当发生故障时,shadow会临时插入自己来代替失败的驱动程序,以它的名义为请求服务。在保护内核和应用程序不受故障影响的同时,影子驱动程序将失败的驱动程序恢复到可以恢复处理请求的状态。

我们的影子驱动设计体现了四个原则:

  1. 设备驱动程序故障应该对驱动程序的客户端隐藏。如果使用驱动程序的操作系统和应用程序无法检测到它已经失败,它们自己也不太可能失败。
  2. 恢复逻辑应该集中在单个子系统中。我们希望将恢复知识整合到少量组件中,以简化实现。
  3. 驱动程序恢复逻辑应该是通用的。驱动程序恢复带来的可靠性提高不应被现有成千上万的驱动程序的潜在不稳定变化所抵消。因此,体系结构必须使一个影子驱动程序能够处理大量设备副驱动程序的恢复。
  4. 恢复服务在不需要的时候应该具有低开销。对于一般情况(即驱动程序正常运行时),恢复系统应该施加相对较小的开销。
    总的来说,这些设计原则旨在最小化制作和使用影子驱动程序所需的成本,同时最大化它们在现有商用操作系统中的价值。

我们在Linux操作系统的一个版本上为声音、网络和IDE存储驱动程序实现了影子驱动程序架构。我们的结果显示,影子驱动程序:(1)屏蔽来自应用程序的设备驱动程序故障,允许应用程序在驱动程序故障期间和之后正常运行,(2)施加最小的性能开销,(3)不需要改变现有的应用程序和设备驱动程序,以及(4)很容易集成到现有的操作系统。

本文介绍了影子驱动程序的设计、实现和性能。下一节回顾保护应用程序不受系统故障影响的一般方法。第3节描述了设备驱动程序和影子驱动程序的设计和组件。第4节介绍了影子驱动程序的结构和在Linux中实现它们所需的机制。第5节介绍了评估影子驱动程序的性能、有效性和复杂性的实验。最后一节总结了我们的工作。

相关工作

本节描述先前关于恢复策略和机制的研究。恢复的重要性在数据库社区中早已为人所知,事务[19]可以防止数据损坏,并允许应用程序管理故障。最近,对故障恢复的需要已经从专门的应用和系统转移到更一般的商品系统领域。

恢复的一般方法是在两台机器上运行应用程序副本,一台是主机器,另一台是备份机器。主服务器的所有输入都被镜像到备份服务器。当主用服务器发生故障后,由备份服务器接管并提供服务。复制可以由硬件[21]、软硬件接口[8]、系统调用接口[2、5、7]或消息传递或应用程序接口[4]执行。类似地,影子驱动程序复制内核和设备驱动程序(主)之间的所有通信,将副本发送给影子驱动程序(备份)。如果驱动程序失败,影子会暂时接管,直到驱动程序恢复。然而,影子与典型的复制方案在几个方面有所不同。首先,因为我们的目标是只容忍驱动程序故障,而不是硬件故障,所以影子驱动程序和“真正的”驱动程序都在同一台机器上运行。第二,也是更重要的一点,影子不是设备驱动程序的副本:它只实现管理故障驱动程序恢复和保护应用程序不受恢复所需要的服务。由于这个原因,阴影通常比它所阴影的驱动程序简单得多。

另一种常见的恢复方法是在出现故障后重新启动应用程序。许多系统定期检查点应用程序状态[26,27,29],而其他系统将检查点与日志结合[2,5,31]。这些系统会从它们的最后一个检查点(可能在另一台机器上)透明地重新启动失败的应用程序,如果存在检查点,则重播日志。影子驱动程序采用类似的方法,重放向驱动程序发出的请求的日志。最近的工作表明,当从应用程序故障中恢复时,这种方法是有限的:应用程序经常在失败之前就被损坏;因此,它们的日志或检查点也可能损坏[10,25]。影子驱动程序只记录请求的一小部分,从而降低了这种可能性。此外,应用程序bug往往是确定性的,并且在应用程序重启[11]后复发。相反,由于内核执行环境[34]的复杂性,驱动程序错误通常会导致暂时性故障。

另一种方法是简单地重新启动失败的组件,例如,卸载和重新加载失败的内核扩展,例如设备驱动程序[33]。重新启动被提议作为构建高可用性软件[9]的一般策略。但是,重新启动强制应用程序处理故障,例如,重新初始化被重新启动的组件丢失的状态。很少有现有的应用程序执行这个[9],那些没有共享失败驱动程序命运的应用程序。影子驱动透明地恢复在重新引导中丢失的驱动状态,对应用程序不可见。

影子驱动程序依赖于设备驱动程序隔离来防止失败的驱动程序破坏操作系统或应用程序。可以通过多种方式提供隔离。Vino[32]使用软件故障隔离[35]封装扩展,并在故障发生后使用事务修复内核状态。nook[33]和Palladium[13]隔离了由虚拟内存硬件执行的保护域中的扩展。微内核[23,38,39]及其衍生物[15,17,20]通过在用户模式下执行扩展来强制隔离。

这些系统不是隐藏驱动程序的故障,而是反映了一种揭示策略,即让应用程序或用户意识到故障。操作系统通常返回一个错误代码,告诉应用程序一个系统调用失败了,但很少有其他的(例如,它不指明哪个组件失败了或失败是如何发生的)。恢复的重担就落在应用程序身上,它必须决定继续执行哪些步骤。如前所述,大多数应用程序无法处理设备驱动程序[37]的故障,因为驱动程序故障通常会导致系统崩溃。当驱动程序出现故障时,这些系统将故障暴露给应用程序,然后应用程序可能会失败。通过在恢复期间模拟设备驱动程序,影子驱动程序隐藏由驱动程序故障引起的错误,从而保护应用程序。

一些系统已经缩小了恢复的范围,将重点放在特定的子系统或组件上。例如,里约热内卢文件缓存[12]通过将单个系统组件(文件缓存)与内核故障隔离开来,从而提供了高性能。Phoenix[3]提供了在多层应用程序中单个有问题的组件类型数据库连接失败后的透明恢复。类似地,我们的影子驱动程序研究集中于单个OS组件类型的恢复,即设备驱动程序,这是导致OS失败的主要原因。通过放弃通用恢复,我们透明地解决了导致应用程序和操作系统故障的主要原因,同时保持了较低的运行时开销。

3.设备驱动程序和影子驱动程序设计

设备驱动程序是一个内核模式的软件组件,提供操作系统和硬件设备之间的接口。驱动程序将内核的请求转换为对硬件的请求。驱动程序依赖于两个接口:驱动程序导出到提供对设备访问的内核的接口,以及驱动程序从操作系统导入的内核接口。例如,图1显示了内核调用一个声音驱动程序来播放音调;作为响应,声音驱动程序将请求转换为I/O指令序列,引导声卡发出声音。

实际上,大多数设备驱动程序都是类的成员,类是由接口定义的。例如,所有网络驱动程序遵循相同的内核驱动程序接口,所有声卡驱动程序遵循相同的内核驱动程序接口。这种面向类的方式简化了向操作系统中引入新驱动程序的过程,因为不需要对操作系统进行更改来适应它们。

除了处理I/O请求,驱动程序还处理配置请求。应用程序可以配置设备,例如,通过设置网卡的带宽或声卡的音量。配置请求可能会改变未来I/O请求的驱动程序和设备行为。

3.1 Driver Faults

大多数驱动程序失败是由于意外输入或[34]事件导致的bug。例如,如果中断在请求处理的敏感部分期间到达,驱动程序可能破坏数据结构。设备驱动程序在响应(1)来自内核的请求流(包括配置和I/O),(2)来自设备的消息,(3)内核环境(可能提高或降低功耗状态,交换内存页,并在任意时间中断驱动程序)时可能崩溃。由一系列配置或I/O请求触发的驱动程序错误称为确定性失败。没有一种通用的恢复技术可以透明地从这种类型的错误中恢复,因为任何完成违规请求的尝试都可能触发错误[11]。相反,瞬态故障是由来自设备或操作系统的额外输入触发的,很少发生。

如果系统在任何操作系统、设备或应用程序状态受到影响之前检测到驱动程序故障并将其停止,则称为故障停止。更隐蔽的故障可能会破坏系统或应用程序,永远不会被检测到。系统对故障的响应决定了一个故障是否为故障停止。例如,一个能够检测和防止对内核数据结构的意外写入的系统对于这样的错误会表现出故障停止行为,而允许损坏的系统则不会。

适当的操作系统技术可以确保驱动程序以一种故障停止的方式执行[32,33,36]。例如,在之前的工作中,我们描述了nook[33],它是一个内核可靠性子系统,在它自己的内核保护域中执行每个驱动程序。Nooks通过内存保护违规、CPU过度使用和传递给内核的某些错误参数来检测故障。当Nooks检测到故障时,它会在驱动程序的保护域中停止执行,并触发恢复进程。我们报告说,在合成故障注入测试[33]中,nook能够检测到大约75%的故障。

影子驱动程序只能从瞬时故障和故障停止故障中恢复。确定性故障可能在驱动程序恢复时再次发生,再次导致故障。相比之下,瞬态故障是由环境因素触发的,这些环境因素不太可能在恢复过程中持续存在。在实践中,许多驱动程序都经历过由复杂的内核执行环境(例如,异步、中断、锁定协议和虚拟内存)[1]引起的短暂故障,这些故障很难找到和修复。相比之下,确定性驱动程序故障更容易在开发的测试阶段被发现和修复,因为这些故障是可重复的。可恢复的故障也必须是故障停止,因为影子驱动程序对系统和应用程序隐藏故障。因此,影子驱动程序需要一个可靠性子系统来检测并在应用程序或操作系统看到故障之前停止故障。尽管影子驱动程序可以使用提供这些服务的任何机制,但我们的实现使用了nook。

3.2 Shadow Drivers

影子驱动程序是提高单个设备驱动程序可靠性的内核代理。它补偿和恢复驱动程序的失败。当一个驱动出现故障时,它的影子将驱动恢复到一个正常的状态,在这个状态下,它可以处理故障前发出的I/O请求。当驱动恢复时,影子驱动服务它的请求。

影子驱动程序以两种模式之一执行:被动或主动。在被动模式下,在正常(非故障)操作中使用,影子驱动程序监视内核和它所影子的设备驱动程序之间的所有通信。这种监视是通过复制过程调用实现的:对设备驱动程序函数的内核调用导致对相应的影子驱动程序函数的自动、相同的调用。类似地,驱动程序对内核函数的调用导致对相应的影子驱动程序函数的自动相同调用。这些被动模式调用对设备驱动程序和内核是透明的。它们不打算向任何一方提供任何服务,仅用于跟踪恢复所需的驱动程序状态。

在从故障中恢复时发生的活动模式中,影子驱动程序执行两个功能。首先,它“模拟”失败的驱动程序,拦截并响应来自内核的调用。因此,内核和高级应用程序继续以尽可能正常的方式运行。其次,影子驱动程序模拟内核并重新启动失败的驱动程序,拦截并响应重新启动的驱动程序对内核的调用。换句话说,在活动模式下,影子驱动对驱动来说就像内核,对内核来说就像驱动。只有影子司机知道这个骗局。这种方法对驱动程序隐藏了恢复细节,驱动程序在发生故障后不知道它正在被影子驱动程序重新启动。

一旦驱动程序重新启动,active-mode影子将驱动程序重新集成到系统中。它会重新建立下载到驱动程序中的任何应用程序配置状态,然后恢复挂起的请求。

影子驱动程序是一种“类驱动程序”,它知道它所影子的驱动程序的接口,但不知道它们的实现。单个影子驱动程序实现可以从类中任何驱动程序的故障中恢复。类取向有三个关键含义。首先,操作系统可以利用一些影子驱动程序的实现来从大量设备驱动程序的故障中恢复。

其次,实现一个影子驱动程序并不需要详细了解它所影子的驱动程序的内部结构。相反,它只需要理解那些驱动程序与内核的交互。最后,如果一个新的驱动程序被加载到内核中,只要这个类的影子已经存在,就不需要新的影子驱动程序。例如,如果在PC上插入新的网络接口卡和驱动,现有的网络影子驱动可以在不改变的情况下影子新驱动。类似地,驱动程序可以在不需要改变其阴影的情况下被修补或更新。Shadow更新仅用于响应内核驱动程序编程接口的更改。

3.3 Taps

如我们所见,影子驱动程序监视运行驱动程序和内核之间的通信,并在故障和恢复期间模拟一个组件到另一个组件。这些活动是通过一种叫做tap的新机制实现的。从概念上讲,tap是位于内核和它的驱动程序之间的t型连接。可以将其设置为在被动模式中复制调用,并在恢复期间重定向它们。

tap以被动或主动模式运行,与附在它上的影子驱动器的状态相对应。在被动模式操作中,tap:(1)调用原始驱动程序,然后(2)用调用的参数和结果调用影子驱动程序。该操作如图2所示.

在失败时,轻拍切换到活动模式,如图3所示。在这种模式下,它:(1)终止驱动程序和内核之间的所有通信,(2)将所有在调用中重定向到它们对应的shadow接口。在活动模式下,内核和正在恢复的设备驱动程序只与影子驱动程序交互。在恢复后,点击返回到它的被动模式状态。

点击依赖于动态分配驱动程序和操作系统之间所有通信的能力。因此,所有进入和离开被跟踪的驱动程序的通信都必须是显式的,比如通过过程调用或消息。大多数司机都是这样操作的,但也有一些不是这样,不能被跟踪。例如,内核视频驱动程序经常通过共享内存区域[22]与用户模式应用程序通信。

3.4 The Shadow Manager

恢复由影子管理器监督,它是一个与所有影子驱动程序接口和控制的内核代理。影子管理器实例化新的影子驱动程序,并注入tap到设备驱动程序和内核之间的调用接口。它还接收来自故障隔离子系统的通知,说明驱动程序由于故障而停止。

当一个驱动出现故障时,影子管理器会将它的tap和影子驱动切换到活动模式。在这种模式下,对驱动程序服务的请求被重定向到一个适当准备的影子驱动程序。然后,影子管理器启动影子驱动程序的恢复序列来恢复驱动程序。当恢复结束时,影子管理器返回影子驱动程序并点击到被动模式操作,以便驱动程序可以恢复服务。

3.5 Summary

我们的设计简化了开发和集成的影子驱动器到现有的系统。每个影子驱动程序都是一个单独的模块,使用设备驱动程序类的行为(接口)编写,允许它隐藏驱动程序故障并在故障后重新启动驱动程序。一个影子驱动程序,通常是被动的,监视内核和驱动程序之间的通信。当驱动程序出现故障时,它成为一个活动代理,然后管理它的恢复。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值