Browse Source

refactor(vfs): 重构statx系统调用的实现 (#1149)

- 将kstat的获取,与posix statx的获取进行分离.
- 修复statx没有处理dirfd的bug
- 在Metadata结构体中新增btime字段,表示文件的创建时间
- 更新多个文件系统的metadata实现,添加对btime的支持
- 引入derive_builder crate以简化Metadata构建过程
- 重构vfs模块,将core重命名为vcore以避免命名冲突
- 实现vfs_statx和vfs_getattr函数,支持更详细的文件属性查询
- 新增LookUpFlags定义,用于路径查找时的标志位

Signed-off-by: longjin <longjin@dragonos.org>
LoGin 14 hours ago
parent
commit
0b89d7130e

+ 85 - 0
kernel/Cargo.lock

@@ -361,6 +361,41 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
 
+[[package]]
+name = "darling"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 2.0.100",
+]
+
 [[package]]
 name = "defer"
 version = "0.2.1"
@@ -399,6 +434,37 @@ dependencies = [
  "thiserror",
 ]
 
+[[package]]
+name = "derive_builder"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
+dependencies = [
+ "derive_builder_macro",
+]
+
+[[package]]
+name = "derive_builder_core"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
+[[package]]
+name = "derive_builder_macro"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
+dependencies = [
+ "derive_builder_core",
+ "syn 2.0.100",
+]
+
 [[package]]
 name = "derive_more"
 version = "0.99.19"
