mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-24 12:34:31 +00:00
cros_async: Make file offsets optional
p{read,write} cannot be used on sockets even if the file offset is 0. Make the file offset optional and fall back to regular read/write when it is not set. BUG=none TEST=cargo test Change-Id: Iff938aabe613b6164782714cfac94743d64f551a Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3033233 Auto-Submit: Chirantan Ekbote <chirantan@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org> Reviewed-by: Noah Gold <nkgold@google.com> Reviewed-by: Woody Chow <woodychow@google.com> Commit-Queue: Chirantan Ekbote <chirantan@chromium.org>
This commit is contained in:
parent
52c97d41bd
commit
c950eb92c5
4 changed files with 124 additions and 73 deletions
|
@ -52,12 +52,16 @@ impl From<Error> for io::Error {
|
|||
#[async_trait(?Send)]
|
||||
pub trait ReadAsync {
|
||||
/// Reads from the iosource at `file_offset` and fill the given `vec`.
|
||||
async fn read_to_vec<'a>(&'a self, file_offset: u64, vec: Vec<u8>) -> Result<(usize, Vec<u8>)>;
|
||||
async fn read_to_vec<'a>(
|
||||
&'a self,
|
||||
file_offset: Option<u64>,
|
||||
vec: Vec<u8>,
|
||||
) -> Result<(usize, Vec<u8>)>;
|
||||
|
||||
/// Reads to the given `mem` at the given offsets from the file starting at `file_offset`.
|
||||
async fn read_to_mem<'a>(
|
||||
&'a self,
|
||||
file_offset: u64,
|
||||
file_offset: Option<u64>,
|
||||
mem: Arc<dyn BackingMemory + Send + Sync>,
|
||||
mem_offsets: &'a [MemRegion],
|
||||
) -> Result<usize>;
|
||||
|
@ -75,14 +79,14 @@ pub trait WriteAsync {
|
|||
/// Writes from the given `vec` to the file starting at `file_offset`.
|
||||
async fn write_from_vec<'a>(
|
||||
&'a self,
|
||||
file_offset: u64,
|
||||
file_offset: Option<u64>,
|
||||
vec: Vec<u8>,
|
||||
) -> Result<(usize, Vec<u8>)>;
|
||||
|
||||
/// Writes from the given `mem` from the given offsets to the file starting at `file_offset`.
|
||||
async fn write_from_mem<'a>(
|
||||
&'a self,
|
||||
file_offset: u64,
|
||||
file_offset: Option<u64>,
|
||||
mem: Arc<dyn BackingMemory + Send + Sync>,
|
||||
mem_offsets: &'a [MemRegion],
|
||||
) -> Result<usize>;
|
||||
|
@ -212,7 +216,7 @@ mod tests {
|
|||
// Start a uring operation and then await the result from an FdExecutor.
|
||||
async fn go(source: UringSource<File>) {
|
||||
let v = vec![0xa4u8; 16];
|
||||
let (len, vec) = source.read_to_vec(0, v).await.unwrap();
|
||||
let (len, vec) = source.read_to_vec(None, v).await.unwrap();
|
||||
assert_eq!(len, 16);
|
||||
assert!(vec.iter().all(|&b| b == 0));
|
||||
}
|
||||
|
@ -243,7 +247,7 @@ mod tests {
|
|||
// Start a poll operation and then await the result from a URingExecutor.
|
||||
async fn go(source: PollSource<File>) {
|
||||
let v = vec![0x2cu8; 16];
|
||||
let (len, vec) = source.read_to_vec(0, v).await.unwrap();
|
||||
let (len, vec) = source.read_to_vec(None, v).await.unwrap();
|
||||
assert_eq!(len, 16);
|
||||
assert!(vec.iter().all(|&b| b == 0));
|
||||
}
|
||||
|
@ -274,7 +278,7 @@ mod tests {
|
|||
async fn go<F: AsRawFd>(async_source: Box<dyn IoSourceExt<F>>) {
|
||||
let v = vec![0x55u8; 32];
|
||||
let v_ptr = v.as_ptr();
|
||||
let ret = async_source.read_to_vec(0, v).await.unwrap();
|
||||
let ret = async_source.read_to_vec(None, v).await.unwrap();
|
||||
assert_eq!(ret.0, 32);
|
||||
let ret_v = ret.1;
|
||||
assert_eq!(v_ptr, ret_v.as_ptr());
|
||||
|
@ -297,7 +301,7 @@ mod tests {
|
|||
async fn go<F: AsRawFd>(async_source: Box<dyn IoSourceExt<F>>) {
|
||||
let v = vec![0x55u8; 32];
|
||||
let v_ptr = v.as_ptr();
|
||||
let ret = async_source.write_from_vec(0, v).await.unwrap();
|
||||
let ret = async_source.write_from_vec(None, v).await.unwrap();
|
||||
assert_eq!(ret.0, 32);
|
||||
let ret_v = ret.1;
|
||||
assert_eq!(v_ptr, ret_v.as_ptr());
|
||||
|
@ -320,7 +324,7 @@ mod tests {
|
|||
let mem = Arc::new(VecIoWrapper::from(vec![0x55u8; 8192]));
|
||||
let ret = async_source
|
||||
.read_to_mem(
|
||||
0,
|
||||
None,
|
||||
Arc::<VecIoWrapper>::clone(&mem),
|
||||
&[
|
||||
MemRegion { offset: 0, len: 32 },
|
||||
|
@ -360,7 +364,7 @@ mod tests {
|
|||
let mem = Arc::new(VecIoWrapper::from(vec![0x55u8; 8192]));
|
||||
let ret = async_source
|
||||
.write_from_mem(
|
||||
0,
|
||||
None,
|
||||
Arc::<VecIoWrapper>::clone(&mem),
|
||||
&[MemRegion { offset: 0, len: 32 }],
|
||||
)
|
||||
|
@ -421,7 +425,7 @@ mod tests {
|
|||
async fn go<F: AsRawFd>(source: Box<dyn IoSourceExt<F>>) {
|
||||
let v = vec![0x55u8; 32];
|
||||
let v_ptr = v.as_ptr();
|
||||
let ret = source.write_from_vec(0, v).await.unwrap();
|
||||
let ret = source.write_from_vec(None, v).await.unwrap();
|
||||
assert_eq!(ret.0, 32);
|
||||
let ret_v = ret.1;
|
||||
assert_eq!(v_ptr, ret_v.as_ptr());
|
||||
|
|
|
@ -97,18 +97,28 @@ impl<F: AsRawFd> ReadAsync for PollSource<F> {
|
|||
/// Reads from the iosource at `file_offset` and fill the given `vec`.
|
||||
async fn read_to_vec<'a>(
|
||||
&'a self,
|
||||
file_offset: u64,
|
||||
file_offset: Option<u64>,
|
||||
mut vec: Vec<u8>,
|
||||
) -> AsyncResult<(usize, Vec<u8>)> {
|
||||
loop {
|
||||
// Safe because this will only modify `vec` and we check the return value.
|
||||
let res = unsafe {
|
||||
libc::pread64(
|
||||
self.as_raw_fd(),
|
||||
vec.as_mut_ptr() as *mut libc::c_void,
|
||||
vec.len(),
|
||||
file_offset as libc::off64_t,
|
||||
)
|
||||
let res = if let Some(offset) = file_offset {
|
||||
unsafe {
|
||||
libc::pread64(
|
||||
self.as_raw_fd(),
|
||||
vec.as_mut_ptr() as *mut libc::c_void,
|
||||
vec.len(),
|
||||
offset as libc::off64_t,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
libc::read(
|
||||
self.as_raw_fd(),
|
||||
vec.as_mut_ptr() as *mut libc::c_void,
|
||||
vec.len(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
if res >= 0 {
|
||||
|
@ -128,7 +138,7 @@ impl<F: AsRawFd> ReadAsync for PollSource<F> {
|
|||
/// Reads to the given `mem` at the given offsets from the file starting at `file_offset`.
|
||||
async fn read_to_mem<'a>(
|
||||
&'a self,
|
||||
file_offset: u64,
|
||||
file_offset: Option<u64>,
|
||||
mem: Arc<dyn BackingMemory + Send + Sync>,
|
||||
mem_offsets: &'a [MemRegion],
|
||||
) -> AsyncResult<usize> {
|
||||
|
@ -140,13 +150,23 @@ impl<F: AsRawFd> ReadAsync for PollSource<F> {
|
|||
loop {
|
||||
// Safe because we trust the kernel not to write path the length given and the length is
|
||||
// guaranteed to be valid from the pointer by io_slice_mut.
|
||||
let res = unsafe {
|
||||
libc::preadv64(
|
||||
self.as_raw_fd(),
|
||||
iovecs.as_mut_ptr() as *mut _,
|
||||
iovecs.len() as i32,
|
||||
file_offset as libc::off64_t,
|
||||
)
|
||||
let res = if let Some(offset) = file_offset {
|
||||
unsafe {
|
||||
libc::preadv64(
|
||||
self.as_raw_fd(),
|
||||
iovecs.as_mut_ptr() as *mut _,
|
||||
iovecs.len() as i32,
|
||||
offset as libc::off64_t,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
libc::readv(
|
||||
self.as_raw_fd(),
|
||||
iovecs.as_mut_ptr() as *mut _,
|
||||
iovecs.len() as i32,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
if res >= 0 {
|
||||
|
@ -202,18 +222,28 @@ impl<F: AsRawFd> WriteAsync for PollSource<F> {
|
|||
/// Writes from the given `vec` to the file starting at `file_offset`.
|
||||
async fn write_from_vec<'a>(
|
||||
&'a self,
|
||||
file_offset: u64,
|
||||
file_offset: Option<u64>,
|
||||
vec: Vec<u8>,
|
||||
) -> AsyncResult<(usize, Vec<u8>)> {
|
||||
loop {
|
||||
// Safe because this will not modify any memory and we check the return value.
|
||||
let res = unsafe {
|
||||
libc::pwrite64(
|
||||
self.as_raw_fd(),
|
||||
vec.as_ptr() as *const libc::c_void,
|
||||
vec.len(),
|
||||
file_offset as libc::off64_t,
|
||||
)
|
||||
let res = if let Some(offset) = file_offset {
|
||||
unsafe {
|
||||
libc::pwrite64(
|
||||
self.as_raw_fd(),
|
||||
vec.as_ptr() as *const libc::c_void,
|
||||
vec.len(),
|
||||
offset as libc::off64_t,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
libc::write(
|
||||
self.as_raw_fd(),
|
||||
vec.as_ptr() as *const libc::c_void,
|
||||
vec.len(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
if res >= 0 {
|
||||
|
@ -233,7 +263,7 @@ impl<F: AsRawFd> WriteAsync for PollSource<F> {
|
|||
/// Writes from the given `mem` from the given offsets to the file starting at `file_offset`.
|
||||
async fn write_from_mem<'a>(
|
||||
&'a self,
|
||||
file_offset: u64,
|
||||
file_offset: Option<u64>,
|
||||
mem: Arc<dyn BackingMemory + Send + Sync>,
|
||||
mem_offsets: &'a [MemRegion],
|
||||
) -> AsyncResult<usize> {
|
||||
|
@ -246,13 +276,23 @@ impl<F: AsRawFd> WriteAsync for PollSource<F> {
|
|||
loop {
|
||||
// Safe because we trust the kernel not to write path the length given and the length is
|
||||
// guaranteed to be valid from the pointer by io_slice_mut.
|
||||
let res = unsafe {
|
||||
libc::pwritev64(
|
||||
self.as_raw_fd(),
|
||||
iovecs.as_ptr() as *mut _,
|
||||
iovecs.len() as i32,
|
||||
file_offset as libc::off64_t,
|
||||
)
|
||||
let res = if let Some(offset) = file_offset {
|
||||
unsafe {
|
||||
libc::pwritev64(
|
||||
self.as_raw_fd(),
|
||||
iovecs.as_ptr() as *mut _,
|
||||
iovecs.len() as i32,
|
||||
offset as libc::off64_t,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
libc::writev(
|
||||
self.as_raw_fd(),
|
||||
iovecs.as_ptr() as *mut _,
|
||||
iovecs.len() as i32,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
if res >= 0 {
|
||||
|
@ -329,7 +369,7 @@ mod tests {
|
|||
let async_source = PollSource::new(f, ex).unwrap();
|
||||
let v = vec![0x55u8; 32];
|
||||
let v_ptr = v.as_ptr();
|
||||
let ret = async_source.read_to_vec(0, v).await.unwrap();
|
||||
let ret = async_source.read_to_vec(None, v).await.unwrap();
|
||||
assert_eq!(ret.0, 32);
|
||||
let ret_v = ret.1;
|
||||
assert_eq!(v_ptr, ret_v.as_ptr());
|
||||
|
@ -347,7 +387,7 @@ mod tests {
|
|||
let async_source = PollSource::new(f, ex).unwrap();
|
||||
let v = vec![0x55u8; 32];
|
||||
let v_ptr = v.as_ptr();
|
||||
let ret = async_source.write_from_vec(0, v).await.unwrap();
|
||||
let ret = async_source.write_from_vec(None, v).await.unwrap();
|
||||
assert_eq!(ret.0, 32);
|
||||
let ret_v = ret.1;
|
||||
assert_eq!(v_ptr, ret_v.as_ptr());
|
||||
|
|
|
@ -44,12 +44,12 @@ impl<F: AsRawFd> crate::ReadAsync for UringSource<F> {
|
|||
/// Reads from the iosource at `file_offset` and fill the given `vec`.
|
||||
async fn read_to_vec<'a>(
|
||||
&'a self,
|
||||
file_offset: u64,
|
||||
file_offset: Option<u64>,
|
||||
vec: Vec<u8>,
|
||||
) -> AsyncResult<(usize, Vec<u8>)> {
|
||||
let buf = Arc::new(VecIoWrapper::from(vec));
|
||||
let op = self.registered_source.start_read_to_mem(
|
||||
file_offset,
|
||||
file_offset.unwrap_or(0),
|
||||
buf.clone(),
|
||||
&[MemRegion {
|
||||
offset: 0,
|
||||
|
@ -107,13 +107,13 @@ impl<F: AsRawFd> crate::ReadAsync for UringSource<F> {
|
|||
/// Reads to the given `mem` at the given offsets from the file starting at `file_offset`.
|
||||
async fn read_to_mem<'a>(
|
||||
&'a self,
|
||||
file_offset: u64,
|
||||
file_offset: Option<u64>,
|
||||
mem: Arc<dyn BackingMemory + Send + Sync>,
|
||||
mem_offsets: &'a [MemRegion],
|
||||
) -> AsyncResult<usize> {
|
||||
let op = self
|
||||
.registered_source
|
||||
.start_read_to_mem(file_offset, mem, mem_offsets)?;
|
||||
let op =
|
||||
self.registered_source
|
||||
.start_read_to_mem(file_offset.unwrap_or(0), mem, mem_offsets)?;
|
||||
let len = op.await?;
|
||||
Ok(len as usize)
|
||||
}
|
||||
|
@ -124,12 +124,12 @@ impl<F: AsRawFd> crate::WriteAsync for UringSource<F> {
|
|||
/// Writes from the given `vec` to the file starting at `file_offset`.
|
||||
async fn write_from_vec<'a>(
|
||||
&'a self,
|
||||
file_offset: u64,
|
||||
file_offset: Option<u64>,
|
||||
vec: Vec<u8>,
|
||||
) -> AsyncResult<(usize, Vec<u8>)> {
|
||||
let buf = Arc::new(VecIoWrapper::from(vec));
|
||||
let op = self.registered_source.start_write_from_mem(
|
||||
file_offset,
|
||||
file_offset.unwrap_or(0),
|
||||
buf.clone(),
|
||||
&[MemRegion {
|
||||
offset: 0,
|
||||
|
@ -149,13 +149,15 @@ impl<F: AsRawFd> crate::WriteAsync for UringSource<F> {
|
|||
/// Writes from the given `mem` from the given offsets to the file starting at `file_offset`.
|
||||
async fn write_from_mem<'a>(
|
||||
&'a self,
|
||||
file_offset: u64,
|
||||
file_offset: Option<u64>,
|
||||
mem: Arc<dyn BackingMemory + Send + Sync>,
|
||||
mem_offsets: &'a [MemRegion],
|
||||
) -> AsyncResult<usize> {
|
||||
let op = self
|
||||
.registered_source
|
||||
.start_write_from_mem(file_offset, mem, mem_offsets)?;
|
||||
let op = self.registered_source.start_write_from_mem(
|
||||
file_offset.unwrap_or(0),
|
||||
mem,
|
||||
mem_offsets,
|
||||
)?;
|
||||
let len = op.await?;
|
||||
Ok(len as usize)
|
||||
}
|
||||
|
@ -243,7 +245,7 @@ mod tests {
|
|||
let buf: Arc<VecIoWrapper> = Arc::new(VecIoWrapper::from(vec![0x44; 8192]));
|
||||
|
||||
let fut = io_obj.read_to_mem(
|
||||
0,
|
||||
None,
|
||||
Arc::<VecIoWrapper>::clone(&buf),
|
||||
&[MemRegion {
|
||||
offset: 0,
|
||||
|
@ -269,7 +271,7 @@ mod tests {
|
|||
let source = UringSource::new(f, ex).unwrap();
|
||||
let v = vec![0x55u8; 32];
|
||||
let v_ptr = v.as_ptr();
|
||||
let ret = source.read_to_vec(0, v).await.unwrap();
|
||||
let ret = source.read_to_vec(None, v).await.unwrap();
|
||||
assert_eq!(ret.0, 32);
|
||||
let ret_v = ret.1;
|
||||
assert_eq!(v_ptr, ret_v.as_ptr());
|
||||
|
@ -291,8 +293,11 @@ mod tests {
|
|||
let source = UringSource::new(f, ex).unwrap();
|
||||
let v = vec![0x55u8; 32];
|
||||
let v2 = vec![0x55u8; 32];
|
||||
let (ret, ret2) =
|
||||
futures::future::join(source.read_to_vec(0, v), source.read_to_vec(32, v2)).await;
|
||||
let (ret, ret2) = futures::future::join(
|
||||
source.read_to_vec(None, v),
|
||||
source.read_to_vec(Some(32), v2),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert!(ret.unwrap().1.iter().all(|&b| b == 0));
|
||||
assert!(ret2.unwrap().1.iter().all(|&b| b == 0));
|
||||
|
@ -305,7 +310,7 @@ mod tests {
|
|||
async fn read_u64<T: AsRawFd>(source: &UringSource<T>) -> u64 {
|
||||
// Init a vec that translates to u64::max;
|
||||
let u64_mem = vec![0xffu8; std::mem::size_of::<u64>()];
|
||||
let (ret, u64_mem) = source.read_to_vec(0, u64_mem).await.unwrap();
|
||||
let (ret, u64_mem) = source.read_to_vec(None, u64_mem).await.unwrap();
|
||||
assert_eq!(ret as usize, std::mem::size_of::<u64>());
|
||||
let mut val = 0u64.to_ne_bytes();
|
||||
val.copy_from_slice(&u64_mem);
|
||||
|
@ -409,7 +414,7 @@ mod tests {
|
|||
let vw = Arc::new(VecIoWrapper::from(v));
|
||||
let ret = source
|
||||
.read_to_mem(
|
||||
0,
|
||||
None,
|
||||
Arc::<VecIoWrapper>::clone(&vw),
|
||||
&[MemRegion { offset: 0, len: 32 }],
|
||||
)
|
||||
|
@ -428,7 +433,7 @@ mod tests {
|
|||
let vw = Arc::new(VecIoWrapper::from(v));
|
||||
let ret = source
|
||||
.read_to_mem(
|
||||
0,
|
||||
None,
|
||||
Arc::<VecIoWrapper>::clone(&vw),
|
||||
&[MemRegion {
|
||||
offset: 32,
|
||||
|
@ -463,7 +468,7 @@ mod tests {
|
|||
let vw = Arc::new(VecIoWrapper::from(v));
|
||||
let ret = source
|
||||
.read_to_mem(
|
||||
0,
|
||||
None,
|
||||
Arc::<VecIoWrapper>::clone(&vw),
|
||||
&[MemRegion {
|
||||
offset: 32,
|
||||
|
@ -563,7 +568,7 @@ mod tests {
|
|||
let v = vec![0x55u8; 64];
|
||||
let vw = Arc::new(crate::mem::VecIoWrapper::from(v));
|
||||
let ret = source
|
||||
.write_from_mem(0, vw, &[MemRegion { offset: 0, len: 32 }])
|
||||
.write_from_mem(None, vw, &[MemRegion { offset: 0, len: 32 }])
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(32, ret);
|
||||
|
@ -589,7 +594,7 @@ mod tests {
|
|||
let source = UringSource::new(f, ex).unwrap();
|
||||
let v = vec![0x55u8; 32];
|
||||
let v_ptr = v.as_ptr();
|
||||
let (ret, ret_v) = source.write_from_vec(0, v).await.unwrap();
|
||||
let (ret, ret_v) = source.write_from_vec(None, v).await.unwrap();
|
||||
assert_eq!(32, ret);
|
||||
assert_eq!(v_ptr, ret_v.as_ptr());
|
||||
}
|
||||
|
@ -614,9 +619,11 @@ mod tests {
|
|||
let source = UringSource::new(f, ex).unwrap();
|
||||
let v = vec![0x55u8; 32];
|
||||
let v2 = vec![0x55u8; 32];
|
||||
let (r, r2) =
|
||||
futures::future::join(source.write_from_vec(0, v), source.write_from_vec(32, v2))
|
||||
.await;
|
||||
let (r, r2) = futures::future::join(
|
||||
source.write_from_vec(None, v),
|
||||
source.write_from_vec(Some(32), v2),
|
||||
)
|
||||
.await;
|
||||
assert_eq!(32, r.unwrap().0);
|
||||
assert_eq!(32, r2.unwrap().0);
|
||||
}
|
||||
|
|
|
@ -429,7 +429,7 @@ impl AsyncDisk for SingleFileDisk {
|
|||
mem_offsets: &'a [cros_async::MemRegion],
|
||||
) -> Result<usize> {
|
||||
self.inner
|
||||
.read_to_mem(file_offset, mem, mem_offsets)
|
||||
.read_to_mem(Some(file_offset), mem, mem_offsets)
|
||||
.await
|
||||
.map_err(Error::ReadToMem)
|
||||
}
|
||||
|
@ -441,7 +441,7 @@ impl AsyncDisk for SingleFileDisk {
|
|||
mem_offsets: &'a [cros_async::MemRegion],
|
||||
) -> Result<usize> {
|
||||
self.inner
|
||||
.write_from_mem(file_offset, mem, mem_offsets)
|
||||
.write_from_mem(Some(file_offset), mem, mem_offsets)
|
||||
.await
|
||||
.map_err(Error::WriteFromMem)
|
||||
}
|
||||
|
@ -480,7 +480,7 @@ impl AsyncDisk for SingleFileDisk {
|
|||
let buf = vec![0u8; write_size];
|
||||
nwritten += self
|
||||
.inner
|
||||
.write_from_vec(file_offset + nwritten as u64, buf)
|
||||
.write_from_vec(Some(file_offset + nwritten as u64), buf)
|
||||
.await
|
||||
.map(|(n, _)| n as u64)
|
||||
.map_err(Error::WriteFromVec)?;
|
||||
|
|
Loading…
Reference in a new issue