diff --git a/kernel/aster-nix/src/device/null.rs b/kernel/aster-nix/src/device/null.rs index e33c6cdf4..b5e9d2571 100644 --- a/kernel/aster-nix/src/device/null.rs +++ b/kernel/aster-nix/src/device/null.rs @@ -19,12 +19,12 @@ impl Device for Null { } impl FileIo for Null { - fn read(&self, _buf: &mut [u8]) -> Result { + fn read(&self, _writer: &mut VmWriter) -> Result { Ok(0) } - fn write(&self, buf: &[u8]) -> Result { - Ok(buf.len()) + fn write(&self, reader: &mut VmReader) -> Result { + Ok(reader.remain()) } fn poll(&self, mask: IoEvents, poller: Option<&mut Poller>) -> IoEvents { diff --git a/kernel/aster-nix/src/device/pty/pty.rs b/kernel/aster-nix/src/device/pty/pty.rs index 18fb0896d..0ceb05423 100644 --- a/kernel/aster-nix/src/device/pty/pty.rs +++ b/kernel/aster-nix/src/device/pty/pty.rs @@ -99,9 +99,10 @@ impl PtyMaster { } impl FileIo for PtyMaster { - fn read(&self, buf: &mut [u8]) -> Result { + fn read(&self, writer: &mut VmWriter) -> Result { + 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 { + fn write(&self, reader: &mut VmReader) -> Result { + 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 { @@ -328,23 +333,28 @@ impl Terminal for PtySlave { } impl FileIo for PtySlave { - fn read(&self, buf: &mut [u8]) -> Result { + fn read(&self, writer: &mut VmWriter) -> Result { + 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 { + fn write(&self, reader: &mut VmReader) -> Result { + 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 { diff --git a/kernel/aster-nix/src/device/random.rs b/kernel/aster-nix/src/device/random.rs index c9bfa7018..672cd5022 100644 --- a/kernel/aster-nix/src/device/random.rs +++ b/kernel/aster-nix/src/device/random.rs @@ -34,12 +34,13 @@ impl Device for Random { } impl FileIo for Random { - fn read(&self, buf: &mut [u8]) -> Result { - Self::getrandom(buf) + fn read(&self, writer: &mut VmWriter) -> Result { + let mut buf = vec![0; writer.avail()]; + Self::getrandom(buf.as_mut_slice()) } - fn write(&self, buf: &[u8]) -> Result { - Ok(buf.len()) + fn write(&self, reader: &mut VmReader) -> Result { + Ok(reader.remain()) } fn poll(&self, mask: IoEvents, poller: Option<&mut Poller>) -> IoEvents { diff --git a/kernel/aster-nix/src/device/tdxguest/mod.rs b/kernel/aster-nix/src/device/tdxguest/mod.rs index 31929dca4..cbb711c8e 100644 --- a/kernel/aster-nix/src/device/tdxguest/mod.rs +++ b/kernel/aster-nix/src/device/tdxguest/mod.rs @@ -58,11 +58,11 @@ impl From for Error { } impl FileIo for TdxGuest { - fn read(&self, _buf: &mut [u8]) -> Result { + fn read(&self, _writer: &mut VmWriter) -> Result { return_errno_with_message!(Errno::EPERM, "Read operation not supported") } - fn write(&self, _buf: &[u8]) -> Result { + fn write(&self, _reader: &mut VmReader) -> Result { return_errno_with_message!(Errno::EPERM, "Write operation not supported") } diff --git a/kernel/aster-nix/src/device/tty/device.rs b/kernel/aster-nix/src/device/tty/device.rs index 5355a024c..106ad864b 100644 --- a/kernel/aster-nix/src/device/tty/device.rs +++ b/kernel/aster-nix/src/device/tty/device.rs @@ -41,11 +41,11 @@ impl Device for TtyDevice { } impl FileIo for TtyDevice { - fn read(&self, buf: &mut [u8]) -> Result { + fn read(&self, writer: &mut VmWriter) -> Result { return_errno_with_message!(Errno::EINVAL, "cannot read tty device"); } - fn write(&self, buf: &[u8]) -> Result { + fn write(&self, reader: &mut VmReader) -> Result { return_errno_with_message!(Errno::EINVAL, "cannot write tty device"); } diff --git a/kernel/aster-nix/src/device/tty/mod.rs b/kernel/aster-nix/src/device/tty/mod.rs index 89da51133..d62771e68 100644 --- a/kernel/aster-nix/src/device/tty/mod.rs +++ b/kernel/aster-nix/src/device/tty/mod.rs @@ -72,13 +72,17 @@ impl Tty { } impl FileIo for Tty { - fn read(&self, buf: &mut [u8]) -> Result { + fn read(&self, writer: &mut VmWriter) -> Result { + 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 { - if let Ok(content) = alloc::str::from_utf8(buf) { + fn write(&self, reader: &mut VmReader) -> Result { + let buf = reader.collect()?; + if let Ok(content) = alloc::str::from_utf8(&buf) { print!("{content}"); } else { println!("Not utf-8 content: {:?}", buf); diff --git a/kernel/aster-nix/src/device/urandom.rs b/kernel/aster-nix/src/device/urandom.rs index 701701de1..188e2ca79 100644 --- a/kernel/aster-nix/src/device/urandom.rs +++ b/kernel/aster-nix/src/device/urandom.rs @@ -34,12 +34,13 @@ impl Device for Urandom { } impl FileIo for Urandom { - fn read(&self, buf: &mut [u8]) -> Result { - Self::getrandom(buf) + fn read(&self, writer: &mut VmWriter) -> Result { + let mut buf = vec![0; writer.avail()]; + Self::getrandom(buf.as_mut_slice()) } - fn write(&self, buf: &[u8]) -> Result { - Ok(buf.len()) + fn write(&self, reader: &mut VmReader) -> Result { + Ok(reader.remain()) } fn poll(&self, mask: IoEvents, poller: Option<&mut Poller>) -> IoEvents { diff --git a/kernel/aster-nix/src/device/zero.rs b/kernel/aster-nix/src/device/zero.rs index dd279ab75..e883296ca 100644 --- a/kernel/aster-nix/src/device/zero.rs +++ b/kernel/aster-nix/src/device/zero.rs @@ -19,15 +19,17 @@ impl Device for Zero { } impl FileIo for Zero { - fn read(&self, buf: &mut [u8]) -> Result { - for byte in buf.iter_mut() { - *byte = 0; + fn read(&self, writer: &mut VmWriter) -> Result { + // 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 { - Ok(buf.len()) + fn write(&self, reader: &mut VmReader) -> Result { + Ok(reader.remain()) } fn poll(&self, mask: IoEvents, poller: Option<&mut Poller>) -> IoEvents { diff --git a/kernel/aster-nix/src/error.rs b/kernel/aster-nix/src/error.rs index 10eafb002..204af7261 100644 --- a/kernel/aster-nix/src/error.rs +++ b/kernel/aster-nix/src/error.rs @@ -189,8 +189,8 @@ impl AsRef for Error { } impl From 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 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 for Error { fn from(error: aster_block::bio::BioEnqueueError) -> Self { match error { diff --git a/kernel/aster-nix/src/fs/devpts/ptmx.rs b/kernel/aster-nix/src/fs/devpts/ptmx.rs index bc4169607..6c83447b7 100644 --- a/kernel/aster-nix/src/fs/devpts/ptmx.rs +++ b/kernel/aster-nix/src/fs/devpts/ptmx.rs @@ -132,19 +132,19 @@ impl Inode for Ptmx { self.metadata.write().ctime = time; } - fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result { Ok(0) } - fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result { + fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result { Ok(0) } - fn write_at(&self, offset: usize, buf: &[u8]) -> Result { + fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result { Ok(0) } - fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result { + fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result { Ok(0) } @@ -178,11 +178,11 @@ impl Device for Inner { } impl FileIo for Inner { - fn read(&self, buf: &mut [u8]) -> Result { + fn read(&self, writer: &mut VmWriter) -> Result { return_errno_with_message!(Errno::EINVAL, "cannot read ptmx"); } - fn write(&self, buf: &[u8]) -> Result { + fn write(&self, reader: &mut VmReader) -> Result { return_errno_with_message!(Errno::EINVAL, "cannot write ptmx"); } diff --git a/kernel/aster-nix/src/fs/devpts/slave.rs b/kernel/aster-nix/src/fs/devpts/slave.rs index c2def5503..282564db1 100644 --- a/kernel/aster-nix/src/fs/devpts/slave.rs +++ b/kernel/aster-nix/src/fs/devpts/slave.rs @@ -113,20 +113,20 @@ impl Inode for PtySlaveInode { self.metadata.write().ctime = time; } - fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { - self.device.read(buf) + fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result { + self.device.read(writer) } - fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result { - self.device.read(buf) + fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result { + self.device.read(writer) } - fn write_at(&self, offset: usize, buf: &[u8]) -> Result { - self.device.write(buf) + fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result { + self.device.write(reader) } - fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result { - self.device.write(buf) + fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result { + self.device.write(reader) } fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { diff --git a/kernel/aster-nix/src/fs/epoll/epoll_file.rs b/kernel/aster-nix/src/fs/epoll/epoll_file.rs index e888689d4..d4bcbe81b 100644 --- a/kernel/aster-nix/src/fs/epoll/epoll_file.rs +++ b/kernel/aster-nix/src/fs/epoll/epoll_file.rs @@ -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 { + fn read(&self, writer: &mut VmWriter) -> Result { return_errno_with_message!(Errno::EINVAL, "epoll files do not support read"); } - fn write(&self, buf: &[u8]) -> Result { + fn write(&self, reader: &mut VmReader) -> Result { return_errno_with_message!(Errno::EINVAL, "epoll files do not support write"); } diff --git a/kernel/aster-nix/src/fs/exfat/inode.rs b/kernel/aster-nix/src/fs/exfat/inode.rs index b324099f1..959dca178 100644 --- a/kernel/aster-nix/src/fs/exfat/inode.rs +++ b/kernel/aster-nix/src/fs/exfat/inode.rs @@ -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 { + fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result { 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 { + fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result { 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 { + fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result { + 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 { + fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result { + 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> { diff --git a/kernel/aster-nix/src/fs/exfat/mod.rs b/kernel/aster-nix/src/fs/exfat/mod.rs index 74d540fa2..fb2a77009 100644 --- a/kernel/aster-nix/src/fs/exfat/mod.rs +++ b/kernel/aster-nix/src/fs/exfat/mod.rs @@ -276,7 +276,7 @@ mod test { let root = fs.root_inode() as Arc; 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: {:?}", diff --git a/kernel/aster-nix/src/fs/ext2/impl_for_vfs/inode.rs b/kernel/aster-nix/src/fs/ext2/impl_for_vfs/inode.rs index 2f0200c76..8f1ef3c17 100644 --- a/kernel/aster-nix/src/fs/ext2/impl_for_vfs/inode.rs +++ b/kernel/aster-nix/src/fs/ext2/impl_for_vfs/inode.rs @@ -111,20 +111,20 @@ impl Inode for Ext2Inode { Some(self.page_cache()) } - fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { - self.read_at(offset, buf) + fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result { + self.read_at(offset, writer) } - fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result { - self.read_direct_at(offset, buf) + fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result { + self.read_direct_at(offset, writer) } - fn write_at(&self, offset: usize, buf: &[u8]) -> Result { - self.write_at(offset, buf) + fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result { + self.write_at(offset, reader) } - fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result { - self.write_direct_at(offset, buf) + fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result { + self.write_direct_at(offset, reader) } fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result> { diff --git a/kernel/aster-nix/src/fs/ext2/inode.rs b/kernel/aster-nix/src/fs/ext2/inode.rs index 269cb9980..4db9b3d9c 100644 --- a/kernel/aster-nix/src/fs/ext2/inode.rs +++ b/kernel/aster-nix/src/fs/ext2/inode.rs @@ -620,14 +620,14 @@ impl Inode { inner.device_id() } - pub fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + pub fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result { 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 { + pub fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result { 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 { + pub fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result { 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 { + pub fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result { 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 { + pub fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result { 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 { + pub fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result { 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 { - self.page_cache.pages().write_bytes(offset, buf)?; - Ok(buf.len()) + pub fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result { + 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 { - let new_size = offset + buf.len(); + pub fn extend_write_at(&mut self, offset: usize, reader: &mut VmReader) -> Result { + 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 { + pub fn write_direct_at(&mut self, offset: usize, reader: &mut VmReader) -> Result { 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 }; diff --git a/kernel/aster-nix/src/fs/file_handle.rs b/kernel/aster-nix/src/fs/file_handle.rs index b0242db1d..677354abc 100644 --- a/kernel/aster-nix/src/fs/file_handle.rs +++ b/kernel/aster-nix/src/fs/file_handle.rs @@ -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 { + fn read(&self, writer: &mut VmWriter) -> Result { return_errno_with_message!(Errno::EBADF, "the file is not valid for reading"); } - fn write(&self, buf: &[u8]) -> Result { + fn write(&self, reader: &mut VmReader) -> Result { 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 { + fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result { 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 { + fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result { return_errno_with_message!(Errno::ESPIPE, "write_at is not supported"); } @@ -131,4 +131,24 @@ impl dyn FileLike { pub fn downcast_ref(&self) -> Option<&T> { (self as &dyn Any).downcast_ref::() } + + pub fn read_bytes(&self, buf: &mut [u8]) -> Result { + let mut writer = VmWriter::from(buf).to_fallible(); + self.read(&mut writer) + } + + pub fn write_bytes(&self, buf: &[u8]) -> Result { + let mut reader = VmReader::from(buf).to_fallible(); + self.write(&mut reader) + } + + pub fn read_bytes_at(&self, offset: usize, buf: &mut [u8]) -> Result { + 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 { + let mut reader = VmReader::from(buf).to_fallible(); + self.write_at(offset, &mut reader) + } } diff --git a/kernel/aster-nix/src/fs/inode_handle/dyn_cap.rs b/kernel/aster-nix/src/fs/inode_handle/dyn_cap.rs index 87f76707c..1a0a5e674 100644 --- a/kernel/aster-nix/src/fs/inode_handle/dyn_cap.rs +++ b/kernel/aster-nix/src/fs/inode_handle/dyn_cap.rs @@ -98,32 +98,32 @@ impl FileLike for InodeHandle { fn set_group(&self, gid: Gid) -> Result<()>; fn seek(&self, seek_from: SeekFrom) -> Result; - fn read(&self, buf: &mut [u8]) -> Result { + fn read(&self, writer: &mut VmWriter) -> Result { 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 { + fn write(&self, reader: &mut VmReader) -> Result { 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 { + fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result { 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 { + fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result { 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<()> { diff --git a/kernel/aster-nix/src/fs/inode_handle/mod.rs b/kernel/aster-nix/src/fs/inode_handle/mod.rs index 5900b0671..9e39e0d6c 100644 --- a/kernel/aster-nix/src/fs/inode_handle/mod.rs +++ b/kernel/aster-nix/src/fs/inode_handle/mod.rs @@ -43,22 +43,22 @@ struct InodeHandle_ { } impl InodeHandle_ { - pub fn read(&self, buf: &mut [u8]) -> Result { + pub fn read(&self, writer: &mut VmWriter) -> Result { 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 { + pub fn write(&self, reader: &mut VmReader) -> Result { 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 { + pub fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result { 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 { + pub fn write_at(&self, mut offset: usize, reader: &mut VmReader) -> Result { 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 Drop for InodeHandle { } pub trait FileIo: Send + Sync + 'static { - fn read(&self, buf: &mut [u8]) -> Result; + fn read(&self, writer: &mut VmWriter) -> Result; - fn write(&self, buf: &[u8]) -> Result; + fn write(&self, reader: &mut VmReader) -> Result; fn poll(&self, mask: IoEvents, poller: Option<&mut Poller>) -> IoEvents; diff --git a/kernel/aster-nix/src/fs/inode_handle/static_cap.rs b/kernel/aster-nix/src/fs/inode_handle/static_cap.rs index 452fdc893..d79677a4b 100644 --- a/kernel/aster-nix/src/fs/inode_handle/static_cap.rs +++ b/kernel/aster-nix/src/fs/inode_handle/static_cap.rs @@ -8,8 +8,8 @@ use crate::prelude::*; impl InodeHandle> { #[require(R > Read)] - pub fn read(&self, buf: &mut [u8]) -> Result { - self.0.read(buf) + pub fn read(&self, writer: &mut VmWriter) -> Result { + self.0.read(writer) } #[require(R > Read)] @@ -18,8 +18,8 @@ impl InodeHandle> { } #[require(R > Write)] - pub fn write(&self, buf: &[u8]) -> Result { - self.0.write(buf) + pub fn write(&self, reader: &mut VmReader) -> Result { + self.0.write(reader) } #[require(R > Read)] diff --git a/kernel/aster-nix/src/fs/pipe.rs b/kernel/aster-nix/src/fs/pipe.rs index 432abaebc..e6ad0a422 100644 --- a/kernel/aster-nix/src/fs/pipe.rs +++ b/kernel/aster-nix/src/fs/pipe.rs @@ -41,12 +41,15 @@ impl Pollable for PipeReader { } impl FileLike for PipeReader { - fn read(&self, buf: &mut [u8]) -> Result { - if self.status_flags().contains(StatusFlags::O_NONBLOCK) { - self.consumer.try_read(buf) + fn read(&self, writer: &mut VmWriter) -> Result { + 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 { + fn write(&self, reader: &mut VmReader) -> Result { + 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() + } } diff --git a/kernel/aster-nix/src/fs/procfs/template/file.rs b/kernel/aster-nix/src/fs/procfs/template/file.rs index f7a1832ef..092618a01 100644 --- a/kernel/aster-nix/src/fs/procfs/template/file.rs +++ b/kernel/aster-nix/src/fs/procfs/template/file.rs @@ -62,24 +62,24 @@ impl Inode for ProcFile { InodeType::File } - fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result { 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 { - self.read_at(offset, buf) + fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result { + self.read_at(offset, writer) } - fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { + fn write_at(&self, _offset: usize, _reader: &mut VmReader) -> Result { Err(Error::new(Errno::EPERM)) } - fn write_direct_at(&self, _offset: usize, _buf: &[u8]) -> Result { + fn write_direct_at(&self, _offset: usize, _reader: &mut VmReader) -> Result { Err(Error::new(Errno::EPERM)) } diff --git a/kernel/aster-nix/src/fs/procfs/template/sym.rs b/kernel/aster-nix/src/fs/procfs/template/sym.rs index 4e724869c..e3ef882df 100644 --- a/kernel/aster-nix/src/fs/procfs/template/sym.rs +++ b/kernel/aster-nix/src/fs/procfs/template/sym.rs @@ -59,19 +59,19 @@ impl Inode for ProcSym { InodeType::SymLink } - fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result { + fn read_at(&self, _offset: usize, _writer: &mut VmWriter) -> Result { Err(Error::new(Errno::EPERM)) } - fn read_direct_at(&self, _offset: usize, _buf: &mut [u8]) -> Result { + fn read_direct_at(&self, _offset: usize, _writer: &mut VmWriter) -> Result { Err(Error::new(Errno::EPERM)) } - fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { + fn write_at(&self, _offset: usize, _reader: &mut VmReader) -> Result { Err(Error::new(Errno::EPERM)) } - fn write_direct_at(&self, _offset: usize, _buf: &[u8]) -> Result { + fn write_direct_at(&self, _offset: usize, _reader: &mut VmReader) -> Result { Err(Error::new(Errno::EPERM)) } diff --git a/kernel/aster-nix/src/fs/ramfs/fs.rs b/kernel/aster-nix/src/fs/ramfs/fs.rs index 39a621871..65d9c4012 100644 --- a/kernel/aster-nix/src/fs/ramfs/fs.rs +++ b/kernel/aster-nix/src/fs/ramfs/fs.rs @@ -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 { + fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result { 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 { - self.read_at(offset, buf) + fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result { + self.read_at(offset, writer) } - fn write_at(&self, offset: usize, buf: &[u8]) -> Result { + fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result { + 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 { - self.write_at(offset, buf) + fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result { + self.write_at(offset, reader) } fn size(&self) -> usize { diff --git a/kernel/aster-nix/src/fs/utils/inode.rs b/kernel/aster-nix/src/fs/utils/inode.rs index 9e7e40942..98fad0a24 100644 --- a/kernel/aster-nix/src/fs/utils/inode.rs +++ b/kernel/aster-nix/src/fs/utils/inode.rs @@ -280,19 +280,19 @@ pub trait Inode: Any + Sync + Send { None } - fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result { Err(Error::new(Errno::EISDIR)) } - fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result { + fn read_direct_at(&self, offset: usize, writer: &mut VmWriter) -> Result { Err(Error::new(Errno::EISDIR)) } - fn write_at(&self, offset: usize, buf: &[u8]) -> Result { + fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result { Err(Error::new(Errno::EISDIR)) } - fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result { + fn write_direct_at(&self, offset: usize, reader: &mut VmReader) -> Result { Err(Error::new(Errno::EISDIR)) } @@ -397,7 +397,7 @@ impl dyn Inode { (self as &dyn Any).downcast_ref::() } - pub fn read_all(&self, buf: &mut Vec) -> Result { + pub fn read_to_end(&self, buf: &mut Vec) -> Result { 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) -> Result { + pub fn read_direct_to_end(&self, buf: &mut Vec) -> Result { 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 { + 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 { + 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 { + 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 { + 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 { + 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) diff --git a/kernel/aster-nix/src/fs/utils/random_test.rs b/kernel/aster-nix/src/fs/utils/random_test.rs index cfaefae66..65c10942d 100644 --- a/kernel/aster-nix/src/fs/utils/random_test.rs +++ b/kernel/aster-nix/src/fs/utils/random_test.rs @@ -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 [{:?}, {:?}): {:?}", diff --git a/kernel/aster-nix/src/net/socket/ip/datagram/mod.rs b/kernel/aster-nix/src/net/socket/ip/datagram/mod.rs index 1e6e1dc4f..b72c210e3 100644 --- a/kernel/aster-nix/src/net/socket/ip/datagram/mod.rs +++ b/kernel/aster-nix/src/net/socket/ip/datagram/mod.rs @@ -185,13 +185,17 @@ impl Pollable for DatagramSocket { } impl FileLike for DatagramSocket { - fn read(&self, buf: &mut [u8]) -> Result { + fn read(&self, writer: &mut VmWriter) -> Result { + 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 { + fn write(&self, reader: &mut VmReader) -> Result { + 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) -> Option> { diff --git a/kernel/aster-nix/src/net/socket/ip/stream/mod.rs b/kernel/aster-nix/src/net/socket/ip/stream/mod.rs index 8c57565e6..b55e964b6 100644 --- a/kernel/aster-nix/src/net/socket/ip/stream/mod.rs +++ b/kernel/aster-nix/src/net/socket/ip/stream/mod.rs @@ -344,16 +344,20 @@ impl Pollable for StreamSocket { } impl FileLike for StreamSocket { - fn read(&self, buf: &mut [u8]) -> Result { + fn read(&self, writer: &mut VmWriter) -> Result { + 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 { + fn write(&self, reader: &mut VmReader) -> Result { + 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 { diff --git a/kernel/aster-nix/src/net/socket/unix/stream/socket.rs b/kernel/aster-nix/src/net/socket/unix/stream/socket.rs index 53919919d..ed63822bf 100644 --- a/kernel/aster-nix/src/net/socket/unix/stream/socket.rs +++ b/kernel/aster-nix/src/net/socket/unix/stream/socket.rs @@ -128,16 +128,20 @@ impl FileLike for UnixStreamSocket { Some(self) } - fn read(&self, buf: &mut [u8]) -> Result { + fn read(&self, writer: &mut VmWriter) -> Result { + 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 { + fn write(&self, reader: &mut VmReader) -> Result { + 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 { diff --git a/kernel/aster-nix/src/net/socket/vsock/stream/socket.rs b/kernel/aster-nix/src/net/socket/vsock/stream/socket.rs index fa2695bf5..65654eaaa 100644 --- a/kernel/aster-nix/src/net/socket/vsock/stream/socket.rs +++ b/kernel/aster-nix/src/net/socket/vsock/stream/socket.rs @@ -137,14 +137,20 @@ impl FileLike for VsockStreamSocket { Some(self) } - fn read(&self, buf: &mut [u8]) -> Result { + fn read(&self, writer: &mut VmWriter) -> Result { + 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 { + fn write(&self, reader: &mut VmReader) -> Result { + let buf = reader.collect()?; // TODO: Set correct flags - self.send(buf, SendRecvFlags::empty()) + self.send(&buf, SendRecvFlags::empty()) } fn status_flags(&self) -> StatusFlags { diff --git a/kernel/aster-nix/src/process/program_loader/elf/load_elf.rs b/kernel/aster-nix/src/process/program_loader/elf/load_elf.rs index 08af1fe82..929286921 100644 --- a/kernel/aster-nix/src/process/program_loader/elf/load_elf.rs +++ b/kernel/aster-nix/src/process/program_loader/elf/load_elf.rs @@ -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))) diff --git a/kernel/aster-nix/src/process/program_loader/mod.rs b/kernel/aster-nix/src/process/program_loader/mod.rs index 9c9b110fb..a18706c81 100644 --- a/kernel/aster-nix/src/process/program_loader/mod.rs +++ b/kernel/aster-nix/src/process/program_loader/mod.rs @@ -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)? { diff --git a/kernel/aster-nix/src/syscall/eventfd.rs b/kernel/aster-nix/src/syscall/eventfd.rs index f9c16f1d2..0e3b93714 100644 --- a/kernel/aster-nix/src/syscall/eventfd.rs +++ b/kernel/aster-nix/src/syscall/eventfd.rs @@ -156,9 +156,9 @@ impl Pollable for EventFile { } impl FileLike for EventFile { - fn read(&self, buf: &mut [u8]) -> Result { + fn read(&self, writer: &mut VmWriter) -> Result { let read_len = core::mem::size_of::(); - 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 { + fn write(&self, reader: &mut VmReader) -> Result { let write_len = core::mem::size_of::(); - 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::()?; // Try to add counter val at first if self.add_counter_val(supplied_value).is_ok() { diff --git a/kernel/aster-nix/src/syscall/pread64.rs b/kernel/aster-nix/src/syscall/pread64.rs index 0ba295db9..ff7f38432 100644 --- a/kernel/aster-nix/src/syscall/pread64.rs +++ b/kernel/aster-nix/src/syscall/pread64.rs @@ -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 _)) diff --git a/kernel/aster-nix/src/syscall/preadv.rs b/kernel/aster-nix/src/syscall/preadv.rs index 42209e30b..0e37fa63f 100644 --- a/kernel/aster-nix/src/syscall/preadv.rs +++ b/kernel/aster-nix/src/syscall/preadv.rs @@ -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() { diff --git a/kernel/aster-nix/src/syscall/pwrite64.rs b/kernel/aster-nix/src/syscall/pwrite64.rs index 0779af3d7..c3b2a0909 100644 --- a/kernel/aster-nix/src/syscall/pwrite64.rs +++ b/kernel/aster-nix/src/syscall/pwrite64.rs @@ -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 _)) } diff --git a/kernel/aster-nix/src/syscall/pwritev.rs b/kernel/aster-nix/src/syscall/pwritev.rs index 833025a45..79c93ae0b 100644 --- a/kernel/aster-nix/src/syscall/pwritev.rs +++ b/kernel/aster-nix/src/syscall/pwritev.rs @@ -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) diff --git a/kernel/aster-nix/src/syscall/read.rs b/kernel/aster-nix/src/syscall/read.rs index da7e2dd22..be2d4607c 100644 --- a/kernel/aster-nix/src/syscall/read.rs +++ b/kernel/aster-nix/src/syscall/read.rs @@ -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 _)) diff --git a/kernel/aster-nix/src/syscall/sendfile.rs b/kernel/aster-nix/src/syscall/sendfile.rs index bcb8137ec..f5744dd59 100644 --- a/kernel/aster-nix/src/syscall/sendfile.rs +++ b/kernel/aster-nix/src/syscall/sendfile.rs @@ -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) => { diff --git a/kernel/aster-nix/src/syscall/write.rs b/kernel/aster-nix/src/syscall/write.rs index c9818e08c..2f65c944b 100644 --- a/kernel/aster-nix/src/syscall/write.rs +++ b/kernel/aster-nix/src/syscall/write.rs @@ -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 _)) diff --git a/kernel/aster-nix/src/vm/vmo/dyn_cap.rs b/kernel/aster-nix/src/vm/vmo/dyn_cap.rs index 0aa548764..1b1ccdc43 100644 --- a/kernel/aster-nix/src/vm/vmo/dyn_cap.rs +++ b/kernel/aster-nix/src/vm/vmo/dyn_cap.rs @@ -27,7 +27,7 @@ impl Vmo { pub fn commit(&self, range: Range) -> 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 { } impl VmIo for Vmo { - 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()` diff --git a/kernel/aster-nix/src/vm/vmo/mod.rs b/kernel/aster-nix/src/vm/vmo/mod.rs index 4c1ce5c90..62c6f29fe 100644 --- a/kernel/aster-nix/src/vm/vmo/mod.rs +++ b/kernel/aster-nix/src/vm/vmo/mod.rs @@ -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 = 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 = 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) -> 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(()) } diff --git a/kernel/aster-nix/src/vm/vmo/static_cap.rs b/kernel/aster-nix/src/vm/vmo/static_cap.rs index dfd723c21..e623a068f 100644 --- a/kernel/aster-nix/src/vm/vmo/static_cap.rs +++ b/kernel/aster-nix/src/vm/vmo/static_cap.rs @@ -28,7 +28,7 @@ impl Vmo> { #[require(R > Write)] pub fn commit(&self, range: Range) -> Result<()> { self.0 - .commit_and_operate(&range, |_| {}, CommitFlags::empty())?; + .commit_and_operate(&range, |_| Ok(()), CommitFlags::empty())?; Ok(()) } @@ -111,15 +111,15 @@ impl Vmo> { } impl VmIo for Vmo> { - 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(()) } } diff --git a/kernel/comps/block/src/impl_block_device.rs b/kernel/comps/block/src/impl_block_device.rs index 41f68c606..c145086ff 100644 --- a/kernel/comps/block/src/impl_block_device.rs +++ b/kernel/comps/block/src/impl_block_device.rs @@ -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, diff --git a/ostd/src/io_mem.rs b/ostd/src/io_mem.rs index 9a17cd431..54ecd8299 100644 --- a/ostd/src/io_mem.rs +++ b/ostd/src/io_mem.rs @@ -5,7 +5,10 @@ use core::{mem::size_of, ops::Range}; use crate::{ - mm::{kspace::LINEAR_MAPPING_BASE_VADDR, paddr_to_vaddr, HasPaddr, Paddr, Vaddr, VmIo}, + mm::{ + kspace::LINEAR_MAPPING_BASE_VADDR, paddr_to_vaddr, HasPaddr, Paddr, Vaddr, VmIo, VmReader, + VmWriter, + }, Error, Pod, Result, }; @@ -17,25 +20,27 @@ pub struct IoMem { } impl VmIo for IoMem { - fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> crate::Result<()> { - self.check_range(offset, buf.len())?; + fn read(&self, offset: usize, writer: &mut VmWriter) -> crate::Result<()> { + let read_len = writer.avail(); + self.check_range(offset, read_len)?; unsafe { core::ptr::copy( (self.virtual_address + offset) as *const u8, - buf.as_mut_ptr(), - buf.len(), + writer.cursor(), + read_len, ); } Ok(()) } - fn write_bytes(&self, offset: usize, buf: &[u8]) -> crate::Result<()> { - self.check_range(offset, buf.len())?; + fn write(&self, offset: usize, reader: &mut VmReader) -> crate::Result<()> { + let write_len = reader.remain(); + self.check_range(offset, write_len)?; unsafe { core::ptr::copy( - buf.as_ptr(), + reader.cursor(), (self.virtual_address + offset) as *mut u8, - buf.len(), + write_len, ); } Ok(()) diff --git a/ostd/src/mm/dma/dma_coherent.rs b/ostd/src/mm/dma/dma_coherent.rs index 1baaf4394..777a867fc 100644 --- a/ostd/src/mm/dma/dma_coherent.rs +++ b/ostd/src/mm/dma/dma_coherent.rs @@ -167,12 +167,12 @@ impl Drop for DmaCoherentInner { } impl VmIo for DmaCoherent { - fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> { - self.inner.vm_segment.read_bytes(offset, buf) + fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> { + self.inner.vm_segment.read(offset, writer) } - fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> { - self.inner.vm_segment.write_bytes(offset, buf) + fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> { + self.inner.vm_segment.write(offset, reader) } } diff --git a/ostd/src/mm/dma/dma_stream.rs b/ostd/src/mm/dma/dma_stream.rs index ed32062fe..56d9828ad 100644 --- a/ostd/src/mm/dma/dma_stream.rs +++ b/ostd/src/mm/dma/dma_stream.rs @@ -202,19 +202,19 @@ impl Drop for DmaStreamInner { impl VmIo for DmaStream { /// Reads data into the buffer. - fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<(), Error> { + fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<(), Error> { if self.inner.direction == DmaDirection::ToDevice { return Err(Error::AccessDenied); } - self.inner.vm_segment.read_bytes(offset, buf) + self.inner.vm_segment.read(offset, writer) } /// Writes data from the buffer. - fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<(), Error> { + fn write(&self, offset: usize, reader: &mut VmReader) -> Result<(), Error> { if self.inner.direction == DmaDirection::FromDevice { return Err(Error::AccessDenied); } - self.inner.vm_segment.write_bytes(offset, buf) + self.inner.vm_segment.write(offset, reader) } } @@ -282,18 +282,18 @@ impl<'a> DmaStreamSlice<'a> { } impl VmIo for DmaStreamSlice<'_> { - fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<(), Error> { - if buf.len() + offset > self.len { + fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<(), Error> { + if writer.avail() + offset > self.len { return Err(Error::InvalidArgs); } - self.stream.read_bytes(self.offset + offset, buf) + self.stream.read(self.offset + offset, writer) } - fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<(), Error> { - if buf.len() + offset > self.len { + fn write(&self, offset: usize, reader: &mut VmReader) -> Result<(), Error> { + if reader.remain() + offset > self.len { return Err(Error::InvalidArgs); } - self.stream.write_bytes(self.offset + offset, buf) + self.stream.write(self.offset + offset, reader) } } diff --git a/ostd/src/mm/frame/mod.rs b/ostd/src/mm/frame/mod.rs index 01f1ad844..bc41dc1ff 100644 --- a/ostd/src/mm/frame/mod.rs +++ b/ostd/src/mm/frame/mod.rs @@ -24,7 +24,7 @@ use super::{ }; use crate::{ mm::{ - io::{VmIo, VmReader, VmWriter}, + io::{FallibleVmRead, FallibleVmWrite, VmIo, VmReader, VmWriter}, paddr_to_vaddr, HasPaddr, Paddr, PAGE_SIZE, }, Error, Result, @@ -133,42 +133,55 @@ impl<'a> Frame { } impl VmIo for Frame { - fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> { + fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> { + let read_len = writer.avail().min(self.size().saturating_sub(offset)); // Do bound check with potential integer overflow in mind - let max_offset = offset.checked_add(buf.len()).ok_or(Error::Overflow)?; + let max_offset = offset.checked_add(read_len).ok_or(Error::Overflow)?; if max_offset > self.size() { return Err(Error::InvalidArgs); } - let len = self.reader().skip(offset).read(&mut buf.into()); - debug_assert!(len == buf.len()); + let len = self + .reader() + .skip(offset) + .read_fallible(writer) + .map_err(|(e, _)| e)?; + debug_assert!(len == read_len); Ok(()) } - fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> { + fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> { + let write_len = reader.remain().min(self.size().saturating_sub(offset)); // Do bound check with potential integer overflow in mind - let max_offset = offset.checked_add(buf.len()).ok_or(Error::Overflow)?; + let max_offset = offset.checked_add(write_len).ok_or(Error::Overflow)?; if max_offset > self.size() { return Err(Error::InvalidArgs); } - let len = self.writer().skip(offset).write(&mut buf.into()); - debug_assert!(len == buf.len()); + let len = self + .writer() + .skip(offset) + .write_fallible(reader) + .map_err(|(e, _)| e)?; + debug_assert!(len == write_len); Ok(()) } } impl VmIo for alloc::vec::Vec { - fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> { + fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> { // Do bound check with potential integer overflow in mind - let max_offset = offset.checked_add(buf.len()).ok_or(Error::Overflow)?; + let max_offset = offset.checked_add(writer.avail()).ok_or(Error::Overflow)?; if max_offset > self.len() * PAGE_SIZE { return Err(Error::InvalidArgs); } let num_skip_pages = offset / PAGE_SIZE; let mut start = offset % PAGE_SIZE; - let mut buf_writer: VmWriter = buf.into(); for frame in self.iter().skip(num_skip_pages) { - let read_len = frame.reader().skip(start).read(&mut buf_writer); + let read_len = frame + .reader() + .skip(start) + .read_fallible(writer) + .map_err(|(e, _)| e)?; if read_len == 0 { break; } @@ -177,18 +190,21 @@ impl VmIo for alloc::vec::Vec { Ok(()) } - fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> { + fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> { // Do bound check with potential integer overflow in mind - let max_offset = offset.checked_add(buf.len()).ok_or(Error::Overflow)?; + let max_offset = offset.checked_add(reader.remain()).ok_or(Error::Overflow)?; if max_offset > self.len() * PAGE_SIZE { return Err(Error::InvalidArgs); } let num_skip_pages = offset / PAGE_SIZE; let mut start = offset % PAGE_SIZE; - let mut buf_reader: VmReader = buf.into(); for frame in self.iter().skip(num_skip_pages) { - let write_len = frame.writer().skip(start).write(&mut buf_reader); + let write_len = frame + .writer() + .skip(start) + .write_fallible(reader) + .map_err(|(e, _)| e)?; if write_len == 0 { break; } diff --git a/ostd/src/mm/frame/segment.rs b/ostd/src/mm/frame/segment.rs index 53b44a6eb..504190d6a 100644 --- a/ostd/src/mm/frame/segment.rs +++ b/ostd/src/mm/frame/segment.rs @@ -9,7 +9,8 @@ use super::Frame; use crate::{ mm::{ page::{cont_pages::ContPages, meta::FrameMeta, Page}, - HasPaddr, Infallible, Paddr, VmIo, VmReader, VmWriter, PAGE_SIZE, + FallibleVmRead, FallibleVmWrite, HasPaddr, Infallible, Paddr, VmIo, VmReader, VmWriter, + PAGE_SIZE, }, Error, Result, }; @@ -114,25 +115,35 @@ impl<'a> Segment { } impl VmIo for Segment { - fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> { + fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> { + let read_len = writer.avail(); // Do bound check with potential integer overflow in mind - let max_offset = offset.checked_add(buf.len()).ok_or(Error::Overflow)?; + let max_offset = offset.checked_add(read_len).ok_or(Error::Overflow)?; if max_offset > self.nbytes() { return Err(Error::InvalidArgs); } - let len = self.reader().skip(offset).read(&mut buf.into()); - debug_assert!(len == buf.len()); + let len = self + .reader() + .skip(offset) + .read_fallible(writer) + .map_err(|(e, _)| e)?; + debug_assert!(len == read_len); Ok(()) } - fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> { + fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> { + let write_len = reader.remain(); // Do bound check with potential integer overflow in mind - let max_offset = offset.checked_add(buf.len()).ok_or(Error::Overflow)?; + let max_offset = offset.checked_add(reader.remain()).ok_or(Error::Overflow)?; if max_offset > self.nbytes() { return Err(Error::InvalidArgs); } - let len = self.writer().skip(offset).write(&mut buf.into()); - debug_assert!(len == buf.len()); + let len = self + .writer() + .skip(offset) + .write_fallible(reader) + .map_err(|(e, _)| e)?; + debug_assert!(len == write_len); Ok(()) } } diff --git a/ostd/src/mm/io.rs b/ostd/src/mm/io.rs index 31c94a427..53356da69 100644 --- a/ostd/src/mm/io.rs +++ b/ostd/src/mm/io.rs @@ -40,6 +40,7 @@ //! user space, making it impossible to avoid data races). However, they may produce erroneous //! results, such as unexpected bytes being copied, but do not cause soundness problems. +use alloc::vec; use core::marker::PhantomData; use align_ext::AlignExt; @@ -69,14 +70,26 @@ use crate::{ /// [`Segment`]: crate::mm::Segment /// [`Frame`]: crate::mm::Frame pub trait VmIo: Send + Sync { + /// Reads requested data at a specified offset into a given `VmWriter`. + /// + /// # No short reads + /// + /// On success, the `writer` must be written with the requested data + /// completely. If, for any reason, the requested data is only partially + /// available, then the method shall return an error. + fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()>; + /// Reads a specified number of bytes at a specified offset into a given buffer. /// /// # No short reads /// - /// On success, the output `buf` must be filled with the requested data - /// completely. If, for any reason, the requested data is only partially - /// available, then the method shall return an error. - fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()>; + /// Similar to [`read`]. + /// + /// [`read`]: VmIo::read + fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> { + let mut writer = VmWriter::from(buf).to_fallible(); + self.read(offset, &mut writer) + } /// Reads a value of a specified type at a specified offset. fn read_val(&self, offset: usize) -> Result { @@ -89,9 +102,9 @@ pub trait VmIo: Send + Sync { /// /// # No short reads /// - /// Similar to [`read_bytes`]. + /// Similar to [`read`]. /// - /// [`read_bytes`]: VmIo::read_bytes + /// [`read`]: VmIo::read fn read_slice(&self, offset: usize, slice: &mut [T]) -> Result<()> { let len_in_bytes = core::mem::size_of_val(slice); let ptr = slice as *mut [T] as *mut u8; @@ -101,14 +114,26 @@ pub trait VmIo: Send + Sync { self.read_bytes(offset, buf) } + /// Writes all data from a given `VmReader` at a specified offset. + /// + /// # No short writes + /// + /// On success, the data from the `reader` must be read to the VM object entirely. + /// If, for any reason, the input data can only be written partially, + /// then the method shall return an error. + fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()>; + /// Writes a specified number of bytes from a given buffer at a specified offset. /// /// # No short writes /// - /// On success, the input `buf` must be written to the VM object entirely. - /// If, for any reason, the input data can only be written partially, - /// then the method shall return an error. - fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()>; + /// Similar to [`write`]. + /// + /// [`write`]: VmIo::write + fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> { + let mut reader = VmReader::from(buf).to_fallible(); + self.write(offset, &mut reader) + } /// Writes a value of a specified type at a specified offset. fn write_val(&self, offset: usize, new_val: &T) -> Result<()> { @@ -120,9 +145,9 @@ pub trait VmIo: Send + Sync { /// /// # No short write /// - /// Similar to [`write_bytes`]. + /// Similar to [`write`]. /// - /// [`write_bytes`]: VmIo::write_bytes + /// [`write`]: VmIo::write fn write_slice(&self, offset: usize, slice: &[T]) -> Result<()> { let len_in_bytes = core::mem::size_of_val(slice); let ptr = slice as *const [T] as *const u8; @@ -219,9 +244,11 @@ macro_rules! impl_vm_io_pointer { ($typ:ty,$from:tt) => { #[inherit_methods(from = $from)] impl VmIo for $typ { + fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()>; fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()>; fn read_val(&self, offset: usize) -> Result; fn read_slice(&self, offset: usize, slice: &mut [F]) -> Result<()>; + fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()>; fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()>; fn write_val(&self, offset: usize, new_val: &F) -> Result<()>; fn write_slice(&self, offset: usize, slice: &[F]) -> Result<()>; @@ -364,7 +391,7 @@ macro_rules! impl_read_fallible { return Ok(0); } - // SAFETY: The source and destionation are subsets of memory ranges specified by + // SAFETY: The source and destination are subsets of memory ranges specified by // the reader and writer, so they are either valid for reading and writing or in // user space. let copied_len = unsafe { @@ -437,7 +464,7 @@ impl<'a> VmReader<'a, Infallible> { return 0; } - // SAFETY: The source and destionation are subsets of memory ranges specified by the reader + // SAFETY: The source and destination are subsets of memory ranges specified by the reader // and writer, so they are valid for reading and writing. unsafe { memcpy(writer.cursor, self.cursor, copy_len); @@ -545,6 +572,25 @@ impl<'a> VmReader<'a, Fallible> { })?; Ok(val) } + + /// Collects all the remaining bytes into a `Vec`. + /// + /// If the memory read failed, this method will return `Err` + /// and the current reader's cursor remains pointing to + /// the original starting position. + pub fn collect(&mut self) -> Result> { + let mut buf = vec![0u8; self.remain()]; + self.read_fallible(&mut buf.as_mut_slice().into()) + .map_err(|(err, copied_len)| { + // SAFETY: The `copied_len` is the number of bytes read so far. + // So the `cursor` can be moved back to the original position. + unsafe { + self.cursor = self.cursor.sub(copied_len); + } + err + })?; + Ok(buf) + } } impl<'a, Fallibility> VmReader<'a, Fallibility> {