diff --git a/kernel/driver/fs/ext2/src/data.rs b/kernel/driver/fs/ext2/src/data.rs index b0b0d6dc..885925b8 100644 --- a/kernel/driver/fs/ext2/src/data.rs +++ b/kernel/driver/fs/ext2/src/data.rs @@ -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(), diff --git a/kernel/driver/fs/ext2/src/dir/mod.rs b/kernel/driver/fs/ext2/src/dir/mod.rs index 108627d2..910eee86 100644 --- a/kernel/driver/fs/ext2/src/dir/mod.rs +++ b/kernel/driver/fs/ext2/src/dir/mod.rs @@ -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> { diff --git a/kernel/driver/fs/ext2/src/inode/cache.rs b/kernel/driver/fs/ext2/src/inode/cache.rs index 548558c0..f8a6d814 100644 --- a/kernel/driver/fs/ext2/src/inode/cache.rs +++ b/kernel/driver/fs/ext2/src/inode/cache.rs @@ -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 diff --git a/kernel/driver/fs/ext2/src/lib.rs b/kernel/driver/fs/ext2/src/lib.rs index ed50efcb..c077d7c5 100644 --- a/kernel/driver/fs/ext2/src/lib.rs +++ b/kernel/driver/fs/ext2/src/lib.rs @@ -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,