ext2: check for inode deletion before pulling from cache

This commit is contained in:
Mark Poliakov 2025-01-02 13:47:14 +02:00
parent 68d0568af3
commit 17e2fba8b7
4 changed files with 44 additions and 25 deletions

View File

@ -241,6 +241,10 @@ impl Inode {
unsafe { GroupId::from_raw(self.uid as _) }
}
pub fn is_deleted(&self) -> bool {
self.hard_links == 0
}
pub fn metadata(&self, fs: &Ext2Fs, ino: u32) -> Metadata {
Metadata {
uid: self.user_id(),

View File

@ -170,19 +170,9 @@ impl DirectoryNode {
let child = InodeAccess::new(self.inode.cache().clone(), ino);
child.link().await?;
let ty = child
.amap_mut(async |child_inode| {
// Get child inode type indicator which may or may not be used in the dirent
let ty = child_inode
.mode
.dirent_indicator()
.ok_or(Error::InvalidArgument)?;
child_inode.inc_hard_count();
child_inode.dtime = 0;
Ok(ty)
})
.map(|inode| inode.mode.dirent_indicator().ok_or(Error::InvalidArgument))
.await?;
// Insert the entry
@ -195,7 +185,9 @@ impl DirectoryNode {
// Otherwise, allocate a new block and extend the directory
extend(inode, &self.fs, name, ino, ty).await
})
.await
.await?;
Ok(())
}
async fn prepare_for_removal(&self) -> Result<(), Error> {

View File

@ -46,7 +46,7 @@ impl InodeAccess {
&self,
mapper: F,
) -> Result<T, Error> {
let inode = self.inode_cache.entry(self.ino).await?;
let inode = self.inode_cache.get(self.ino).await?;
let lock = inode.read();
mapper(&lock.inode)
}
@ -55,7 +55,7 @@ impl InodeAccess {
&self,
mapper: F,
) -> Result<T, Error> {
let inode = self.inode_cache.entry(self.ino).await?;
let inode = self.inode_cache.get(self.ino).await?;
let mut lock = inode.write();
let result = mapper(&mut lock.inode);
self.inode_cache.put(self.ino, &mut lock).await?;
@ -66,7 +66,7 @@ impl InodeAccess {
&self,
mapper: F,
) -> Result<T, Error> {
let inode = self.inode_cache.entry(self.ino).await?;
let inode = self.inode_cache.get(self.ino).await?;
let lock = inode.read();
mapper(&lock.inode).await
}
@ -75,7 +75,7 @@ impl InodeAccess {
&self,
mapper: F,
) -> Result<T, Error> {
let inode = self.inode_cache.entry(self.ino).await?;
let inode = self.inode_cache.get(self.ino).await?;
let mut lock = inode.write();
let result = mapper(&mut lock.inode).await;
self.inode_cache.put(self.ino, &mut lock).await?;
@ -176,6 +176,7 @@ impl InodeAccess {
) -> Result<NodeRef, Error> {
log::info!("ext2: allocated inode #{ino}");
let cache = fs.inode_cache.get().clone();
let now = real_time().seconds as u32;
let mut imode = InodeMode::default_for_type(ty);
@ -193,7 +194,7 @@ impl InodeAccess {
)
.await?;
let this = InodeAccess::new(fs.inode_cache.get().clone(), ino);
let this = InodeAccess::new(cache, ino);
let fs = fs.clone();
let node = match ty {
FileType::Directory => DirectoryNode::create(fs, this, parent_ino).await?,
@ -205,6 +206,15 @@ impl InodeAccess {
Ok(node)
}
pub async fn link(&self) -> Result<(), Error> {
let inode = self.inode_cache.entry(self.ino, true).await?;
let mut inode = inode.write();
inode.hard_links += 1;
inode.dtime = 0;
self.inode_cache.put(self.ino, &mut inode).await?;
Ok(())
}
pub async fn allocate(
fs: &Arc<Ext2Fs>,
ty: FileType,
@ -256,22 +266,35 @@ impl InodeCache {
Ok(())
}
async fn fetch_inode(&self, ino: u32) -> Result<Arc<IrqSafeRwLock<InodeHolder>>, Error> {
async fn fetch_inode(
&self,
ino: u32,
allow_deleted: bool,
) -> Result<Arc<IrqSafeRwLock<InodeHolder>>, Error> {
let inode = self.fs.read_inode(ino).await?;
if inode.is_deleted() && !allow_deleted {
return Err(Error::DoesNotExist);
}
Ok(Arc::new(IrqSafeRwLock::new(InodeHolder {
inode,
dirty: false,
})))
}
async fn entry(&self, ino: u32) -> Result<Arc<IrqSafeRwLock<InodeHolder>>, Error> {
async fn entry(
&self,
ino: u32,
allow_deleted: bool,
) -> Result<Arc<IrqSafeRwLock<InodeHolder>>, Error> {
if ino < 1 || ino > self.fs.total_inodes {
return Err(Error::InvalidFile);
}
let mut lock = self.cache.lock().await;
let (value, evicted) = lock
.try_get_or_insert_with_async(ino, || self.fetch_inode(ino))
.try_get_or_insert_with_async(ino, || self.fetch_inode(ino, allow_deleted))
.await?;
let value = value.clone();
@ -284,6 +307,10 @@ impl InodeCache {
Ok(value)
}
async fn get(&self, ino: u32) -> Result<Arc<IrqSafeRwLock<InodeHolder>>, Error> {
self.entry(ino, false).await
}
async fn put(&self, ino: u32, holder: &mut InodeHolder) -> Result<(), Error> {
if self.synchronous {
// Immediately write-back

View File

@ -272,10 +272,6 @@ impl Ext2Fs {
inode_cache: OneTimeInit::new(),
sb_position: data::SUPERBLOCK_OFFSET,
// state: IrqSafeRwLock::new(State {
// superblock,
// dirty: false,
// }),
bgdt,
required_features,