Skip to content

Commit 34b75fd

Browse files
alyssaisstefano-garzarella
authored andcommitted
vhost_user: don't take ownership of Listener
The vhost-device devices all call VhostUserDaemon::serve in a loop, to handle reconnections. This is not ideal, because a new listener is created each loop iteration, which means that each time, the old socket is unlinked and a new one is created. This means that there's a potential race where a frontend attempts to connect to the backend before the new socket is created. A more robust way to achieve this would be to have the devices create their own listeners, and pass the same one to VhostUserDaemon::start on each loop iteration, instead of letting VhostUserDaemon::serve create it repeatedly. This was not previously possible though, because VhostUserDaemon::start consumed the listener, even though it didn't need to. Because it's now possible to call VhostUserDaemon::start multiple times with the same socket, I've removed the TODO about handling reconnection. Signed-off-by: Alyssa Ross <[email protected]>
1 parent e20a5a5 commit 34b75fd

File tree

6 files changed

+20
-19
lines changed

6 files changed

+20
-19
lines changed

vhost-user-backend/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Added
66
### Changed
77
- [[#308](https://github.com/rust-vmm/vhost/pull/308)] Replace Eventfd with EventNotifier/EventConsumer.
8+
- [[#321](https://github.com/rust-vmm/vhost/pull/321)] Don't take ownership of listener in `VhostUserDaemon::start`.
89

910
### Deprecated
1011
### Fixed

vhost-user-backend/src/lib.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,7 @@ where
162162
///
163163
/// *Note:* A convenience function [VhostUserDaemon::serve] exists that
164164
/// may be a better option than this for simple use-cases.
165-
// TODO: the current implementation has limitations that only one incoming connection will be
166-
// handled from the listener. Should it be enhanced to support reconnection?
167-
pub fn start(&mut self, listener: Listener) -> Result<()> {
165+
pub fn start(&mut self, listener: &mut Listener) -> Result<()> {
168166
let mut backend_listener = BackendListener::new(listener, self.handler.clone())
169167
.map_err(Error::CreateBackendListener)?;
170168
let backend_handler = self.accept(&mut backend_listener)?;
@@ -215,9 +213,9 @@ where
215213
/// *Note:* See [VhostUserDaemon::start] and [VhostUserDaemon::wait] if you
216214
/// need more flexibility.
217215
pub fn serve<P: AsRef<Path>>(&mut self, socket: P) -> Result<()> {
218-
let listener = Listener::new(socket, true).map_err(Error::CreateVhostUserListener)?;
216+
let mut listener = Listener::new(socket, true).map_err(Error::CreateVhostUserListener)?;
219217

220-
self.start(listener)?;
218+
self.start(&mut listener)?;
221219
let result = self.wait();
222220

223221
// Regardless of the result, we want to signal worker threads to exit
@@ -279,9 +277,9 @@ mod tests {
279277
drop(socket)
280278
});
281279

282-
let listener = Listener::new(&path, false).unwrap();
280+
let mut listener = Listener::new(&path, false).unwrap();
283281
barrier.wait();
284-
daemon.start(listener).unwrap();
282+
daemon.start(&mut listener).unwrap();
285283
barrier.wait();
286284
// Above process generates a `HandleRequest(PartialMessage)` error.
287285
daemon.wait().unwrap_err();

vhost-user-backend/tests/vhost-user-server.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,9 @@ fn vhost_user_server_with_fn<F: FnOnce(Arc<Mutex<MockVhostBackend>>, Arc<Barrier
260260
let path1 = path.clone();
261261
let thread = thread::spawn(move || cb(&path1, barrier2));
262262

263-
let listener = Listener::new(&path, false).unwrap();
263+
let mut listener = Listener::new(&path, false).unwrap();
264264
barrier.wait();
265-
daemon.start(listener).unwrap();
265+
daemon.start(&mut listener).unwrap();
266266
barrier.wait();
267267

268268
server_fn(backend, barrier);

vhost/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
`From<UnixListener>` for `vhost_user::Listener`.
88

99
### Changed
10+
- [[#321](https://github.com/rust-vmm/vhost/pull/321)] Don't take ownership of listener in `BackendListener`.
11+
1012
### Deprecated
1113
### Fixed
1214
- [[#304]](https://github.com/rust-vmm/vhost/pull/304) Fix building docs.

vhost/src/vhost_user/backend.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ use super::message::*;
1010
use super::{BackendReqHandler, Result, VhostUserBackendReqHandler};
1111

1212
/// Vhost-user backend side connection listener.
13-
pub struct BackendListener<S: VhostUserBackendReqHandler> {
14-
listener: Listener,
13+
pub struct BackendListener<'a, S: VhostUserBackendReqHandler> {
14+
listener: &'a mut Listener,
1515
backend: Option<Arc<S>>,
1616
}
1717

1818
/// Sets up a listener for incoming frontend connections, and handles construction
1919
/// of a Backend on success.
20-
impl<S: VhostUserBackendReqHandler> BackendListener<S> {
20+
impl<'a, S: VhostUserBackendReqHandler> BackendListener<'a, S> {
2121
/// Create a unix domain socket for incoming frontend connections.
22-
pub fn new(listener: Listener, backend: Arc<S>) -> Result<Self> {
22+
pub fn new(listener: &'a mut Listener, backend: Arc<S>) -> Result<Self> {
2323
Ok(BackendListener {
2424
listener,
2525
backend: Some(backend),
@@ -55,9 +55,9 @@ mod tests {
5555
#[test]
5656
fn test_backend_listener_set_nonblocking() {
5757
let backend = Arc::new(Mutex::new(DummyBackendReqHandler::new()));
58-
let listener =
58+
let mut listener =
5959
Listener::new("/tmp/vhost_user_lib_unit_test_backend_nonblocking", true).unwrap();
60-
let backend_listener = BackendListener::new(listener, backend).unwrap();
60+
let backend_listener = BackendListener::new(&mut listener, backend).unwrap();
6161

6262
backend_listener.set_nonblocking(true).unwrap();
6363
backend_listener.set_nonblocking(false).unwrap();
@@ -73,8 +73,8 @@ mod tests {
7373

7474
let path = "/tmp/vhost_user_lib_unit_test_backend_accept";
7575
let backend = Arc::new(Mutex::new(DummyBackendReqHandler::new()));
76-
let listener = Listener::new(path, true).unwrap();
77-
let mut backend_listener = BackendListener::new(listener, backend).unwrap();
76+
let mut listener = Listener::new(path, true).unwrap();
77+
let mut backend_listener = BackendListener::new(&mut listener, backend).unwrap();
7878

7979
backend_listener.set_nonblocking(true).unwrap();
8080
assert!(backend_listener.accept().unwrap().is_none());

vhost/src/vhost_user/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,8 @@ mod tests {
293293
P: AsRef<Path>,
294294
S: VhostUserBackendReqHandler,
295295
{
296-
let listener = Listener::new(&path, true).unwrap();
297-
let mut backend_listener = BackendListener::new(listener, backend).unwrap();
296+
let mut listener = Listener::new(&path, true).unwrap();
297+
let mut backend_listener = BackendListener::new(&mut listener, backend).unwrap();
298298
let frontend = Frontend::connect(&path, 1).unwrap();
299299
(frontend, backend_listener.accept().unwrap().unwrap())
300300
}

0 commit comments

Comments
 (0)