Skip to content

[1.12 Backport] Fix greedy block device #5277

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.12.1]

### Fixed

- [#5277](https://github.com/firecracker-microvm/firecracker/pull/5277): Fixed a
bug allowing the block device to starve all other devices when backed by a
sufficiently slow drive.

## [1.12.0]

### Added
Expand Down
3 changes: 3 additions & 0 deletions src/vmm/src/devices/virtio/balloon/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ impl Balloon {
}
}
}
queue.advance_used_ring_idx();

if needs_interrupt {
self.signal_used_queue()?;
Expand All @@ -379,6 +380,7 @@ impl Balloon {
queue.add_used(head.index, 0).map_err(BalloonError::Queue)?;
needs_interrupt = true;
}
queue.advance_used_ring_idx();

if needs_interrupt {
self.signal_used_queue()
Expand Down Expand Up @@ -450,6 +452,7 @@ impl Balloon {
self.queues[STATS_INDEX]
.add_used(index, 0)
.map_err(BalloonError::Queue)?;
self.queues[STATS_INDEX].advance_used_ring_idx();
self.signal_used_queue()
} else {
error!("Failed to update balloon stats, missing descriptor.");
Expand Down
69 changes: 35 additions & 34 deletions src/vmm/src/devices/virtio/block/virtio/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,24 +384,6 @@
}
}

fn add_used_descriptor(
queue: &mut Queue,
index: u16,
len: u32,
irq_trigger: &IrqTrigger,
block_metrics: &BlockDeviceMetrics,
) {
queue.add_used(index, len).unwrap_or_else(|err| {
error!("Failed to add available descriptor head {}: {}", index, err)
});

if queue.prepare_kick() {
irq_trigger.trigger_irq(IrqType::Vring).unwrap_or_else(|_| {
block_metrics.event_fails.inc();
});
}
}

/// Device specific function for peaking inside a queue and processing descriptors.
pub fn process_queue(&mut self, queue_index: usize) {
// This is safe since we checked in the event handler that the device is activated.
Expand All @@ -422,7 +404,6 @@
break;
}

used_any = true;
request.process(&mut self.disk, head.index, mem, &self.metrics)
}
Err(err) => {
Expand All @@ -443,16 +424,27 @@
break;
}
ProcessingResult::Executed(finished) => {
Self::add_used_descriptor(
queue,
head.index,
finished.num_bytes_to_mem,
&self.irq_trigger,
&self.metrics,
);
used_any = true;
queue
.add_used(head.index, finished.num_bytes_to_mem)
.unwrap_or_else(|err| {
error!(
"Failed to add available descriptor head {}: {}",

Check warning on line 432 in src/vmm/src/devices/virtio/block/virtio/device.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/devices/virtio/block/virtio/device.rs#L431-L432

Added lines #L431 - L432 were not covered by tests
head.index, err
)
});
}
}
}
queue.advance_used_ring_idx();

if used_any && queue.prepare_kick() {
self.irq_trigger
.trigger_irq(IrqType::Vring)
.unwrap_or_else(|_| {
self.metrics.event_fails.inc();

Check warning on line 445 in src/vmm/src/devices/virtio/block/virtio/device.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/devices/virtio/block/virtio/device.rs#L445

Added line #L445 was not covered by tests
});
}

if let FileEngine::Async(ref mut engine) = self.disk.file_engine {
if let Err(err) = engine.kick_submission_queue() {
Expand Down Expand Up @@ -493,17 +485,26 @@
),
};
let finished = pending.finish(mem, res, &self.metrics);

Self::add_used_descriptor(
queue,
finished.desc_idx,
finished.num_bytes_to_mem,
&self.irq_trigger,
&self.metrics,
);
queue
.add_used(finished.desc_idx, finished.num_bytes_to_mem)
.unwrap_or_else(|err| {
error!(
"Failed to add available descriptor head {}: {}",

Check warning on line 492 in src/vmm/src/devices/virtio/block/virtio/device.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/devices/virtio/block/virtio/device.rs#L491-L492

Added lines #L491 - L492 were not covered by tests
finished.desc_idx, err
)
});
}
}
}
queue.advance_used_ring_idx();

