Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion arch/x64/exceptions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,12 @@ unsigned interrupt_descriptor_table::register_interrupt_handler(
}
}
}
abort();
// No free IDT vector. Vectors 0..31 are CPU exceptions and are never
// returned here, so 0 is an unambiguous "exhausted" sentinel. Returning it
// rather than aborting lets MSI-X allocation (msix_vector) fail gracefully
// and lets a device fall back to fewer queues instead of crashing the boot
// when many multiqueue devices exhaust the 224 usable vectors.
return 0;
}

void interrupt_descriptor_table::unregister_handler(unsigned vector)
Expand Down
17 changes: 15 additions & 2 deletions drivers/msi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ msix_vector::msix_vector(pci::function* dev)

msix_vector::~msix_vector()
{
idt.unregister_handler(_vector);
// _vector == 0 means IDT vector allocation failed (see the ctor); there is
// nothing to unregister in that case.
if (_vector) {
idt.unregister_handler(_vector);
}
}

pci::function* msix_vector::get_pci_function(void)
Expand Down Expand Up @@ -198,7 +202,16 @@ std::vector<msix_vector*> interrupt_manager::request_vectors(unsigned num_vector
auto num = std::min(num_vectors, num_entries);

for (unsigned i = 0; i < num; ++i) {
results.push_back(new msix_vector(_dev));
auto* vec = new msix_vector(_dev);
// A zero vector means the global IDT vector pool is exhausted. Stop
// here and return however many we did get; easy_register() treats a
// short result as failure so the caller can fall back to fewer queues
// rather than crash.
if (!vec->get_vector()) {
delete vec;
break;
}
results.push_back(vec);
}

return (results);
Expand Down
14 changes: 14 additions & 0 deletions drivers/virtio-blk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,20 @@ blk::blk(virtio_device& virtio_dev)
// base class did not set up.
_num_queues = virtio_driver::_num_queues;

// Cap the number of queues we arm with an interrupt against the shared
// MSI-X vector budget. Each queue uses one vector, and the x86-64 IDT has
// only 224 usable vectors shared by every device; a high-vCPU guest with
// several multiqueue virtio devices can otherwise exhaust them at boot.
// Extra probed virtqueues beyond this cap are simply left unused - I/O is
// steered only to queues 0.._num_queues-1, all of which have a serviced
// interrupt.
unsigned granted = reserve_msix_vectors(_num_queues);
if (granted < (unsigned)_num_queues) {
virtio_i("virtio-blk: capping active queues from %d to %d (MSI-X budget)\n",
_num_queues, granted);
_num_queues = granted;
}

// Resize per-queue lock vector now that _num_queues is known.
_queue_locks = std::vector<mutex>(_num_queues);

Expand Down
Loading