Refactor all io APIs of vfs based on VmReader/VmWriter

This commit is contained in:
Shaowei Song
2024-08-22 07:52:20 +00:00
committed by Tate, Hongliang Tian
parent 837c7bebb6
commit dce796cdde
50 changed files with 566 additions and 376 deletions

View File

@ -19,12 +19,12 @@ impl Device for Null {
}
impl FileIo for Null {
fn read(&self, _buf: &mut [u8]) -> Result<usize> {
fn read(&self, _writer: &mut VmWriter) -> Result<usize> {
Ok(0)
}
fn write(&self, buf: &[u8]) -> Result<usize> {
Ok(buf.len())
fn write(&self, reader: &mut VmReader) -> Result<usize> {
Ok(reader.remain())
}
fn poll(&self, mask: IoEvents, poller: Option<&mut Poller>) -> IoEvents {

View File

@ -99,9 +99,10 @@ impl PtyMaster {
}
impl FileIo for PtyMaster {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
let read_len = writer.avail();
// TODO: deal with nonblocking read
if buf.is_empty() {
if read_len == 0 {
return Ok(0);
}
@ -124,17 +125,21 @@ impl FileIo for PtyMaster {
continue;
}
let read_len = input.len().min(buf.len());
input.pop_slice(&mut buf[..read_len]);
let read_len = input.len().min(read_len);
let mut buf = vec![0u8; read_len];
input.pop_slice(&mut buf);
writer.write_fallible(&mut buf.as_slice().into())?;
self.update_state(&input);
return Ok(read_len);
}
}
fn write(&self, buf: &[u8]) -> Result<usize> {
fn write(&self, reader: &mut VmReader) -> Result<usize> {
let buf = reader.collect()?;
let write_len = buf.len();
let mut input = self.input.lock();
for character in buf {
self.output.push_char(*character, |content| {
self.output.push_char(character, |content| {
for byte in content.as_bytes() {
input.push_overwrite(*byte);
}
@ -142,7 +147,7 @@ impl FileIo for PtyMaster {
}
self.update_state(&input);
Ok(buf.len())
Ok(write_len)
}
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
@ -328,23 +333,28 @@ impl Terminal for PtySlave {
}
impl FileIo for PtySlave {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
let mut buf = vec![0u8; writer.avail()];
self.job_control.wait_until_in_foreground()?;
self.master().output.read(buf)
let read_len = self.master().output.read(&mut buf)?;
writer.write_fallible(&mut buf.as_slice().into())?;
Ok(read_len)
}
fn write(&self, buf: &[u8]) -> Result<usize> {
fn write(&self, reader: &mut VmReader) -> Result<usize> {
let buf = reader.collect()?;
let write_len = buf.len();
let master = self.master();
for ch in buf {
// do we need to add '\r' here?
if *ch == b'\n' {
if ch == b'\n' {
master.slave_push_char(b'\r');
master.slave_push_char(b'\n');
} else {
master.slave_push_char(*ch);
master.slave_push_char(ch);
}
}
Ok(buf.len())
Ok(write_len)
}
fn poll(&self, mask: IoEvents, poller: Option<&mut Poller>) -> IoEvents {

View File

@ -34,12 +34,13 @@ impl Device for Random {
}
impl FileIo for Random {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
Self::getrandom(buf)
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
let mut buf = vec![0; writer.avail()];
Self::getrandom(buf.as_mut_slice())
}
fn write(&self, buf: &[u8]) -> Result<usize> {
Ok(buf.len())
fn write(&self, reader: &mut VmReader) -> Result<usize> {
Ok(reader.remain())
}
fn poll(&self, mask: IoEvents, poller: Option<&mut Poller>) -> IoEvents {

View File

@ -58,11 +58,11 @@ impl From<TdCallError> for Error {
}
impl FileIo for TdxGuest {
fn read(&self, _buf: &mut [u8]) -> Result<usize> {
fn read(&self, _writer: &mut VmWriter) -> Result<usize> {
return_errno_with_message!(Errno::EPERM, "Read operation not supported")
}
fn write(&self, _buf: &[u8]) -> Result<usize> {
fn write(&self, _reader: &mut VmReader) -> Result<usize> {
return_errno_with_message!(Errno::EPERM, "Write operation not supported")
}

View File

@ -41,11 +41,11 @@ impl Device for TtyDevice {
}
impl FileIo for TtyDevice {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
return_errno_with_message!(Errno::EINVAL, "cannot read tty device");
}
fn write(&self, buf: &[u8]) -> Result<usize> {
fn write(&self, reader: &mut VmReader) -> Result<usize> {
return_errno_with_message!(Errno::EINVAL, "cannot write tty device");
}

View File

@ -72,13 +72,17 @@ impl Tty {
}
impl FileIo for Tty {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
let mut buf = vec![0; writer.avail()];
self.job_control.wait_until_in_foreground()?;
self.ldisc.read(buf)
let read_len = self.ldisc.read(buf.as_mut_slice())?;
writer.write_fallible(&mut buf.as_slice().into())?;
Ok(read_len)
}
fn write(&self, buf: &[u8]) -> Result<usize> {
if let Ok(content) = alloc::str::from_utf8(buf) {
fn write(&self, reader: &mut VmReader) -> Result<usize> {
let buf = reader.collect()?;
if let Ok(content) = alloc::str::from_utf8(&buf) {
print!("{content}");
} else {
println!("Not utf-8 content: {:?}", buf);

View File

@ -34,12 +34,13 @@ impl Device for Urandom {
}
impl FileIo for Urandom {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
Self::getrandom(buf)
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
let mut buf = vec![0; writer.avail()];
Self::getrandom(buf.as_mut_slice())
}
fn write(&self, buf: &[u8]) -> Result<usize> {
Ok(buf.len())
fn write(&self, reader: &mut VmReader) -> Result<usize> {
Ok(reader.remain())
}
fn poll(&self, mask: IoEvents, poller: Option<&mut Poller>) -> IoEvents {

View File

@ -19,15 +19,17 @@ impl Device for Zero {
}
impl FileIo for Zero {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
for byte in buf.iter_mut() {
*byte = 0;
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
// TODO: Use more efficient way when need to read a bunch of zeros once.
let read_len = writer.avail();
for _ in 0..read_len {
writer.write_val(&0u8)?;
}
Ok(buf.len())
Ok(read_len)
}
fn write(&self, buf: &[u8]) -> Result<usize> {
Ok(buf.len())
fn write(&self, reader: &mut VmReader) -> Result<usize> {
Ok(reader.remain())
}
fn poll(&self, mask: IoEvents, poller: Option<&mut Poller>) -> IoEvents {

View File

@ -189,8 +189,8 @@ impl AsRef<Error> for Error {
}
impl From<ostd::Error> for Error {
fn from(frame_error: ostd::Error) -> Self {
match frame_error {
fn from(ostd_error: ostd::Error) -> Self {
match ostd_error {
ostd::Error::AccessDenied => Error::new(Errno::EFAULT),
ostd::Error::NoMemory => Error::new(Errno::ENOMEM),
ostd::Error::InvalidArgs => Error::new(Errno::EINVAL),
@ -203,6 +203,13 @@ impl From<ostd::Error> for Error {
}
}
impl From<(ostd::Error, usize)> for Error {
// Used in fallible memory read/write API
fn from(ostd_error: (ostd::Error, usize)) -> Self {
Error::from(ostd_error.0)
}
}
impl From<aster_block::bio::BioEnqueueError> for Error {
fn from(error: aster_block::bio::BioEnqueueError) -> Self {
match error {

View File

@ -132,19 +132,19 @@ impl Inode for Ptmx {
self.metadata.write().ctime = time;
}
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
Ok(0)
}
fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
Ok(0)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
Ok(0)
}
fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
Ok(0)
}
@ -178,11 +178,11 @@ impl Device for Inner {
}
impl FileIo for Inner {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
return_errno_with_message!(Errno::EINVAL, "cannot read ptmx");
}
fn write(&self, buf: &[u8]) -> Result<usize> {
fn write(&self, reader: &mut VmReader) -> Result<usize> {
return_errno_with_message!(Errno::EINVAL, "cannot write ptmx");
}

View File

@ -113,20 +113,20 @@ impl Inode for PtySlaveInode {
self.metadata.write().ctime = time;
}
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
self.device.read(buf)
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
self.device.read(writer)
}
fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
self.device.read(buf)
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
self.device.read(writer)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
self.device.write(buf)
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
self.device.write(reader)
}
fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
self.device.write(buf)
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
self.device.write(reader)
}
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {

View File

@ -329,11 +329,11 @@ impl Pollable for EpollFile {
// Implement the common methods required by FileHandle
impl FileLike for EpollFile {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
return_errno_with_message!(Errno::EINVAL, "epoll files do not support read");
}
fn write(&self, buf: &[u8]) -> Result<usize> {
fn write(&self, reader: &mut VmReader) -> Result<usize> {
return_errno_with_message!(Errno::EINVAL, "epoll files do not support write");
}

View File

@ -1221,7 +1221,7 @@ impl Inode for ExfatInode {
Some(self.inner.read().page_cache.pages().dup())
}
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
let inner = self.inner.upread();
if inner.inode_type.is_directory() {
return_errno!(Errno::EISDIR)
@ -1229,25 +1229,22 @@ impl Inode for ExfatInode {
let (read_off, read_len) = {
let file_size = inner.size;
let start = file_size.min(offset);
let end = file_size.min(offset + buf.len());
let end = file_size.min(offset + writer.avail());
(start, end - start)
};
inner
.page_cache
.pages()
.read_bytes(read_off, &mut buf[..read_len])?;
inner.page_cache.pages().read(read_off, writer)?;
inner.upgrade().update_atime()?;
Ok(read_len)
}
// The offset and the length of buffer must be multiples of the block size.
fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
let inner = self.inner.upread();
if inner.inode_type.is_directory() {
return_errno!(Errno::EISDIR)
}
if !is_block_aligned(offset) || !is_block_aligned(buf.len()) {
if !is_block_aligned(offset) || !is_block_aligned(writer.avail()) {
return_errno_with_message!(Errno::EINVAL, "not block-aligned");
}
@ -1256,7 +1253,9 @@ impl Inode for ExfatInode {
let (read_off, read_len) = {
let file_size = inner.size;
let start = file_size.min(offset).align_down(sector_size);
let end = file_size.min(offset + buf.len()).align_down(sector_size);
let end = file_size
.min(offset + writer.avail())
.align_down(sector_size);
(start, end - start)
};
@ -1278,8 +1277,7 @@ impl Inode for ExfatInode {
let physical_bid =
Bid::from_offset(cur_cluster.cluster_id() as usize * cluster_size + cur_offset);
inner.fs().block_device().read_block(physical_bid, &frame)?;
frame.read_bytes(0, &mut buf[buf_offset..buf_offset + BLOCK_SIZE])?;
frame.read(0, writer).unwrap();
buf_offset += BLOCK_SIZE;
cur_offset += BLOCK_SIZE;
@ -1293,7 +1291,8 @@ impl Inode for ExfatInode {
Ok(read_len)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
let write_len = reader.remain();
// We need to obtain the fs lock to resize the file.
let new_size = {
let mut inner = self.inner.write();
@ -1303,7 +1302,7 @@ impl Inode for ExfatInode {
let file_size = inner.size;
let file_allocated_size = inner.size_allocated;
let new_size = offset + buf.len();
let new_size = offset + write_len;
let fs = inner.fs();
let fs_guard = fs.lock();
if new_size > file_size {
@ -1317,7 +1316,7 @@ impl Inode for ExfatInode {
// Locks released here, so that file write can be parallized.
let inner = self.inner.upread();
inner.page_cache.pages().write_bytes(offset, buf)?;
inner.page_cache.pages().write(offset, reader)?;
// Update timestamps and size.
{
@ -1336,21 +1335,22 @@ impl Inode for ExfatInode {
inner.sync_all(&fs_guard)?;
}
Ok(buf.len())
Ok(write_len)
}
fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
let write_len = reader.remain();
let inner = self.inner.upread();
if inner.inode_type.is_directory() {
return_errno!(Errno::EISDIR)
}
if !is_block_aligned(offset) || !is_block_aligned(buf.len()) {
if !is_block_aligned(offset) || !is_block_aligned(write_len) {
return_errno_with_message!(Errno::EINVAL, "not block-aligned");
}
let file_size = inner.size;
let file_allocated_size = inner.size_allocated;
let end_offset = offset + buf.len();
let end_offset = offset + write_len;
let start = offset.min(file_size);
let end = end_offset.min(file_size);
@ -1370,7 +1370,6 @@ impl Inode for ExfatInode {
};
let inner = self.inner.upread();
let mut buf_offset = 0;
let start_pos = inner.start_chain.walk_to_cluster_at_offset(offset)?;
let cluster_size = inner.fs().cluster_size();
@ -1382,14 +1381,13 @@ impl Inode for ExfatInode {
.uninit(true)
.alloc_single()
.unwrap();
frame.write_bytes(0, &buf[buf_offset..buf_offset + BLOCK_SIZE])?;
frame.write(0, reader)?;
frame
};
let physical_bid =
Bid::from_offset(cur_cluster.cluster_id() as usize * cluster_size + cur_offset);
let fs = inner.fs();
fs.block_device().write_block(physical_bid, &frame)?;
buf_offset += BLOCK_SIZE;
cur_offset += BLOCK_SIZE;
if cur_offset >= cluster_size {
@ -1412,7 +1410,7 @@ impl Inode for ExfatInode {
inner.sync_metadata(&fs_guard)?;
}
Ok(buf_offset)
Ok(write_len)
}
fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>> {

View File

@ -276,7 +276,7 @@ mod test {
let root = fs.root_inode() as Arc<dyn Inode>;
let file_name = "a.txt";
let a_inode = create_file(root.clone(), file_name);
let _ = a_inode.write_at(8192, &[0, 1, 2, 3, 4]);
let _ = a_inode.write_bytes_at(8192, &[0, 1, 2, 3, 4]);
let unlink_result = root.unlink(file_name);
assert!(
@ -336,7 +336,7 @@ mod test {
let inode = create_file(root.clone(), file_name);
if fs.num_free_clusters() > file_id as u32 {
let _ = inode.write_at(file_id * cluster_size, &[0, 1, 2, 3, 4]);
let _ = inode.write_bytes_at(file_id * cluster_size, &[0, 1, 2, 3, 4]);
}
}
@ -464,7 +464,7 @@ mod test {
//Use a prime number to make each sector different.
*num = (i % 107) as u8;
}
let _ = a_inode.write_at(0, &buf);
let _ = a_inode.write_bytes_at(0, &buf);
let new_name = "HELLO.TXT";
let rename_result = root.rename(file_name, &root.clone(), new_name);
@ -482,7 +482,7 @@ mod test {
// test read after rename
let a_inode_new = root.lookup(new_name).unwrap();
let mut read = vec![0u8; BUF_SIZE];
let read_after_rename = a_inode_new.read_at(0, &mut read);
let read_after_rename = a_inode_new.read_bytes_at(0, &mut read);
assert!(
read_after_rename.is_ok() && read_after_rename.clone().unwrap() == BUF_SIZE,
"Fail to read after rename: {:?}",
@ -493,7 +493,7 @@ mod test {
// test write after rename
const NEW_BUF_SIZE: usize = 9 * PAGE_SIZE + 23;
let new_buf = vec![7u8; NEW_BUF_SIZE];
let new_write_after_rename = a_inode_new.write_at(0, &new_buf);
let new_write_after_rename = a_inode_new.write_bytes_at(0, &new_buf);
assert!(
new_write_after_rename.is_ok()
&& new_write_after_rename.clone().unwrap() == NEW_BUF_SIZE,
@ -502,7 +502,7 @@ mod test {
);
let mut new_read = vec![0u8; NEW_BUF_SIZE];
let _ = a_inode_new.read_at(0, &mut new_read);
let _ = a_inode_new.read_bytes_at(0, &mut new_read);
assert!(
new_buf.eq(&new_read),
"New read and new write mismatch after rename"
@ -630,7 +630,7 @@ mod test {
*num = (i % 107) as u8;
}
let write_result = file.write_direct_at(0, &buf);
let write_result = file.write_bytes_direct_at(0, &buf);
assert!(
write_result.is_ok(),
"Fs failed to write direct: {:?}",
@ -638,7 +638,7 @@ mod test {
);
let mut read = vec![0u8; BUF_SIZE];
let read_result = file.read_direct_at(0, &mut read);
let read_result = file.read_bytes_direct_at(0, &mut read);
assert!(
read_result.is_ok(),
"Fs failed to read direct: {:?}",
@ -662,7 +662,7 @@ mod test {
*num = (i % 107) as u8;
}
let write_result = file.write_at(0, &buf);
let write_result = file.write_bytes_at(0, &buf);
assert!(
write_result.is_ok(),
"Fs failed to write: {:?}",
@ -670,7 +670,7 @@ mod test {
);
let mut read = vec![0u8; BUF_SIZE];
let read_result = file.read_at(0, &mut read);
let read_result = file.read_bytes_at(0, &mut read);
assert!(
read_result.is_ok(),
"Fs failed to read: {:?}",
@ -706,19 +706,19 @@ mod test {
for i in 0..steps {
let start = i * write_len;
let end = BUF_SIZE.min(start + write_len);
a.write_at(start, &buf_a[start..end]).unwrap();
b.write_at(start, &buf_b[start..end]).unwrap();
a.write_bytes_at(start, &buf_a[start..end]).unwrap();
b.write_bytes_at(start, &buf_b[start..end]).unwrap();
}
let mut read = vec![0u8; BUF_SIZE];
a.read_at(0, &mut read).unwrap();
a.read_bytes_at(0, &mut read).unwrap();
assert!(
buf_a.eq(&read),
"File a mismatch. Data read result:{:?}",
read
);
b.read_at(0, &mut read).unwrap();
b.read_bytes_at(0, &mut read).unwrap();
assert!(
buf_b.eq(&read),
"File b mismatch. Data read result:{:?}",
@ -1032,7 +1032,7 @@ mod test {
buf.resize(size, 0);
rng.fill_bytes(&mut buf);
let write_result = inode.write_at(0, &buf);
let write_result = inode.write_bytes_at(0, &buf);
assert!(
write_result.is_ok(),
"Fail to write after resize expand from {:?}pgs to {:?}pgs: {:?}",
@ -1052,7 +1052,7 @@ mod test {
buf.resize(size, 0);
rng.fill_bytes(&mut buf);
let write_result = inode.write_at(0, &buf);
let write_result = inode.write_bytes_at(0, &buf);
assert!(
write_result.is_ok(),
"Fail to write after resize shrink from {:?}pgs to {:?}pgs: {:?}",

View File

@ -111,20 +111,20 @@ impl Inode for Ext2Inode {
Some(self.page_cache())
}
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
self.read_at(offset, buf)
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
self.read_at(offset, writer)
}
fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
self.read_direct_at(offset, buf)
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
self.read_direct_at(offset, writer)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
self.write_at(offset, buf)
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
self.write_at(offset, reader)
}
fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
self.write_direct_at(offset, buf)
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
self.write_direct_at(offset, reader)
}
fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>> {

View File

@ -620,14 +620,14 @@ impl Inode {
inner.device_id()
}
pub fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
pub fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
let bytes_read = {
let inner = self.inner.read();
if inner.file_type() != FileType::File {
return_errno!(Errno::EISDIR);
}
inner.read_at(offset, buf)?
inner.read_at(offset, writer)?
};
self.set_atime(now());
@ -636,17 +636,17 @@ impl Inode {
}
// The offset and the length of buffer must be multiples of the block size.
pub fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
pub fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
let bytes_read = {
let inner = self.inner.read();
if inner.file_type() != FileType::File {
return_errno!(Errno::EISDIR);
}
if !is_block_aligned(offset) || !is_block_aligned(buf.len()) {
if !is_block_aligned(offset) || !is_block_aligned(writer.avail()) {
return_errno_with_message!(Errno::EINVAL, "not block-aligned");
}
inner.read_direct_at(offset, buf)?
inner.read_direct_at(offset, writer)?
};
self.set_atime(now());
@ -654,7 +654,7 @@ impl Inode {
Ok(bytes_read)
}
pub fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
pub fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
let bytes_written = {
let inner = self.inner.upread();
if inner.file_type() != FileType::File {
@ -662,12 +662,12 @@ impl Inode {
}
let file_size = inner.file_size();
let new_size = offset + buf.len();
let new_size = offset + reader.remain();
if new_size > file_size {
let mut inner = inner.upgrade();
inner.extend_write_at(offset, buf)?
inner.extend_write_at(offset, reader)?
} else {
inner.write_at(offset, buf)?
inner.write_at(offset, reader)?
}
};
@ -679,18 +679,18 @@ impl Inode {
}
// The offset and the length of buffer must be multiples of the block size.
pub fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
pub fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
let bytes_written = {
let inner = self.inner.upread();
if inner.file_type() != FileType::File {
return_errno!(Errno::EISDIR);
}
if !is_block_aligned(offset) || !is_block_aligned(buf.len()) {
if !is_block_aligned(offset) || !is_block_aligned(reader.remain()) {
return_errno_with_message!(Errno::EINVAL, "not block aligned");
}
let mut inner = inner.upgrade();
inner.write_direct_at(offset, buf)?
inner.write_direct_at(offset, reader)?
};
let now = now();
@ -916,56 +916,58 @@ impl Inner {
Ok(())
}
pub fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
pub fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
let (offset, read_len) = {
let file_size = self.inode_impl.file_size();
let start = file_size.min(offset);
let end = file_size.min(offset + buf.len());
let end = file_size.min(offset + writer.avail());
(start, end - start)
};
self.page_cache
.pages()
.read_bytes(offset, &mut buf[..read_len])?;
self.page_cache.pages().read(offset, writer)?;
Ok(read_len)
}
pub fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
pub fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
let (offset, read_len) = {
let file_size = self.inode_impl.file_size();
let start = file_size.min(offset).align_down(BLOCK_SIZE);
let end = file_size.min(offset + buf.len()).align_down(BLOCK_SIZE);
let end = file_size
.min(offset + writer.avail())
.align_down(BLOCK_SIZE);
(start, end - start)
};
self.page_cache.discard_range(offset..offset + read_len);
let start_bid = Bid::from_offset(offset).to_raw() as Ext2Bid;
let buf_nblocks = buf.len() / BLOCK_SIZE;
let buf_nblocks = read_len / BLOCK_SIZE;
let segment = FrameAllocOptions::new(buf_nblocks)
.uninit(true)
.alloc_contiguous()?;
self.inode_impl.read_blocks(start_bid, &segment)?;
segment.read_bytes(0, buf)?;
segment.read(0, writer)?;
Ok(read_len)
}
pub fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
self.page_cache.pages().write_bytes(offset, buf)?;
Ok(buf.len())
pub fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
let write_len = reader.remain();
self.page_cache.pages().write(offset, reader)?;
Ok(write_len)
}
pub fn extend_write_at(&mut self, offset: usize, buf: &[u8]) -> Result<usize> {
let new_size = offset + buf.len();
pub fn extend_write_at(&mut self, offset: usize, reader: &mut VmReader) -> Result<usize> {
let write_len = reader.remain();
let new_size = offset + write_len;
self.page_cache.resize(new_size)?;
self.page_cache.pages().write_bytes(offset, buf)?;
self.page_cache.pages().write(offset, reader)?;
self.inode_impl.resize(new_size)?;
Ok(buf.len())
Ok(write_len)
}
pub fn write_direct_at(&mut self, offset: usize, buf: &[u8]) -> Result<usize> {
pub fn write_direct_at(&mut self, offset: usize, reader: &mut VmReader) -> Result<usize> {
let file_size = self.inode_impl.file_size();
let write_len = buf.len();
let write_len = reader.remain();
let end_offset = offset + write_len;
let start = offset.min(file_size);
@ -982,7 +984,7 @@ impl Inner {
let segment = FrameAllocOptions::new(buf_nblocks)
.uninit(true)
.alloc_contiguous()?;
segment.write_bytes(0, buf)?;
segment.write(0, reader)?;
segment
};

View File

@ -17,11 +17,11 @@ use crate::{
/// The basic operations defined on a file
pub trait FileLike: Pollable + Send + Sync + Any {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
return_errno_with_message!(Errno::EBADF, "the file is not valid for reading");
}
fn write(&self, buf: &[u8]) -> Result<usize> {
fn write(&self, reader: &mut VmReader) -> Result<usize> {
return_errno_with_message!(Errno::EBADF, "the file is not valid for writing");
}
@ -31,7 +31,7 @@ pub trait FileLike: Pollable + Send + Sync + Any {
/// Unlike [`read`], `read_at` will not change the file offset.
///
/// [`read`]: FileLike::read
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
return_errno_with_message!(Errno::ESPIPE, "read_at is not supported");
}
@ -42,7 +42,7 @@ pub trait FileLike: Pollable + Send + Sync + Any {
/// If the file is append-only, the `offset` will be ignored.
///
/// [`write`]: FileLike::write
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
return_errno_with_message!(Errno::ESPIPE, "write_at is not supported");
}
@ -131,4 +131,24 @@ impl dyn FileLike {
pub fn downcast_ref<T: FileLike>(&self) -> Option<&T> {
(self as &dyn Any).downcast_ref::<T>()
}
pub fn read_bytes(&self, buf: &mut [u8]) -> Result<usize> {
let mut writer = VmWriter::from(buf).to_fallible();
self.read(&mut writer)
}
pub fn write_bytes(&self, buf: &[u8]) -> Result<usize> {
let mut reader = VmReader::from(buf).to_fallible();
self.write(&mut reader)
}
pub fn read_bytes_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
let mut writer = VmWriter::from(buf).to_fallible();
self.read_at(offset, &mut writer)
}
pub fn write_bytes_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
let mut reader = VmReader::from(buf).to_fallible();
self.write_at(offset, &mut reader)
}
}

View File

@ -98,32 +98,32 @@ impl FileLike for InodeHandle<Rights> {
fn set_group(&self, gid: Gid) -> Result<()>;
fn seek(&self, seek_from: SeekFrom) -> Result<usize>;
fn read(&self, buf: &mut [u8]) -> Result<usize> {
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
if !self.1.contains(Rights::READ) {
return_errno_with_message!(Errno::EBADF, "file is not readable");
}
self.0.read(buf)
self.0.read(writer)
}
fn write(&self, buf: &[u8]) -> Result<usize> {
fn write(&self, reader: &mut VmReader) -> Result<usize> {
if !self.1.contains(Rights::WRITE) {
return_errno_with_message!(Errno::EBADF, "file is not writable");
}
self.0.write(buf)
self.0.write(reader)
}
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
if !self.1.contains(Rights::READ) {
return_errno_with_message!(Errno::EBADF, "file is not readable");
}
self.0.read_at(offset, buf)
self.0.read_at(offset, writer)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
if !self.1.contains(Rights::WRITE) {
return_errno_with_message!(Errno::EBADF, "file is not writable");
}
self.0.write_at(offset, buf)
self.0.write_at(offset, reader)
}
fn resize(&self, new_size: usize) -> Result<()> {

View File

@ -43,22 +43,22 @@ struct InodeHandle_ {
}
impl InodeHandle_ {
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
pub fn read(&self, writer: &mut VmWriter) -> Result<usize> {
if let Some(ref file_io) = self.file_io {
return file_io.read(buf);
return file_io.read(writer);
}
let mut offset = self.offset.lock();
let len = self.read_at(*offset, buf)?;
let len = self.read_at(*offset, writer)?;
*offset += len;
Ok(len)
}
pub fn write(&self, buf: &[u8]) -> Result<usize> {
pub fn write(&self, reader: &mut VmReader) -> Result<usize> {
if let Some(ref file_io) = self.file_io {
return file_io.write(buf);
return file_io.write(reader);
}
let mut offset = self.offset.lock();
@ -67,25 +67,25 @@ impl InodeHandle_ {
*offset = self.dentry.size();
}
let len = self.write_at(*offset, buf)?;
let len = self.write_at(*offset, reader)?;
*offset += len;
Ok(len)
}
pub fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
pub fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
if let Some(ref file_io) = self.file_io {
todo!("support read_at for FileIo");
}
if self.status_flags().contains(StatusFlags::O_DIRECT) {
self.dentry.inode().read_direct_at(offset, buf)
self.dentry.inode().read_direct_at(offset, writer)
} else {
self.dentry.inode().read_at(offset, buf)
self.dentry.inode().read_at(offset, writer)
}
}
pub fn write_at(&self, mut offset: usize, buf: &[u8]) -> Result<usize> {
pub fn write_at(&self, mut offset: usize, reader: &mut VmReader) -> Result<usize> {
if let Some(ref file_io) = self.file_io {
todo!("support write_at for FileIo");
}
@ -96,9 +96,9 @@ impl InodeHandle_ {
}
if self.status_flags().contains(StatusFlags::O_DIRECT) {
self.dentry.inode().write_direct_at(offset, buf)
self.dentry.inode().write_direct_at(offset, reader)
} else {
self.dentry.inode().write_at(offset, buf)
self.dentry.inode().write_at(offset, reader)
}
}
@ -108,9 +108,9 @@ impl InodeHandle_ {
}
let len = if self.status_flags().contains(StatusFlags::O_DIRECT) {
self.dentry.inode().read_direct_all(buf)?
self.dentry.inode().read_direct_to_end(buf)?
} else {
self.dentry.inode().read_all(buf)?
self.dentry.inode().read_to_end(buf)?
};
Ok(len)
}
@ -378,9 +378,9 @@ impl<R> Drop for InodeHandle<R> {
}
pub trait FileIo: Send + Sync + 'static {
fn read(&self, buf: &mut [u8]) -> Result<usize>;
fn read(&self, writer: &mut VmWriter) -> Result<usize>;
fn write(&self, buf: &[u8]) -> Result<usize>;
fn write(&self, reader: &mut VmReader) -> Result<usize>;
fn poll(&self, mask: IoEvents, poller: Option<&mut Poller>) -> IoEvents;

View File

@ -8,8 +8,8 @@ use crate::prelude::*;
impl<R: TRights> InodeHandle<TRightSet<R>> {
#[require(R > Read)]
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
self.0.read(buf)
pub fn read(&self, writer: &mut VmWriter) -> Result<usize> {
self.0.read(writer)
}
#[require(R > Read)]
@ -18,8 +18,8 @@ impl<R: TRights> InodeHandle<TRightSet<R>> {
}
#[require(R > Write)]
pub fn write(&self, buf: &[u8]) -> Result<usize> {
self.0.write(buf)
pub fn write(&self, reader: &mut VmReader) -> Result<usize> {
self.0.write(reader)
}
#[require(R > Read)]

View File

@ -41,12 +41,15 @@ impl Pollable for PipeReader {
}
impl FileLike for PipeReader {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
if self.status_flags().contains(StatusFlags::O_NONBLOCK) {
self.consumer.try_read(buf)
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
let mut buf = vec![0u8; writer.avail()];
let read_len = if self.status_flags().contains(StatusFlags::O_NONBLOCK) {
self.consumer.try_read(&mut buf)?
} else {
self.wait_events(IoEvents::IN, || self.consumer.try_read(buf))
}
self.wait_events(IoEvents::IN, || self.consumer.try_read(&mut buf))?
};
writer.write_fallible(&mut buf.as_slice().into())?;
Ok(read_len)
}
fn status_flags(&self) -> StatusFlags {
@ -123,11 +126,12 @@ impl Pollable for PipeWriter {
}
impl FileLike for PipeWriter {
fn write(&self, buf: &[u8]) -> Result<usize> {
fn write(&self, reader: &mut VmReader) -> Result<usize> {
let buf = reader.collect()?;
if self.status_flags().contains(StatusFlags::O_NONBLOCK) {
self.producer.try_write(buf)
self.producer.try_write(&buf)
} else {
self.wait_events(IoEvents::OUT, || self.producer.try_write(buf))
self.wait_events(IoEvents::OUT, || self.producer.try_write(&buf))
}
}
@ -275,11 +279,11 @@ mod test {
fn test_read_empty() {
test_blocking(
|writer| {
assert_eq!(writer.write(&[1]).unwrap(), 1);
assert_eq!(writer.write(&mut reader_from(&[1])).unwrap(), 1);
},
|reader| {
let mut buf = [0; 1];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.read(&mut writer_from(&mut buf)).unwrap(), 1);
assert_eq!(&buf, &[1]);
},
Ordering::ReadThenWrite,
@ -290,14 +294,14 @@ mod test {
fn test_write_full() {
test_blocking(
|writer| {
assert_eq!(writer.write(&[1, 2]).unwrap(), 1);
assert_eq!(writer.write(&[2]).unwrap(), 1);
assert_eq!(writer.write(&mut reader_from(&[1, 2])).unwrap(), 1);
assert_eq!(writer.write(&mut reader_from(&[2])).unwrap(), 1);
},
|reader| {
let mut buf = [0; 2];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.read(&mut writer_from(&mut buf)).unwrap(), 1);
assert_eq!(&buf[..1], &[1]);
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.read(&mut writer_from(&mut buf)).unwrap(), 1);
assert_eq!(&buf[..1], &[2]);
},
Ordering::WriteThenRead,
@ -310,7 +314,7 @@ mod test {
|writer| drop(writer),
|reader| {
let mut buf = [0; 1];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.read(&mut writer_from(&mut buf)).unwrap(), 0);
},
Ordering::ReadThenWrite,
);
@ -320,11 +324,22 @@ mod test {
fn test_write_closed() {
test_blocking(
|writer| {
assert_eq!(writer.write(&[1, 2]).unwrap(), 1);
assert_eq!(writer.write(&[2]).unwrap_err().error(), Errno::EPIPE);
assert_eq!(writer.write(&mut reader_from(&[1, 2])).unwrap(), 1);
assert_eq!(
writer.write(&mut reader_from(&[2])).unwrap_err().error(),
Errno::EPIPE
);
},
|reader| drop(reader),
Ordering::WriteThenRead,
);
}
fn reader_from(buf: &[u8]) -> VmReader {
VmReader::from(buf).to_fallible()
}
fn writer_from(buf: &mut [u8]) -> VmWriter {
VmWriter::from(buf).to_fallible()
}
}

View File

@ -62,24 +62,24 @@ impl<F: FileOps + 'static> Inode for ProcFile<F> {
InodeType::File
}
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
let data = self.inner.data()?;
let start = data.len().min(offset);
let end = data.len().min(offset + buf.len());
let end = data.len().min(offset + writer.avail());
let len = end - start;
buf[0..len].copy_from_slice(&data[start..end]);
writer.write_fallible(&mut (&data[start..end]).into())?;
Ok(len)
}
fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
self.read_at(offset, buf)
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
self.read_at(offset, writer)
}
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
fn write_at(&self, _offset: usize, _reader: &mut VmReader) -> Result<usize> {
Err(Error::new(Errno::EPERM))
}
fn write_direct_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
fn write_direct_at(&self, _offset: usize, _reader: &mut VmReader) -> Result<usize> {
Err(Error::new(Errno::EPERM))
}

View File

@ -59,19 +59,19 @@ impl<S: SymOps + 'static> Inode for ProcSym<S> {
InodeType::SymLink
}
fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize> {
fn read_at(&self, _offset: usize, _writer: &mut VmWriter) -> Result<usize> {
Err(Error::new(Errno::EPERM))
}
fn read_direct_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize> {
fn read_direct_at(&self, _offset: usize, _writer: &mut VmWriter) -> Result<usize> {
Err(Error::new(Errno::EPERM))
}
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
fn write_at(&self, _offset: usize, _reader: &mut VmReader) -> Result<usize> {
Err(Error::new(Errno::EPERM))
}
fn write_direct_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
fn write_direct_at(&self, _offset: usize, _reader: &mut VmReader) -> Result<usize> {
Err(Error::new(Errno::EPERM))
}

View File

@ -514,12 +514,12 @@ impl Inode for RamInode {
.map(|page_cache| page_cache.pages().dup())
}
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
let read_len = {
let self_inode = self.node.read();
if let Some(device) = self_inode.inner.as_device() {
device.read(buf)?
device.read(writer)?
} else {
let Some(page_cache) = self_inode.inner.as_file() else {
return_errno_with_message!(Errno::EISDIR, "read is not supported");
@ -527,12 +527,10 @@ impl Inode for RamInode {
let (offset, read_len) = {
let file_size = self_inode.metadata.size;
let start = file_size.min(offset);
let end = file_size.min(offset + buf.len());
let end = file_size.min(offset + writer.avail());
(start, end - start)
};
page_cache
.pages()
.read_bytes(offset, &mut buf[..read_len])?;
page_cache.pages().read(offset, writer)?;
read_len
}
};
@ -542,15 +540,16 @@ impl Inode for RamInode {
Ok(read_len)
}
fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
self.read_at(offset, buf)
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
self.read_at(offset, writer)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
let write_len = reader.remain();
let self_inode = self.node.upread();
if let Some(device) = self_inode.inner.as_device() {
let device_written_len = device.write(buf)?;
let device_written_len = device.write(reader)?;
let mut self_inode = self_inode.upgrade();
let now = now();
self_inode.set_mtime(now);
@ -562,12 +561,12 @@ impl Inode for RamInode {
return_errno_with_message!(Errno::EISDIR, "write is not supported");
};
let file_size = self_inode.metadata.size;
let new_size = offset + buf.len();
let new_size = offset + write_len;
let should_expand_size = new_size > file_size;
if should_expand_size {
page_cache.resize(new_size)?;
}
page_cache.pages().write_bytes(offset, buf)?;
page_cache.pages().write(offset, reader)?;
let mut self_inode = self_inode.upgrade();
let now = now();
@ -577,11 +576,11 @@ impl Inode for RamInode {
self_inode.resize(new_size);
}
Ok(buf.len())
Ok(write_len)
}
fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
self.write_at(offset, buf)
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
self.write_at(offset, reader)
}
fn size(&self) -> usize {

View File

@ -280,19 +280,19 @@ pub trait Inode: Any + Sync + Send {
None
}
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
Err(Error::new(Errno::EISDIR))
}
fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result<usize> {
Err(Error::new(Errno::EISDIR))
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
Err(Error::new(Errno::EISDIR))
}
fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
Err(Error::new(Errno::EISDIR))
}
@ -397,7 +397,7 @@ impl dyn Inode {
(self as &dyn Any).downcast_ref::<T>()
}
pub fn read_all(&self, buf: &mut Vec<u8>) -> Result<usize> {
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
if !self.type_().support_read() {
return_errno!(Errno::EISDIR);
}
@ -406,10 +406,12 @@ impl dyn Inode {
if buf.len() < file_size {
buf.resize(file_size, 0);
}
self.read_at(0, &mut buf[..file_size])
let mut writer = VmWriter::from(&mut buf[..file_size]).to_fallible();
self.read_at(0, &mut writer)
}
pub fn read_direct_all(&self, buf: &mut Vec<u8>) -> Result<usize> {
pub fn read_direct_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
if !self.type_().support_read() {
return_errno!(Errno::EISDIR);
}
@ -418,7 +420,9 @@ impl dyn Inode {
if buf.len() < file_size {
buf.resize(file_size, 0);
}
self.read_direct_at(0, &mut buf[..file_size])
let mut writer = VmWriter::from(&mut buf[..file_size]).to_fallible();
self.read_direct_at(0, &mut writer)
}
pub fn writer(&self, from_offset: usize) -> InodeWriter {
@ -427,6 +431,26 @@ impl dyn Inode {
offset: from_offset,
}
}
pub fn read_bytes_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
let mut writer = VmWriter::from(buf).to_fallible();
self.read_at(offset, &mut writer)
}
pub fn write_bytes_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
let mut reader = VmReader::from(buf).to_fallible();
self.write_at(offset, &mut reader)
}
pub fn read_bytes_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
let mut writer = VmWriter::from(buf).to_fallible();
self.read_direct_at(offset, &mut writer)
}
pub fn write_bytes_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
let mut reader = VmReader::from(buf).to_fallible();
self.write_direct_at(offset, &mut reader)
}
}
pub struct InodeWriter<'a> {
@ -437,9 +461,10 @@ pub struct InodeWriter<'a> {
impl<'a> Write for InodeWriter<'a> {
#[inline]
fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
let mut reader = VmReader::from(buf).to_fallible();
let write_len = self
.inner
.write_at(self.offset, buf)
.write_at(self.offset, &mut reader)
.map_err(|_| IoError::new(IoErrorKind::WriteZero, "failed to write buffer"))?;
self.offset += write_len;
Ok(write_len)

View File

@ -398,7 +398,7 @@ impl FileInMemory {
self.name, offset, len
);
let mut buf = vec![0; len];
let read_result = self.inode.read_at(offset, &mut buf);
let read_result = self.inode.read_bytes_at(offset, &mut buf);
assert!(
read_result.is_ok(),
"Fail to read file in range [{:?}, {:?}): {:?}",
@ -430,7 +430,7 @@ impl FileInMemory {
);
let mut buf = vec![0; write_len];
rng.fill_bytes(&mut buf);
let write_result = self.inode.write_at(write_start_offset, &buf);
let write_result = self.inode.write_bytes_at(write_start_offset, &buf);
assert!(
write_result.is_ok(),
"Fail to write file in range [{:?}, {:?}): {:?}",

View File

@ -185,13 +185,17 @@ impl Pollable for DatagramSocket {
}
impl FileLike for DatagramSocket {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
let mut buf = vec![0u8; writer.avail()];
// TODO: set correct flags
let flags = SendRecvFlags::empty();
self.recv(buf, flags).map(|(len, _)| len)
let read_len = self.recv(&mut buf, flags).map(|(len, _)| len)?;
writer.write_fallible(&mut buf.as_slice().into())?;
Ok(read_len)
}
fn write(&self, buf: &[u8]) -> Result<usize> {
fn write(&self, reader: &mut VmReader) -> Result<usize> {
let buf = reader.collect()?;
let remote = self.remote_endpoint().ok_or_else(|| {
Error::with_message(
Errno::EDESTADDRREQ,
@ -203,7 +207,7 @@ impl FileLike for DatagramSocket {
let flags = SendRecvFlags::empty();
// TODO: Block if send buffer is full
self.try_send(buf, &remote, flags)
self.try_send(&buf, &remote, flags)
}
fn as_socket(self: Arc<Self>) -> Option<Arc<dyn Socket>> {

View File

@ -344,16 +344,20 @@ impl Pollable for StreamSocket {
}
impl FileLike for StreamSocket {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
let mut buf = vec![0u8; writer.avail()];
// TODO: Set correct flags
let flags = SendRecvFlags::empty();
self.recv(buf, flags).map(|(len, _)| len)
let read_len = self.recv(&mut buf, flags).map(|(len, _)| len)?;
writer.write_fallible(&mut buf.as_slice().into())?;
Ok(read_len)
}
fn write(&self, buf: &[u8]) -> Result<usize> {
fn write(&self, reader: &mut VmReader) -> Result<usize> {
let buf = reader.collect()?;
// TODO: Set correct flags
let flags = SendRecvFlags::empty();
self.send(buf, flags)
self.send(&buf, flags)
}
fn status_flags(&self) -> StatusFlags {

View File

@ -128,16 +128,20 @@ impl FileLike for UnixStreamSocket {
Some(self)
}
fn read(&self, buf: &mut [u8]) -> Result<usize> {
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
let mut buf = vec![0u8; writer.avail()];
// TODO: Set correct flags
let flags = SendRecvFlags::empty();
self.recv(buf, flags)
let read_len = self.recv(&mut buf, flags)?;
writer.write_fallible(&mut buf.as_slice().into())?;
Ok(read_len)
}
fn write(&self, buf: &[u8]) -> Result<usize> {
fn write(&self, reader: &mut VmReader) -> Result<usize> {
let buf = reader.collect()?;
// TODO: Set correct flags
let flags = SendRecvFlags::empty();
self.send(buf, flags)
self.send(&buf, flags)
}
fn status_flags(&self) -> StatusFlags {

View File

@ -137,14 +137,20 @@ impl FileLike for VsockStreamSocket {
Some(self)
}
fn read(&self, buf: &mut [u8]) -> Result<usize> {
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
let mut buf = vec![0u8; writer.avail()];
// TODO: Set correct flags
self.recv(buf, SendRecvFlags::empty()).map(|(len, _)| len)
let read_len = self
.recv(&mut buf, SendRecvFlags::empty())
.map(|(len, _)| len)?;
writer.write_fallible(&mut buf.as_slice().into())?;
Ok(read_len)
}
fn write(&self, buf: &[u8]) -> Result<usize> {
fn write(&self, reader: &mut VmReader) -> Result<usize> {
let buf = reader.collect()?;
// TODO: Set correct flags
self.send(buf, SendRecvFlags::empty())
self.send(&buf, SendRecvFlags::empty())
}
fn status_flags(&self) -> StatusFlags {

View File

@ -97,7 +97,7 @@ fn lookup_and_parse_ldso(
let ldso_elf = {
let mut buf = Box::new([0u8; PAGE_SIZE]);
let inode = ldso_file.inode();
inode.read_at(0, &mut *buf)?;
inode.read_bytes_at(0, &mut *buf)?;
Elf::parse_elf(&*buf)?
};
Ok(Some((ldso_file, ldso_elf)))

View File

@ -36,7 +36,7 @@ pub fn load_program_to_vm(
let file_header = {
// read the first page of file header
let mut file_header_buffer = Box::new([0u8; PAGE_SIZE]);
inode.read_at(0, &mut *file_header_buffer)?;
inode.read_bytes_at(0, &mut *file_header_buffer)?;
file_header_buffer
};
if let Some(mut new_argv) = parse_shebang_line(&*file_header)? {

View File

@ -156,9 +156,9 @@ impl Pollable for EventFile {
}
impl FileLike for EventFile {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
let read_len = core::mem::size_of::<u64>();
if buf.len() < read_len {
if writer.avail() < read_len {
return_errno_with_message!(Errno::EINVAL, "buf len is less len u64 size");
}
@ -183,10 +183,10 @@ impl FileLike for EventFile {
// Copy value from counter, and set the new counter value
if self.flags.lock().contains(Flags::EFD_SEMAPHORE) {
buf[..read_len].copy_from_slice(1u64.as_bytes());
writer.write_fallible(&mut 1u64.as_bytes().into())?;
*counter -= 1;
} else {
buf[..read_len].copy_from_slice((*counter).as_bytes());
writer.write_fallible(&mut (*counter).as_bytes().into())?;
*counter = 0;
}
@ -197,13 +197,13 @@ impl FileLike for EventFile {
Ok(read_len)
}
fn write(&self, buf: &[u8]) -> Result<usize> {
fn write(&self, reader: &mut VmReader) -> Result<usize> {
let write_len = core::mem::size_of::<u64>();
if buf.len() < write_len {
if reader.remain() < write_len {
return_errno_with_message!(Errno::EINVAL, "buf len is less than the size of u64");
}
let supplied_value = u64::from_bytes(buf);
let supplied_value = reader.read_val::<u64>()?;
// Try to add counter val at first
if self.add_counter_val(supplied_value).is_ok() {

View File

@ -31,11 +31,12 @@ pub fn sys_pread64(
}
let read_len = {
let mut buffer = vec![0u8; user_buf_len];
let read_len = file.read_at(offset as usize, &mut buffer)?;
ctx.get_user_space()
.write_bytes(user_buf_ptr, &mut VmReader::from(buffer.as_slice()))?;
read_len
let mut writer = ctx
.process
.root_vmar()
.vm_space()
.writer(user_buf_ptr, user_buf_len)?;
file.read_at(offset as usize, &mut writer)?
};
Ok(SyscallReturn::Return(read_len as _))

View File

@ -112,7 +112,7 @@ fn do_sys_preadv(
// but the current implementation does not ensure atomicity.
// A suitable fix would be to add a `readv` method for the `FileLike` trait,
// allowing each subsystem to implement atomicity.
let read_len = file.read_at(cur_offset, &mut buffer)?;
let read_len = file.read_bytes_at(cur_offset, &mut buffer)?;
io_vec.write_exact_to_user(&buffer)?;
total_len += read_len;
cur_offset += read_len;
@ -160,7 +160,7 @@ fn do_sys_readv(
// but the current implementation does not ensure atomicity.
// A suitable fix would be to add a `readv` method for the `FileLike` trait,
// allowing each subsystem to implement atomicity.
let read_len = file.read(&mut buffer)?;
let read_len = file.read_bytes(&mut buffer)?;
io_vec.write_exact_to_user(&buffer)?;
total_len += read_len;
if read_len == 0 || read_len < buffer.len() {

View File

@ -29,9 +29,11 @@ pub fn sys_pwrite64(
return_errno_with_message!(Errno::EINVAL, "offset + user_buf_len overflow");
}
let mut buffer = vec![0u8; user_buf_len];
ctx.get_user_space()
.read_bytes(user_buf_ptr, &mut VmWriter::from(buffer.as_mut_slice()))?;
let write_len = file.write_at(offset as _, &buffer)?;
let mut reader = ctx
.process
.root_vmar()
.vm_space()
.reader(user_buf_ptr, user_buf_len)?;
let write_len = file.write_at(offset as _, &mut reader)?;
Ok(SyscallReturn::Return(write_len as _))
}

View File

@ -103,7 +103,7 @@ fn do_sys_pwritev(
// but the current implementation does not ensure atomicity.
// A suitable fix would be to add a `writev` method for the `FileLike` trait,
// allowing each subsystem to implement atomicity.
let write_len = file.write_at(cur_offset, &buffer)?;
let write_len = file.write_bytes_at(cur_offset, &buffer)?;
total_len += write_len;
cur_offset += write_len;
}
@ -144,7 +144,7 @@ fn do_sys_writev(
// but the current implementation does not ensure atomicity.
// A suitable fix would be to add a `writev` method for the `FileLike` trait,
// allowing each subsystem to implement atomicity.
let write_len = file.write(&buffer)?;
let write_len = file.write_bytes(&buffer)?;
total_len += write_len;
}
Ok(total_len)

View File

@ -1,7 +1,5 @@
// SPDX-License-Identifier: MPL-2.0
use core::cmp::min;
use super::SyscallReturn;
use crate::{fs::file_table::FileDesc, prelude::*};
@ -25,15 +23,14 @@ pub fn sys_read(
// the user specified an empty buffer, we should detect errors by checking
// the file discriptor. If no errors detected, return 0 successfully.
let read_len = if buf_len != 0 {
let mut read_buf = vec![0u8; buf_len];
let read_len = file.read(&mut read_buf)?;
ctx.get_user_space().write_bytes(
user_buf_addr,
&mut VmReader::from(&read_buf[..min(read_len, buf_len)]),
)?;
read_len
let mut writer = ctx
.process
.root_vmar()
.vm_space()
.writer(user_buf_addr, buf_len)?;
file.read(&mut writer)?
} else {
file.read(&mut [])?
file.read_bytes(&mut [])?
};
Ok(SyscallReturn::Return(read_len as _))

View File

@ -63,13 +63,13 @@ pub fn sys_sendfile(
// Read from `in_file`
let read_res = if let Some(offset) = offset.as_mut() {
let res = in_file.read_at(*offset, &mut buffer[..max_readlen]);
let res = in_file.read_bytes_at(*offset, &mut buffer[..max_readlen]);
if let Ok(len) = res.as_ref() {
*offset += *len;
}
res
} else {
in_file.read(&mut buffer[..max_readlen])
in_file.read_bytes(&mut buffer[..max_readlen])
};
let read_len = match read_res {
@ -89,7 +89,7 @@ pub fn sys_sendfile(
// Note: `sendfile` allows sending partial data,
// so short reads and short writes are all acceptable
let write_res = out_file.write(&buffer[..read_len]);
let write_res = out_file.write_bytes(&buffer[..read_len]);
match write_res {
Ok(len) => {

View File

@ -23,13 +23,14 @@ pub fn sys_write(
// the user specified an empty buffer, we should detect errors by checking
// the file discriptor. If no errors detected, return 0 successfully.
let write_len = if user_buf_len != 0 {
let mut buffer = vec![0u8; user_buf_len];
ctx.get_user_space()
.read_bytes(user_buf_ptr, &mut VmWriter::from(buffer.as_mut_slice()))?;
debug!("write content = {:?}", buffer);
file.write(&buffer)?
let mut reader = ctx
.process
.root_vmar()
.vm_space()
.reader(user_buf_ptr, user_buf_len)?;
file.write(&mut reader)?
} else {
file.write(&[])?
file.write_bytes(&[])?
};
Ok(SyscallReturn::Return(write_len as _))

View File

@ -27,7 +27,7 @@ impl Vmo<Rights> {
pub fn commit(&self, range: Range<usize>) -> Result<()> {
self.check_rights(Rights::WRITE)?;
self.0
.commit_and_operate(&range, |_| {}, CommitFlags::empty())?;
.commit_and_operate(&range, |_| Ok(()), CommitFlags::empty())?;
Ok(())
}
@ -116,15 +116,15 @@ impl Vmo<Rights> {
}
impl VmIo for Vmo<Rights> {
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> ostd::Result<()> {
fn read(&self, offset: usize, writer: &mut VmWriter) -> ostd::Result<()> {
self.check_rights(Rights::READ)?;
self.0.read_bytes(offset, buf)?;
self.0.read(offset, writer)?;
Ok(())
}
fn write_bytes(&self, offset: usize, buf: &[u8]) -> ostd::Result<()> {
fn write(&self, offset: usize, reader: &mut VmReader) -> ostd::Result<()> {
self.check_rights(Rights::WRITE)?;
self.0.write_bytes(offset, buf)?;
self.0.write(offset, reader)?;
Ok(())
}
// TODO: Support efficient `write_vals()`

View File

@ -11,7 +11,7 @@ use align_ext::AlignExt;
use aster_rights::Rights;
use ostd::{
collections::xarray::{CursorMut, XArray},
mm::{Frame, FrameAllocOptions, Infallible, VmReader, VmWriter},
mm::{Frame, FrameAllocOptions, VmReader, VmWriter},
};
use crate::prelude::*;
@ -269,7 +269,7 @@ impl Vmo_ {
commit_flags: CommitFlags,
) -> Result<()>
where
F: FnMut(Frame),
F: FnMut(Frame) -> Result<()>,
{
self.pages.with(|pages, size| {
if range.end > size {
@ -280,7 +280,7 @@ impl Vmo_ {
let mut cursor = pages.cursor_mut(page_idx_range.start as u64);
for page_idx in page_idx_range {
let committed_page = self.commit_with_cursor(&mut cursor, commit_flags)?;
operate(committed_page);
operate(committed_page)?;
cursor.next();
}
Ok(())
@ -300,30 +300,30 @@ impl Vmo_ {
}
/// Reads the specified amount of buffer content starting from the target offset in the VMO.
pub fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
let read_len = buf.len();
pub fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> {
let read_len = writer.avail().min(self.size().saturating_sub(offset));
let read_range = offset..(offset + read_len);
let mut read_offset = offset % PAGE_SIZE;
let mut buf_writer: VmWriter<Infallible> = buf.into();
let read = move |page: Frame| {
page.reader().skip(read_offset).read(&mut buf_writer);
let read = move |page: Frame| -> Result<()> {
page.reader().skip(read_offset).read_fallible(writer)?;
read_offset = 0;
Ok(())
};
self.commit_and_operate(&read_range, read, CommitFlags::empty())
}
/// Writes the specified amount of buffer content starting from the target offset in the VMO.
pub fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
let write_len = buf.len();
pub fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> {
let write_len = reader.remain();
let write_range = offset..(offset + write_len);
let mut write_offset = offset % PAGE_SIZE;
let mut buf_reader: VmReader<Infallible> = buf.into();
let mut write = move |page: Frame| {
page.writer().skip(write_offset).write(&mut buf_reader);
let mut write = move |page: Frame| -> Result<()> {
page.writer().skip(write_offset).write_fallible(reader)?;
write_offset = 0;
Ok(())
};
if write_range.len() < PAGE_SIZE {
@ -358,7 +358,8 @@ impl Vmo_ {
/// Clears the target range in current VMO.
pub fn clear(&self, range: Range<usize>) -> Result<()> {
let buffer = vec![0u8; range.end - range.start];
self.write_bytes(range.start, &buffer)?;
let mut reader = VmReader::from(buffer.as_slice()).to_fallible();
self.write(range.start, &mut reader)?;
Ok(())
}

View File

@ -28,7 +28,7 @@ impl<R: TRights> Vmo<TRightSet<R>> {
#[require(R > Write)]
pub fn commit(&self, range: Range<usize>) -> Result<()> {
self.0
.commit_and_operate(&range, |_| {}, CommitFlags::empty())?;
.commit_and_operate(&range, |_| Ok(()), CommitFlags::empty())?;
Ok(())
}
@ -111,15 +111,15 @@ impl<R: TRights> Vmo<TRightSet<R>> {
}
impl<R: TRights> VmIo for Vmo<TRightSet<R>> {
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> ostd::Result<()> {
fn read(&self, offset: usize, writer: &mut VmWriter) -> ostd::Result<()> {
self.check_rights(Rights::READ)?;
self.0.read_bytes(offset, buf)?;
self.0.read(offset, writer)?;
Ok(())
}
fn write_bytes(&self, offset: usize, buf: &[u8]) -> ostd::Result<()> {
fn write(&self, offset: usize, reader: &mut VmReader) -> ostd::Result<()> {
self.check_rights(Rights::WRITE)?;
self.0.write_bytes(offset, buf)?;
self.0.write(offset, reader)?;
Ok(())
}
}

View File

@ -1,6 +1,8 @@
// SPDX-License-Identifier: MPL-2.0
use ostd::mm::{Frame, FrameAllocOptions, Segment, VmIo};
use ostd::mm::{
FallibleVmRead, FallibleVmWrite, Frame, FrameAllocOptions, Segment, VmIo, VmReader, VmWriter,
};
use super::{
bio::{Bio, BioEnqueueError, BioSegment, BioStatus, BioType, BioWaiter, SubmittedBio},
@ -76,24 +78,25 @@ impl dyn BlockDevice {
impl VmIo for dyn BlockDevice {
/// Reads consecutive bytes of several sectors in size.
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> ostd::Result<()> {
if offset % SECTOR_SIZE != 0 || buf.len() % SECTOR_SIZE != 0 {
fn read(&self, offset: usize, writer: &mut VmWriter) -> ostd::Result<()> {
let read_len = writer.avail();
if offset % SECTOR_SIZE != 0 || read_len % SECTOR_SIZE != 0 {
return Err(ostd::Error::InvalidArgs);
}
if buf.is_empty() {
if read_len == 0 {
return Ok(());
}
let (bio, bio_segment) = {
let num_blocks = {
let first = Bid::from_offset(offset).to_raw();
let last = Bid::from_offset(offset + buf.len() - 1).to_raw();
let last = Bid::from_offset(offset + read_len - 1).to_raw();
last - first + 1
};
let segment = FrameAllocOptions::new(num_blocks as usize)
.uninit(true)
.alloc_contiguous()?;
let bio_segment = BioSegment::from_segment(segment, offset % BLOCK_SIZE, buf.len());
let bio_segment = BioSegment::from_segment(segment, offset % BLOCK_SIZE, read_len);
(
Bio::new(
@ -109,7 +112,10 @@ impl VmIo for dyn BlockDevice {
let status = bio.submit_and_wait(self)?;
match status {
BioStatus::Complete => {
let _ = bio_segment.reader().read(&mut buf.into());
let _ = bio_segment
.reader()
.read_fallible(writer)
.map_err(|(e, _)| e)?;
Ok(())
}
_ => Err(ostd::Error::IoError),
@ -117,28 +123,30 @@ impl VmIo for dyn BlockDevice {
}
/// Writes consecutive bytes of several sectors in size.
fn write_bytes(&self, offset: usize, buf: &[u8]) -> ostd::Result<()> {
if offset % SECTOR_SIZE != 0 || buf.len() % SECTOR_SIZE != 0 {
fn write(&self, offset: usize, reader: &mut VmReader) -> ostd::Result<()> {
let write_len = reader.remain();
if offset % SECTOR_SIZE != 0 || write_len % SECTOR_SIZE != 0 {
return Err(ostd::Error::InvalidArgs);
}
if buf.is_empty() {
if write_len == 0 {
return Ok(());
}
let bio = {
let num_blocks = {
let first = Bid::from_offset(offset).to_raw();
let last = Bid::from_offset(offset + buf.len() - 1).to_raw();
let last = Bid::from_offset(offset + write_len - 1).to_raw();
last - first + 1
};
let segment = FrameAllocOptions::new(num_blocks as usize)
.uninit(true)
.alloc_contiguous()?;
segment.write_bytes(offset % BLOCK_SIZE, buf)?;
segment.write(offset % BLOCK_SIZE, reader)?;
let len = segment
.writer()
.skip(offset % BLOCK_SIZE)
.write(&mut buf.into());
.write_fallible(reader)
.map_err(|(e, _)| e)?;
let bio_segment = BioSegment::from_segment(segment, offset % BLOCK_SIZE, len);
Bio::new(
BioType::Write,