@@ -435,6 +501,7 @@ dependencies = [
  "bitmap",
  "cfg-if",
  "defer",
+ "derive_builder",
  "driver_base_macros",
  "elf 0.7.2",
  "fdt",
@@ -546,6 +613,12 @@ name = "fdt"
 version = "0.2.0-alpha1"
 source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/fdt?rev=9862813020#98628130200086c2e55dae0d997ac4daeb590e90"
 
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
 [[package]]
 name = "foldhash"
 version = "0.1.5"
@@ -668,6 +741,12 @@ dependencies = [
  "kdepends",
 ]
 
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
 [[package]]
 name = "indexmap"
 version = "1.9.3"
@@ -1558,6 +1637,12 @@ version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
 
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
 [[package]]
 name = "syn"
 version = "1.0.109"

+ 1 - 0
kernel/Cargo.toml

@@ -79,6 +79,7 @@ static-keys = { version = "=0.7" }
 
 defer = "0.2.1"
 cfg-if = { version = "1.0.0" }
+derive_builder = { version = "0.20.2", default-features = false, features = ["alloc"] }
 
 
 # target为x86_64时,使用下面的依赖

+ 1 - 1
kernel/src/debug/tracing/tracepoint.rs

@@ -162,7 +162,7 @@ macro_rules! define_event_trace{
             #[derive(Debug)]
             #[repr(C)]
             #[allow(non_snake_case)]
-
+            #[allow(non_camel_case_types)]
             struct [<__ $name _TracePointMeta>]{
                 trace_point: &'static $crate::debug::tracing::tracepoint::TracePoint,
                 print_func: fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*),

+ 2 - 1
kernel/src/driver/input/ps2_mouse/ps_mouse_device.rs

@@ -31,7 +31,7 @@ use crate::{
         devfs::{devfs_register, DevFS, DeviceINode},
         kernfs::KernFSInode,
         vfs::{
-            core::generate_inode_id, syscall::ModeType, utils::DName, FilePrivateData, FileSystem,
+            syscall::ModeType, utils::DName, vcore::generate_inode_id, FilePrivateData, FileSystem,
             FileType, IndexNode, Metadata,
         },
     },
@@ -198,6 +198,7 @@ impl Ps2MouseDevice {
                     atime: PosixTimeSpec::default(),
                     mtime: PosixTimeSpec::default(),
                     ctime: PosixTimeSpec::default(),
+                    btime: PosixTimeSpec::default(),
                     file_type: FileType::CharDevice, // 文件夹,block设备,char设备
                     mode: ModeType::from_bits_truncate(0o644),
                     nlinks: 1,

+ 3 - 1
kernel/src/driver/keyboard/ps2_keyboard.rs

@@ -22,7 +22,7 @@ use crate::{
     filesystem::{
         devfs::{devfs_register, DevFS, DeviceINode},
         vfs::{
-            core::generate_inode_id, file::FileMode, syscall::ModeType, FilePrivateData,
+            file::FileMode, syscall::ModeType, vcore::generate_inode_id, FilePrivateData,
             FileSystem, FileType, IndexNode, Metadata,
         },
     },
@@ -86,6 +86,7 @@ impl LockedPS2KeyBoardInode {
                 atime: PosixTimeSpec::default(),
                 mtime: PosixTimeSpec::default(),
                 ctime: PosixTimeSpec::default(),
+                btime: PosixTimeSpec::default(),
                 file_type: FileType::CharDevice, // 文件夹,block设备,char设备
                 mode: ModeType::from_bits_truncate(0o666),
                 nlinks: 1,
@@ -155,6 +156,7 @@ impl IndexNode for LockedPS2KeyBoardInode {
         inode.metadata.atime = metadata.atime;
         inode.metadata.mtime = metadata.mtime;
         inode.metadata.ctime = metadata.ctime;
+        inode.metadata.btime = metadata.btime;
         inode.metadata.mode = metadata.mode;
         inode.metadata.uid = metadata.uid;
         inode.metadata.gid = metadata.gid;

+ 4 - 1
kernel/src/filesystem/devfs/mod.rs

@@ -3,10 +3,10 @@ pub mod null_dev;
 pub mod zero_dev;
 
 use super::vfs::{
-    core::{generate_inode_id, ROOT_INODE},
     file::FileMode,
     syscall::ModeType,
     utils::DName,
+    vcore::{generate_inode_id, ROOT_INODE},
     FilePrivateData, FileSystem, FileType, FsInfo, IndexNode, Magic, Metadata, SuperBlock,
 };
 use crate::{
@@ -284,6 +284,7 @@ impl DevFSInode {
                 atime: PosixTimeSpec::default(),
                 mtime: PosixTimeSpec::default(),
                 ctime: PosixTimeSpec::default(),
+                btime: PosixTimeSpec::default(),
                 file_type: dev_type_, // 文件夹
                 mode,
                 nlinks: 1,
@@ -375,6 +376,7 @@ impl LockedDevFSInode {
                 atime: PosixTimeSpec::default(),
                 mtime: PosixTimeSpec::default(),
                 ctime: PosixTimeSpec::default(),
+                btime: PosixTimeSpec::default(),
                 file_type,
                 mode,
                 nlinks: 1,
@@ -531,6 +533,7 @@ impl IndexNode for LockedDevFSInode {
         inode.metadata.atime = metadata.atime;
         inode.metadata.mtime = metadata.mtime;
         inode.metadata.ctime = metadata.ctime;
+        inode.metadata.btime = metadata.btime;
         inode.metadata.mode = metadata.mode;
         inode.metadata.uid = metadata.uid;
         inode.metadata.gid = metadata.gid;

+ 3 - 1
kernel/src/filesystem/devfs/null_dev.rs

@@ -2,7 +2,7 @@ use crate::driver::base::device::device_number::DeviceNumber;
 use crate::filesystem::vfs::file::FileMode;
 use crate::filesystem::vfs::syscall::ModeType;
 use crate::filesystem::vfs::{
-    core::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata,
+    vcore::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata,
 };
 use crate::libs::spinlock::SpinLockGuard;
 use crate::{libs::spinlock::SpinLock, time::PosixTimeSpec};
@@ -45,6 +45,7 @@ impl LockedNullInode {
                 atime: PosixTimeSpec::default(),
                 mtime: PosixTimeSpec::default(),
                 ctime: PosixTimeSpec::default(),
+                btime: PosixTimeSpec::default(),
                 file_type: FileType::CharDevice, // 文件夹,block设备,char设备
                 mode: ModeType::from_bits_truncate(0o666),
                 nlinks: 1,
@@ -101,6 +102,7 @@ impl IndexNode for LockedNullInode {
         inode.metadata.atime = metadata.atime;
         inode.metadata.mtime = metadata.mtime;
         inode.metadata.ctime = metadata.ctime;
+        inode.metadata.btime = metadata.btime;
         inode.metadata.mode = metadata.mode;
         inode.metadata.uid = metadata.uid;
         inode.metadata.gid = metadata.gid;

+ 3 - 1
kernel/src/filesystem/devfs/zero_dev.rs

@@ -2,7 +2,7 @@ use crate::driver::base::device::device_number::DeviceNumber;
 use crate::filesystem::vfs::file::FileMode;
 use crate::filesystem::vfs::syscall::ModeType;
 use crate::filesystem::vfs::{
-    core::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata,
+    vcore::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata,
 };
 use crate::libs::spinlock::SpinLockGuard;
 use crate::{libs::spinlock::SpinLock, time::PosixTimeSpec};
@@ -45,6 +45,7 @@ impl LockedZeroInode {
                 atime: PosixTimeSpec::default(),
                 mtime: PosixTimeSpec::default(),
                 ctime: PosixTimeSpec::default(),
+                btime: PosixTimeSpec::default(),
                 file_type: FileType::CharDevice, // 文件夹,block设备,char设备
                 mode: ModeType::from_bits_truncate(0o666),
                 nlinks: 1,
@@ -101,6 +102,7 @@ impl IndexNode for LockedZeroInode {
         inode.metadata.atime = metadata.atime;
         inode.metadata.mtime = metadata.mtime;
         inode.metadata.ctime = metadata.ctime;
+        inode.metadata.btime = metadata.btime;
         inode.metadata.mode = metadata.mode;
         inode.metadata.uid = metadata.uid;
         inode.metadata.gid = metadata.gid;

+ 3 - 2
kernel/src/filesystem/devpts/mod.rs

@@ -22,14 +22,14 @@ use crate::{
             tty_device::{PtyType, TtyDevice, TtyType},
         },
     },
-    filesystem::vfs::{core::do_mount_mkdir, syscall::ModeType, FileType},
+    filesystem::vfs::{syscall::ModeType, vcore::do_mount_mkdir, FileType},
     init::initcall::INITCALL_FS,
     libs::spinlock::{SpinLock, SpinLockGuard},
     time::PosixTimeSpec,
 };
 
 use super::vfs::{
-    core::generate_inode_id, FilePrivateData, FileSystem, FsInfo, IndexNode, Metadata,
+    vcore::generate_inode_id, FilePrivateData, FileSystem, FsInfo, IndexNode, Metadata,
 };
 
 const DEV_PTYFS_MAX_NAMELEN: usize = 16;
@@ -109,6 +109,7 @@ impl LockedDevPtsFSInode {
                     atime: PosixTimeSpec::default(),
                     mtime: PosixTimeSpec::default(),
                     ctime: PosixTimeSpec::default(),
+                    btime: PosixTimeSpec::default(),
                     file_type: FileType::Dir,
                     mode: ModeType::from_bits_truncate(0o777),
                     nlinks: 1,

+ 3 - 1
kernel/src/filesystem/fat/fs.rs

@@ -23,9 +23,9 @@ use crate::mm::VmFaultReason;
 use crate::{
     driver::base::block::{block_device::LBA_SIZE, disk_info::Partition, SeekFrom},
     filesystem::vfs::{
-        core::generate_inode_id,
         file::{FileMode, FilePrivateData},
         syscall::ModeType,
+        vcore::generate_inode_id,
         FileSystem, FileType, IndexNode, InodeId, Metadata,
     },
     libs::{
@@ -227,6 +227,7 @@ impl LockedFATInode {
                 atime: PosixTimeSpec::default(),
                 mtime: PosixTimeSpec::default(),
                 ctime: PosixTimeSpec::default(),
+                btime: PosixTimeSpec::default(),
                 file_type,
                 mode: ModeType::from_bits_truncate(0o777),
                 nlinks: 1,
@@ -377,6 +378,7 @@ impl FATFileSystem {
                 atime: PosixTimeSpec::default(),
                 mtime: PosixTimeSpec::default(),
                 ctime: PosixTimeSpec::default(),
+                btime: PosixTimeSpec::default(),
                 file_type: FileType::Dir,
                 mode: ModeType::from_bits_truncate(0o777),
                 nlinks: 1,

+ 3 - 1
kernel/src/filesystem/kernfs/mod.rs

@@ -22,7 +22,7 @@ use crate::{
 use self::callback::{KernCallbackData, KernFSCallback, KernInodePrivateData};
 
 use super::vfs::{
-    core::generate_inode_id, file::FileMode, syscall::ModeType, FilePrivateData, FileSystem,
+    file::FileMode, syscall::ModeType, vcore::generate_inode_id, FilePrivateData, FileSystem,
     FileType, FsInfo, IndexNode, InodeId, Magic, Metadata, SuperBlock,
 };
 
@@ -94,6 +94,7 @@ impl KernFS {
             atime: PosixTimeSpec::new(0, 0),
             mtime: PosixTimeSpec::new(0, 0),
             ctime: PosixTimeSpec::new(0, 0),
+            btime: PosixTimeSpec::new(0, 0),
             dev_id: 0,
             inode_id: generate_inode_id(),
             file_type: FileType::Dir,
@@ -525,6 +526,7 @@ impl KernFSInode {
             atime: PosixTimeSpec::new(0, 0),
             mtime: PosixTimeSpec::new(0, 0),
             ctime: PosixTimeSpec::new(0, 0),
+            btime: PosixTimeSpec::new(0, 0),
             dev_id: 0,
             inode_id: generate_inode_id(),
             file_type: file_type.into(),

+ 4 - 1
kernel/src/filesystem/procfs/mod.rs

@@ -15,7 +15,7 @@ use crate::{
     arch::mm::LockedFrameAllocator,
     driver::base::device::device_number::DeviceNumber,
     filesystem::vfs::{
-        core::{generate_inode_id, ROOT_INODE},
+        vcore::{generate_inode_id, ROOT_INODE},
         FileType,
     },
     libs::{
@@ -361,6 +361,7 @@ impl ProcFS {
                     atime: PosixTimeSpec::default(),
                     mtime: PosixTimeSpec::default(),
                     ctime: PosixTimeSpec::default(),
+                    btime: PosixTimeSpec::default(),
                     file_type: FileType::Dir,
                     mode: ModeType::from_bits_truncate(0o555),
                     nlinks: 1,
@@ -656,6 +657,7 @@ impl IndexNode for LockedProcFSInode {
         inode.metadata.atime = metadata.atime;
         inode.metadata.mtime = metadata.mtime;
         inode.metadata.ctime = metadata.ctime;
+        inode.metadata.btime = metadata.btime;
         inode.metadata.mode = metadata.mode;
         inode.metadata.uid = metadata.uid;
         inode.metadata.gid = metadata.gid;
@@ -708,6 +710,7 @@ impl IndexNode for LockedProcFSInode {
                     atime: PosixTimeSpec::default(),
                     mtime: PosixTimeSpec::default(),
                     ctime: PosixTimeSpec::default(),
+                    btime: PosixTimeSpec::default(),
                     file_type,
                     mode,
                     nlinks: 1,

+ 5 - 1
kernel/src/filesystem/ramfs/mod.rs

@@ -5,7 +5,7 @@ use crate::filesystem::vfs::{FileSystemMakerData, FSMAKER};
 use crate::libs::rwlock::RwLock;
 use crate::{
     driver::base::device::device_number::DeviceNumber,
-    filesystem::vfs::{core::generate_inode_id, FileType},
+    filesystem::vfs::{vcore::generate_inode_id, FileType},
     ipc::pipe::LockedPipeInode,
     libs::casting::DowncastArc,
     libs::spinlock::{SpinLock, SpinLockGuard},
@@ -86,6 +86,7 @@ impl RamFSInode {
                 atime: PosixTimeSpec::default(),
                 mtime: PosixTimeSpec::default(),
                 ctime: PosixTimeSpec::default(),
+                btime: PosixTimeSpec::default(),
                 file_type: FileType::Dir,
                 mode: ModeType::from_bits_truncate(0o777),
                 nlinks: 1,
@@ -281,6 +282,7 @@ impl IndexNode for LockedRamFSInode {
         inode.metadata.atime = metadata.atime;
         inode.metadata.mtime = metadata.mtime;
         inode.metadata.ctime = metadata.ctime;
+        inode.metadata.btime = metadata.btime;
         inode.metadata.mode = metadata.mode;
         inode.metadata.uid = metadata.uid;
         inode.metadata.gid = metadata.gid;
@@ -332,6 +334,7 @@ impl IndexNode for LockedRamFSInode {
                 atime: PosixTimeSpec::default(),
                 mtime: PosixTimeSpec::default(),
                 ctime: PosixTimeSpec::default(),
+                btime: PosixTimeSpec::default(),
                 file_type,
                 mode,
                 nlinks: 1,
@@ -594,6 +597,7 @@ impl IndexNode for LockedRamFSInode {
                 atime: PosixTimeSpec::default(),
                 mtime: PosixTimeSpec::default(),
                 ctime: PosixTimeSpec::default(),
+                btime: PosixTimeSpec::default(),
                 file_type: FileType::Pipe,
                 mode,
                 nlinks: 1,

+ 2 - 0
kernel/src/filesystem/vfs/fcntl.rs

@@ -101,6 +101,8 @@ bitflags! {
         /// 应用于整个子树。
         /// AT_RECURSIVE: 0x8000
         const AT_RECURSIVE = 0x8000;
+
+        const AT_GETATTR_NOSEC = i32::MIN;
     }
 }
 

+ 30 - 6
kernel/src/filesystem/vfs/mod.rs

@@ -1,13 +1,15 @@
-pub mod core;
 pub mod fcntl;
 pub mod file;
 pub mod mount;
 pub mod open;
+pub mod stat;
 pub mod syscall;
 pub mod utils;
+pub mod vcore;
 
 use ::core::{any::Any, fmt::Debug, sync::atomic::AtomicUsize};
 use alloc::{string::String, sync::Arc, vec::Vec};
+use derive_builder::Builder;
 use intertrait::CastFromSync;
 use system_error::SystemError;
 
@@ -25,8 +27,8 @@ use crate::{
     time::PosixTimeSpec,
 };
 
-use self::{core::generate_inode_id, file::FileMode, syscall::ModeType, utils::DName};
-pub use self::{core::ROOT_INODE, file::FilePrivateData, mount::MountFS};
+use self::{file::FileMode, syscall::ModeType, utils::DName, vcore::generate_inode_id};
+pub use self::{file::FilePrivateData, mount::MountFS, vcore::ROOT_INODE};
 
 use super::page_cache::PageCache;
 
@@ -59,6 +61,22 @@ pub enum FileType {
     Socket,
 }
 
+impl From<FileType> for ModeType {
+    fn from(val: FileType) -> Self {
+        match val {
+            FileType::File => ModeType::S_IFREG,
+            FileType::Dir => ModeType::S_IFDIR,
+            FileType::BlockDevice => ModeType::S_IFBLK,
+            FileType::CharDevice => ModeType::S_IFCHR,
+            FileType::SymLink => ModeType::S_IFLNK,
+            FileType::Socket => ModeType::S_IFSOCK,
+            FileType::Pipe => ModeType::S_IFIFO,
+            FileType::KvmDevice => ModeType::S_IFCHR,
+            FileType::FramebufferDevice => ModeType::S_IFCHR,
+        }
+    }
+}
+
 #[allow(dead_code)]
 #[derive(Debug, Clone)]
 pub enum SpecialNodeData {
@@ -781,7 +799,8 @@ impl dyn IndexNode {
 /// IndexNode的元数据
 ///
 /// 对应Posix2008中的sys/stat.h中的定义 https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html
-#[derive(Debug, PartialEq, Eq, Clone)]
+#[derive(Debug, PartialEq, Eq, Clone, Builder)]
+#[builder(no_std, setter(into))]
 pub struct Metadata {
     /// 当前inode所在的文件系统的设备号
     pub dev_id: usize,
@@ -803,12 +822,15 @@ pub struct Metadata {
     /// inode最后一次被访问的时间
     pub atime: PosixTimeSpec,
 
-    /// inode最后一次修改的时间
+    /// inode的文件数据最后一次修改的时间
     pub mtime: PosixTimeSpec,
 
-    /// inode的创建时间
+    /// inode的元数据、权限或文件内容最后一次发生改变的时间
     pub ctime: PosixTimeSpec,
 
+    /// inode的创建时间
+    pub btime: PosixTimeSpec,
+
     /// 文件类型
     pub file_type: FileType,
 
@@ -839,6 +861,7 @@ impl Default for Metadata {
             atime: PosixTimeSpec::default(),
             mtime: PosixTimeSpec::default(),
             ctime: PosixTimeSpec::default(),
+            btime: PosixTimeSpec::default(),
             file_type: FileType::File,
             mode: ModeType::empty(),
             nlinks: 1,
@@ -975,6 +998,7 @@ impl Metadata {
             atime: PosixTimeSpec::default(),
             mtime: PosixTimeSpec::default(),
             ctime: PosixTimeSpec::default(),
+            btime: PosixTimeSpec::default(),
             file_type,
             mode,
             nlinks: 1,

+ 15 - 0
kernel/src/filesystem/vfs/mount.rs

@@ -749,3 +749,18 @@ impl Debug for MountList {
         f.debug_map().entries(MOUNT_LIST().0.read().iter()).finish()
     }
 }
+
+/// 判断给定的inode是否为其所在文件系统的根inode
+///
+/// ## 返回值
+///
+/// - `true`: 是根inode
+/// - `false`: 不是根inode或者传入的inode不是MountFSInode类型,或者调用inode的metadata方法时报错了。
+pub fn is_mountpoint_root(inode: &Arc<dyn IndexNode>) -> bool {
+    let mnt_inode = inode.as_any_ref().downcast_ref::<MountFSInode>();
+    if let Some(mnt) = mnt_inode {
+        return mnt.is_mountpoint_root().unwrap_or(false);
+    }
+
+    return false;
+}

+ 398 - 0
kernel/src/filesystem/vfs/stat.rs

@@ -0,0 +1,398 @@
+use system_error::SystemError;
+
+use crate::{
+    filesystem::vfs::{mount::is_mountpoint_root, vcore::do_file_lookup_at},
+    syscall::user_access::UserBufferWriter,
+    time::PosixTimeSpec,
+};
+use alloc::sync::Arc;
+
+use super::{
+    fcntl::AtFlags,
+    syscall::{ModeType, PosixStatx, PosixStatxMask, StxAttributes},
+    IndexNode,
+};
+
+#[derive(Clone)]
+pub struct KStat {
+    pub result_mask: PosixStatxMask, // What fields the user got
+    pub mode: ModeType,              // umode_t
+    pub nlink: u32,
+    pub blksize: u32, // Preferred I/O size
+    pub attributes: StxAttributes,
+    pub attributes_mask: StxAttributes,
+    pub ino: u64,
+    pub dev: i64,             // dev_t
+    pub rdev: i64,            // dev_t
+    pub uid: u32,             // kuid_t
+    pub gid: u32,             // kgid_t
+    pub size: usize,          // loff_t
+    pub atime: PosixTimeSpec, // struct timespec64
+    pub mtime: PosixTimeSpec, // struct timespec64
+    pub ctime: PosixTimeSpec, // struct timespec64
+    pub btime: PosixTimeSpec, // File creation time
+    pub blocks: u64,
+    pub mnt_id: u64,
+    pub dio_mem_align: u32,
+    pub dio_offset_align: u32,
+}
+
+impl Default for KStat {
+    fn default() -> Self {
+        Self {
+            result_mask: PosixStatxMask::empty(),
+            mode: ModeType::empty(),
+            nlink: Default::default(),
+            blksize: Default::default(),
+            attributes: StxAttributes::empty(),
+            attributes_mask: StxAttributes::empty(),
+            ino: Default::default(),
+            dev: Default::default(),
+            rdev: Default::default(),
+            uid: Default::default(),
+            gid: Default::default(),
+            size: Default::default(),
+            atime: Default::default(),
+            mtime: Default::default(),
+            ctime: Default::default(),
+            btime: Default::default(),
+            blocks: Default::default(),
+            mnt_id: Default::default(),
+            dio_mem_align: Default::default(),
+            dio_offset_align: Default::default(),
+        }
+    }
+}
+
+bitflags! {
+    ///  https://code.dragonos.org.cn/xref/linux-6.6.21/include/linux/namei.h?fi=LOOKUP_FOLLOW#21
+    pub struct LookUpFlags: u32 {
+        /// follow links at the end
+        const FOLLOW = 0x0001;
+        /// require a directory
+        const DIRECTORY = 0x0002;
+        /// force terminal automount
+        const AUTOMOUNT = 0x0004;
+        /// accept empty path [user_... only]
+        const EMPTY = 0x4000;
+        /// follow mounts in the starting point
+        const DOWN = 0x8000;
+        /// follow mounts in the end
+        const MOUNTPOINT = 0x0080;
+        /// tell ->d_revalidate() to trust no cache
+        const REVAL = 0x0020;
+        /// RCU pathwalk mode; semi-internal
+        const RCU = 0x0040;
+        /// ... in open
+        const OPEN = 0x0100;
+        /// ... in object creation
+        const CREATE = 0x0200;
+        /// ... in exclusive creation
+        const EXCL = 0x0400;
+        /// ... in destination of rename()
+        const RENAME_TARGET = 0x0800;
+        /// internal use only
+        const PARENT = 0x0010;
+        /// No symlink crossing
+        const NO_SYMLINKS = 0x010000;
+        /// No nd_jump_link() crossing
+        const NO_MAGICLINKS = 0x020000;
+        /// No mountpoint crossing
+        const NO_XDEV = 0x040000;
+        /// No escaping from starting point
+        const BENEATH = 0x080000;
+        /// Treat dirfd as fs root
+        const IN_ROOT = 0x100000;
+        /// Only do cached lookup
+        const CACHED = 0x200000;
+        ///  LOOKUP_* flags which do scope-related checks based on the dirfd.
+        const IS_SCOPED = LookUpFlags::BENEATH.bits | LookUpFlags::IN_ROOT.bits;
+    }
+}
+
+impl From<AtFlags> for LookUpFlags {
+    fn from(value: AtFlags) -> Self {
+        let mut lookup_flags = LookUpFlags::empty();
+
+        if !value.contains(AtFlags::AT_SYMLINK_NOFOLLOW) {
+            lookup_flags |= LookUpFlags::FOLLOW;
+        }
+
+        if !value.contains(AtFlags::AT_NO_AUTOMOUNT) {
+            lookup_flags |= LookUpFlags::AUTOMOUNT;
+        }
+
+        if value.contains(AtFlags::AT_EMPTY_PATH) {
+            lookup_flags |= LookUpFlags::EMPTY;
+        }
+
+        lookup_flags
+    }
+}
+
+/// https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#232
+#[inline(never)]
+pub fn vfs_statx(
+    dfd: i32,
+    filename: &str,
+    flags: AtFlags,
+    request_mask: PosixStatxMask,
+) -> Result<KStat, SystemError> {
+    let lookup_flags: LookUpFlags = flags.into();
+
+    // Validate flags - only allowed flags are AT_SYMLINK_NOFOLLOW, AT_NO_AUTOMOUNT, AT_EMPTY_PATH, AT_STATX_SYNC_TYPE
+    if flags.intersects(
+        !(AtFlags::AT_SYMLINK_NOFOLLOW
+            | AtFlags::AT_NO_AUTOMOUNT
+            | AtFlags::AT_EMPTY_PATH
+            | AtFlags::AT_STATX_SYNC_TYPE),
+    ) {
+        return Err(SystemError::EINVAL);
+    }
+    let inode = do_file_lookup_at(dfd, filename, lookup_flags)?;
+
+    let mut kstat = vfs_getattr(&inode, request_mask, flags)?;
+    if is_mountpoint_root(&inode) {
+        kstat
+            .attributes
+            .insert(StxAttributes::STATX_ATTR_MOUNT_ROOT);
+    }
+    kstat
+        .attributes_mask
+        .insert(StxAttributes::STATX_ATTR_MOUNT_ROOT);
+
+    // todo: 添加 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#266 这里的逻辑
+
+    Ok(kstat)
+}
+
+/// 获取文件的增强基本属性
+///
+/// # 参数
+/// - `path`: 目标文件路径
+/// - `stat`: 用于返回统计信息的结构体
+/// - `request_mask`: PosixStatxMask标志位,指示调用者需要哪些属性
+/// - `query_flags`: 查询模式(AT_STATX_SYNC_TYPE)
+///
+/// # 描述
+/// 向文件系统请求文件的属性。调用者必须通过request_mask和query_flags指定需要的信息。
+///
+/// 如果文件是远程的:
+/// - 可以通过传递AT_STATX_FORCE_SYNC强制文件系统从后端存储更新属性
+/// - 可以通过传递AT_STATX_DONT_SYNC禁止更新
+///
+/// request_mask中必须设置相应的位来指示调用者需要检索哪些属性。
+/// 未请求的属性也可能被返回,但其值可能是近似的,如果是远程文件,
+/// 可能没有与服务器同步。
+///
+/// # 返回值
+/// 成功时返回0,失败时返回负的错误码
+///
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#165
+#[inline(never)]
+pub fn vfs_getattr(
+    inode: &Arc<dyn IndexNode>,
+    request_mask: PosixStatxMask,
+    mut at_flags: AtFlags,
+) -> Result<KStat, SystemError> {
+    if at_flags.contains(AtFlags::AT_GETATTR_NOSEC) {
+        return Err(SystemError::EPERM);
+    }
+
+    let mut kstat = KStat::default();
+    kstat.result_mask |= PosixStatxMask::STATX_BASIC_STATS;
+    at_flags &= AtFlags::AT_STATX_SYNC_TYPE;
+
+    let metadata = inode.metadata()?;
+    if metadata.atime.is_empty() {
+        kstat.result_mask.remove(PosixStatxMask::STATX_ATIME);
+    }
+
+    // todo: 添加automount和dax属性
+
+    kstat.blksize = metadata.blk_size as u32;
+    if request_mask.contains(PosixStatxMask::STATX_MODE)
+        || request_mask.contains(PosixStatxMask::STATX_TYPE)
+    {
+        kstat.mode = metadata.mode;
+    }
+    if request_mask.contains(PosixStatxMask::STATX_NLINK) {
+        kstat.nlink = metadata.nlinks as u32;
+    }
+    if request_mask.contains(PosixStatxMask::STATX_UID) {
+        kstat.uid = metadata.uid as u32;
+    }
+    if request_mask.contains(PosixStatxMask::STATX_GID) {
+        kstat.gid = metadata.gid as u32;
+    }
+    if request_mask.contains(PosixStatxMask::STATX_ATIME) {
+        kstat.atime.tv_sec = metadata.atime.tv_sec;
+        kstat.atime.tv_nsec = metadata.atime.tv_nsec;
+    }
+    if request_mask.contains(PosixStatxMask::STATX_MTIME) {
+        kstat.mtime.tv_sec = metadata.mtime.tv_sec;
+        kstat.mtime.tv_nsec = metadata.mtime.tv_nsec;
+    }
+    if request_mask.contains(PosixStatxMask::STATX_CTIME) {
+        // ctime是文件上次修改状态的时间
+        kstat.ctime.tv_sec = metadata.ctime.tv_sec;
+        kstat.ctime.tv_nsec = metadata.ctime.tv_nsec;
+    }
+    if request_mask.contains(PosixStatxMask::STATX_INO) {
+        kstat.ino = metadata.inode_id.into() as u64;
+    }
+    if request_mask.contains(PosixStatxMask::STATX_SIZE) {
+        kstat.size = metadata.size as usize;
+    }
+    if request_mask.contains(PosixStatxMask::STATX_BLOCKS) {
+        kstat.blocks = metadata.blocks as u64;
+    }
+
+    if request_mask.contains(PosixStatxMask::STATX_BTIME) {
+        // btime是文件创建时间
+        kstat.btime.tv_sec = metadata.btime.tv_sec;
+        kstat.btime.tv_nsec = metadata.btime.tv_nsec;
+    }
+    if request_mask.contains(PosixStatxMask::STATX_ALL) {
+        kstat.attributes = StxAttributes::STATX_ATTR_APPEND;
+        kstat.attributes_mask |=
+            StxAttributes::STATX_ATTR_AUTOMOUNT | StxAttributes::STATX_ATTR_DAX;
+        kstat.dev = metadata.dev_id as i64;
+        kstat.rdev = metadata.raw_dev.data() as i64;
+    }
+
+    // 把文件类型加入mode里面 (todo: 在具体的文件系统里面去实现这个操作。这里只是权宜之计)
+    kstat.mode |= metadata.file_type.into();
+
+    return Ok(kstat);
+}
+
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#660
+pub(super) fn do_statx(
+    dfd: i32,
+    filename: &str,
+    flags: u32,
+    mask: u32,
+    user_kstat_ptr: usize,
+) -> Result<(), SystemError> {
+    let mask = PosixStatxMask::from_bits_truncate(mask);
+    if mask.contains(PosixStatxMask::STATX_RESERVED) {
+        return Err(SystemError::EINVAL);
+    }
+
+    let flags = AtFlags::from_bits_truncate(flags as i32);
+    if flags.contains(AtFlags::AT_STATX_SYNC_TYPE) {
+        return Err(SystemError::EINVAL);
+    }
+
+    let kstat = vfs_statx(dfd, filename, flags, mask)?;
+    cp_statx(kstat, user_kstat_ptr)
+}
+
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#622
+#[inline(never)]
+fn cp_statx(kstat: KStat, user_buf_ptr: usize) -> Result<(), SystemError> {
+    let mut userbuf = UserBufferWriter::new(
+        user_buf_ptr as *mut PosixStatx,
+        size_of::<PosixStatx>(),
+        true,
+    )?;
+    let mut statx: PosixStatx = PosixStatx::new();
+
+    // Copy fields from KStat to PosixStatx
+    statx.stx_mask = kstat.result_mask & !PosixStatxMask::STATX_CHANGE_COOKIE;
+    statx.stx_blksize = kstat.blksize;
+    statx.stx_attributes = kstat.attributes & !StxAttributes::STATX_ATTR_CHANGE_MONOTONIC;
+    statx.stx_nlink = kstat.nlink;
+    statx.stx_uid = kstat.uid;
+    statx.stx_gid = kstat.gid;
+    statx.stx_mode = kstat.mode;
+    statx.stx_inode = kstat.ino;
+    statx.stx_size = kstat.size as i64;
+    statx.stx_blocks = kstat.blocks;
+    statx.stx_attributes_mask = kstat.attributes_mask;
+
+    // Copy time fields
+    statx.stx_atime = kstat.atime;
+    statx.stx_btime = kstat.btime;
+    statx.stx_ctime = kstat.ctime;
+    statx.stx_mtime = kstat.mtime;
+
+    // Convert device numbers
+    statx.stx_rdev_major = ((kstat.rdev >> 32) & 0xffff_ffff) as u32; // MAJOR equivalent
+    statx.stx_rdev_minor = (kstat.rdev & 0xffff_ffff) as u32; // MINOR equivalent
+    statx.stx_dev_major = ((kstat.dev >> 32) & 0xffff_ffff) as u32; // MAJOR equivalent
+    statx.stx_dev_minor = (kstat.dev & 0xffff_ffff) as u32; // MINOR equivalent
+
+    statx.stx_mnt_id = kstat.mnt_id;
+    statx.stx_dio_mem_align = kstat.dio_mem_align;
+    statx.stx_dio_offset_align = kstat.dio_offset_align;
+
+    // Write to user space
+    userbuf.copy_one_to_user(&statx, 0)?;
+    Ok(())
+}
+
+// 注意!这个结构体定义的貌似不太对,需要修改!
+#[repr(C)]
+#[derive(Clone, Copy)]
+/// # 文件信息结构体
+pub struct PosixKstat {
+    /// 硬件设备ID
+    pub dev_id: u64,
+    /// inode号
+    pub inode: u64,
+    /// 硬链接数
+    pub nlink: u64,
+    /// 文件权限
+    pub mode: ModeType,
+    /// 所有者用户ID
+    pub uid: i32,
+    /// 所有者组ID
+    pub gid: i32,
+    /// 设备ID
+    pub rdev: i64,
+    /// 文件大小
+    pub size: i64,
+    /// 文件系统块大小
+    pub blcok_size: i64,
+    /// 分配的512B块数
+    pub blocks: u64,
+    /// 最后访问时间
+    pub atime: PosixTimeSpec,
+    /// 最后修改时间
+    pub mtime: PosixTimeSpec,
+    /// 最后状态变化时间
+    pub ctime: PosixTimeSpec,
+    /// 用于填充结构体大小的空白数据
+    pub _pad: [i8; 24],
+}
+impl PosixKstat {
+    pub(super) fn new() -> Self {
+        Self {
+            inode: 0,
+            dev_id: 0,
+            mode: ModeType::empty(),
+            nlink: 0,
+            uid: 0,
+            gid: 0,
+            rdev: 0,
+            size: 0,
+            atime: PosixTimeSpec {
+                tv_sec: 0,
+                tv_nsec: 0,
+            },
+            mtime: PosixTimeSpec {
+                tv_sec: 0,
+                tv_nsec: 0,
+            },
+            ctime: PosixTimeSpec {
+                tv_sec: 0,
+                tv_nsec: 0,
+            },
+            blcok_size: 0,
+            blocks: 0,
+            _pad: Default::default(),
+        }
+    }
+}

+ 43 - 188
kernel/src/filesystem/vfs/syscall.rs

@@ -10,7 +10,7 @@ use crate::producefs;
 use crate::syscall::user_access::UserBufferReader;
 use crate::{
     driver::base::{block::SeekFrom, device::device_number::DeviceNumber},
-    filesystem::vfs::{core as Vcore, file::FileDescriptorVec},
+    filesystem::vfs::{file::FileDescriptorVec, vcore as Vcore},
     libs::rwlock::RwLockWriteGuard,
     mm::{verify_area, VirtAddr},
     process::ProcessManager,
@@ -21,15 +21,16 @@ use crate::{
     time::{syscall::PosixTimeval, PosixTimeSpec},
 };
 
-use super::core::do_symlinkat;
+use super::stat::{do_statx, PosixKstat};
+use super::vcore::do_symlinkat;
 use super::{
-    core::{do_mkdir_at, do_remove_dir, do_unlink_at},
     fcntl::{AtFlags, FcntlCommand, FD_CLOEXEC},
     file::{File, FileMode},
     open::{
         do_faccessat, do_fchmodat, do_fchownat, do_sys_open, do_utimensat, do_utimes, ksys_fchown,
     },
     utils::{rsplit_path, user_path_at},
+    vcore::{do_mkdir_at, do_remove_dir, do_unlink_at},
     Dirent, FileType, IndexNode, SuperBlock, FSMAKER, MAX_PATHLEN, ROOT_INODE,
     VFS_MAX_FOLLOW_SYMLINK_TIMES,
 };
@@ -88,126 +89,65 @@ bitflags! {
     }
 }
 
-#[repr(C)]
-#[derive(Clone, Copy)]
-/// # 文件信息结构体
-pub struct PosixKstat {
-    /// 硬件设备ID
-    dev_id: u64,
-    /// inode号
-    inode: u64,
-    /// 硬链接数
-    nlink: u64,
-    /// 文件权限
-    mode: ModeType,
-    /// 所有者用户ID
-    uid: i32,
-    /// 所有者组ID
-    gid: i32,
-    /// 设备ID
-    rdev: i64,
-    /// 文件大小
-    size: i64,
-    /// 文件系统块大小
-    blcok_size: i64,
-    /// 分配的512B块数
-    blocks: u64,
-    /// 最后访问时间
-    atime: PosixTimeSpec,
-    /// 最后修改时间
-    mtime: PosixTimeSpec,
-    /// 最后状态变化时间
-    ctime: PosixTimeSpec,
-    /// 用于填充结构体大小的空白数据
-    pub _pad: [i8; 24],
-}
-impl PosixKstat {
-    fn new() -> Self {
-        Self {
-            inode: 0,
-            dev_id: 0,
-            mode: ModeType { bits: 0 },
-            nlink: 0,
-            uid: 0,
-            gid: 0,
-            rdev: 0,
-            size: 0,
-            atime: PosixTimeSpec {
-                tv_sec: 0,
-                tv_nsec: 0,
-            },
-            mtime: PosixTimeSpec {
-                tv_sec: 0,
-                tv_nsec: 0,
-            },
-            ctime: PosixTimeSpec {
-                tv_sec: 0,
-                tv_nsec: 0,
-            },
-            blcok_size: 0,
-            blocks: 0,
-            _pad: Default::default(),
-        }
-    }
-}
-
 #[repr(C)]
 #[derive(Clone, Copy)]
 /// # 文件信息结构体X
 pub struct PosixStatx {
     /* 0x00 */
-    stx_mask: PosixStatxMask,
+    pub stx_mask: PosixStatxMask,
     /// 文件系统块大小
-    stx_blksize: u32,
+    pub stx_blksize: u32,
     /// Flags conveying information about the file [uncond]
-    stx_attributes: StxAttributes,
+    pub stx_attributes: StxAttributes,
     /* 0x10 */
     /// 硬链接数
-    stx_nlink: u32,
+    pub stx_nlink: u32,
     /// 所有者用户ID
-    stx_uid: u32,
+    pub stx_uid: u32,
     /// 所有者组ID
-    stx_gid: u32,
+    pub stx_gid: u32,
     /// 文件权限
-    stx_mode: ModeType,
+    pub stx_mode: ModeType,
 
     /* 0x20 */
     /// inode号
-    stx_inode: u64,
+    pub stx_inode: u64,
     /// 文件大小
-    stx_size: i64,
+    pub stx_size: i64,
     /// 分配的512B块数
-    stx_blocks: u64,
+    pub stx_blocks: u64,
     /// Mask to show what's supported in stx_attributes
-    stx_attributes_mask: StxAttributes,
+    pub stx_attributes_mask: StxAttributes,
 
     /* 0x40 */
     /// 最后访问时间
-    stx_atime: PosixTimeSpec,
+    pub stx_atime: PosixTimeSpec,
     /// 文件创建时间
-    stx_btime: PosixTimeSpec,
+    pub stx_btime: PosixTimeSpec,
     /// 最后状态变化时间
-    stx_ctime: PosixTimeSpec,
+    pub stx_ctime: PosixTimeSpec,
     /// 最后修改时间
-    stx_mtime: PosixTimeSpec,
+    pub stx_mtime: PosixTimeSpec,
 
     /* 0x80 */
     /// 主设备ID
-    stx_rdev_major: u32,
+    pub stx_rdev_major: u32,
     /// 次设备ID
-    stx_rdev_minor: u32,
+    pub stx_rdev_minor: u32,
     /// 主硬件设备ID
-    stx_dev_major: u32,
+    pub stx_dev_major: u32,
     /// 次硬件设备ID
-    stx_dev_minor: u32,
+    pub stx_dev_minor: u32,
 
     /* 0x90 */
-    stx_mnt_id: u64,
-    stx_dio_mem_align: u32,
-    stx_dio_offset_align: u32,
+    pub stx_mnt_id: u64,
+    pub stx_dio_mem_align: u32,
+    pub stx_dio_offset_align: u32,
 }
+
 impl PosixStatx {
-    fn new() -> Self {
+    #[inline(never)]
+    pub(super) fn new() -> Self {
         Self {
             stx_mask: PosixStatxMask::STATX_BASIC_STATS,
             stx_blksize: 0,
@@ -301,6 +241,9 @@ bitflags! {
 
         /// Reserved for future struct statx expansion
         const STATX_RESERVED = 0x80000000;
+
+        /// Want/got stx_change_attr
+        const STATX_CHANGE_COOKIE = 0x40000000;
     }
 }
 
@@ -324,6 +267,8 @@ bitflags! {
         const STATX_ATTR_VERITY = 0x00100000;
         /// 文件当前处于 DAX 状态 CPU直接访问
         const STATX_ATTR_DAX = 0x00200000;
+        /// version monotonically increases
+        const STATX_ATTR_CHANGE_MONOTONIC = 0x8000000000000000;
     }
 }
 
@@ -1411,112 +1356,22 @@ impl Syscall {
         return Ok(0);
     }
 
-    pub fn do_statx(
-        fd: i32,
-        path: *const u8,
+    #[inline(never)]
+    pub fn statx(
+        dfd: i32,
+        filename_ptr: usize,
         flags: u32,
         mask: u32,
-        usr_kstat: *mut PosixStatx,
+        user_kstat_ptr: usize,
     ) -> Result<usize, SystemError> {
-        if usr_kstat.is_null() {
+        if user_kstat_ptr == 0 {
             return Err(SystemError::EFAULT);
         }
 
-        let mask = PosixStatxMask::from_bits_truncate(mask);
-
-        if mask.contains(PosixStatxMask::STATX_RESERVED) {
-            return Err(SystemError::ENAVAIL);
-        }
-
-        let flags = FileMode::from_bits_truncate(flags);
-        let ofd = Self::open(path, flags.bits(), ModeType::empty().bits, true)?;
-
-        let binding = ProcessManager::current_pcb().fd_table();
-        let fd_table_guard = binding.read();
-        let file = fd_table_guard
-            .get_file_by_fd(ofd as i32)
-            .ok_or(SystemError::EBADF)?;
-        // drop guard 以避免无法调度的问题
-        drop(fd_table_guard);
-        let mut writer = UserBufferWriter::new(usr_kstat, size_of::<PosixStatx>(), true)?;
-        let mut tmp: PosixStatx = PosixStatx::new();
-        // 获取文件信息
-        let metadata = file.metadata()?;
-
-        tmp.stx_mask |= PosixStatxMask::STATX_BASIC_STATS;
-        tmp.stx_blksize = metadata.blk_size as u32;
-        if mask.contains(PosixStatxMask::STATX_MODE) || mask.contains(PosixStatxMask::STATX_TYPE) {
-            tmp.stx_mode = metadata.mode;
-        }
-        if mask.contains(PosixStatxMask::STATX_NLINK) {
-            tmp.stx_nlink = metadata.nlinks as u32;
-        }
-        if mask.contains(PosixStatxMask::STATX_UID) {
-            tmp.stx_uid = metadata.uid as u32;
-        }
-        if mask.contains(PosixStatxMask::STATX_GID) {
-            tmp.stx_gid = metadata.gid as u32;
-        }
-        if mask.contains(PosixStatxMask::STATX_ATIME) {
-            tmp.stx_atime.tv_sec = metadata.atime.tv_sec;
-            tmp.stx_atime.tv_nsec = metadata.atime.tv_nsec;
-        }
-        if mask.contains(PosixStatxMask::STATX_MTIME) {
-            tmp.stx_mtime.tv_sec = metadata.ctime.tv_sec;
-            tmp.stx_mtime.tv_nsec = metadata.ctime.tv_nsec;
-        }
-        if mask.contains(PosixStatxMask::STATX_CTIME) {
-            // ctime是文件上次修改状态的时间
-            tmp.stx_ctime.tv_sec = metadata.mtime.tv_sec;
-            tmp.stx_ctime.tv_nsec = metadata.mtime.tv_nsec;
-        }
-        if mask.contains(PosixStatxMask::STATX_INO) {
-            tmp.stx_inode = metadata.inode_id.into() as u64;
-        }
-        if mask.contains(PosixStatxMask::STATX_SIZE) {
-            tmp.stx_size = metadata.size;
-        }
-        if mask.contains(PosixStatxMask::STATX_BLOCKS) {
-            tmp.stx_blocks = metadata.blocks as u64;
-        }
-
-        if mask.contains(PosixStatxMask::STATX_BTIME) {
-            // btime是文件创建时间
-            tmp.stx_btime.tv_sec = metadata.ctime.tv_sec;
-            tmp.stx_btime.tv_nsec = metadata.ctime.tv_nsec;
-        }
-        if mask.contains(PosixStatxMask::STATX_ALL) {
-            tmp.stx_attributes = StxAttributes::STATX_ATTR_APPEND;
-            tmp.stx_attributes_mask |=
-                StxAttributes::STATX_ATTR_AUTOMOUNT | StxAttributes::STATX_ATTR_DAX;
-            tmp.stx_dev_major = metadata.dev_id as u32;
-            tmp.stx_dev_minor = metadata.dev_id as u32; //
-            tmp.stx_rdev_major = metadata.raw_dev.data();
-            tmp.stx_rdev_minor = metadata.raw_dev.data();
-        }
-        if mask.contains(PosixStatxMask::STATX_MNT_ID) {
-            tmp.stx_mnt_id = 0;
-        }
-        if mask.contains(PosixStatxMask::STATX_DIOALIGN) {
-            tmp.stx_dio_mem_align = 0;
-            tmp.stx_dio_offset_align = 0;
-        }
+        let filename = check_and_clone_cstr(filename_ptr as *const u8, Some(MAX_PATHLEN))?;
+        let filename_str = filename.to_str().map_err(|_| SystemError::EINVAL)?;
 
-        match file.file_type() {
-            FileType::File => tmp.stx_mode.insert(ModeType::S_IFREG),
-            FileType::Dir => tmp.stx_mode.insert(ModeType::S_IFDIR),
-            FileType::BlockDevice => tmp.stx_mode.insert(ModeType::S_IFBLK),
-            FileType::CharDevice => tmp.stx_mode.insert(ModeType::S_IFCHR),
-            FileType::SymLink => tmp.stx_mode.insert(ModeType::S_IFLNK),
-            FileType::Socket => tmp.stx_mode.insert(ModeType::S_IFSOCK),
-            FileType::Pipe => tmp.stx_mode.insert(ModeType::S_IFIFO),
-            FileType::KvmDevice => tmp.stx_mode.insert(ModeType::S_IFCHR),
-            FileType::FramebufferDevice => tmp.stx_mode.insert(ModeType::S_IFCHR),
-        }
-
-        writer.copy_one_to_user(&tmp, 0)?;
-        Self::close(fd as usize).ok();
-        return Ok(0);
+        do_statx(dfd, filename_str, flags, mask, user_kstat_ptr).map(|_| 0)
     }
 
     pub fn mknod(

+ 11 - 0
kernel/src/filesystem/vfs/core.rs → kernel/src/filesystem/vfs/vcore.rs

@@ -26,6 +26,7 @@ use super::{
     fcntl::AtFlags,
     file::FileMode,
     mount::{init_mountlist, MOUNT_LIST},
+    stat::LookUpFlags,
     syscall::UmountFlag,
     utils::{rsplit_path, user_path_at},
     FilePrivateData, IndexNode, InodeId, VFS_MAX_FOLLOW_SYMLINK_TIMES,
@@ -396,3 +397,13 @@ pub fn do_umount2(
     };
     return do_umount();
 }
+
+pub(super) fn do_file_lookup_at(
+    dfd: i32,
+    path: &str,
+    lookup_flags: LookUpFlags,
+) -> Result<Arc<dyn IndexNode>, SystemError> {
+    let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dfd, path)?;
+    let follow_final = lookup_flags.contains(LookUpFlags::FOLLOW);
+    return inode.lookup_follow_symlink2(&path, VFS_MAX_FOLLOW_SYMLINK_TIMES, follow_final);
+}

+ 1 - 1
kernel/src/init/init.rs

@@ -9,7 +9,7 @@ use crate::{
         video::VideoRefreshManager,
     },
     exception::{init::irq_init, softirq::softirq_init, InterruptArch},
-    filesystem::vfs::core::vfs_init,
+    filesystem::vfs::vcore::vfs_init,
     init::init_intertrait,
     libs::{
         futex::futex::Futex,

+ 1 - 1
kernel/src/init/initial_kthread.rs

@@ -9,7 +9,7 @@ use system_error::SystemError;
 use crate::{
     arch::{interrupt::TrapFrame, process::arch_switch_to_user},
     driver::net::e1000e::e1000e::e1000e_init,
-    filesystem::vfs::core::mount_root_fs,
+    filesystem::vfs::vcore::mount_root_fs,
     namespaces::NsProxy,
     net::net_core::net_init,
     process::{

+ 2 - 1
kernel/src/ipc/pipe.rs

@@ -3,7 +3,7 @@ use core::sync::atomic::compiler_fence;
 use crate::{
     arch::ipc::signal::{SigCode, Signal},
     filesystem::vfs::{
-        core::generate_inode_id, file::FileMode, syscall::ModeType, FilePrivateData, FileSystem,
+        file::FileMode, syscall::ModeType, vcore::generate_inode_id, FilePrivateData, FileSystem,
         FileType, IndexNode, Metadata, PollableInode,
     },
     libs::{
@@ -128,6 +128,7 @@ impl LockedPipeInode {
                 atime: PosixTimeSpec::default(),
                 mtime: PosixTimeSpec::default(),
                 ctime: PosixTimeSpec::default(),
+                btime: PosixTimeSpec::default(),
                 file_type: FileType::Pipe,
                 mode: ModeType::from_bits_truncate(0o666),
                 nlinks: 1,

+ 10 - 11
kernel/src/syscall/mod.rs

@@ -5,7 +5,7 @@ use core::{
 
 use crate::{
     arch::{ipc::signal::SigSet, syscall::nr::*},
-    filesystem::vfs::syscall::{PosixStatfs, PosixStatx},
+    filesystem::vfs::syscall::PosixStatfs,
     ipc::shm::{ShmCtlCmd, ShmFlags, ShmId, ShmKey},
     libs::{futex::constant::FutexFlag, rand::GRandFlags},
     mm::{page::PAGE_4K_SIZE, syscall::MremapFlags},
@@ -29,7 +29,8 @@ use crate::{
     filesystem::vfs::{
         fcntl::{AtFlags, FcntlCommand},
         file::FileMode,
-        syscall::{ModeType, PosixKstat, UtimensFlags},
+        stat::PosixKstat,
+        syscall::{ModeType, UtimensFlags},
         MAX_PATHLEN,
     },
     libs::align::page_align_up,
@@ -811,15 +812,13 @@ impl Syscall {
                 Self::fstatfs(fd, statfs)
             }
 
-            SYS_STATX => {
-                let fd = args[0] as i32;
-                let path = args[1] as *const u8;
-                let flags = args[2] as u32;
-                let mask = args[3] as u32;
-                let kstat = args[4] as *mut PosixStatx;
-
-                Self::do_statx(fd, path, flags, mask, kstat)
-            }
+            SYS_STATX => Self::statx(
+                args[0] as i32,
+                args[1],
+                args[2] as u32,
+                args[3] as u32,
+                args[4],
+            ),
 
             #[cfg(target_arch = "x86_64")]
             SYS_EPOLL_CREATE => Self::epoll_create(args[0] as i32),

+ 4 - 0
kernel/src/time/mod.rs

@@ -65,6 +65,10 @@ impl PosixTimeSpec {
         };
     }
 
+    pub fn is_empty(&self) -> bool {
+        self.tv_nsec == 0 && self.tv_sec == 0
+    }
+
     /// 获取当前时间
     #[inline(always)]
     pub fn now() -> Self {

+ 4 - 1
kernel/src/virt/vm/kvm_dev.rs

@@ -13,9 +13,9 @@ use crate::{
     filesystem::{
         devfs::{devfs_register, DevFS, DeviceINode},
         vfs::{
-            core::generate_inode_id,
             file::{File, FileMode},
             syscall::ModeType,
+            vcore::generate_inode_id,
             FileType, IndexNode, Metadata,
         },
     },
@@ -61,6 +61,7 @@ impl LockedKvmInode {
                 atime: PosixTimeSpec::default(),
                 mtime: PosixTimeSpec::default(),
                 ctime: PosixTimeSpec::default(),
+                btime: PosixTimeSpec::default(),
                 file_type: FileType::KvmDevice, // 文件夹,block设备,char设备
                 mode: ModeType::S_IALLUGO,
                 nlinks: 1,
@@ -202,6 +203,7 @@ impl KvmInstance {
                 atime: PosixTimeSpec::default(),
                 mtime: PosixTimeSpec::default(),
                 ctime: PosixTimeSpec::default(),
+                btime: PosixTimeSpec::default(),
                 file_type: FileType::KvmDevice,
                 mode: ModeType::S_IALLUGO,
                 nlinks: 1,
@@ -332,6 +334,7 @@ impl KvmVcpuDev {
                 atime: PosixTimeSpec::default(),
                 mtime: PosixTimeSpec::default(),
                 ctime: PosixTimeSpec::default(),
+                btime: PosixTimeSpec::default(),
                 file_type: FileType::KvmDevice, // 文件夹,block设备,char设备
                 mode: ModeType::S_IALLUGO,
                 nlinks: 1,