mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-11 04:26:38 +00:00
io_uring: Pin iovecs in memory
Pointers to the iovec structs are shared with the kernel for the duration of an I/O operation and so must be pinned in memory. Use Pin<Box<[iovec]>> instead of Vec<iovec> to express this and also to prevent any changes made in the future from accidentally doing something that causes the memory location of the iovecs to change. BUG=none TEST=unit tests Change-Id: I317f3a6f68d457b0b0a6c86494d506b0e978b5fb Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2387823 Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Chirantan Ekbote <chirantan@chromium.org> Reviewed-by: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
parent
b6c1eba580
commit
370ee0fb75
1 changed files with 29 additions and 16 deletions
|
@ -10,6 +10,7 @@ use std::collections::BTreeMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||||
|
use std::pin::Pin;
|
||||||
use std::ptr::null_mut;
|
use std::ptr::null_mut;
|
||||||
use std::sync::atomic::{AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
|
|
||||||
|
@ -94,7 +95,7 @@ pub struct URingContext {
|
||||||
submit_ring: SubmitQueueState,
|
submit_ring: SubmitQueueState,
|
||||||
submit_queue_entries: SubmitQueueEntries,
|
submit_queue_entries: SubmitQueueEntries,
|
||||||
complete_ring: CompleteQueueState,
|
complete_ring: CompleteQueueState,
|
||||||
io_vecs: Vec<libc::iovec>,
|
io_vecs: Pin<Box<[libc::iovec]>>,
|
||||||
in_flight: usize, // The number of pending operations.
|
in_flight: usize, // The number of pending operations.
|
||||||
added: usize, // The number of ops added since the last call to `io_uring_enter`.
|
added: usize, // The number of ops added since the last call to `io_uring_enter`.
|
||||||
num_sqes: usize, // The total number of sqes allocated in shared memory.
|
num_sqes: usize, // The total number of sqes allocated in shared memory.
|
||||||
|
@ -157,13 +158,16 @@ impl URingContext {
|
||||||
submit_ring,
|
submit_ring,
|
||||||
submit_queue_entries,
|
submit_queue_entries,
|
||||||
complete_ring,
|
complete_ring,
|
||||||
io_vecs: vec![
|
io_vecs: Pin::from(
|
||||||
libc::iovec {
|
vec![
|
||||||
iov_base: null_mut(),
|
libc::iovec {
|
||||||
iov_len: 0
|
iov_base: null_mut(),
|
||||||
};
|
iov_len: 0
|
||||||
num_sqe
|
};
|
||||||
],
|
num_sqe
|
||||||
|
]
|
||||||
|
.into_boxed_slice(),
|
||||||
|
),
|
||||||
added: 0,
|
added: 0,
|
||||||
num_sqes: ring_params.sq_entries as usize,
|
num_sqes: ring_params.sq_entries as usize,
|
||||||
in_flight: 0,
|
in_flight: 0,
|
||||||
|
@ -282,7 +286,12 @@ impl URingContext {
|
||||||
where
|
where
|
||||||
I: Iterator<Item = libc::iovec>,
|
I: Iterator<Item = libc::iovec>,
|
||||||
{
|
{
|
||||||
self.add_writev(iovecs.collect(), fd, offset, user_data)
|
self.add_writev(
|
||||||
|
Pin::from(iovecs.collect::<Vec<_>>().into_boxed_slice()),
|
||||||
|
fd,
|
||||||
|
offset,
|
||||||
|
user_data,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asynchronously writes to `fd` from the addresses given in `iovecs`.
|
/// Asynchronously writes to `fd` from the addresses given in `iovecs`.
|
||||||
|
@ -295,7 +304,7 @@ impl URingContext {
|
||||||
/// The iovecs reference must be kept alive until the op returns.
|
/// The iovecs reference must be kept alive until the op returns.
|
||||||
pub unsafe fn add_writev(
|
pub unsafe fn add_writev(
|
||||||
&mut self,
|
&mut self,
|
||||||
iovecs: Vec<libc::iovec>,
|
iovecs: Pin<Box<[libc::iovec]>>,
|
||||||
fd: RawFd,
|
fd: RawFd,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
user_data: UserData,
|
user_data: UserData,
|
||||||
|
@ -327,7 +336,12 @@ impl URingContext {
|
||||||
where
|
where
|
||||||
I: Iterator<Item = libc::iovec>,
|
I: Iterator<Item = libc::iovec>,
|
||||||
{
|
{
|
||||||
self.add_readv(iovecs.collect(), fd, offset, user_data)
|
self.add_readv(
|
||||||
|
Pin::from(iovecs.collect::<Vec<_>>().into_boxed_slice()),
|
||||||
|
fd,
|
||||||
|
offset,
|
||||||
|
user_data,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asynchronously reads from `fd` to the addresses given in `iovecs`.
|
/// Asynchronously reads from `fd` to the addresses given in `iovecs`.
|
||||||
|
@ -340,7 +354,7 @@ impl URingContext {
|
||||||
/// The iovecs reference must be kept alive until the op returns.
|
/// The iovecs reference must be kept alive until the op returns.
|
||||||
pub unsafe fn add_readv(
|
pub unsafe fn add_readv(
|
||||||
&mut self,
|
&mut self,
|
||||||
iovecs: Vec<libc::iovec>,
|
iovecs: Pin<Box<[libc::iovec]>>,
|
||||||
fd: RawFd,
|
fd: RawFd,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
user_data: UserData,
|
user_data: UserData,
|
||||||
|
@ -588,7 +602,7 @@ struct CompleteQueueState {
|
||||||
completed: usize,
|
completed: usize,
|
||||||
//For ops that pass in arrays of iovecs, they need to be valid for the duration of the
|
//For ops that pass in arrays of iovecs, they need to be valid for the duration of the
|
||||||
//operation because the kernel might read them at any time.
|
//operation because the kernel might read them at any time.
|
||||||
pending_op_addrs: BTreeMap<UserData, Vec<libc::iovec>>,
|
pending_op_addrs: BTreeMap<UserData, Pin<Box<[libc::iovec]>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompleteQueueState {
|
impl CompleteQueueState {
|
||||||
|
@ -610,7 +624,7 @@ impl CompleteQueueState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_op_data(&mut self, user_data: UserData, addrs: Vec<libc::iovec>) {
|
fn add_op_data(&mut self, user_data: UserData, addrs: Pin<Box<[libc::iovec]>>) {
|
||||||
self.pending_op_addrs.insert(user_data, addrs);
|
self.pending_op_addrs.insert(user_data, addrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,12 +770,11 @@ mod tests {
|
||||||
vec![IoSliceMut::new(buf)]
|
vec![IoSliceMut::new(buf)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|slice| std::mem::transmute::<IoSliceMut, libc::iovec>(slice))
|
.map(|slice| std::mem::transmute::<IoSliceMut, libc::iovec>(slice))
|
||||||
.collect::<Vec<libc::iovec>>()
|
|
||||||
};
|
};
|
||||||
let (user_data_ret, res) = unsafe {
|
let (user_data_ret, res) = unsafe {
|
||||||
// Safe because the `wait` call waits until the kernel is done with `buf`.
|
// Safe because the `wait` call waits until the kernel is done with `buf`.
|
||||||
uring
|
uring
|
||||||
.add_readv_iter(io_vecs.into_iter(), fd, offset, user_data)
|
.add_readv_iter(io_vecs, fd, offset, user_data)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
uring.wait().unwrap().next().unwrap()
|
uring.wait().unwrap().next().unwrap()
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue