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:
Chirantan Ekbote 2021-07-16 16:44:13 +09:00 committed by Commit Bot
parent 52c97d41bd
commit c950eb92c5
4 changed files with 124 additions and 73 deletions

View file

@ -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());

View file

@ -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());

View file

@ -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);
}

View file

@ -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)?;