[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, "");
}
let mut writer = DirentBufWriter::<T>::new(buf);
let written_size = file_ref.iterate_entries(&mut writer)?;
Ok(written_size)
let written_len = file_ref.iterate_entries(&mut writer)?;
Ok(written_len)
}
struct DirentBufWriter<'a, T: Dirent> {
buf: &'a mut [u8],
written_size: usize,
written_len: usize,
phantom: PhantomData<T>,
}
@ -37,40 +37,34 @@ impl<'a, T: Dirent> DirentBufWriter<'a, T> {
fn new(buf: &'a mut [u8]) -> Self {
Self {
buf,
written_size: 0,
written_len: 0,
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> {
fn write_entry(
&mut self,
name: &str,
ino: u64,
type_: FileType,
) -> rcore_fs::vfs::Result<usize> {
let written_len = self
.try_write(&name, ino, type_)
fn write_entry(&mut self, name: &str, ino: u64, type_: FileType) -> rcore_fs::vfs::Result<()> {
let dirent: T = Dirent::new(name, ino, type_);
if self.buf.len() - self.written_len < dirent.rec_len() {
return Err(FsError::InvalidParam);
}
dirent
.serialize(&mut self.buf[self.written_len..], name, type_)
.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 {
fn new(name: &str, ino: u64, type_: FileType) -> Self;
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
@ -106,7 +100,7 @@ impl Dirent for LinuxDirent64 {
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 {
let ptr = buf.as_mut_ptr() as *mut Self;
ptr.write(*self);
@ -154,7 +148,7 @@ impl Dirent for LinuxDirent {
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 {
let ptr = buf.as_mut_ptr() as *mut Self;
ptr.write(*self);

@ -269,10 +269,9 @@ impl INode for HNode {
return Err(FsError::NotDir);
}
let idx = ctx.pos();
let mut total_written_len = 0;
for entry in try_std!(self.path.read_dir()).skip(idx) {
let entry = try_std!(entry);
let written_len = match ctx.write_entry(
if let Err(e) = ctx.write_entry(
&entry
.file_name()
.into_string()
@ -283,18 +282,14 @@ impl INode for HNode {
.map_err(|_| FsError::InvalidParam)?
.into_fs_filetype(),
) {
Ok(written_len) => written_len,
Err(e) => {
if total_written_len == 0 {
if ctx.written_len() == 0 {
return Err(e);
} else {
break;
}
}
};
total_written_len += written_len;
}
Ok(total_written_len)
Ok(ctx.written_len())
}
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> {
let file = self.0.read().unwrap();
let mut total_written_len = 0;
let idx = ctx.pos();
// Write first two special entries
if idx == 0 {
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 {
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
let skipped = if idx < 2 { 0 } else { idx - 2 };
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
@ -192,11 +191,10 @@ impl DirProcINode for LockedProcRootINode {
&mut ctx,
&process.pid().to_string(),
PROC_INO,
vfs::FileType::Dir,
&mut total_written_len
vfs::FileType::Dir
);
}
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> {
let file = self.0.read().unwrap();
let mut total_written_len = 0;
let idx = ctx.pos();
// 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
let skipped = if idx < 2 { 0 } else { idx - 2 };
let main_thread = match file.process_ref.main_thread() {
Some(main_thread) => main_thread,
None => {
return Ok(total_written_len);
return Ok(ctx.written_len());
}
};
let fds = main_thread.files().lock().unwrap().fds();
for fd in fds.iter().skip(skipped) {
write_entry!(
&mut ctx,
&fd.to_string(),
PROC_INO,
vfs::FileType::SymLink,
&mut total_written_len
);
write_entry!(&mut ctx, &fd.to_string(), PROC_INO, vfs::FileType::SymLink);
}
Ok(total_written_len)
Ok(ctx.written_len())
}
}

@ -115,29 +115,21 @@ impl DirProcINode for LockedPidDirINode {
fn iterate_entries(&self, mut ctx: &mut DirentWriterContext) -> vfs::Result<usize> {
let file = self.0.read().unwrap();
let mut total_written_len = 0;
let idx = ctx.pos();
// 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
let skipped = if idx < 2 { 0 } else { idx - 2 };
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
if idx <= 2 + file.entries.len() {
write_entry!(
&mut ctx,
"fd",
PROC_INO,
vfs::FileType::Dir,
&mut total_written_len
);
write_entry!(&mut ctx, "fd", PROC_INO, vfs::FileType::Dir);
}
Ok(total_written_len)
Ok(ctx.written_len())
}
}

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