系统状态变更¶
有些用户非常不愿意重启系统。 这就需要提供更多的 livepatch 并保持它们之间的一些兼容性。
使用累积 livepatch 可以更容易地维护更多的 livepatch。 每个新的 livepatch 完全替换任何旧的 livepatch。 它可以保留、添加甚至删除修复。 并且由于原子替换功能,通常可以安全地将任何版本的 livepatch 替换为任何其他版本。
问题可能出在影子变量和回调上。 它们可能会改变系统行为或状态,使其不再安全地返回并使用旧的 livepatch 或原始内核代码。 此外,任何新的 livepatch 都必须能够检测到已经安装的 livepatch 所做的更改。
这就是 livepatch 系统状态跟踪发挥作用的地方。 它允许
存储操作和恢复系统状态所需的数据
使用更改 ID 和版本定义 livepatch 之间的兼容性
1. Livepatch 系统状态 API¶
系统状态可能会被多个 livepatch 回调或新使用的代码修改。 此外,必须能够找到已安装的 livepatch 所做的更改。
每个修改后的状态都由 struct klp_state
描述,请参阅 include/linux/livepatch.h。
每个 livepatch 定义一个 struct klp_states 数组。 它们提到 livepatch 修改的所有状态。
livepatch 作者必须为每个 struct klp_state
定义以下两个字段
id
用于标识受影响的系统状态的非零数字。
version
描述给定 livepatch 支持的系统状态更改变体的数字。
可以使用以下两个函数操作状态
获取与给定 livepatch 和状态 ID 关联的
struct klp_state
。
获取与给定功能 ID 和已安装的 livepatch 关联的
struct klp_state
。
2. Livepatch 兼容性¶
系统状态版本用于防止加载不兼容的 livepatch。 检查在启用 livepatch 时完成。 规则是
允许任何全新的系统状态修改。
对于已修改的系统状态,允许使用相同或更高版本的系统状态修改。
累积 livepatch 必须处理来自已安装的 livepatch 的所有系统状态修改。
允许非累积 livepatch 触及已修改的系统状态。
3. 支持的场景¶
Livepatch 有其生命周期,系统状态变更也是如此。 每个兼容的 livepatch 都必须支持以下场景
当启用 livepatch 并且该状态尚未被正在被替换的 livepatch 修改时,修改系统状态。
接管或更新系统状态修改,如果它已经被正在被替换的 livepatch 完成。
禁用 livepatch 时,恢复原始状态。
还原转换时,恢复先前的状态。 可能是原始系统状态或正在被替换的 livepatch 所做的状态修改。
当发生错误且无法启用 livepatch 时,删除任何已做的更改。
4. 预期用法¶
系统状态通常由 livepatch 回调修改。 每个回调的预期角色如下
pre_patch()
必要时分配 *state->data*。 分配可能会失败,并且 *pre_patch()* 是唯一可以停止加载 livepatch 的回调。 如果数据已由先前安装的 livepatch 提供,则不需要分配。
在转换完成之前,执行新代码所需的任何其他准备操作。 例如,初始化 *state->data*。
系统状态本身通常在 *post_patch()* 中修改,此时整个系统都能够处理它。
发生错误时清理自己的烂摊子。 这可以通过自定义代码或显式调用 *post_unpatch()* 来完成。
post_patch()
当它们兼容时,从先前的 livepatch 复制 *state->data*。
进行实际的系统状态修改。 最终允许新代码使用它。
确保 *state->data* 具有所有必要的信息。
当不再需要时,从替换的 livepatch 中释放 *state->data*。
pre_unpatch()
防止 livepatch 添加的代码依赖于系统状态更改。
还原系统状态修改。
post_unpatch()
通过检查 *
klp_get_prev_state()
* 区分转换反转和 livepatch 禁用。在转换反转的情况下,恢复先前的系统状态。 这可能意味着什么都不做。
删除任何不再需要的设置或数据。
注意
*pre_unpatch()* 通常执行与 *post_patch()* 对称的操作。 唯一的区别是它仅在禁用 livepatch 时被调用。 因此,它不需要关心任何先前安装的 livepatch。
*post_unpatch()* 通常执行与 *pre_patch()* 对称的操作。 它也可能在转换反转期间被调用。 因此,它必须处理先前安装的 livepatch 的状态。