if queue.prepare_kick() {
self.irq_trigger
.trigger_irq(IrqType::Vring)
.unwrap_or_else(|_| {
self.metrics.event_fails.inc();

Check warning on line 505 in src/vmm/src/devices/virtio/block/virtio/device.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/devices/virtio/block/virtio/device.rs#L505

Added line #L505 was not covered by tests
});
}
}

pub fn process_async_completion_event(&mut self) {
Expand Down
10 changes: 5 additions & 5 deletions src/vmm/src/devices/virtio/mmio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@
// eventfds, but nothing will happen other than supurious wakeups.
// . Do not reset config_generation and keep it monotonically increasing
for queue in self.locked_device().queues_mut() {
*queue = Queue::new(queue.get_max_size());
*queue = Queue::new(queue.max_size);

Check warning on line 160 in src/vmm/src/devices/virtio/mmio.rs

View check run for this annotation

Codecov / codecov/patch

src/vmm/src/devices/virtio/mmio.rs#L160

Added line #L160 was not covered by tests
}
}

Expand Down Expand Up @@ -253,7 +253,7 @@
}
features
}
0x34 => self.with_queue(0, |q| u32::from(q.get_max_size())),
0x34 => self.with_queue(0, |q| u32::from(q.max_size)),
0x44 => self.with_queue(0, |q| u32::from(q.ready)),
0x60 => {
// For vhost-user backed devices we need some additional
Expand Down Expand Up @@ -489,17 +489,17 @@
assert!(!d.are_queues_valid());

d.queue_select = 0;
assert_eq!(d.with_queue(0, Queue::get_max_size), 16);
assert_eq!(d.with_queue(0, |q| q.max_size), 16);
assert!(d.with_queue_mut(|q| q.size = 16));
assert_eq!(d.locked_device().queues()[d.queue_select as usize].size, 16);

d.queue_select = 1;
assert_eq!(d.with_queue(0, Queue::get_max_size), 32);
assert_eq!(d.with_queue(0, |q| q.max_size), 32);
assert!(d.with_queue_mut(|q| q.size = 16));
assert_eq!(d.locked_device().queues()[d.queue_select as usize].size, 16);

d.queue_select = 2;
assert_eq!(d.with_queue(0, Queue::get_max_size), 0);
assert_eq!(d.with_queue(0, |q| q.max_size), 0);
assert!(!d.with_queue_mut(|q| q.size = 16));

assert!(!d.are_queues_valid());
Expand Down
4 changes: 3 additions & 1 deletion src/vmm/src/devices/virtio/net/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ impl RxBuffers {
/// This will let the guest know that about all the `DescriptorChain` object that has been
/// used to receive a frame from the TAP.
fn finish_frame(&mut self, rx_queue: &mut Queue) {
rx_queue.advance_used_ring(self.used_descriptors);
rx_queue.advance_next_used(self.used_descriptors);
self.used_descriptors = 0;
self.used_bytes = 0;
}
Expand Down Expand Up @@ -396,6 +396,7 @@ impl Net {
NetQueue::Rx => &mut self.queues[RX_INDEX],
NetQueue::Tx => &mut self.queues[TX_INDEX],
};
queue.advance_used_ring_idx();

if queue.prepare_kick() {
self.irq_trigger
Expand Down Expand Up @@ -1065,6 +1066,7 @@ pub mod tests {
impl Net {
pub fn finish_frame(&mut self) {
self.rx_buffer.finish_frame(&mut self.queues[RX_INDEX]);
self.queues[RX_INDEX].advance_used_ring_idx();
}
}

Expand Down
Loading