Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions kernel/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion kernel/crates/kdepends/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ crc = { path = "../crc" }
memoffset = "0.9.0"
ringbuffer = "0.15.0"
xarray = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/xarray", rev = "de93b57c34", features = ["slab-friendly"] }
another_ext4 = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/another_ext4.git", rev = "bf782ff294", default-features = false }
another_ext4 = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/another_ext4.git", rev = "8bc384254c", default-features = false }

# 一个无锁MPSC队列
[dependencies.thingbuf]
Expand Down
27 changes: 19 additions & 8 deletions kernel/src/filesystem/ext4/filesystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,29 @@ impl FileSystem for Ext4FileSystem {
}

impl Ext4FileSystem {
/// 探测 gendisk 是否包含 ext4 文件系统
pub fn probe(gendisk: &Arc<GenDisk>) -> Result<bool, SystemError> {
Ok(another_ext4::Ext4::load(gendisk.clone())
.map(|_| true)
.unwrap_or(false))
}

pub fn from_gendisk(mount_data: Arc<GenDisk>) -> Result<Arc<dyn FileSystem>, SystemError> {
let raw_dev = mount_data.device_num();
let fs = another_ext4::Ext4::load(mount_data)?;
let root_inode: Arc<LockedExt4Inode> =
Arc::new(LockedExt4Inode(SpinLock::new(Ext4Inode {
inner_inode_num: another_ext4::EXT4_ROOT_INO,
fs_ptr: Weak::default(),
page_cache: None,
children: BTreeMap::new(),
dname: DName::from("/"),
vfs_inode_id: generate_inode_id(),
})));
Arc::new_cyclic(|self_ref: &Weak<LockedExt4Inode>| {
LockedExt4Inode(SpinLock::new(Ext4Inode {
inner_inode_num: another_ext4::EXT4_ROOT_INO,
fs_ptr: Weak::default(),
page_cache: None,
children: BTreeMap::new(),
dname: DName::from("/"),
vfs_inode_id: generate_inode_id(),
parent: self_ref.clone(),
self_ref: self_ref.clone(),
}))
});

let fs = Arc::new(Ext4FileSystem {
fs,
Expand Down
21 changes: 15 additions & 6 deletions kernel/src/filesystem/ext4/gendisk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@ use alloc::boxed::Box;
use kdepends::another_ext4;
use system_error::SystemError;

use crate::driver::base::block::block_device::LBA_SIZE;
use crate::driver::base::block::gendisk::GenDisk;

impl GenDisk {
fn convert_from_ext4_blkid(&self, ext4_blkid: u64) -> (usize, usize, usize) {
let size = self.block_size_log2();
let start_block_offset =
ext4_blkid as usize * (another_ext4::BLOCK_SIZE / (1 << size as usize));
let lba_id_start = self.block_offset_2_disk_blkid(start_block_offset);
let block_count = another_ext4::BLOCK_SIZE / (1 << size as usize);
(start_block_offset, lba_id_start, block_count)
// another_ext4 的逻辑块固定为 4096 字节(another_ext4::BLOCK_SIZE)。
//
// DragonOS 块设备的“LBA”语义固定为 512 字节(LBA_SIZE)。
// GenDisk::block_offset_2_disk_blkid() 与 BlockDevice::read_at()/write_at()
// 都是以 512B LBA 为单位进行寻址的。
//
// 因此这里必须把 ext4 的 4K block id 转成“512B LBA 偏移”,
// 不能使用底层设备的 blk_size_log2(否则当设备上报 4K 物理块时会导致寻址单位混乱,
// 进而读到错误数据,表现为 extent tree 解析失败/随机 ENOENT)。
let blocks_per_ext4_block = another_ext4::BLOCK_SIZE / LBA_SIZE;
let start_lba_offset = ext4_blkid as usize * blocks_per_ext4_block;
let lba_id_start = self.block_offset_2_disk_blkid(start_lba_offset);
let block_count = blocks_per_ext4_block;
(start_lba_offset, lba_id_start, block_count)
}
}

Expand Down
184 changes: 130 additions & 54 deletions kernel/src/filesystem/ext4/inode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ pub struct Ext4Inode {

// 对应vfs的inode id,用于标识系统中唯一的inode
pub(super) vfs_inode_id: InodeId,

// 指向父级IndexNode的Weak指针
pub(super) parent: Weak<LockedExt4Inode>,

// 指向自身的Weak指针,用于获取Arc<Self>
pub(super) self_ref: Weak<LockedExt4Inode>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -71,7 +77,14 @@ impl IndexNode for LockedExt4Inode {
another_ext4::InodeMode::from_bits_truncate(file_mode.bits() as u16),
)?;
let dname = DName::from(name);
let inode = LockedExt4Inode::new(id, guard.fs_ptr.clone(), dname.clone());
// 通过self_ref获取Arc<Self>,然后转换为Arc<dyn IndexNode>
let self_arc = guard.self_ref.upgrade().ok_or(SystemError::ENOENT)?;
let inode = LockedExt4Inode::new(
id,
guard.fs_ptr.clone(),
dname.clone(),
Some(Arc::downgrade(&self_arc)),
);
// 更新 children 缓存
guard.children.insert(dname, inode.clone());
drop(guard);
Expand Down Expand Up @@ -99,42 +112,56 @@ impl IndexNode for LockedExt4Inode {
buf: &mut [u8],
data: PrivateData,
) -> Result<usize, SystemError> {
let guard = self.0.lock();

let len = core::cmp::min(len, buf.len());
let buf = &mut buf[0..len];
let ext4 = &guard.concret_fs().fs;
if let Some(page_cache) = &guard.page_cache {

// 关键修复:不要在持有 Ext4 inode 自旋锁期间调用 PageCache::{read,write}。
// PageCache 读写路径内部会调用 inode.metadata() 获取文件大小:
// - prepare_read(): inode.metadata()
// 若此处持有 inode 锁,则会在 metadata() 再次尝试获取同一把锁而自旋死锁。
let (fs, inode_num, page_cache) = {
let guard = self.0.lock();
(
guard.concret_fs(),
guard.inner_inode_num,
guard.page_cache.clone(),
)
};

if let Some(page_cache) = page_cache {
let time = PosixTimeSpec::now().tv_sec.to_u32().unwrap_or_else(|| {
log::warn!("Failed to get current time, using 0");
0
});
ext4.setattr(
guard.inner_inode_num,
None,
None,
None,
None,
Some(time),
None,
None,
None,
)
.map_err(SystemError::from)?;
fs.fs
.setattr(
inode_num,
None,
None,
None,
None,
Some(time),
None,
None,
None,
)
.map_err(SystemError::from)?;
page_cache.read(offset, buf)
} else {
self.read_direct(offset, len, buf, data)
}
}

fn read_sync(&self, offset: usize, buf: &mut [u8]) -> Result<usize, SystemError> {
let guard = self.0.lock();
let ext4 = &guard.concret_fs().fs;
let inode_num = guard.inner_inode_num;
match ext4.getattr(inode_num)?.ftype {
let (fs, inode_num) = {
let guard = self.0.lock();
(guard.concret_fs(), guard.inner_inode_num)
};
match fs.fs.getattr(inode_num)?.ftype {
FileType::Directory => Err(SystemError::EISDIR),
FileType::Unknown => Err(SystemError::EROFS),
FileType::RegularFile => ext4.read(inode_num, offset, buf).map_err(From::from),
FileType::RegularFile => fs.fs.read(inode_num, offset, buf).map_err(From::from),
FileType::SymLink => fs.fs.readlink(inode_num, offset, buf).map_err(From::from),
_ => Err(SystemError::EINVAL),
}
}
Expand All @@ -157,44 +184,54 @@ impl IndexNode for LockedExt4Inode {
buf: &[u8],
data: PrivateData,
) -> Result<usize, SystemError> {
let guard = self.0.lock();
let ext4 = &guard.concret_fs().fs;
let len = core::cmp::min(len, buf.len());
let buf = &buf[0..len];
if let Some(page_cache) = &guard.page_cache {
let write_len = PageCache::write(page_cache, offset, buf)?;
let old_file_size = ext4.getattr(guard.inner_inode_num)?.size;

let (fs, inode_num, page_cache) = {
let guard = self.0.lock();
(
guard.concret_fs(),
guard.inner_inode_num,
guard.page_cache.clone(),
)
};

if let Some(page_cache) = page_cache {
let write_len = PageCache::write(&page_cache, offset, buf)?;
let old_file_size = fs.fs.getattr(inode_num)?.size;
let current_file_size = core::cmp::max(old_file_size, (offset + write_len) as u64);
let time = PosixTimeSpec::now().tv_sec.to_u32().unwrap_or_else(|| {
log::warn!("Failed to get current time, using 0");
0
});
ext4.setattr(
guard.inner_inode_num,
None,
None,
None,
Some(current_file_size),
None,
Some(time),
None,
None,
)
.map_err(SystemError::from)?;
fs.fs
.setattr(
inode_num,
None,
None,
None,
Some(current_file_size),
None,
Some(time),
None,
None,
)
.map_err(SystemError::from)?;
Ok(write_len)
} else {
self.write_direct(offset, len, buf, data)
}
}

fn write_sync(&self, offset: usize, buf: &[u8]) -> Result<usize, SystemError> {
let guard = self.0.lock();
let ext4 = &guard.concret_fs().fs;
let inode_num = guard.inner_inode_num;
match ext4.getattr(inode_num)?.ftype {
let (fs, inode_num) = {
let guard = self.0.lock();
(guard.concret_fs(), guard.inner_inode_num)
};
match fs.fs.getattr(inode_num)?.ftype {
FileType::Directory => Err(SystemError::EISDIR),
FileType::Unknown => Err(SystemError::EROFS),
FileType::RegularFile => ext4.write(inode_num, offset, buf).map_err(From::from),
FileType::RegularFile => fs.fs.write(inode_num, offset, buf).map_err(From::from),
_ => Err(SystemError::EINVAL),
}
}
Expand Down Expand Up @@ -225,11 +262,31 @@ impl IndexNode for LockedExt4Inode {
return Ok(child.clone() as Arc<dyn IndexNode>);
}
let next_inode = guard.concret_fs().fs.lookup(guard.inner_inode_num, name)?;
let inode = LockedExt4Inode::new(next_inode, guard.fs_ptr.clone(), dname.clone());
// 通过self_ref获取Arc<Self>,然后转换为Arc<dyn IndexNode>
let self_arc = guard.self_ref.upgrade().ok_or(SystemError::ENOENT)?;
let inode = LockedExt4Inode::new(
next_inode,
guard.fs_ptr.clone(),
dname.clone(),
Some(Arc::downgrade(&self_arc)),
);
guard.children.insert(dname, inode.clone());
Ok(inode)
}

fn parent(&self) -> Result<Arc<dyn IndexNode>, SystemError> {
// 只有目录才有父目录的概念
// 先检查当前inode是否为目录
let guard = self.0.lock();

// 如果存储了父级指针,直接返回
if let Some(parent) = guard.parent.upgrade() {
return Ok(parent);
}

Err(SystemError::ENOENT)
}

fn list(&self) -> Result<Vec<String>, SystemError> {
let guard = self.0.lock();
let dentry = guard.concret_fs().fs.listdir(guard.inner_inode_num)?;
Expand Down Expand Up @@ -292,12 +349,18 @@ impl IndexNode for LockedExt4Inode {
}

fn metadata(&self) -> Result<vfs::Metadata, SystemError> {
let guard = self.0.lock();
let ext4 = &guard.concret_fs().fs;
let attr = ext4.getattr(guard.inner_inode_num)?;
let raw_dev = guard.fs_ptr.upgrade().unwrap().raw_dev;
let (fs, inode_num, vfs_inode_id) = {
let guard = self.0.lock();
(
guard.concret_fs(),
guard.inner_inode_num,
guard.vfs_inode_id,
)
};
let attr = fs.fs.getattr(inode_num)?;
let raw_dev = fs.raw_dev;
Ok(vfs::Metadata {
inode_id: guard.vfs_inode_id,
inode_id: vfs_inode_id,
size: attr.size as i64,
blk_size: another_ext4::BLOCK_SIZE,
blocks: attr.blocks as usize,
Expand Down Expand Up @@ -445,12 +508,18 @@ impl LockedExt4Inode {
inode_num: u32,
fs_ptr: Weak<super::filesystem::Ext4FileSystem>,
dname: DName,
parent: Option<Weak<LockedExt4Inode>>,
) -> Arc<Self> {
let inode = Arc::new(LockedExt4Inode(SpinLock::new(Ext4Inode::new(
inode_num, fs_ptr, dname,
))));
let inode = Arc::new({
LockedExt4Inode(SpinLock::new(Ext4Inode::new(
inode_num, fs_ptr, dname, parent,
)))
});
let mut guard = inode.0.lock();

// 设置self_ref
guard.self_ref = Arc::downgrade(&inode);

let page_cache = PageCache::new(Some(Arc::downgrade(&inode) as Weak<dyn IndexNode>));
guard.page_cache = Some(page_cache);

Expand Down Expand Up @@ -482,14 +551,21 @@ impl Ext4Inode {
.expect("Ext4FileSystem should be alive")
}

pub fn new(inode_num: u32, fs_ptr: Weak<Ext4FileSystem>, dname: DName) -> Self {
pub fn new(
inode_num: u32,
fs_ptr: Weak<Ext4FileSystem>,
dname: DName,
parent: Option<Weak<LockedExt4Inode>>,
) -> Self {
Self {
inner_inode_num: inode_num,
fs_ptr,
page_cache: None,
children: BTreeMap::new(),
dname,
vfs_inode_id: generate_inode_id(),
parent: parent.unwrap_or_default(),
self_ref: Weak::new(), // 将在LockedExt4Inode::new()中设置
}
}
}
Expand Down
Loading
Loading