From b4eb05a17f0f65668f69e7979660874ef8e01a2e Mon Sep 17 00:00:00 2001 From: TTaq <103996388+TTaq@users.noreply.github.com> Date: Thu, 21 Mar 2024 19:59:10 +0800 Subject: [PATCH] Statx (#632) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 实现statx及测试的应用程序 --- kernel/src/filesystem/vfs/syscall.rs | 284 +++++++++++++++++++++++++ kernel/src/syscall/mod.rs | 12 ++ user/apps/test_statx/.gitignore | 2 + user/apps/test_statx/Cargo.toml | 8 + user/apps/test_statx/Makefile | 56 +++++ user/apps/test_statx/src/main.rs | 63 ++++++ user/dadk/config/test_statx_0_1_0.dadk | 25 +++ 7 files changed, 450 insertions(+) create mode 100644 user/apps/test_statx/.gitignore create mode 100644 user/apps/test_statx/Cargo.toml create mode 100644 user/apps/test_statx/Makefile create mode 100644 user/apps/test_statx/src/main.rs create mode 100644 user/dadk/config/test_statx_0_1_0.dadk diff --git a/kernel/src/filesystem/vfs/syscall.rs b/kernel/src/filesystem/vfs/syscall.rs index 8642fd72..7c5b81fd 100644 --- a/kernel/src/filesystem/vfs/syscall.rs +++ b/kernel/src/filesystem/vfs/syscall.rs @@ -146,6 +146,182 @@ impl PosixKstat { } } +#[repr(C)] +#[derive(Clone, Copy)] +/// # 文件信息结构体X +pub struct PosixStatx { + /* 0x00 */ + stx_mask: PosixStatxMask, + /// 文件系统块大小 + stx_blksize: u32, + /// Flags conveying information about the file [uncond] + stx_attributes: StxAttributes, + /* 0x10 */ + /// 硬链接数 + stx_nlink: u32, + /// 所有者用户ID + stx_uid: u32, + /// 所有者组ID + stx_gid: u32, + /// 文件权限 + stx_mode: ModeType, + + /* 0x20 */ + /// inode号 + stx_inode: u64, + /// 文件大小 + stx_size: i64, + /// 分配的512B块数 + stx_blocks: u64, + /// Mask to show what's supported in stx_attributes + stx_attributes_mask: StxAttributes, + + /* 0x40 */ + /// 最后访问时间 + stx_atime: TimeSpec, + /// 文件创建时间 + stx_btime: TimeSpec, + /// 最后状态变化时间 + stx_ctime: TimeSpec, + /// 最后修改时间 + stx_mtime: TimeSpec, + + /* 0x80 */ + /// 主设备ID + stx_rdev_major: u32, + /// 次设备ID + stx_rdev_minor: u32, + /// 主硬件设备ID + stx_dev_major: u32, + /// 次硬件设备ID + stx_dev_minor: u32, + + /* 0x90 */ + stx_mnt_id: u64, + stx_dio_mem_align: u32, + stx_dio_offset_align: u32, +} +impl PosixStatx { + fn new() -> Self { + Self { + stx_mask: PosixStatxMask::STATX_BASIC_STATS, + stx_blksize: 0, + stx_attributes: StxAttributes::STATX_ATTR_APPEND, + stx_nlink: 0, + stx_uid: 0, + stx_gid: 0, + stx_mode: ModeType { bits: 0 }, + stx_inode: 0, + stx_size: 0, + stx_blocks: 0, + stx_attributes_mask: StxAttributes::STATX_ATTR_APPEND, + stx_atime: TimeSpec { + tv_sec: 0, + tv_nsec: 0, + }, + stx_btime: TimeSpec { + tv_sec: 0, + tv_nsec: 0, + }, + stx_ctime: TimeSpec { + tv_sec: 0, + tv_nsec: 0, + }, + stx_mtime: TimeSpec { + tv_sec: 0, + tv_nsec: 0, + }, + stx_rdev_major: 0, + stx_rdev_minor: 0, + stx_dev_major: 0, + stx_dev_minor: 0, + stx_mnt_id: 0, + stx_dio_mem_align: 0, + stx_dio_offset_align: 0, + } + } +} + +bitflags! { + pub struct PosixStatxMask: u32{ + /// Want stx_mode & S_IFMT + const STATX_TYPE = 0x00000001; + + /// Want stx_mode & ~S_IFMT + const STATX_MODE = 0x00000002; + + /// Want stx_nlink + const STATX_NLINK = 0x00000004; + + /// Want stx_uid + const STATX_UID = 0x00000008; + + /// Want stx_gid + const STATX_GID = 0x00000010; + + /// Want stx_atime + const STATX_ATIME = 0x00000020; + + /// Want stx_mtime + const STATX_MTIME = 0x00000040; + + /// Want stx_ctime + const STATX_CTIME = 0x00000080; + + /// Want stx_ino + const STATX_INO = 0x00000100; + + /// Want stx_size + const STATX_SIZE = 0x00000200; + + /// Want stx_blocks + const STATX_BLOCKS = 0x00000400; + + /// [All of the above] + const STATX_BASIC_STATS = 0x000007ff; + + /// Want stx_btime + const STATX_BTIME = 0x00000800; + + /// The same as STATX_BASIC_STATS | STATX_BTIME. + /// It is deprecated and should not be used. + const STATX_ALL = 0x00000fff; + + /// Want stx_mnt_id (since Linux 5.8) + const STATX_MNT_ID = 0x00001000; + + /// Want stx_dio_mem_align and stx_dio_offset_align + /// (since Linux 6.1; support varies by filesystem) + const STATX_DIOALIGN = 0x00002000; + + /// Reserved for future struct statx expansion + const STATX_RESERVED = 0x80000000; + } +} + +bitflags! { + pub struct StxAttributes: u64 { + /// 文件被文件系统压缩 + const STATX_ATTR_COMPRESSED = 0x00000004; + /// 文件被标记为不可修改 + const STATX_ATTR_IMMUTABLE = 0x00000010; + /// 文件是只追加写入的 + const STATX_ATTR_APPEND = 0x00000020; + /// 文件不会被备份 + const STATX_ATTR_NODUMP = 0x00000040; + /// 文件需要密钥才能在文件系统中解密 + const STATX_ATTR_ENCRYPTED = 0x00000800; + /// 目录是自动挂载触发器 + const STATX_ATTR_AUTOMOUNT = 0x00001000; + /// 目录是挂载点的根目录 + const STATX_ATTR_MOUNT_ROOT = 0x00002000; + /// 文件受到 Verity 保护 + const STATX_ATTR_VERITY = 0x00100000; + /// 文件当前处于 DAX 状态 CPU直接访问 + const STATX_ATTR_DAX = 0x00200000; + } +} + /// /// Arguments for how openat2(2) should open the target path. If only @flags and /// @mode are non-zero, then openat2(2) operates very similarly to openat(2). @@ -928,6 +1104,114 @@ impl Syscall { return r; } + pub fn do_statx( + fd: i32, + path: *const u8, + flags: u32, + mask: u32, + usr_kstat: *mut PosixStatx, + ) -> Result { + if usr_kstat.is_null() { + 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::(), true)?; + let mut tmp: PosixStatx = PosixStatx::new(); + // 获取文件信息 + let metadata = file.lock().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() as u32; + tmp.stx_rdev_minor = metadata.raw_dev.data() as u32; + } + 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; + } + + match file.lock().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); + } + pub fn mknod( path: *const u8, mode: ModeType, diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 1396d3b4..5d6a8dad 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -7,6 +7,7 @@ use core::{ use crate::{ arch::{ipc::signal::SigSet, syscall::nr::*}, driver::base::device::device_number::DeviceNumber, + filesystem::vfs::syscall::PosixStatx, libs::{futex::constant::FutexFlag, rand::GRandFlags}, mm::syscall::MremapFlags, net::syscall::MsgHdr, @@ -20,6 +21,7 @@ use crate::{ use num_traits::FromPrimitive; use system_error::SystemError; +use uefi::proto::debug; use crate::{ arch::{cpu::cpu_reset, interrupt::TrapFrame, MMArch}, @@ -703,6 +705,16 @@ impl Syscall { Self::stat(path, kstat) } + 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_EPOLL_CREATE => Self::epoll_create(args[0] as i32), SYS_EPOLL_CREATE1 => Self::epoll_create1(args[0]), diff --git a/user/apps/test_statx/.gitignore b/user/apps/test_statx/.gitignore new file mode 100644 index 00000000..06aba01b --- /dev/null +++ b/user/apps/test_statx/.gitignore @@ -0,0 +1,2 @@ +Cargo.lock +/target diff --git a/user/apps/test_statx/Cargo.toml b/user/apps/test_statx/Cargo.toml new file mode 100644 index 00000000..fa7b212a --- /dev/null +++ b/user/apps/test_statx/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "test_statx" +version = "0.1.0" +edition = "2021" + +[dependencies] +libc = "0.2.153" +sc = "0.2.7" diff --git a/user/apps/test_statx/Makefile b/user/apps/test_statx/Makefile new file mode 100644 index 00000000..0239a062 --- /dev/null +++ b/user/apps/test_statx/Makefile @@ -0,0 +1,56 @@ +TOOLCHAIN="+nightly-2023-08-15-x86_64-unknown-linux-gnu" +# RUSTFLAGS+="-C target-feature=+crt-static -C link-arg=-no-pie" + +ifdef DADK_CURRENT_BUILD_DIR +# 如果是在dadk中编译,那么安装到dadk的安装目录中 + INSTALL_DIR = $(DADK_CURRENT_BUILD_DIR) +else +# 如果是在本地编译,那么安装到当前目录下的install目录中 + INSTALL_DIR = ./install +endif + +ifeq ($(ARCH), x86_64) + export RUST_TARGET=x86_64-unknown-linux-musl +else ifeq ($(ARCH), riscv64) + export RUST_TARGET=riscv64gc-unknown-linux-gnu +else +# 默认为x86_86,用于本地编译 + export RUST_TARGET=x86_64-unknown-linux-musl +endif + +run: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) + +build: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) + +clean: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) + +test: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) + +doc: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) doc --target $(RUST_TARGET) + +fmt: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt + +fmt-check: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) fmt --check + +run-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --target $(RUST_TARGET) --release + +build-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --target $(RUST_TARGET) --release + +clean-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --target $(RUST_TARGET) --release + +test-release: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --target $(RUST_TARGET) --release + +.PHONY: install +install: + RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path . --no-track --root $(INSTALL_DIR) --force diff --git a/user/apps/test_statx/src/main.rs b/user/apps/test_statx/src/main.rs new file mode 100644 index 00000000..a7f4524c --- /dev/null +++ b/user/apps/test_statx/src/main.rs @@ -0,0 +1,63 @@ +use libc::syscall; +use libc::AT_FDCWD; +use std::ffi::CString; + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct Statx { + pub stx_mask: u32, + pub stx_blksize: u32, + pub stx_attributes: u64, + pub stx_nlink: u32, + pub stx_uid: u32, + pub stx_gid: u32, + pub stx_mode: u16, + __statx_pad1: [u16; 1], + pub stx_ino: u64, + pub stx_size: u64, + pub stx_blocks: u64, + pub stx_attributes_mask: u64, + pub stx_atime: StatxTimestamp, + pub stx_btime: StatxTimestamp, + pub stx_ctime: StatxTimestamp, + pub stx_mtime: StatxTimestamp, + pub stx_rdev_major: u32, + pub stx_rdev_minor: u32, + pub stx_dev_major: u32, + pub stx_dev_minor: u32, + pub stx_mnt_id: u64, + pub stx_dio_mem_align: u32, + pub stx_dio_offset_align: u32, + __statx_pad3: [u64; 12], +} + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct StatxTimestamp { + pub tv_sec: i64, + pub tv_nsec: u32, + pub __statx_timestamp_pad1: [i32; 1], +} + +fn main() { + let path = CString::new("/bin/about.elf").expect("Failed to create CString"); + let mut statxbuf: Statx = unsafe { std::mem::zeroed() }; + let x = sc::nr::STATX as i64; + + let result = unsafe { + syscall( + x, + AT_FDCWD, + path.as_ptr(), + libc::AT_SYMLINK_NOFOLLOW, + 0x7ff, + &mut statxbuf, + ) + }; + + if result != -1 { + println!("statx succeeded: {:?}", statxbuf); + } else { + eprintln!("statx failed"); + } +} diff --git a/user/dadk/config/test_statx_0_1_0.dadk b/user/dadk/config/test_statx_0_1_0.dadk new file mode 100644 index 00000000..ea694e98 --- /dev/null +++ b/user/dadk/config/test_statx_0_1_0.dadk @@ -0,0 +1,25 @@ +{ + "name": "test_statx", + "version": "0.1.0", + "description": "statx测试", + "task_type": { + "BuildFromSource": { + "Local": { + "path": "apps/test_statx" + } + } + }, + "depends": [], + "build": { + "build_command": "make install" + }, + "install": { + "in_dragonos_path": "/" + }, + "clean": { + "clean_command": "make clean" + }, + "envs": [], + "build_once": false, + "install_once": false +} \ No newline at end of file