Fix the potential deadlock issue of Ext2

This commit is contained in:
LI Qing 2024-05-23 13:50:33 +08:00 committed by Tate, Hongliang Tian
parent a1f36979d7
commit 68aebe4175

View File

@ -3,6 +3,8 @@
#![allow(dead_code)] #![allow(dead_code)]
#![allow(unused_variables)] #![allow(unused_variables)]
use alloc::rc::Rc;
use inherit_methods_macro::inherit_methods; use inherit_methods_macro::inherit_methods;
use super::{ use super::{
@ -79,6 +81,10 @@ impl Inode {
file_type: FileType, file_type: FileType,
file_perm: FilePerm, file_perm: FilePerm,
) -> Result<Arc<Self>> { ) -> Result<Arc<Self>> {
if name.len() > MAX_FNAME_LEN {
return_errno!(Errno::ENAMETOOLONG);
}
let inner = self.inner.upread(); let inner = self.inner.upread();
if inner.file_type() != FileType::Dir { if inner.file_type() != FileType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
@ -86,11 +92,7 @@ impl Inode {
if inner.hard_links() == 0 { if inner.hard_links() == 0 {
return_errno_with_message!(Errno::ENOENT, "dir removed"); return_errno_with_message!(Errno::ENOENT, "dir removed");
} }
if name.len() > MAX_FNAME_LEN { if inner.get_entry(name).is_some() {
return_errno!(Errno::ENAMETOOLONG);
}
if inner.get_entry(name, 0).is_some() {
return_errno!(Errno::EEXIST); return_errno!(Errno::EEXIST);
} }
@ -105,7 +107,7 @@ impl Inode {
let new_entry = DirEntry::new(inode.ino, name, file_type); let new_entry = DirEntry::new(inode.ino, name, file_type);
let mut inner = inner.upgrade(); let mut inner = inner.upgrade();
if let Err(e) = inner.append_entry(new_entry, 0) { if let Err(e) = inner.append_entry(new_entry) {
self.fs().free_inode(inode.ino, is_dir).unwrap(); self.fs().free_inode(inode.ino, is_dir).unwrap();
return Err(e); return Err(e);
} }
@ -113,6 +115,10 @@ impl Inode {
} }
pub fn lookup(&self, name: &str) -> Result<Arc<Self>> { pub fn lookup(&self, name: &str) -> Result<Arc<Self>> {
if name.len() > MAX_FNAME_LEN {
return_errno!(Errno::ENAMETOOLONG);
}
let inner = self.inner.read(); let inner = self.inner.read();
if inner.file_type() != FileType::Dir { if inner.file_type() != FileType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
@ -120,18 +126,17 @@ impl Inode {
if inner.hard_links() == 0 { if inner.hard_links() == 0 {
return_errno_with_message!(Errno::ENOENT, "dir removed"); return_errno_with_message!(Errno::ENOENT, "dir removed");
} }
if name.len() > MAX_FNAME_LEN {
return_errno!(Errno::ENAMETOOLONG);
}
let ino = inner let ino = inner.get_entry_ino(name).ok_or(Error::new(Errno::ENOENT))?;
.get_entry_ino(name, 0)
.ok_or(Error::new(Errno::ENOENT))?;
drop(inner); drop(inner);
self.fs().lookup_inode(ino) self.fs().lookup_inode(ino)
} }
pub fn link(&self, inode: &Inode, name: &str) -> Result<()> { pub fn link(&self, inode: &Inode, name: &str) -> Result<()> {
if name.len() > MAX_FNAME_LEN {
return_errno!(Errno::ENAMETOOLONG);
}
let inner = self.inner.upread(); let inner = self.inner.upread();
if inner.file_type() != FileType::Dir { if inner.file_type() != FileType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
@ -139,21 +144,19 @@ impl Inode {
if inner.hard_links() == 0 { if inner.hard_links() == 0 {
return_errno_with_message!(Errno::ENOENT, "dir removed"); return_errno_with_message!(Errno::ENOENT, "dir removed");
} }
if name.len() > MAX_FNAME_LEN {
return_errno!(Errno::ENAMETOOLONG);
}
let inode_type = inode.file_type(); let inode_type = inode.file_type();
if inode_type == FileType::Dir { if inode_type == FileType::Dir {
return_errno!(Errno::EPERM); return_errno!(Errno::EPERM);
} }
if inner.get_entry(name, 0).is_some() { if inner.get_entry(name).is_some() {
return_errno!(Errno::EEXIST); return_errno!(Errno::EEXIST);
} }
let new_entry = DirEntry::new(inode.ino, name, inode_type); let new_entry = DirEntry::new(inode.ino, name, inode_type);
let mut inner = inner.upgrade(); let mut inner = inner.upgrade();
inner.append_entry(new_entry, 0)?; inner.append_entry(new_entry)?;
drop(inner); drop(inner);
inode.inner.write().inc_hard_links(); inode.inner.write().inc_hard_links();
@ -161,65 +164,71 @@ impl Inode {
} }
pub fn unlink(&self, name: &str) -> Result<()> { pub fn unlink(&self, name: &str) -> Result<()> {
let inner = self.inner.upread();
if inner.file_type() != FileType::Dir {
return_errno!(Errno::ENOTDIR);
}
if inner.hard_links() == 0 {
return_errno_with_message!(Errno::ENOENT, "dir removed");
}
if name == "." || name == ".." { if name == "." || name == ".." {
return_errno!(Errno::EISDIR); return_errno!(Errno::EISDIR);
} }
if name.len() > MAX_FNAME_LEN {
return_errno!(Errno::ENAMETOOLONG);
}
let inode = { let file = self.lookup(name)?;
let ino = inner if file.file_type() == FileType::Dir {
.get_entry_ino(name, 0)
.ok_or(Error::new(Errno::ENOENT))?;
self.fs().lookup_inode(ino)?
};
if inode.file_type() == FileType::Dir {
return_errno!(Errno::EISDIR); return_errno!(Errno::EISDIR);
} }
let mut inner = inner.upgrade(); let (mut self_inner, mut file_inner) = write_lock_two_inodes(self, &file);
inner.remove_entry(name, 0)?; // When we got the lock, the dir may have been modified by another thread
drop(inner); if self_inner.hard_links() == 0 {
return_errno_with_message!(Errno::ENOENT, "dir removed");
}
let (offset, new_ino) = self_inner
.get_entry(name)
.map(|(offset, entry)| (offset, entry.ino()))
.ok_or(Error::new(Errno::ENOENT))?;
if file.ino != new_ino {
return_errno!(Errno::ENOENT);
}
let potential_new_file = self.fs().lookup_inode(file.ino)?;
if !Arc::ptr_eq(&file, &potential_new_file) {
return_errno!(Errno::ENOENT);
}
inode.inner.write().dec_hard_links(); self_inner.remove_entry_at(name, offset)?;
file_inner.dec_hard_links();
Ok(()) Ok(())
} }
pub fn rmdir(&self, name: &str) -> Result<()> { pub fn rmdir(&self, name: &str) -> Result<()> {
let self_inner = self.inner.upread();
if self_inner.file_type() != FileType::Dir {
return_errno!(Errno::ENOTDIR);
}
if self_inner.hard_links() == 0 {
return_errno_with_message!(Errno::ENOENT, "dir removed");
}
if name == "." { if name == "." {
return_errno_with_message!(Errno::EINVAL, "rmdir on ."); return_errno_with_message!(Errno::EINVAL, "rmdir on .");
} }
if name == ".." { if name == ".." {
return_errno_with_message!(Errno::ENOTEMPTY, "rmdir on .."); return_errno_with_message!(Errno::ENOTEMPTY, "rmdir on ..");
} }
if name.len() > MAX_FNAME_LEN {
return_errno!(Errno::ENAMETOOLONG); let dir_inode = self.lookup(name)?;
let dir_inner = dir_inode.inner.read();
if dir_inner.file_type() != FileType::Dir {
return_errno!(Errno::ENOTDIR);
} }
if dir_inner.entry_count() > 2 {
return_errno!(Errno::ENOTEMPTY);
}
drop(dir_inner);
let dir_inode = { let (mut self_inner, mut dir_inner) = write_lock_two_inodes(self, &dir_inode);
let ino = self_inner // When we got the lock, the dir may have been modified by another thread
.get_entry_ino(name, 0) if self_inner.hard_links() == 0 {
return_errno_with_message!(Errno::ENOENT, "dir removed");
}
let (offset, new_ino) = self_inner
.get_entry(name)
.map(|(offset, entry)| (offset, entry.ino()))
.ok_or(Error::new(Errno::ENOENT))?; .ok_or(Error::new(Errno::ENOENT))?;
self.fs().lookup_inode(ino)? if dir_inode.ino != new_ino {
}; return_errno!(Errno::ENOENT);
}
// FIXME: There may be a deadlock here. let potential_new_dir = self.fs().lookup_inode(dir_inode.ino)?;
let dir_inner = dir_inode.inner.upread(); if !Arc::ptr_eq(&dir_inode, &potential_new_dir) {
return_errno!(Errno::ENOENT);
}
if dir_inner.file_type() != FileType::Dir { if dir_inner.file_type() != FileType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
@ -227,11 +236,7 @@ impl Inode {
return_errno!(Errno::ENOTEMPTY); return_errno!(Errno::ENOTEMPTY);
} }
let mut self_inner = self_inner.upgrade(); self_inner.remove_entry_at(name, offset)?;
self_inner.remove_entry(name, 0)?;
drop(self_inner);
let mut dir_inner = dir_inner.upgrade();
dir_inner.dec_hard_links(); dir_inner.dec_hard_links();
dir_inner.dec_hard_links(); // For "." dir_inner.dec_hard_links(); // For "."
Ok(()) Ok(())
@ -247,29 +252,57 @@ impl Inode {
return_errno_with_message!(Errno::ENOENT, "dir removed"); return_errno_with_message!(Errno::ENOENT, "dir removed");
} }
let (src_offset, src_inode) = { let fs = self.fs();
let (src_offset, src_inode, src_inode_typ) = {
let (offset, entry) = self_inner let (offset, entry) = self_inner
.get_entry(old_name, 0) .get_entry(old_name)
.ok_or(Error::new(Errno::ENOENT))?; .ok_or(Error::new(Errno::ENOENT))?;
(offset, self.fs().lookup_inode(entry.ino())?) (offset, fs.lookup_inode(entry.ino())?, entry.type_())
}; };
let Some((dst_offset, dst_entry)) = self_inner.get_entry(new_name, 0) else { let Some(dst_ino) = self_inner.get_entry_ino(new_name) else {
let mut self_inner = self_inner.upgrade(); let mut self_inner = self_inner.upgrade();
self_inner.rename_entry(old_name, new_name, src_offset)?; self_inner.rename_entry_at(old_name, new_name, src_offset)?;
return Ok(()); return Ok(());
}; };
if src_inode.ino == dst_ino {
if src_inode.ino == dst_entry.ino() {
// Same inode, do nothing // Same inode, do nothing
return Ok(()); return Ok(());
} }
let dst_inode = fs.lookup_inode(dst_ino)?;
drop(self_inner);
let dst_inode = self.fs().lookup_inode(dst_entry.ino())?; let (mut self_inner, mut dst_inner) = write_lock_two_inodes(self, &dst_inode);
// FIXME: There may be a deadlock here. // When we got the lock, the dir may have been modified by another thread
let dst_inner = dst_inode.inner.upread(); if self_inner.hard_links() == 0 {
let dst_inode_type = dst_inner.file_type(); return_errno_with_message!(Errno::ENOENT, "dir removed");
match (src_inode.file_type(), dst_inode_type) { }
let (src_offset, new_src_ino) = self_inner
.get_entry(old_name)
.map(|(offset, entry)| (offset, entry.ino()))
.ok_or(Error::new(Errno::ENOENT))?;
if src_inode.ino != new_src_ino {
return_errno!(Errno::ENOENT);
}
let potential_new_src = fs.lookup_inode(src_inode.ino)?;
if !Arc::ptr_eq(&src_inode, &potential_new_src) {
return_errno!(Errno::ENOENT);
}
let (dst_offset, new_dst_entry) = self_inner
.get_entry(new_name)
.ok_or(Error::new(Errno::ENOENT))?;
if dst_inode.ino != new_dst_entry.ino() {
return_errno!(Errno::ENOENT);
}
let potential_new_dst = fs.lookup_inode(dst_inode.ino)?;
if !Arc::ptr_eq(&dst_inode, &potential_new_dst) {
return_errno!(Errno::ENOENT);
}
let dst_inode_typ = new_dst_entry.type_();
match (src_inode_typ, dst_inode_typ) {
(FileType::Dir, FileType::Dir) => { (FileType::Dir, FileType::Dir) => {
if dst_inner.entry_count() > 2 { if dst_inner.entry_count() > 2 {
return_errno!(Errno::ENOTEMPTY); return_errno!(Errno::ENOTEMPTY);
@ -283,16 +316,11 @@ impl Inode {
} }
_ => {} _ => {}
} }
let dst_is_dir = dst_inode_type == FileType::Dir;
let mut self_inner = self_inner.upgrade(); self_inner.remove_entry_at(new_name, dst_offset)?;
self_inner.remove_entry(new_name, dst_offset)?; self_inner.rename_entry_at(old_name, new_name, src_offset)?;
self_inner.rename_entry(old_name, new_name, src_offset)?;
drop(self_inner);
let mut dst_inner = dst_inner.upgrade();
dst_inner.dec_hard_links(); dst_inner.dec_hard_links();
if dst_is_dir { if dst_inode_typ == FileType::Dir {
dst_inner.dec_hard_links(); // For "." dst_inner.dec_hard_links(); // For "."
} }
@ -312,9 +340,7 @@ impl Inode {
return self.rename_within(old_name, new_name); return self.rename_within(old_name, new_name);
} }
// FIXME: There may be a deadlock here. let (self_inner, target_inner) = read_lock_two_inodes(self, target);
let self_inner = self.inner.upread();
let target_inner = target.inner.upread();
if self_inner.file_type() != FileType::Dir || target_inner.file_type() != FileType::Dir { if self_inner.file_type() != FileType::Dir || target_inner.file_type() != FileType::Dir {
return_errno!(Errno::ENOTDIR); return_errno!(Errno::ENOTDIR);
} }
@ -322,49 +348,108 @@ impl Inode {
return_errno_with_message!(Errno::ENOENT, "dir removed"); return_errno_with_message!(Errno::ENOENT, "dir removed");
} }
let (src_offset, src_inode) = { let fs = self.fs();
let (src_offset, src_inode, src_inode_typ) = {
let (offset, entry) = self_inner let (offset, entry) = self_inner
.get_entry(old_name, 0) .get_entry(old_name)
.ok_or(Error::new(Errno::ENOENT))?; .ok_or(Error::new(Errno::ENOENT))?;
(offset, self.fs().lookup_inode(entry.ino())?) (offset, fs.lookup_inode(entry.ino())?, entry.type_())
}; };
// Avoid renaming a directory to a subdirectory of itself // Avoid renaming a directory to a subdirectory of itself
if src_inode.ino == target.ino { if src_inode.ino == target.ino {
return_errno!(Errno::EINVAL); return_errno!(Errno::EINVAL);
} }
let src_inode_type = src_inode.file_type(); let is_dir = src_inode_typ == FileType::Dir;
let is_dir = src_inode_type == FileType::Dir;
let Some((dst_offset, dst_entry)) = target_inner.get_entry(new_name, 0) else { let Some(dst_ino) = target_inner.get_entry_ino(new_name) else {
let mut self_inner = self_inner.upgrade();
let mut target_inner = target_inner.upgrade();
self_inner.remove_entry(old_name, src_offset)?;
let new_entry = DirEntry::new(src_inode.ino, new_name, src_inode_type);
target_inner.append_entry(new_entry, 0)?;
drop(self_inner); drop(self_inner);
drop(target_inner); drop(target_inner);
let mut write_guards = if is_dir {
write_lock_multiple_inodes(vec![&src_inode, target, self])
} else {
write_lock_multiple_inodes(vec![target, self])
};
// When we got the lock, the dir may have been modified by another thread
let mut self_inner = write_guards.pop().unwrap();
let mut target_inner = write_guards.pop().unwrap();
if self_inner.hard_links() == 0 || target_inner.hard_links() == 0 {
return_errno_with_message!(Errno::ENOENT, "dir removed");
}
let (src_offset, new_src_ino) = self_inner
.get_entry(old_name)
.map(|(offset, entry)| (offset, entry.ino()))
.ok_or(Error::new(Errno::ENOENT))?;
if src_inode.ino != new_src_ino {
return_errno!(Errno::ENOENT);
}
let potential_new_src = fs.lookup_inode(src_inode.ino)?;
if !Arc::ptr_eq(&src_inode, &potential_new_src) {
return_errno!(Errno::ENOENT);
}
self_inner.remove_entry_at(old_name, src_offset)?;
let new_entry = DirEntry::new(src_inode.ino, new_name, src_inode_typ);
target_inner.append_entry(new_entry)?;
if is_dir { if is_dir {
src_inode.inner.write().set_parent_ino(target.ino)?; let mut src_inner = write_guards.pop().unwrap();
src_inner.set_parent_ino(target.ino)?;
} }
return Ok(()); return Ok(());
}; };
if src_inode.ino == dst_ino {
if src_inode.ino == dst_entry.ino() {
// Same inode, do nothing // Same inode, do nothing
return Ok(()); return Ok(());
} }
// Avoid renaming a subdirectory to a directory. // Avoid renaming a subdirectory to a directory.
if self.ino == dst_entry.ino() { if self.ino == dst_ino {
return_errno!(Errno::ENOTEMPTY); return_errno!(Errno::ENOTEMPTY);
} }
let dst_inode = fs.lookup_inode(dst_ino)?;
drop(self_inner);
drop(target_inner);
let dst_inode = self.fs().lookup_inode(dst_entry.ino())?; let mut write_guards = if is_dir {
// FIXME: There may be a deadlock here. write_lock_multiple_inodes(vec![&src_inode, &dst_inode, target, self])
let dst_inner = dst_inode.inner.upread(); } else {
let dst_inode_type = dst_inner.file_type(); write_lock_multiple_inodes(vec![&dst_inode, target, self])
match (src_inode_type, dst_inode_type) { };
// When we got the lock, the dir may have been modified by another thread
let mut self_inner = write_guards.pop().unwrap();
let mut target_inner = write_guards.pop().unwrap();
if self_inner.hard_links() == 0 || target_inner.hard_links() == 0 {
return_errno_with_message!(Errno::ENOENT, "dir removed");
}
let (src_offset, new_src_ino) = self_inner
.get_entry(old_name)
.map(|(offset, entry)| (offset, entry.ino()))
.ok_or(Error::new(Errno::ENOENT))?;
if src_inode.ino != new_src_ino {
return_errno!(Errno::ENOENT);
}
let potential_new_src = fs.lookup_inode(src_inode.ino)?;
if !Arc::ptr_eq(&src_inode, &potential_new_src) {
return_errno!(Errno::ENOENT);
}
let (dst_offset, new_dst_entry) = target_inner
.get_entry(new_name)
.ok_or(Error::new(Errno::ENOENT))?;
if dst_inode.ino != new_dst_entry.ino() {
return_errno!(Errno::ENOENT);
}
let potential_new_dst = fs.lookup_inode(dst_inode.ino)?;
if !Arc::ptr_eq(&dst_inode, &potential_new_dst) {
return_errno!(Errno::ENOENT);
}
let mut dst_inner = write_guards.pop().unwrap();
let dst_inode_typ = new_dst_entry.type_();
match (src_inode_typ, dst_inode_typ) {
(FileType::Dir, FileType::Dir) => { (FileType::Dir, FileType::Dir) => {
if dst_inner.entry_count() > 2 { if dst_inner.entry_count() > 2 {
return_errno!(Errno::ENOTEMPTY); return_errno!(Errno::ENOTEMPTY);
@ -378,24 +463,16 @@ impl Inode {
} }
_ => {} _ => {}
} }
let mut self_inner = self_inner.upgrade();
let mut target_inner = target_inner.upgrade();
self_inner.remove_entry(old_name, src_offset)?;
target_inner.remove_entry(new_name, dst_offset)?;
let new_entry = DirEntry::new(src_inode.ino, new_name, src_inode_type);
target_inner.append_entry(new_entry, 0)?;
drop(self_inner);
drop(target_inner);
let mut dst_inner = dst_inner.upgrade(); self_inner.remove_entry_at(old_name, src_offset)?;
target_inner.remove_entry_at(new_name, dst_offset)?;
let new_entry = DirEntry::new(src_inode.ino, new_name, src_inode_typ);
target_inner.append_entry(new_entry)?;
dst_inner.dec_hard_links(); dst_inner.dec_hard_links();
if is_dir { if is_dir {
dst_inner.dec_hard_links(); // For "." dst_inner.dec_hard_links(); // For "."
} let mut src_inner = write_guards.pop().unwrap();
drop(dst_inner); src_inner.set_parent_ino(target.ino)?;
if is_dir {
src_inode.inner.write().set_parent_ino(target.ino)?;
} }
Ok(()) Ok(())
@ -583,6 +660,48 @@ impl Debug for Inode {
} }
} }
fn read_lock_two_inodes<'a>(
this: &'a Inode,
other: &'a Inode,
) -> (RwMutexReadGuard<'a, Inner>, RwMutexReadGuard<'a, Inner>) {
if this.ino < other.ino {
let this = this.inner.read();
let other = other.inner.read();
(this, other)
} else {
let other = other.inner.read();
let this = this.inner.read();
(this, other)
}
}
fn write_lock_two_inodes<'a>(
this: &'a Inode,
other: &'a Inode,
) -> (RwMutexWriteGuard<'a, Inner>, RwMutexWriteGuard<'a, Inner>) {
let mut write_guards = write_lock_multiple_inodes(vec![this, other]);
let other_guard = write_guards.pop().unwrap();
let this_guard = write_guards.pop().unwrap();
(this_guard, other_guard)
}
fn write_lock_multiple_inodes(inodes: Vec<&Inode>) -> Vec<RwMutexWriteGuard<'_, Inner>> {
// Record the index information of the input
let mut ordered_inodes: Vec<(usize, &Inode)> = inodes.into_iter().enumerate().collect();
// Sort in ascending order of ino
ordered_inodes.sort_unstable_by_key(|&(_, inode)| inode.ino);
// Acquire the guards in order, and record by the input index.
// This ensures that the output order is consistent with the input.
let mut guards = vec![None; ordered_inodes.len()];
for (original_idx, inode) in ordered_inodes {
guards[original_idx] = Some(Rc::new(inode.inner.write()));
}
guards
.into_iter()
.map(|guard| Rc::into_inner(guard.unwrap()).unwrap())
.collect()
}
struct Inner { struct Inner {
inode_impl: Arc<InodeImpl>, inode_impl: Arc<InodeImpl>,
page_cache: PageCache, page_cache: PageCache,
@ -741,28 +860,28 @@ impl Inner {
} }
fn init_dir(&mut self, self_ino: u32, parent_ino: u32) -> Result<()> { fn init_dir(&mut self, self_ino: u32, parent_ino: u32) -> Result<()> {
self.append_entry(DirEntry::self_entry(self_ino), 0)?; self.append_entry(DirEntry::self_entry(self_ino))?;
self.append_entry(DirEntry::parent_entry(parent_ino), 0)?; self.append_entry(DirEntry::parent_entry(parent_ino))?;
Ok(()) Ok(())
} }
pub fn get_entry_ino(&self, name: &str, offset: usize) -> Option<u32> { pub fn get_entry_ino(&self, name: &str) -> Option<u32> {
self.get_entry(name, offset).map(|(_, entry)| entry.ino()) self.get_entry(name).map(|(_, entry)| entry.ino())
} }
pub fn get_entry(&self, name: &str, offset: usize) -> Option<(usize, DirEntry)> { pub fn get_entry(&self, name: &str) -> Option<(usize, DirEntry)> {
DirEntryReader::new(&self.page_cache, offset).find(|(offset, entry)| entry.name() == name) DirEntryReader::new(&self.page_cache, 0).find(|(offset, entry)| entry.name() == name)
} }
pub fn entry_count(&self) -> usize { pub fn entry_count(&self) -> usize {
DirEntryReader::new(&self.page_cache, 0).count() DirEntryReader::new(&self.page_cache, 0).count()
} }
pub fn append_entry(&mut self, entry: DirEntry, offset: usize) -> Result<()> { pub fn append_entry(&mut self, entry: DirEntry) -> Result<()> {
let is_dir = entry.type_() == FileType::Dir; let is_dir = entry.type_() == FileType::Dir;
let is_parent = entry.name() == ".."; let is_parent = entry.name() == "..";
DirEntryWriter::new(&self.page_cache, offset).append_entry(entry)?; DirEntryWriter::new(&self.page_cache, 0).append_entry(entry)?;
let file_size = self.inode_impl.file_size(); let file_size = self.inode_impl.file_size();
let page_cache_size = self.page_cache.pages().size(); let page_cache_size = self.page_cache.pages().size();
if page_cache_size > file_size { if page_cache_size > file_size {
@ -774,7 +893,7 @@ impl Inner {
Ok(()) Ok(())
} }
pub fn remove_entry(&mut self, name: &str, offset: usize) -> Result<()> { pub fn remove_entry_at(&mut self, name: &str, offset: usize) -> Result<()> {
let entry = DirEntryWriter::new(&self.page_cache, offset).remove_entry(name)?; let entry = DirEntryWriter::new(&self.page_cache, offset).remove_entry(name)?;
let is_dir = entry.type_() == FileType::Dir; let is_dir = entry.type_() == FileType::Dir;
let file_size = self.inode_impl.file_size(); let file_size = self.inode_impl.file_size();
@ -788,7 +907,7 @@ impl Inner {
Ok(()) Ok(())
} }
pub fn rename_entry(&mut self, old_name: &str, new_name: &str, offset: usize) -> Result<()> { pub fn rename_entry_at(&mut self, old_name: &str, new_name: &str, offset: usize) -> Result<()> {
DirEntryWriter::new(&self.page_cache, offset).rename_entry(old_name, new_name)?; DirEntryWriter::new(&self.page_cache, offset).rename_entry(old_name, new_name)?;
let file_size = self.inode_impl.file_size(); let file_size = self.inode_impl.file_size();
let page_cache_size = self.page_cache.pages().size(); let page_cache_size = self.page_cache.pages().size();
@ -799,7 +918,7 @@ impl Inner {
} }
pub fn set_parent_ino(&mut self, parent_ino: u32) -> Result<()> { pub fn set_parent_ino(&mut self, parent_ino: u32) -> Result<()> {
let (offset, mut entry) = self.get_entry("..", 0).unwrap(); let (offset, mut entry) = self.get_entry("..").unwrap();
entry.set_ino(parent_ino); entry.set_ino(parent_ino);
DirEntryWriter::new(&self.page_cache, offset).write_entry(&entry)?; DirEntryWriter::new(&self.page_cache, offset).write_entry(&entry)?;
Ok(()) Ok(())