Skip to content

Commit 940c504

Browse files
committed
fix: more compliant VIRTIO notifications
VIRTIO spec states: ``` After the device writes a descriptor index into the used ring: If the idx field in the used ring (which determined where that descriptor index was placed) was equal to used_event, the device MUST send a notification. ``` The current implementation does not follow this very precisely. It bumps used ring index when new descriptors are added to the used ring. But the check if the notification is needed is postponed to later processing stage. To be more VIRTIO spec compliant simply move the logic for updating the used ring index into the later processing stage as well, just before the check if the notification should be send. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 0b59747 commit 940c504

File tree

6 files changed

+35
-31
lines changed

6 files changed

+35
-31
lines changed

src/vmm/src/devices/virtio/balloon/device.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ impl Balloon {
362362
}
363363
}
364364
}
365+
queue.advance_used_ring_idx();
365366

366367
if needs_interrupt {
367368
self.signal_used_queue()?;
@@ -380,6 +381,7 @@ impl Balloon {
380381
queue.add_used(head.index, 0)?;
381382
needs_interrupt = true;
382383
}
384+
queue.advance_used_ring_idx();
383385

384386
if needs_interrupt {
385387
self.signal_used_queue()
@@ -453,6 +455,7 @@ impl Balloon {
453455
// and sending a used buffer notification
454456
if let Some(index) = self.stats_desc_index.take() {
455457
self.queues[STATS_INDEX].add_used(index, 0)?;
458+
self.queues[STATS_INDEX].advance_used_ring_idx();
456459
self.signal_used_queue()
457460
} else {
458461
error!("Failed to update balloon stats, missing descriptor.");
@@ -606,8 +609,7 @@ impl VirtioDevice for Balloon {
606609

607610
fn activate(&mut self, mem: GuestMemoryMmap) -> Result<(), ActivateError> {
608611
for q in self.queues.iter_mut() {
609-
q.initialize(&mem)
610-
.map_err(ActivateError::QueueError)?;
612+
q.initialize(&mem).map_err(ActivateError::QueueError)?;
611613
}
612614

613615
self.device_state = DeviceState::Activated(mem);

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ impl VirtioBlock {
436436
}
437437
}
438438
}
439+
queue.advance_used_ring_idx();
439440

440441
if queue.prepare_kick() {
441442
self.irq_trigger
@@ -497,6 +498,7 @@ impl VirtioBlock {
497498
}
498499
}
499500
}
501+
queue.advance_used_ring_idx();
500502

501503
if queue.prepare_kick() {
502504
self.irq_trigger

src/vmm/src/devices/virtio/net/device.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ impl RxBuffers {
207207
/// This will let the guest know that about all the `DescriptorChain` object that has been
208208
/// used to receive a frame from the TAP.
209209
fn finish_frame(&mut self, rx_queue: &mut Queue) {
210-
rx_queue.advance_used_ring(self.used_descriptors);
210+
rx_queue.advance_next_used(self.used_descriptors);
211211
self.used_descriptors = 0;
212212
self.used_bytes = 0;
213213
}
@@ -396,6 +396,7 @@ impl Net {
396396
NetQueue::Rx => &mut self.queues[RX_INDEX],
397397
NetQueue::Tx => &mut self.queues[TX_INDEX],
398398
};
399+
queue.advance_used_ring_idx();
399400

400401
if queue.prepare_kick() {
401402
self.irq_trigger
@@ -1000,8 +1001,7 @@ impl VirtioDevice for Net {
10001001

10011002
fn activate(&mut self, mem: GuestMemoryMmap) -> Result<(), ActivateError> {
10021003
for q in self.queues.iter_mut() {
1003-
q.initialize(&mem)
1004-
.map_err(ActivateError::QueueError)?;
1004+
q.initialize(&mem).map_err(ActivateError::QueueError)?;
10051005
}
10061006

10071007
let event_idx = self.has_feature(u64::from(VIRTIO_RING_F_EVENT_IDX));

src/vmm/src/devices/virtio/queue.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -653,20 +653,23 @@ impl Queue {
653653
}
654654

655655
/// Advance queue and used ring by `n` elements.
656-
pub fn advance_used_ring(&mut self, n: u16) {
656+
pub fn advance_next_used(&mut self, n: u16) {
657657
self.num_added += Wrapping(n);
658658
self.next_used += Wrapping(n);
659+
}
659660

661+
/// Set the used ring index to the current `next_used` value.
662+
/// Should be called once after number of `add_used` calls.
663+
pub fn advance_used_ring_idx(&mut self) {
660664
// This fence ensures all descriptor writes are visible before the index update is.
661665
fence(Ordering::Release);
662-
663666
self.used_ring_idx_set(self.next_used.0);
664667
}
665668

666669
/// Puts an available descriptor head into the used ring for use by the guest.
667670
pub fn add_used(&mut self, desc_index: u16, len: u32) -> Result<(), QueueError> {
668671
self.write_used_element(0, desc_index, len)?;
669-
self.advance_used_ring(1);
672+
self.advance_next_used(1);
670673
Ok(())
671674
}
672675

src/vmm/src/devices/virtio/rng/device.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ impl Entropy {
185185
}
186186
}
187187
}
188+
self.queues[RNG_QUEUE].advance_used_ring_idx();
188189

189190
if used_any {
190191
self.signal_used_queue().unwrap_or_else(|err| {
@@ -294,8 +295,7 @@ impl VirtioDevice for Entropy {
294295

295296
fn activate(&mut self, mem: GuestMemoryMmap) -> Result<(), ActivateError> {
296297
for q in self.queues.iter_mut() {
297-
q.initialize(&mem)
298-
.map_err(ActivateError::QueueError)?;
298+
q.initialize(&mem).map_err(ActivateError::QueueError)?;
299299
}
300300

301301
self.activate_event.write(1).map_err(|_| {

src/vmm/src/devices/virtio/vsock/device.rs

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,10 @@ where
149149
// This is safe since we checked in the event handler that the device is activated.
150150
let mem = self.device_state.mem().unwrap();
151151

152+
let queue = &mut self.queues[RXQ_INDEX];
152153
let mut have_used = false;
153154

154-
while let Some(head) = self.queues[RXQ_INDEX].pop()? {
155+
while let Some(head) = queue.pop()? {
155156
let index = head.index;
156157
let used_len = match self.rx_packet.parse(mem, head) {
157158
Ok(()) => {
@@ -174,7 +175,7 @@ where
174175
// We are using a consuming iterator over the virtio buffers, so, if we
175176
// can't fill in this buffer, we'll need to undo the
176177
// last iterator step.
177-
self.queues[RXQ_INDEX].undo_pop();
178+
queue.undo_pop();
178179
break;
179180
}
180181
}
@@ -185,12 +186,11 @@ where
185186
};
186187

187188
have_used = true;
188-
self.queues[RXQ_INDEX]
189-
.add_used(index, used_len)
190-
.unwrap_or_else(|err| {
191-
error!("Failed to add available descriptor {}: {}", index, err)
192-
});
189+
queue.add_used(index, used_len).unwrap_or_else(|err| {
190+
error!("Failed to add available descriptor {}: {}", index, err)
191+
});
193192
}
193+
queue.advance_used_ring_idx();
194194

195195
Ok(have_used)
196196
}
@@ -202,37 +202,35 @@ where
202202
// This is safe since we checked in the event handler that the device is activated.
203203
let mem = self.device_state.mem().unwrap();
204204

205+
let queue = &mut self.queues[TXQ_INDEX];
205206
let mut have_used = false;
206207

207-
while let Some(head) = self.queues[TXQ_INDEX].pop()? {
208+
while let Some(head) = queue.pop()? {
208209
let index = head.index;
209210
// let pkt = match VsockPacket::from_tx_virtq_head(mem, head) {
210211
match self.tx_packet.parse(mem, head) {
211212
Ok(()) => (),
212213
Err(err) => {
213214
error!("vsock: error reading TX packet: {:?}", err);
214215
have_used = true;
215-
self.queues[TXQ_INDEX]
216-
.add_used(index, 0)
217-
.unwrap_or_else(|err| {
218-
error!("Failed to add available descriptor {}: {}", index, err);
219-
});
216+
queue.add_used(index, 0).unwrap_or_else(|err| {
217+
error!("Failed to add available descriptor {}: {}", index, err);
218+
});
220219
continue;
221220
}
222221
};
223222

224223
if self.backend.send_pkt(&self.tx_packet).is_err() {
225-
self.queues[TXQ_INDEX].undo_pop();
224+
queue.undo_pop();
226225
break;
227226
}
228227

229228
have_used = true;
230-
self.queues[TXQ_INDEX]
231-
.add_used(index, 0)
232-
.unwrap_or_else(|err| {
233-
error!("Failed to add available descriptor {}: {}", index, err);
234-
});
229+
queue.add_used(index, 0).unwrap_or_else(|err| {
230+
error!("Failed to add available descriptor {}: {}", index, err);
231+
});
235232
}
233+
queue.advance_used_ring_idx();
236234

237235
Ok(have_used)
238236
}
@@ -331,8 +329,7 @@ where
331329

332330
fn activate(&mut self, mem: GuestMemoryMmap) -> Result<(), ActivateError> {
333331
for q in self.queues.iter_mut() {
334-
q.initialize(&mem)
335-
.map_err(ActivateError::QueueError)?;
332+
q.initialize(&mem).map_err(ActivateError::QueueError)?;
336333
}
337334

338335
if self.queues.len() != defs::VSOCK_NUM_QUEUES {

0 commit comments

Comments
 (0)