Skip to content

Commit

Permalink
fix: fix kernel panic when triggering 100 thousands VirtIO device IRQs
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Dec 28, 2024
1 parent 193229e commit 087e6d4
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 20 deletions.
6 changes: 4 additions & 2 deletions src/virtio-console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ bool virtio_console::write_next_chars_to_host(i_device_state_access *a, uint32_t
os_putchars(chunk.data(), chunk_len);
}
// Consume the queue and notify the driver
if (!consume_and_notify_queue(a, queue_idx, desc_idx)) {
if (!consume_queue(a, queue_idx, desc_idx)) {
notify_device_needs_reset(a);
return false;
}
Expand Down Expand Up @@ -106,10 +106,12 @@ bool virtio_console::write_next_chars_to_guest(i_device_state_access *a) {
return false;
}
// Consume the queue and notify the driver
if (!consume_and_notify_queue(a, queue_idx, desc_idx, chunk_len, VIRTQ_USED_F_NO_NOTIFY)) {
if (!consume_queue(a, queue_idx, desc_idx, chunk_len, VIRTQ_USED_F_NO_NOTIFY)) {
notify_device_needs_reset(a);
return false;
}
// After consuming a queue, we must notify the driver right-away
notify_queue_used(a);
return true;
}

Expand Down
19 changes: 7 additions & 12 deletions src/virtio-device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,24 +438,19 @@ bool virtio_device::prepare_queue_write(i_device_state_access *a, uint32_t queue
return true;
}

bool virtio_device::consume_and_notify_queue(i_device_state_access *a, uint32_t queue_idx, uint16_t desc_idx,
uint32_t written_len, uint16_t used_flags) {
bool virtio_device::consume_queue(i_device_state_access *a, uint32_t queue_idx, uint16_t desc_idx, uint32_t written_len,
uint16_t used_flags) {
// A device MUST NOT consume buffers or send any used buffer notifications to the driver before DRIVER_OK.
assert(driver_ok);
assert(queue_idx < VIRTIO_QUEUE_COUNT);
#ifdef DEBUG_VIRTIO
std::ignore = fprintf(stderr, "virtio[%d]: consume_queue queue_idx=%d desc_idx=%d written_len=%d\n", virtio_idx,
queue_idx, desc_idx, written_len);
#endif
// Retrieve queue
virtq &vq = queue[queue_idx];
// Consume the buffer, so the driver is free to reuse it again
if (!vq.consume_desc(a, desc_idx, written_len, used_flags)) {
return false;
}
#ifdef DEBUG_VIRTIO
std::ignore = fprintf(stderr, "virtio[%d]: consume_and_notify_queue queue_idx=%d desc_idx=%d written_len=%d\n",
virtio_idx, queue_idx, desc_idx, written_len);
#endif
// After consuming a queue, we must notify the driver right-away
notify_queue_used(a);
return true;
return vq.consume_desc(a, desc_idx, written_len, used_flags);
}

void virtio_device::on_device_queue_notify(i_device_state_access *a, uint32_t queue_idx) {
Expand Down
6 changes: 3 additions & 3 deletions src/virtio-device.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,14 +314,14 @@ class virtio_device {
bool prepare_queue_write(i_device_state_access *a, uint32_t queue_idx, uint16_t *pdesc_idx,
uint32_t *pwrite_avail_len) const;

/// Consume an available queue's descriptor (sets it as used) and notify the driver.
/// Consume an available queue's descriptor (sets it as used).
/// \param queue_idx Queue index to consume and notify.
/// \param desc_idx Queue's available descriptor index to set as used.
/// \param written_len Amount of bytes written to the descriptor buffer.
/// \param used_flags Used flags, see virtq_used_flags.
/// \returns True if there are no errors, false otherwise.
bool consume_and_notify_queue(i_device_state_access *a, uint32_t queue_idx, uint16_t desc_idx,
uint32_t written_len = 0, uint16_t used_flags = 0);
bool consume_queue(i_device_state_access *a, uint32_t queue_idx, uint16_t desc_idx, uint32_t written_len = 0,
uint16_t used_flags = 0);

/// \brief Called when driver request a device reset, this function must clean-up all device internal state.
virtual void on_device_reset() = 0;
Expand Down
6 changes: 4 additions & 2 deletions src/virtio-net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ bool virtio_net::write_next_packet_to_host(i_device_state_access *a, uint32_t qu
return false;
}
// Consume the queue and notify the driver
if (!consume_and_notify_queue(a, queue_idx, desc_idx)) {
if (!consume_queue(a, queue_idx, desc_idx)) {
notify_device_needs_reset(a);
return false;
}
Expand Down Expand Up @@ -137,10 +137,12 @@ bool virtio_net::read_next_packet_from_host(i_device_state_access *a) {
return false;
}
// Consume and notify the queue
if (!consume_and_notify_queue(a, queue_idx, desc_idx, written_len)) {
if (!consume_queue(a, queue_idx, desc_idx, written_len)) {
notify_device_needs_reset(a);
return false;
}
// After consuming a queue, we must notify the driver right-away
notify_queue_used(a);
return true;
}

Expand Down
4 changes: 3 additions & 1 deletion src/virtio-p9fs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2468,10 +2468,12 @@ bool virtio_p9fs_device::send_reply(virtq_serializer &&mout_msg, uint16_t tag, p
return false;
}
// Consume the queue and notify the driver
if (!consume_and_notify_queue(out_msg.a, out_msg.queue_idx, out_msg.desc_idx, out_msg.length, 0)) {
if (!consume_queue(out_msg.a, out_msg.queue_idx, out_msg.desc_idx, out_msg.length, 0)) {
notify_device_needs_reset(out_msg.a);
return false;
}
// After consuming a queue, we must notify the driver right-away
notify_queue_used(out_msg.a);
return true;
}

Expand Down

0 comments on commit 087e6d4

Please sign in to comment.