devices: virtio_net: handle errors in tapfd poll adding/removal

Add error handling for adding/removing the tapfd to epoll.

We only remove the tap fd from the poll context if the tap is
readable, i.e. it would busy loop, so don't assume it's removed
from the poll context when there's a deferred rx frame.

BUG=chromium:1010742
TEST=arcvm network works

Change-Id: I84aab2dbe7ea31d724f04d3b3fb0a6916f232300
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1842399
Tested-by: kokoro <noreply+kokoro@google.com>
Tested-by: Stephen Barber <smbarber@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
Commit-Queue: Stephen Barber <smbarber@chromium.org>
This commit is contained in:
Stephen Barber 2019-10-04 15:20:05 -07:00 committed by Commit Bot
parent 04e9c03f03
commit 7595d80248

View file

@ -10,7 +10,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::thread; use std::thread;
use libc::EAGAIN; use libc::{EAGAIN, EEXIST};
use net_sys; use net_sys;
use net_util::{Error as TapError, MacAddress, TapT}; use net_util::{Error as TapError, MacAddress, TapT};
use sys_util::guest_memory::Error as MemoryError; use sys_util::guest_memory::Error as MemoryError;
@ -237,9 +237,12 @@ where
if self.rx_single_frame() { if self.rx_single_frame() {
self.deferred_rx = false; self.deferred_rx = false;
} else { } else {
// The guest has not yet made any buffers available. Remove the // There is an outstanding deferred frame and the guest has not yet
// tapfd from the poll context until more are made available. // made any buffers available. Remove the tapfd from the poll
poll_ctx.delete(&self.tap).map_err(NetError::PollDeleteTap); // context until more are made available.
poll_ctx
.delete(&self.tap)
.map_err(NetError::PollDeleteTap)?;
continue; continue;
} }
} }
@ -253,10 +256,14 @@ where
// There should be a buffer available now to receive the frame into. // There should be a buffer available now to receive the frame into.
if self.deferred_rx && self.rx_single_frame() { if self.deferred_rx && self.rx_single_frame() {
// The guest has made buffers available, so add the tap back to the // The guest has made buffers available, so add the tap back to the
// poll context. // poll context in case it was removed.
poll_ctx match poll_ctx.add(&self.tap, Token::RxTap) {
.add(&self.tap, Token::RxTap) Ok(_) => {}
.map_err(NetError::PollAddTap); Err(e) if e.errno() == EEXIST => {}
Err(e) => {
return Err(NetError::PollAddTap(e));
}
}
self.deferred_rx = false; self.deferred_rx = false;
} }
} }