io_uring: handle EINTR

Handle EINTR returned from io_uring_enter. This fixes an issue where
trying to strace an io_uring enabled device would cause the device to
exit.

BUG=None
TEST=attach strace to io_uring enabled crosvm

Change-Id: I2e808a51c3274b98f1caa18dbedd3164f2bd6aef
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3881686
Commit-Queue: David Stevens <stevensd@chromium.org>
Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org>
Reviewed-by: Takaya Saeki <takayas@chromium.org>
This commit is contained in:
David Stevens 2022-09-08 14:51:44 +09:00 committed by crosvm LUCI
parent c59c68751c
commit b2b11c32e5

View file

@ -636,18 +636,28 @@ impl URingContext {
self.in_flight.fetch_add(added, Ordering::Release);
}
Err(e) => {
self.submit_ring.lock().fail_submit(added);
// An EBUSY return means that some completed events must be processed before
// submitting more, so wait for some to finish without pushing the new sqes in
// that case.
// An EINTR means we successfully submitted the events but were interrupted while
// waiting, so just wait again.
// Any other error should be propagated up.
if wait_nr == 0 || e != libc::EBUSY {
if e != libc::EINTR {
self.submit_ring.lock().fail_submit(added);
}
if wait_nr == 0 || (e != libc::EBUSY && e != libc::EINTR) {
return Err(Error::RingEnter(e));
}
// An ebusy return means that some completed events must be processed before
// submitting more, wait for some to finish without pushing the new sqes in
// that case.
unsafe {
io_uring_enter(self.ring_file.as_raw_fd(), 0, wait_nr, flags)
.map_err(Error::RingEnter)?;
loop {
// Safe because the only memory modified is in the completion queue.
let res =
unsafe { io_uring_enter(self.ring_file.as_raw_fd(), 0, wait_nr, flags) };
if res != Err(libc::EINTR) {
return res.map_err(Error::RingEnter);
}
}
}
}