Skip to content

Commit bae368d

Browse files
authored
Merge branch 'main' into aml_error_handling
2 parents 6f7bfeb + 5f73d2b commit bae368d

File tree

7 files changed

+81
-3
lines changed

7 files changed

+81
-3
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@ and this project adheres to
1414
`VIRTIO_NET_F_RX_MRGBUF` support to the `virtio-net` device. When this feature
1515
is negotiated, guest `virtio-net` driver can perform more efficient memory
1616
management which in turn improves RX and TX performance.
17+
- [#4460](https://github.com/firecracker-microvm/firecracker/pull/4460): Add a
18+
call to
19+
[`KVM_KVMCLOCK_CTRL`](https://docs.kernel.org/virt/kvm/api.html#kvm-kvmclock-ctrl)
20+
after pausing vCPUs on x86_64 architectures. This ioctl sets a flag in the KVM
21+
state of the vCPU indicating that it has been paused by the host userspace. In
22+
guests that use kvmclock, the soft lockup watchdog checks this flag. If it is
23+
set, it won't trigger the lockup condition. Calling the ioctl for guests that
24+
don't use kvmclock will fail. These failures are not fatal. We log the failure
25+
and increase the `vcpu.kvmclock_ctrl_fails` metric.
1726

1827
### Changed
1928

resources/seccomp/x86_64-unknown-linux-musl.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,18 @@
12541254
}
12551255
]
12561256
},
1257+
{
1258+
"syscall": "ioctl",
1259+
"args": [
1260+
{
1261+
"index": 1,
1262+
"type": "dword",
1263+
"op": "eq",
1264+
"val": 44717,
1265+
"comment": "KVM_KVMCLOCK_CTRL. We call this after pausing vCPUs to avoid soft lockups in the guest."
1266+
}
1267+
]
1268+
},
12571269
{
12581270
"syscall": "sched_yield",
12591271
"comment": "Used by the rust standard library in std::sync::mpmc. Firecracker uses mpsc channels from this module for inter-thread communication"

src/vmm/src/logger/metrics.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,8 @@ pub struct VcpuMetrics {
779779
pub exit_mmio_write: SharedIncMetric,
780780
/// Number of errors during this VCPU's run.
781781
pub failures: SharedIncMetric,
782+
/// Number of times that the `KVM_KVMCLOCK_CTRL` ioctl failed.
783+
pub kvmclock_ctrl_fails: SharedIncMetric,
782784
/// Provides Min/max/sum for KVM exits handling input IO.
783785
pub exit_io_in_agg: LatencyAggregateMetrics,
784786
/// Provides Min/max/sum for KVM exits handling output IO.
@@ -797,6 +799,7 @@ impl VcpuMetrics {
797799
exit_mmio_read: SharedIncMetric::new(),
798800
exit_mmio_write: SharedIncMetric::new(),
799801
failures: SharedIncMetric::new(),
802+
kvmclock_ctrl_fails: SharedIncMetric::new(),
800803
exit_io_in_agg: LatencyAggregateMetrics::new(),
801804
exit_io_out_agg: LatencyAggregateMetrics::new(),
802805
exit_mmio_read_agg: LatencyAggregateMetrics::new(),

src/vmm/src/vstate/vcpu/mod.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,15 @@ impl Vcpu {
336336
.send(VcpuResponse::Paused)
337337
.expect("vcpu channel unexpectedly closed");
338338

339-
// TODO: we should call `KVM_KVMCLOCK_CTRL` here to make sure
340-
// TODO continued: the guest soft lockup watchdog does not panic on Resume.
339+
// Calling `KVM_KVMCLOCK_CTRL` to make sure the guest softlockup watchdog
340+
// does not panic on resume, see https://docs.kernel.org/virt/kvm/api.html .
341+
// We do not want to fail if the call is not successful, because depending
342+
// that may be acceptable depending on the workload.
343+
#[cfg(target_arch = "x86_64")]
344+
if let Err(err) = self.kvm_vcpu.fd.kvmclock_ctrl() {
345+
METRICS.vcpu.kvmclock_ctrl_fails.inc();
346+
warn!("KVM_KVMCLOCK_CTRL call failed {}", err);
347+
}
341348

342349
// Move to 'paused' state.
343350
state = StateMachine::next(Self::paused);

tests/framework/utils.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
# SPDX-License-Identifier: Apache-2.0
33
"""Generic utility functions that are used in the framework."""
4+
import errno
45
import functools
56
import json
67
import logging
@@ -453,7 +454,9 @@ def get_process_pidfd(pid):
453454
"""Get a pidfd file descriptor for the process with PID `pid`
454455
455456
Will return a pid file descriptor for the process with PID `pid` if it is
456-
still alive. If the process has already exited it will return `None`.
457+
still alive. If the process has already exited we will receive either a
458+
`ProcessLookupError` exception or and an `OSError` exception with errno `EINVAL`.
459+
In these cases, we will return `None`.
457460
458461
Any other error while calling the system call, will raise an OSError
459462
exception.
@@ -462,6 +465,11 @@ def get_process_pidfd(pid):
462465
pidfd = os.pidfd_open(pid)
463466
except ProcessLookupError:
464467
return None
468+
except OSError as err:
469+
if err.errno == errno.EINVAL:
470+
return None
471+
472+
raise
465473

466474
return pidfd
467475

tests/host_tools/fcmetrics.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ def validate_fc_metrics(metrics):
234234
"exit_mmio_read",
235235
"exit_mmio_write",
236236
"failures",
237+
"kvmclock_ctrl_fails",
237238
{"exit_io_in_agg": latency_agg_metrics_fields},
238239
{"exit_io_out_agg": latency_agg_metrics_fields},
239240
{"exit_mmio_read_agg": latency_agg_metrics_fields},

tests/integration_tests/functional/test_pause_resume.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
# SPDX-License-Identifier: Apache-2.0
33
"""Basic tests scenarios for snapshot save/restore."""
44

5+
import platform
6+
import time
7+
58
import pytest
69

710

@@ -127,3 +130,38 @@ def test_pause_resume_preboot(uvm_nano):
127130
# Try to resume microvm when not running, it must fail.
128131
with pytest.raises(RuntimeError, match=expected_err):
129132
basevm.api.vm.patch(state="Resumed")
133+
134+
135+
@pytest.mark.skipif(
136+
platform.machine() != "x86_64", reason="Only x86_64 supports pvclocks."
137+
)
138+
def test_kvmclock_ctrl(uvm_plain_any):
139+
"""
140+
Test that pausing vCPUs does not trigger a soft lock-up
141+
"""
142+
143+
microvm = uvm_plain_any
144+
microvm.help.enable_console()
145+
microvm.spawn()
146+
microvm.basic_config()
147+
microvm.add_net_iface()
148+
microvm.start()
149+
150+
# Launch reproducer in host
151+
# This launches `ls -R /` in a loop inside the guest. The command writes its output in the
152+
# console. This detail is important as it writing in the console seems to increase the probability
153+
# that we will pause the execution inside the kernel and cause a lock up. Setting KVM_CLOCK_CTRL
154+
# bit that informs the guest we're pausing the vCPUs, should avoid that lock up.
155+
microvm.ssh.check_output(
156+
"timeout 60 sh -c 'while true; do ls -R /; done' > /dev/ttyS0 2>&1 < /dev/null &"
157+
)
158+
159+
for _ in range(12):
160+
microvm.api.vm.patch(state="Paused")
161+
time.sleep(5)
162+
microvm.api.vm.patch(state="Resumed")
163+
164+
dmesg = microvm.ssh.check_output("dmesg").stdout
165+
assert "rcu_sched self-detected stall on CPU" not in dmesg
166+
assert "rcu_preempt detected stalls on CPUs/tasks" not in dmesg
167+
assert "BUG: soft lockup -" not in dmesg

0 commit comments

Comments
 (0)