Skip to content

Commit a1e09a5

Browse files
feat(ext2): optimize DirEntryIter
* Read a block at a time since a directory entry cannot span between multiple data blocks. * Only allocate once, ie, on the creation of the iterator. * Reuse the same allocated chunk for the rest of the items. * Return a mutable reference instead of an owned allocated item (expensive). Signed-off-by: Anhad Singh <[email protected]>
1 parent c1455ba commit a1e09a5

File tree

3 files changed

+73
-32
lines changed

3 files changed

+73
-32
lines changed

src/aero_kernel/src/fs/ext2/disk.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,16 @@ impl DirEntry {
162162
let name_bytes = unsafe { self.name.as_mut_slice(name.len()) };
163163
name_bytes.copy_from_slice(name.as_bytes());
164164
}
165+
166+
pub fn name(&self) -> &str {
167+
unsafe { core::str::from_utf8_unchecked(self.name.as_slice(self.name_size as usize)) }
168+
}
169+
170+
#[inline]
171+
pub fn is_used(&self) -> bool {
172+
// value of 0 indicates that the entry is not used
173+
self.inode != 0
174+
}
165175
}
166176

167177
#[repr(u8)]

src/aero_kernel/src/fs/ext2/mod.rs

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use super::cache::{DirCacheItem, INodeCacheItem};
4343
use super::path::PathBuf;
4444
use super::{cache, FileSystemError, Path};
4545

46-
use super::inode::{DirEntry, INodeInterface, Metadata, PollFlags, PollTable};
46+
use super::inode::{self, INodeInterface, Metadata, PollFlags, PollTable};
4747
use super::FileSystem;
4848

