Skip to content

Commit a7735d5

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "hardware: Reject requests for no hyperthreads on hosts with HT"
2 parents 1d114a8 + 9c27033 commit a7735d5

File tree

4 files changed

+99
-16
lines changed

4 files changed

+99
-16
lines changed

nova/tests/functional/libvirt/test_numa_servers.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -384,12 +384,7 @@ def test_create_server_with_isolate_thread_policy_fails(self):
384384
}
385385
flavor_id = self._create_flavor(vcpu=2, extra_spec=extra_spec)
386386

387-
# FIXME(stephenfin): This should go to error status since there should
388-
# not be a host available
389-
expected_usage = {
390-
'DISK_GB': 20, 'MEMORY_MB': 2048, 'PCPU': 0, 'VCPU': 2,
391-
}
392-
self._run_build_test(flavor_id, expected_usage=expected_usage)
387+
self._run_build_test(flavor_id, end_status='ERROR')
393388

394389
def test_create_server_with_pcpu(self):
395390
"""Create a server using an explicit 'resources:PCPU' request.

nova/tests/unit/virt/test_hardware.py

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3749,10 +3749,13 @@ def test_get_pinning_host_siblings_large_instance_odd_fit(self):
37493749
got_topo = objects.VirtCPUTopology(sockets=1, cores=5, threads=1)
37503750
self.assertEqualTopology(got_topo, inst_pin.cpu_topology)
37513751

3752+
# TODO(stephenfin): Remove when we drop support for vcpu_pin_set
37523753
def test_get_pinning_isolate_policy_too_few_fully_free_cores(self):
37533754
host_pin = objects.NUMACell(
37543755
id=0,
3755-
cpuset=set(),
3756+
# Simulate a legacy host with vcpu_pin_set configuration,
3757+
# meaning cpuset == pcpuset
3758+
cpuset=set([0, 1, 2, 3]),
37563759
pcpuset=set([0, 1, 2, 3]),
37573760
memory=4096,
37583761
memory_usage=0,
@@ -3774,10 +3777,13 @@ def test_get_pinning_isolate_policy_too_few_fully_free_cores(self):
37743777

37753778
self.assertIsNone(inst_pin)
37763779

3780+
# TODO(stephenfin): Remove when we drop support for vcpu_pin_set
37773781
def test_get_pinning_isolate_policy_no_fully_free_cores(self):
37783782
host_pin = objects.NUMACell(
37793783
id=0,
3780-
cpuset=set(),
3784+
# Simulate a legacy host with vcpu_pin_set configuration,
3785+
# meaning cpuset == pcpuset
3786+
cpuset=set([0, 1, 2, 3]),
37813787
pcpuset=set([0, 1, 2, 3]),
37823788
memory=4096,
37833789
memory_usage=0,
@@ -3799,10 +3805,13 @@ def test_get_pinning_isolate_policy_no_fully_free_cores(self):
37993805

38003806
self.assertIsNone(inst_pin)
38013807

3808+
# TODO(stephenfin): Remove when we drop support for vcpu_pin_set
38023809
def test_get_pinning_isolate_policy_fits(self):
38033810
host_pin = objects.NUMACell(
38043811
id=0,
3805-
cpuset=set(),
3812+
# Simulate a legacy host with vcpu_pin_set configuration,
3813+
# meaning cpuset == pcpuset
3814+
cpuset=set([0, 1, 2, 3]),
38063815
pcpuset=set([0, 1, 2, 3]),
38073816
memory=4096,
38083817
memory_usage=0,
@@ -3825,10 +3834,13 @@ def test_get_pinning_isolate_policy_fits(self):
38253834
got_topo = objects.VirtCPUTopology(sockets=1, cores=2, threads=1)
38263835
self.assertEqualTopology(got_topo, inst_pin.cpu_topology)
38273836

3837+
# TODO(stephenfin): Remove when we drop support for vcpu_pin_set
38283838
def test_get_pinning_isolate_policy_fits_ht_host(self):
38293839
host_pin = objects.NUMACell(
38303840
id=0,
3831-
cpuset=set(),
3841+
# Simulate a legacy host with vcpu_pin_set configuration,
3842+
# meaning cpuset == pcpuset
3843+
cpuset=set([0, 1, 2, 3]),
38323844
pcpuset=set([0, 1, 2, 3]),
38333845
memory=4096,
38343846
memory_usage=0,
@@ -3852,10 +3864,13 @@ def test_get_pinning_isolate_policy_fits_ht_host(self):
38523864
got_topo = objects.VirtCPUTopology(sockets=1, cores=2, threads=1)
38533865
self.assertEqualTopology(got_topo, inst_pin.cpu_topology)
38543866

3867+
# TODO(stephenfin): Remove when we drop support for vcpu_pin_set
38553868
def test_get_pinning_isolate_policy_fits_w_usage(self):
38563869
host_pin = objects.NUMACell(
38573870
id=0,
3858-
cpuset=set(),
3871+
# Simulate a legacy host with vcpu_pin_set configuration,
3872+
# meaning cpuset == pcpuset
3873+
cpuset=set([0, 1, 2, 3, 4, 5, 6, 7]),
38593874
pcpuset=set([0, 1, 2, 3, 4, 5, 6, 7]),
38603875
memory=4096,
38613876
memory_usage=0,
@@ -3879,6 +3894,38 @@ def test_get_pinning_isolate_policy_fits_w_usage(self):
38793894
got_topo = objects.VirtCPUTopology(sockets=1, cores=2, threads=1)
38803895
self.assertEqualTopology(got_topo, inst_pin.cpu_topology)
38813896

3897+
# TODO(stephenfin): Remove when we drop support for vcpu_pin_set
3898+
@mock.patch.object(hw, 'LOG')
3899+
def test_get_pinning_isolate_policy_bug_1889633(self, mock_log):
3900+
host_pin = objects.NUMACell(
3901+
id=0,
3902+
cpuset={0, 1, 4, 5},
3903+
pcpuset={2, 3, 6, 7},
3904+
memory=4096,
3905+
memory_usage=0,
3906+
pinned_cpus=set(),
3907+
siblings=[{0, 4}, {1, 5}, {2, 6}, {3, 7}],
3908+
mempages=[],
3909+
)
3910+
inst_pin = objects.InstanceNUMACell(
3911+
cpuset=set(),
3912+
pcpuset={0, 1},
3913+
memory=2048,
3914+
cpu_policy=fields.CPUAllocationPolicy.DEDICATED,
3915+
cpu_thread_policy=fields.CPUThreadAllocationPolicy.ISOLATE,
3916+
)
3917+
limits = objects.NUMATopologyLimits(
3918+
cpu_allocation_ratio=2, ram_allocation_ratio=2,
3919+
)
3920+
3921+
# host has hyperthreads, which means no NUMA topology should be built
3922+
inst_topo = hw._numa_fit_instance_cell(host_pin, inst_pin, limits)
3923+
self.assertIsNone(inst_topo)
3924+
self.assertIn(
3925+
'Host supports hyperthreads, but instance requested no',
3926+
mock_log.warning.call_args[0][0],
3927+
)
3928+
38823929

38833930
class CPUPinningTestCase(test.NoDBTestCase, _CPUPinningTestCaseBase):
38843931
def test_host_numa_fit_instance_to_host_single_cell(self):
@@ -4898,11 +4945,14 @@ def test_isolate_full_usage(self):
48984945

48994946
self.assertEqual(set([0, 1]), host_topo.cells[0].pinned_cpus)
49004947

4948+
# TODO(stephenfin): Remove when we drop support for vcpu_pin_set
49014949
def test_isolate_w_isolate_thread_alloc(self):
49024950
host_topo = objects.NUMATopology(cells=[
49034951
objects.NUMACell(
49044952
id=0,
4905-
cpuset=set(),
4953+
# Simulate a legacy host with vcpu_pin_set configuration,
4954+
# meaning cpuset == pcpuset
4955+
cpuset=set([0, 1, 2, 3, 4, 5]),
49064956
pcpuset=set([0, 1, 2, 3, 4, 5]),
49074957
memory=2048,
49084958
cpu_usage=0,
@@ -4925,11 +4975,14 @@ def test_isolate_w_isolate_thread_alloc(self):
49254975
self.assertEqual({0: 0, 1: 2}, inst_topo.cells[0].cpu_pinning)
49264976
self.assertEqual(set([4]), inst_topo.cells[0].cpuset_reserved)
49274977

4978+
# TODO(stephenfin): Remove when we drop support for vcpu_pin_set
49284979
def test_isolate_w_isolate_thread_alloc_usage(self):
49294980
host_topo = objects.NUMATopology(cells=[
49304981
objects.NUMACell(
49314982
id=0,
4932-
cpuset=set(),
4983+
# Simulate a legacy host with vcpu_pin_set configuration,
4984+
# meaning cpuset == pcpuset
4985+
cpuset=set([0, 1, 2, 3, 4, 5]),
49334986
pcpuset=set([0, 1, 2, 3, 4, 5]),
49344987
memory=2048,
49354988
cpu_usage=0,
@@ -5038,11 +5091,14 @@ def test_asymmetric_host(self):
50385091
self.assertEqual({0: 2, 1: 3}, inst_topo.cells[0].cpu_pinning)
50395092
self.assertEqual(set([1]), inst_topo.cells[0].cpuset_reserved)
50405093

5094+
# TODO(stephenfin): Remove when we drop support for vcpu_pin_set
50415095
def test_asymmetric_host_w_isolate_thread_alloc(self):
50425096
host_topo = objects.NUMATopology(cells=[
50435097
objects.NUMACell(
50445098
id=0,
5045-
cpuset=set(),
5099+
# Simulate a legacy host with vcpu_pin_set configuration,
5100+
# meaning cpuset == pcpuset
5101+
cpuset=set([1, 2, 3, 4, 5]),
50465102
pcpuset=set([1, 2, 3, 4, 5]),
50475103
memory=2048,
50485104
cpu_usage=0,
@@ -5052,8 +5108,7 @@ def test_asymmetric_host_w_isolate_thread_alloc(self):
50525108
mempages=[objects.NUMAPagesTopology(
50535109
size_kb=4, total=524288, used=0)])])
50545110
inst_topo = objects.InstanceNUMATopology(
5055-
emulator_threads_policy=(
5056-
fields.CPUEmulatorThreadsPolicy.ISOLATE),
5111+
emulator_threads_policy=fields.CPUEmulatorThreadsPolicy.ISOLATE,
50575112
cells=[objects.InstanceNUMACell(
50585113
id=0,
50595114
cpuset=set(), pcpuset=set([0, 1]), memory=2048,

nova/virt/hardware.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,30 @@ def _get_reserved(sibling_set, vcpus_pinning, num_cpu_reserved=0,
913913
'for the isolate policy without this.')
914914
return
915915

916+
# TODO(stephenfin): Drop this when we drop support for 'vcpu_pin_set'
917+
# NOTE(stephenfin): This is total hack. We're relying on the fact that
918+
# the libvirt driver, which is the only one that currently supports
919+
# pinned CPUs, will set cpuset and pcpuset to the same value if using
920+
# legacy configuration, i.e. 'vcpu_pin_set', as part of
921+
# '_get_host_numa_topology'. They can't be equal otherwise since
922+
# 'cpu_dedicated_set' and 'cpu_shared_set' must be disjoint. Therefore,
923+
# if these are equal, the host that this NUMA cell corresponds to is
924+
# using legacy configuration and it's okay to use the old, "pin a core
925+
# and reserve its siblings" implementation of the 'isolate' policy. If
926+
# they're not, the host is using new-style configuration and we've just
927+
# hit bug #1889633
928+
if threads_per_core != 1 and host_cell.pcpuset != host_cell.cpuset:
929+
LOG.warning(
930+
"Host supports hyperthreads, but instance requested no "
931+
"hyperthreads. This should have been rejected by the "
932+
"scheduler but we likely got here due to the fallback VCPU "
933+
"query. Consider setting '[workarounds] "
934+
"disable_fallback_pcpu_query' to 'True' once hosts are no "
935+
"longer using 'vcpu_pin_set'. Refer to bug #1889633 for more "
936+
"information."
937+
)
938+
return
939+
916940
pinning = _get_pinning(
917941
1, # we only want to "use" one thread per core
918942
sibling_sets[threads_per_core],
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
fixes:
3+
- |
4+
An issue that could result in instances with the ``isolate`` thread policy
5+
(``hw:cpu_thread_policy=isolate``) being scheduled to hosts with SMT
6+
(HyperThreading) and consuming ``VCPU`` instead of ``PCPU`` has been
7+
resolved. See `bug #1889633`__ for more information.
8+
9+
.. __: https://bugs.launchpad.net/nova/+bug/1889633

0 commit comments

Comments
 (0)