【翻译】 一个新的暂停/休眠的基础设施

LWN订阅者的好处

订阅LWN的主要好处是帮助我们继续出版,但除此之外,订阅者可以立即获得所有的网站内容和获得一些额外的网站功能。 请今天就注册吧!

作者: Jonathan Corbet
2008年3月19日
在参加会议时,你们的编辑多年来一直注意观察有多少其他与会者的笔记本电脑上有某种暂停和恢复功能。 毕竟,能够在演讲厅里坐下来,打开盖子,并立即开始通过IRC对演讲者进行抨击,而不必等待整个启动程序的展开,是有明显价值的。 但是,无论人们谈论的是悬挂到内存("suspend")还是悬挂到磁盘("hibernation"),使用这种功能的人都少得令人吃惊。 尽管开发者和发行商已经做出努力,悬挂和休眠对很多人来说仍然不能可靠地工作。

对你的编辑来说,暂停总是有效的,但恢复操作的成功率大约是95%--刚好够继续使用它,同时在不恰当的地方激发出相当多的亵渎。

已经提出了各种修复挂起和休眠的方法;这些方法包括TuxOnIcekexec jump。 不过,另一种可能性是简单地修复现在内核中的代码。 要使这一目标成为现实,还有很多事情要做,包括使整个过程更加健壮,以及将挂起和休眠的情况分开,正如Linus多次强烈指出的那样,这实际上是两个不同的问题。 为此,Rafael Wysocki发布了一个新的设备暂停和休眠基础设施,有可能改善这种情况--但代价是要创建不少于20个独立的设备回调。

对于(相对)简单的暂停情况,有四个基本的回调,每个总线和最终每个设备都应该在新的pm_ops结构中提供:

    int (*prepare)(struct device *dev); int (*suspend)(struct device *dev); int (*resume)(struct device *dev); void (*complete)(struct device *dev);

当系统正在暂停时,每个设备将首先看到对其prepare()回调的调用。 这个调用可以被看作是一种警告,即暂停即将到来,任何必要的准备工作都应该被完成。 这项工作包括防止添加任何新的子设备和任何可能需要用户空间参与的东西。 任何重要的内存分配也应该在这个时候完成;系统在这个时候仍然是正常的,如果有必要,可以执行I/O以使内存可用。 在prepare()应该发生的是实际将设备放入低功耗状态;它需要保持功能和可用性。

像往常一样,返回值为0表示准备成功,而负的错误代码表示失败。 在失败是暂时的情况下(与添加新的子设备的竞赛是一种可能性),回调应该返回-EAGAIN,这将导致在以后的过程中重复尝试。

在稍后的时间里,suspend()将被调用,以实际关闭设备的电源。 在当前的补丁中,每个设备将看到一个prepare()的调用,然后是suspend()。 未来的版本可能会改变情况,使所有的设备在被暂停之前得到一个prepare()的调用;这样一来,即使是最后的prepare()回调也可以指望一个完全运作的系统的可用性。

resume进程调用resume()来唤醒设备,将其恢复到之前的状态,并使其总体上准备好运行。 一旦恢复过程完成,就会调用complete()来清理prepare()留下的东西。 如果暂停进程在系统的其他地方出现故障,也可以在prepare()之后直接调用complete()(没有中间的暂停)。

休眠过程更加复杂,因为有更多的中间状态。 在这种情况下,该过程也是以调用prepare()开始。 然后调用:

    int (*freeze)(struct device *dev); int (*poweroff)(struct device *dev);

freeze()回调发生在创建休眠镜像(被写入持久性存储的系统镜像)之前;它应该使设备进入静止状态,但使其处于运行状态。 然后,在休眠镜像被保存并再次调用prepare()后,poweroff()被调用以关闭设备。

当系统重新上电时,这个过程通过调用以下程序而被逆转:

    int (*quiesce)(struct device *dev); int (*restore)(struct device *dev);

quiesce()的调用将发生在恢复过程的早期,在休眠镜像从磁盘加载之后,但在它被用来重新创建休眠前系统的内存之前。 这个回调应该使设备安静下来,这样内存就可以被重新组装,而不会被设备操作破坏。 随后将调用complete(),然后调用restore(),这应该使设备恢复到一个完全正常的状态。 最后一个complete()的调用完成了整个过程。

还有两个与休眠相关的回调:

    int (*thaw)(struct device *dev); int (*recover)(struct device *dev);

当事情出错时,这些函数将被调用;再一次,每个调用后都会有一个对complete()的调用。 thaw()的目的是撤销freeze()quiesce()所做的工作;它应该使设备回到工作状态。recover()的调用将在创建休眠镜像失败或从该镜像恢复失败时进行;其工作是清理并使硬件回到工作状态。

为了增加乐趣,实际上有两组pm_ops回调。 显然,在这种环境下,与设备的交互是不同的,所以不同的回调是有意义的。 但结果是,必须为完整的暂停和休眠功能提供整整20个回调。 这些回调已经被添加到bus_type结构中,如下:

    struct pm_ops *pm; struct pm_ops *pm_noirq;

pci_driver结构中也添加了相同名称的字段,允许每个设备驱动程序添加其自身版本的这些回调。 目前,如果没有提供pm_ops结构,并且没有驱动程序被转换,则将使用旧的PCI驱动程序suspend()resume()回调(至少在发布的补丁中)。

截至目前,对该补丁的讨论因vger.kernel.org网站的中断而受阻。 不过也有一些问题,在未来的修订中,事情可能会发生变化。 在其他方面,"无IRQ "回调的数量可能会减少。 但是,如果幸运的话,最终的解决方案会让我们都处于一个暂停和休眠都能可靠工作的位置。

这篇文章的索引条目
内核 设备驱动
内核 电源管理
内核 软件挂起


(登录后可发表评论)

猜你喜欢

转载自blog.csdn.net/community_717/article/details/131652256