[libos] Refine the getdents syscall.

This commit is contained in:
LI Qing 2023-03-14 12:00:37 +08:00 committed by volcano
parent bc9e78b360
commit 27a3c75209
7 changed files with 51 additions and 87 deletions

2
deps/sefs vendored

@ -1 +1 @@
Subproject commit 98196fb62f64f0edeacc20d60c30aaaf4a290f70 Subproject commit a771d5d37f2a21b02ee579bab85dc8e551d924e0

@ -23,13 +23,13 @@ fn getdents_common<T: Dirent>(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
return_errno!(ENOTDIR, ""); return_errno!(ENOTDIR, "");
} }
let mut writer = DirentBufWriter::<T>::new(buf); let mut writer = DirentBufWriter::<T>::new(buf);
let written_size = file_ref.iterate_entries(&mut writer)?; let written_len = file_ref.iterate_entries(&mut writer)?;
Ok(written_size) Ok(written_len)
} }
struct DirentBufWriter<'a, T: Dirent> { struct DirentBufWriter<'a, T: Dirent> {
buf: &'a mut [u8], buf: &'a mut [u8],
written_size: usize, written_len: usize,
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }
@ -37,40 +37,34 @@ impl<'a, T: Dirent> DirentBufWriter<'a, T> {
fn new(buf: &'a mut [u8]) -> Self { fn new(buf: &'a mut [u8]) -> Self {
Self { Self {
buf, buf,
written_size: 0, written_len: 0,
phantom: PhantomData, phantom: PhantomData,
} }
} }
fn try_write(&mut self, name: &str, ino: u64, type_: FileType) -> Result<usize> {
let dirent: T = Dirent::new(name, ino, type_);
if self.buf.len() - self.written_size < dirent.rec_len() {
return_errno!(EINVAL, "the given buffer is too small");
}
dirent.dump(&mut self.buf[self.written_size..], name, type_)?;
self.written_size += dirent.rec_len();
Ok(dirent.rec_len())
}
} }
impl<'a, T: Dirent> DirentWriter for DirentBufWriter<'a, T> { impl<'a, T: Dirent> DirentWriter for DirentBufWriter<'a, T> {
fn write_entry( fn write_entry(&mut self, name: &str, ino: u64, type_: FileType) -> rcore_fs::vfs::Result<()> {
&mut self, let dirent: T = Dirent::new(name, ino, type_);
name: &str, if self.buf.len() - self.written_len < dirent.rec_len() {
ino: u64, return Err(FsError::InvalidParam);
type_: FileType, }
) -> rcore_fs::vfs::Result<usize> { dirent
let written_len = self .serialize(&mut self.buf[self.written_len..], name, type_)
.try_write(&name, ino, type_)
.map_err(|_| FsError::InvalidParam)?; .map_err(|_| FsError::InvalidParam)?;
Ok(written_len) self.written_len += dirent.rec_len();
Ok(())
}
fn written_len(&self) -> usize {
self.written_len
} }
} }
trait Dirent: Sync + Send { trait Dirent: Sync + Send {
fn new(name: &str, ino: u64, type_: FileType) -> Self; fn new(name: &str, ino: u64, type_: FileType) -> Self;
fn rec_len(&self) -> usize; fn rec_len(&self) -> usize;
fn dump(&self, buf: &mut [u8], name: &str, type_: FileType) -> Result<()>; fn serialize(&self, buf: &mut [u8], name: &str, type_: FileType) -> Result<()>;
} }
/// Same with struct linux_dirent64 /// Same with struct linux_dirent64
@ -106,7 +100,7 @@ impl Dirent for LinuxDirent64 {
self.rec_len as usize self.rec_len as usize
} }
fn dump(&self, buf: &mut [u8], name: &str, _type_: FileType) -> Result<()> { fn serialize(&self, buf: &mut [u8], name: &str, _type_: FileType) -> Result<()> {
unsafe { unsafe {
let ptr = buf.as_mut_ptr() as *mut Self; let ptr = buf.as_mut_ptr() as *mut Self;
ptr.write(*self); ptr.write(*self);
@ -154,7 +148,7 @@ impl Dirent for LinuxDirent {
self.rec_len as usize self.rec_len as usize
} }
fn dump(&self, buf: &mut [u8], name: &str, type_: FileType) -> Result<()> { fn serialize(&self, buf: &mut [u8], name: &str, type_: FileType) -> Result<()> {
unsafe { unsafe {
let ptr = buf.as_mut_ptr() as *mut Self; let ptr = buf.as_mut_ptr() as *mut Self;
ptr.write(*self); ptr.write(*self);

@ -269,10 +269,9 @@ impl INode for HNode {
return Err(FsError::NotDir); return Err(FsError::NotDir);
} }
let idx = ctx.pos(); let idx = ctx.pos();
let mut total_written_len = 0;
for entry in try_std!(self.path.read_dir()).skip(idx) { for entry in try_std!(self.path.read_dir()).skip(idx) {
let entry = try_std!(entry); let entry = try_std!(entry);
let written_len = match ctx.write_entry( if let Err(e) = ctx.write_entry(
&entry &entry
.file_name() .file_name()
.into_string() .into_string()
@ -283,18 +282,14 @@ impl INode for HNode {
.map_err(|_| FsError::InvalidParam)? .map_err(|_| FsError::InvalidParam)?
.into_fs_filetype(), .into_fs_filetype(),
) { ) {
Ok(written_len) => written_len, if ctx.written_len() == 0 {
Err(e) => { return Err(e);
if total_written_len == 0 { } else {
return Err(e); break;
} else {
break;
}
} }
}; };
total_written_len += written_len;
} }
Ok(total_written_len) Ok(ctx.written_len())
} }
fn io_control(&self, cmd: u32, data: usize) -> Result<()> { fn io_control(&self, cmd: u32, data: usize) -> Result<()> {

@ -159,23 +159,22 @@ impl DirProcINode for LockedProcRootINode {
fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result<usize> { fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result<usize> {
let file = self.0.read().unwrap(); let file = self.0.read().unwrap();
let mut total_written_len = 0;
let idx = ctx.pos(); let idx = ctx.pos();
// Write first two special entries // Write first two special entries
if idx == 0 { if idx == 0 {
let this_inode = file.this.upgrade().unwrap(); let this_inode = file.this.upgrade().unwrap();
write_inode_entry!(&mut ctx, ".", &this_inode, &mut total_written_len); write_inode_entry!(&mut ctx, ".", &this_inode);
} }
if idx <= 1 { if idx <= 1 {
let parent_inode = file.this.upgrade().unwrap(); let parent_inode = file.this.upgrade().unwrap();
write_inode_entry!(&mut ctx, "..", &parent_inode, &mut total_written_len); write_inode_entry!(&mut ctx, "..", &parent_inode);
} }
// Write the non volatile entries // Write the non volatile entries
let skipped = if idx < 2 { 0 } else { idx - 2 }; let skipped = if idx < 2 { 0 } else { idx - 2 };
for (name, inode) in file.non_volatile_entries.iter().skip(skipped) { for (name, inode) in file.non_volatile_entries.iter().skip(skipped) {
write_inode_entry!(&mut ctx, name, inode, &mut total_written_len); write_inode_entry!(&mut ctx, name, inode);
} }
// Write the pid entries // Write the pid entries
@ -192,11 +191,10 @@ impl DirProcINode for LockedProcRootINode {
&mut ctx, &mut ctx,
&process.pid().to_string(), &process.pid().to_string(),
PROC_INO, PROC_INO,
vfs::FileType::Dir, vfs::FileType::Dir
&mut total_written_len
); );
} }
Ok(total_written_len) Ok(ctx.written_len())
} }
} }

@ -55,32 +55,24 @@ impl DirProcINode for LockedProcFdDirINode {
fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result<usize> { fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result<usize> {
let file = self.0.read().unwrap(); let file = self.0.read().unwrap();
let mut total_written_len = 0;
let idx = ctx.pos(); let idx = ctx.pos();
// Write first two special entries // Write first two special entries
write_first_two_entries!(idx, &mut ctx, &file, &mut total_written_len); write_first_two_entries!(idx, &mut ctx, &file);
// Write the fd entries // Write the fd entries
let skipped = if idx < 2 { 0 } else { idx - 2 }; let skipped = if idx < 2 { 0 } else { idx - 2 };
let main_thread = match file.process_ref.main_thread() { let main_thread = match file.process_ref.main_thread() {
Some(main_thread) => main_thread, Some(main_thread) => main_thread,
None => { None => {
return Ok(total_written_len); return Ok(ctx.written_len());
} }
}; };
let fds = main_thread.files().lock().unwrap().fds(); let fds = main_thread.files().lock().unwrap().fds();
for fd in fds.iter().skip(skipped) { for fd in fds.iter().skip(skipped) {
write_entry!( write_entry!(&mut ctx, &fd.to_string(), PROC_INO, vfs::FileType::SymLink);
&mut ctx,
&fd.to_string(),
PROC_INO,
vfs::FileType::SymLink,
&mut total_written_len
);
} }
Ok(ctx.written_len())
Ok(total_written_len)
} }
} }

@ -115,29 +115,21 @@ impl DirProcINode for LockedPidDirINode {
fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result<usize> { fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result<usize> {
let file = self.0.read().unwrap(); let file = self.0.read().unwrap();
let mut total_written_len = 0;
let idx = ctx.pos(); let idx = ctx.pos();
// Write first two special entries // Write first two special entries
write_first_two_entries!(idx, &mut ctx, &file, &mut total_written_len); write_first_two_entries!(idx, &mut ctx, &file);
// Write the normal entries // Write the normal entries
let skipped = if idx < 2 { 0 } else { idx - 2 }; let skipped = if idx < 2 { 0 } else { idx - 2 };
for (name, inode) in file.entries.iter().skip(skipped) { for (name, inode) in file.entries.iter().skip(skipped) {
write_inode_entry!(&mut ctx, name, inode, &mut total_written_len); write_inode_entry!(&mut ctx, name, inode);
} }
// Write the fd entry // Write the fd entry
if idx <= 2 + file.entries.len() { if idx <= 2 + file.entries.len() {
write_entry!( write_entry!(&mut ctx, "fd", PROC_INO, vfs::FileType::Dir);
&mut ctx,
"fd",
PROC_INO,
vfs::FileType::Dir,
&mut total_written_len
);
} }
Ok(ctx.written_len())
Ok(total_written_len)
} }
} }

@ -66,52 +66,45 @@ macro_rules! impl_inode_for_file_or_symlink {
#[macro_export] #[macro_export]
macro_rules! write_first_two_entries { macro_rules! write_first_two_entries {
($idx: expr, $ctx:expr, $file:expr, $total_written:expr) => { ($idx: expr, $ctx:expr, $file:expr) => {
let idx = $idx; let idx = $idx;
let file = $file; let file = $file;
if idx == 0 { if idx == 0 {
let this_inode = file.this.upgrade().unwrap(); let this_inode = file.this.upgrade().unwrap();
write_inode_entry!($ctx, ".", &this_inode, $total_written); write_inode_entry!($ctx, ".", &this_inode);
} }
if idx <= 1 { if idx <= 1 {
write_inode_entry!($ctx, "..", &file.parent, $total_written); write_inode_entry!($ctx, "..", &file.parent);
} }
}; };
} }
#[macro_export] #[macro_export]
macro_rules! write_inode_entry { macro_rules! write_inode_entry {
($ctx:expr, $name:expr, $inode:expr, $total_written:expr) => { ($ctx:expr, $name:expr, $inode:expr) => {
let ctx = $ctx; let ctx = $ctx;
let name = $name; let name = $name;
let ino = $inode.metadata()?.inode; let ino = $inode.metadata()?.inode;
let type_ = $inode.metadata()?.type_; let type_ = $inode.metadata()?.type_;
let total_written = $total_written;
write_entry!(ctx, name, ino, type_, total_written); write_entry!(ctx, name, ino, type_);
}; };
} }
#[macro_export] #[macro_export]
macro_rules! write_entry { macro_rules! write_entry {
($ctx:expr, $name:expr, $ino:expr, $type_:expr, $total_written:expr) => { ($ctx:expr, $name:expr, $ino:expr, $type_:expr) => {
let ctx = $ctx; let ctx = $ctx;
let name = $name; let name = $name;
let ino = $ino; let ino = $ino;
let type_ = $type_; let type_ = $type_;
let total_written = $total_written;
match ctx.write_entry(name, ino as u64, type_) { if let Err(e) = ctx.write_entry(name, ino as u64, type_) {
Ok(written_len) => { if ctx.written_len() == 0 {
*total_written += written_len; return Err(e);
} } else {
Err(e) => { return Ok(ctx.written_len());
if *total_written == 0 {
return Err(e);
} else {
return Ok(*total_written);
}
} }
} }
}; };