Skip to content

Commit f719cce

Browse files
committed
refactor: assert on vcpu TLS set and use
The logic for setting and using vcpu TLS is Firecacker internal and critical to Firecracker function properly. Additionally, errors returned by TLS touching code was always ignored, making these errors useless. In addition, remove the TLS reset function, since Firecracker does not support vcpu movement across different threads. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 309eb66 commit f719cce

File tree

1 file changed

+20
-61
lines changed

1 file changed

+20
-61
lines changed

src/vmm/src/vstate/vcpu.rs

Lines changed: 20 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,6 @@ pub enum VcpuError {
5151
VcpuResponse(KvmVcpuError),
5252
/// Cannot spawn a new vCPU thread: {0}
5353
VcpuSpawn(io::Error),
54-
/// Cannot clean init vcpu TLS
55-
VcpuTlsInit,
56-
/// Vcpu not present in TLS
57-
VcpuTlsNotPresent,
5854
/// Error with gdb request sent
5955
#[cfg(feature = "gdb")]
6056
GdbRequest(GdbTargetError),
@@ -121,34 +117,12 @@ impl Vcpu {
121117
/// This function will return an error if there already is a `Vcpu` present in the TLS.
122118
fn init_thread_local_data(&mut self) -> Result<(), VcpuError> {
123119
Self::TLS_VCPU_PTR.with(|cell: &VcpuCell| {
124-
if cell.get().is_some() {
125-
return Err(VcpuError::VcpuTlsInit);
126-
}
120+
assert!(cell.get().is_none());
127121
cell.set(Some(self as *mut Vcpu));
128122
Ok(())
129123
})
130124
}
131125

132-
/// Deassociates `self` from the current thread.
133-
///
134-
/// Should be called if the current `self` had called `init_thread_local_data()` and
135-
/// now needs to move to a different thread.
136-
///
137-
/// Fails if `self` was not previously associated with the current thread.
138-
fn reset_thread_local_data(&mut self) -> Result<(), VcpuError> {
139-
// Best-effort to clean up TLS. If the `Vcpu` was moved to another thread
140-
// _before_ running this, then there is nothing we can do.
141-
Self::TLS_VCPU_PTR.with(|cell: &VcpuCell| {
142-
if let Some(vcpu_ptr) = cell.get() {
143-
if vcpu_ptr == self as *mut Vcpu {
144-
Self::TLS_VCPU_PTR.with(|cell: &VcpuCell| cell.take());
145-
return Ok(());
146-
}
147-
}
148-
Err(VcpuError::VcpuTlsNotPresent)
149-
})
150-
}
151-
152126
/// Runs `func` for the `Vcpu` associated with the current thread.
153127
///
154128
/// It requires that `init_thread_local_data()` was run on this thread.
@@ -159,20 +133,15 @@ impl Vcpu {
159133
///
160134
/// This is marked unsafe as it allows temporary aliasing through
161135
/// dereferencing from pointer an already borrowed `Vcpu`.
162-
unsafe fn run_on_thread_local<F>(func: F) -> Result<(), VcpuError>
136+
unsafe fn run_on_thread_local<F>(func: F)
163137
where
164138
F: FnOnce(&mut Vcpu),
165139
{
166140
Self::TLS_VCPU_PTR.with(|cell: &VcpuCell| {
167-
if let Some(vcpu_ptr) = cell.get() {
168-
// SAFETY: Dereferencing here is safe since `TLS_VCPU_PTR` is populated/non-empty,
169-
// and it is being cleared on `Vcpu::drop` so there is no dangling pointer.
170-
let vcpu_ref = unsafe { &mut *vcpu_ptr };
171-
func(vcpu_ref);
172-
Ok(())
173-
} else {
174-
Err(VcpuError::VcpuTlsNotPresent)
175-
}
141+
let vcpu_ptr = cell.get().unwrap();
142+
// SAFETY: Dereferencing here is safe since `TLS_VCPU_PTR` is populated/non-empty.
143+
let vcpu_ref = unsafe { &mut *vcpu_ptr };
144+
func(vcpu_ref);
176145
})
177146
}
178147

@@ -183,7 +152,7 @@ impl Vcpu {
183152
// SAFETY: This is safe because it's temporarily aliasing the `Vcpu` object, but we are
184153
// only reading `vcpu.fd` which does not change for the lifetime of the `Vcpu`.
185154
unsafe {
186-
let _ = Vcpu::run_on_thread_local(|vcpu| {
155+
Vcpu::run_on_thread_local(|vcpu| {
187156
vcpu.kvm_vcpu.fd.set_kvm_immediate_exit(1);
188157
fence(Ordering::Release);
189158
});
@@ -617,12 +586,6 @@ fn handle_kvm_exit(
617586
}
618587
}
619588

620-
impl Drop for Vcpu {
621-
fn drop(&mut self) {
622-
let _ = self.reset_thread_local_data();
623-
}
624-
}
625-
626589
/// List of events that the Vcpu can receive.
627590
#[derive(Debug, Clone)]
628591
pub enum VcpuEvent {
@@ -1025,43 +988,39 @@ pub(crate) mod tests {
1025988
}
1026989

1027990
#[test]
1028-
fn test_vcpu_tls() {
991+
#[should_panic]
992+
fn test_vcpu_tls_not_set_panic() {
1029993
let (_, _, mut vcpu) = setup_vcpu(0x1000);
1030994

1031995
// Running on the TLS vcpu should fail before we actually initialize it.
1032996
unsafe {
1033-
Vcpu::run_on_thread_local(|_| ()).unwrap_err();
997+
Vcpu::run_on_thread_local(|_| ());
1034998
}
999+
}
1000+
1001+
#[test]
1002+
fn test_vcpu_tls_set() {
1003+
let (_, _, mut vcpu) = setup_vcpu(0x1000);
10351004

10361005
// Initialize vcpu TLS.
1037-
vcpu.init_thread_local_data().unwrap();
1006+
vcpu.init_thread_local_data();
10381007

10391008
// Validate TLS vcpu is the local vcpu by changing the `id` then validating against
10401009
// the one in TLS.
10411010
vcpu.kvm_vcpu.index = 12;
10421011
unsafe {
1043-
Vcpu::run_on_thread_local(|v| assert_eq!(v.kvm_vcpu.index, 12)).unwrap();
1012+
Vcpu::run_on_thread_local(|v| assert_eq!(v.kvm_vcpu.index, 12));
10441013
}
1045-
1046-
// Reset vcpu TLS.
1047-
vcpu.reset_thread_local_data().unwrap();
1048-
1049-
// Running on the TLS vcpu after TLS reset should fail.
1050-
unsafe {
1051-
Vcpu::run_on_thread_local(|_| ()).unwrap_err();
1052-
}
1053-
1054-
// Second reset should return error.
1055-
vcpu.reset_thread_local_data().unwrap_err();
10561014
}
10571015

10581016
#[test]
1017+
#[should_panic]
10591018
fn test_invalid_tls() {
10601019
let (_, _, mut vcpu) = setup_vcpu(0x1000);
10611020
// Initialize vcpu TLS.
1062-
vcpu.init_thread_local_data().unwrap();
1021+
vcpu.init_thread_local_data();
10631022
// Trying to initialize non-empty TLS should error.
1064-
vcpu.init_thread_local_data().unwrap_err();
1023+
vcpu.init_thread_local_data();
10651024
}
10661025

10671026
#[test]

0 commit comments

Comments
 (0)