4949
pub struct INode {
@@ -301,6 +301,7 @@ impl INode {
301301
entry.entry_size = block_size as _;
302302
entry.inode = inode.id as _;
303303
entry.file_type = file_type;
304+
// JSDJFKDSJFHJK CHECK THIS this is ub
304305
entry.set_name(name);
305306
}
306307

@@ -314,7 +315,7 @@ impl INode {
314315
return Err(FileSystemError::NotDirectory);
315316
}
316317

317-
if DirEntryIter::new(self.sref()).any(|(e, _)| e == name) {
318+
if DirEntryIter::new(self.sref()).any(|entry| entry.name() == name) {
318319
return Err(FileSystemError::EntryExists);
319320
}
320321

@@ -349,7 +350,7 @@ impl INode {
349350
entry: &disk::DirEntry,
350351
) -> Option<DirCacheItem> {
351352
let inode = self.fs.upgrade()?.find_inode(entry.inode as usize, None)?;
352-
Some(DirEntry::new(parent, inode, name.to_string()))
353+
Some(inode::DirEntry::new(parent, inode, name.to_string()))
353354
}
354355

355356
pub fn sref(&self) -> Arc<INode> {
@@ -410,19 +411,19 @@ impl INodeInterface for INode {
410411
}
411412

412413
fn dirent(&self, parent: DirCacheItem, index: usize) -> super::Result<Option<DirCacheItem>> {
413-
if let Some((name, entry)) = DirEntryIter::new(self.sref()).nth(index) {
414-
Ok(self.make_dirent(parent, &name, &entry))
414+
if let Some(entry) = DirEntryIter::new(self.sref()).nth(index) {
415+
Ok(self.make_dirent(parent, entry.name(), entry))
415416
} else {
416417
Ok(None)
417418
}
418419
}
419420

420421
fn lookup(&self, parent: DirCacheItem, name: &str) -> super::Result<DirCacheItem> {
421-
let (name, entry) = DirEntryIter::new(self.sref())
422-
.find(|(ename, _)| ename == name)
422+
let entry = DirEntryIter::new(self.sref())
423+
.find(|entry| entry.name() == name)
423424
.ok_or(FileSystemError::EntryNotFound)?;
424425

425-
Ok(self.make_dirent(parent, &name, &entry).unwrap())
426+
Ok(self.make_dirent(parent, entry.name(), entry).unwrap())
426427
}
427428

428429
fn read_at(&self, offset: usize, usr_buffer: &mut [u8]) -> super::Result<usize> {
@@ -456,7 +457,7 @@ impl INodeInterface for INode {
456457
fn rename(&self, old: DirCacheItem, dest: &str) -> super::Result<()> {
457458
assert!(self.metadata()?.is_directory());
458459

459-
if DirEntryIter::new(self.sref()).any(|(name, _)| name == dest) {
460+
if DirEntryIter::new(self.sref()).any(|entry| entry.name() == dest) {
460461
return Err(FileSystemError::EntryExists);
461462
}
462463

@@ -504,7 +505,7 @@ impl INodeInterface for INode {
504505
}
505506

506507
let inode = self.make_inode(name, FileType::File, None)?;
507-
Ok(DirEntry::new(parent, inode, name.to_string()))
508+
Ok(inode::DirEntry::new(parent, inode, name.to_string()))
508509
}
509510

510511
fn mkdir(&self, name: &str) -> super::Result<INodeCacheItem> {
@@ -645,46 +646,66 @@ impl INodeInterface for INode {
645646
}
646647
}
647648

648-
pub struct DirEntryIter {
649+
pub struct DirEntryIter<'a> {
649650
inode: Arc<INode>,
650651
offset: usize,
652+
653+
current_block: Box<[MaybeUninit<u8>]>,
654+
block_size: usize,
655+
_phantom: core::marker::PhantomData<&'a disk::DirEntry>,
651656
}
652657

653-
impl DirEntryIter {
658+
impl<'a> DirEntryIter<'a> {
654659
pub fn new(inode: Arc<INode>) -> Self {
655-
Self { inode, offset: 0 }
660+
let block_size = inode.fs.upgrade().unwrap().superblock.block_size();
661+
let buf = Box::<[u8]>::new_uninit_slice(block_size);
662+
663+
Self {
664+
inode,
665+
offset: 0,
666+
current_block: buf,
667+
block_size,
668+
669+
_phantom: core::marker::PhantomData,
670+
}
656671
}
657672
}
658673

659-
impl Iterator for DirEntryIter {
660-
type Item = (String, block::DirtyRef<disk::DirEntry>);
674+
impl<'a> Iterator for DirEntryIter<'a> {
675+
type Item = &'a mut disk::DirEntry;
661676

662677
fn next(&mut self) -> Option<Self::Item> {
678+
// Read 1 block at a time.
679+
//
680+
// XXX: A directory entry cannot span between multiple data blocks.
663681
let file_size = self.inode.inode.read().size();
664682

665683
if self.offset + core::mem::size_of::<disk::DirEntry>() > file_size {
666684
return None;
667685
}
668686

669-
let entry = unsafe { self.inode.read_mut::<disk::DirEntry>(self.offset) };
670-
if entry.inode == 0 {
671-
return None;
687+
let block_offset = self.offset % self.block_size;
688+
if block_offset == 0 {
689+
self.inode
690+
.read(self.offset, &mut self.current_block)
691+
.unwrap();
672692
}
673693

674-
let mut name = Box::<[u8]>::new_uninit_slice(entry.name_size as usize);
675-
self.inode
676-
.read(
677-
self.offset + core::mem::size_of::<disk::DirEntry>(),
678-
MaybeUninit::slice_as_bytes_mut(&mut name),
679-
)
680-
.ok()?;
694+
// SAFETY: We have initialized the current block above.
695+
let entry = unsafe {
696+
&mut *self
697+
.current_block
698+
.as_mut_ptr()
699+
.add(block_offset)
700+
.cast::<disk::DirEntry>()
701+
};
681702

682-
// SAFETY: We have initialized the name above.
683-
let name = unsafe { name.assume_init() };
684-
let name = unsafe { core::str::from_utf8_unchecked(&name) };
703+
if !entry.is_used() {
704+
return None;
705+
}
685706

686707
self.offset += entry.entry_size as usize;
687-
Some((name.to_string(), entry))
708+
Some(entry)
688709
}
689710
}
690711

@@ -747,6 +768,6 @@ impl FileSystem for Ext2 {
747768
.find_inode(Ext2::ROOT_INODE_ID, None)
748769
.expect("ext2: invalid filesystem (root inode not found)");
749770

750-
DirEntry::new_root(inode, String::from("/"))
771+
inode::DirEntry::new_root(inode, String::from("/"))
751772
}
752773
}

src/aero_kernel/src/utils/mod.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use core::alloc::Layout;
2121
use core::any::Any;
2222
use core::cell::UnsafeCell;
2323
use core::marker::PhantomData;
24-
use core::mem;
2524
use core::ptr::Unique;
25+
use core::{mem, ptr};
2626

2727
use crate::mem::paging::{align_down, ReadErr, VirtAddr};
2828

@@ -244,11 +244,21 @@ pub struct IncompleteArrayField<T>(PhantomData<T>, [T; 0]);
244244
impl<T> IncompleteArrayField<T> {
245245
#[inline]
246246
pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
247-
self as *mut _ as *mut T
247+
ptr::from_mut(self).cast::<T>()
248+
}
249+
250+
#[inline]
251+
pub unsafe fn as_ptr(&self) -> *const T {
252+
ptr::from_ref(self).cast::<T>()
248253
}
249254

250255
#[inline]
251256
pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
252257
core::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
253258
}
259+
260+
#[inline]
261+
pub unsafe fn as_slice(&self, len: usize) -> &[T] {
262+
core::slice::from_raw_parts(self.as_ptr(), len)
263+
}
254264
}

0 commit comments

Comments
 (0)