arch/x86/virt/vmx/tdx/seamldr.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
The following commit has been merged into the x86/tdx branch of tip:
Commit-ID: c507e80de9471234536953ee2605e569a7de2306
Gitweb: https://git.kernel.org/tip/c507e80de9471234536953ee2605e569a7de2306
Author: Chao Gao <chao.gao@intel.com>
AuthorDate: Wed, 20 May 2026 15:29:04 -07:00
Committer: Dave Hansen <dave.hansen@linux.intel.com>
CommitterDate: Wed, 20 May 2026 15:37:10 -07:00
x86/virt/seamldr: Abort updates after a failed step
A TDX module update is a multi-step process, and any step can fail.
The current update flow continues to later steps after an error.
Continuing after a failure can cause the TDX module to enter an
unrecoverable state.
But certain failures during the initial module shutdown step should
simply return an error to userspace, so the update can be retried
cleanly.
To preserve that recoverability, one option would be to abort the
update only for those failures, since they occur before any TDX module
state is changed. But special-casing specific failures in specific
steps would complicate the do-while() update loop for no benefit.
Simply abort update on any failure, at any step.
Track failures for each step, stop the update loop once a failure is
observed, and do not advance the state machine to the next step.
[ dhansen: style nits ]
Signed-off-by: Chao Gao <chao.gao@intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Kai Huang <kai.huang@intel.com>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Link: https://lore.kernel.org/linux-coco/aQFmOZCdw64z14cJ@google.com/ # [1]
Link: https://patch.msgid.link/20260520133909.409394-16-chao.gao@intel.com
Link: https://patch.msgid.link/20260520222904.645A6FD4@davehans-spike.ostc.intel.com
---
arch/x86/virt/vmx/tdx/seamldr.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index ec45b85..b03dce2 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -202,6 +202,7 @@ enum module_update_state {
static struct update_ctrl {
enum module_update_state state;
int num_ack;
+ int num_failed;
/*
* Protect update_ctrl. Raw spinlock as it will be acquired from
* interrupt-disabled contexts.
@@ -219,12 +220,13 @@ static void __set_target_state(struct update_ctrl *ctrl,
}
/* Last one to ack a state moves to the next state. */
-static void ack_state(struct update_ctrl *ctrl)
+static void ack_state(struct update_ctrl *ctrl, int result)
{
raw_spin_lock(&ctrl->lock);
+ ctrl->num_failed += !!result;
ctrl->num_ack++;
- if (ctrl->num_ack == num_online_cpus())
+ if (ctrl->num_ack == num_online_cpus() && !ctrl->num_failed)
__set_target_state(ctrl, ctrl->state + 1);
raw_spin_unlock(&ctrl->lock);
@@ -234,6 +236,7 @@ static void init_state(struct update_ctrl *ctrl)
{
raw_spin_lock_init(&ctrl->lock);
__set_target_state(ctrl, MODULE_UPDATE_START + 1);
+ ctrl->num_failed = 0;
}
/*
@@ -261,8 +264,9 @@ static int do_seamldr_install_module(void *seamldr_params)
break;
}
- ack_state(&update_ctrl);
- } while (curstate != MODULE_UPDATE_DONE);
+ ack_state(&update_ctrl, ret);
+ } while (curstate != MODULE_UPDATE_DONE &&
+ !READ_ONCE(update_ctrl.num_failed));
return ret;
}
© 2016 - 2026 Red Hat, Inc.