Refactor `Metadata`'s fields and document them.

Besides, change `MajorId`'s lower bound to 0, which is used to
represents a invalid or absent device (pseudo filesystems).
This commit is contained in:
Chaoqun Zheng 2026-01-14 23:11:38 +08:00
parent 9652538807
commit aa33845967
19 changed files with 305 additions and 142 deletions

2
Cargo.lock generated
View File

@ -722,6 +722,8 @@ name = "device-id"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"aster-util", "aster-util",
"id-alloc",
"spin",
] ]
[[package]] [[package]]

View File

@ -7,6 +7,8 @@ edition.workspace = true
[dependencies] [dependencies]
aster-util.workspace = true aster-util.workspace = true
id-alloc.workspace = true
spin.workspace = true
[lints] [lints]
workspace = true workspace = true

View File

@ -13,6 +13,61 @@
#![deny(unsafe_code)] #![deny(unsafe_code)]
use aster_util::ranged_integer::{RangedU16, RangedU32}; use aster_util::ranged_integer::{RangedU16, RangedU32};
use id_alloc::IdAlloc;
use spin::{Mutex, Once};
pub struct PseudoFSDeviceIdAllocator {
minor_allocator: Mutex<IdAlloc>,
}
/// An allocator for pseudo filesystems (no backing block device) device ID.
///
/// This follows the Linux convention where pseudo filesystems use major=0
/// and dynamically allocate minor numbers (starting from 1) to distinguish different
/// pseudo filesystem instances.
///
/// Reference: <https://elixir.bootlin.com/linux/v6.18/source/fs/super.c#L1242-L1271>
impl PseudoFSDeviceIdAllocator {
fn new() -> Self {
let mut minor_allocator = IdAlloc::with_capacity(MinorId::MAX.get() as usize + 1);
// Mark 0 as allocated to ensure minor numbers start from 1.
let _ = minor_allocator.alloc_specific(0);
Self {
minor_allocator: Mutex::new(minor_allocator),
}
}
/// Allocate a device ID for pseudo filesystems.
/// Returns `None` if minor number allocation fails (exhausted).
///
/// # Panics
///
/// Panics if the allocator was not initialized.
pub fn allocate(&self) -> DeviceId {
let major = MajorId::new(0);
let minor = self.minor_allocator.lock().alloc().unwrap() as u32;
DeviceId::new(major, MinorId::new(minor))
}
/// Free a dynamically allocated pseudo filesystem device ID.
///
/// # Panics
///
/// Panics if the device ID's major is not 0.
pub fn release(&mut self, id: DeviceId) {
debug_assert!(id.major().get() == 0);
self.minor_allocator.lock().free(id.minor().get() as usize);
}
}
pub static PSEUDO_FS_DEVICE_ID_ALLOCATOR: Once<PseudoFSDeviceIdAllocator> = Once::new();
pub fn init() {
PSEUDO_FS_DEVICE_ID_ALLOCATOR.call_once(PseudoFSDeviceIdAllocator::new);
}
/// A device ID, embedding the major ID and minor ID. /// A device ID, embedding the major ID and minor ID.
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@ -24,6 +79,11 @@ impl DeviceId {
Self(((major.get() as u32) << 20) | minor.get()) Self(((major.get() as u32) << 20) | minor.get())
} }
/// FIXME: just a placeholder for now.
pub const fn none() -> Self {
Self(0)
}
/// Returns the encoded `u32` value. /// Returns the encoded `u32` value.
pub fn to_raw(&self) -> u32 { pub fn to_raw(&self) -> u32 {
self.0 self.0
@ -38,6 +98,11 @@ impl DeviceId {
pub fn minor(&self) -> MinorId { pub fn minor(&self) -> MinorId {
MinorId::new(self.0 & 0xf_ffff) MinorId::new(self.0 & 0xf_ffff)
} }
/// Checks if the container device is valid (major != 0).
pub fn has_valid_container(&self) -> bool {
self.major().get() != 0
}
} }
impl DeviceId { impl DeviceId {
@ -92,10 +157,13 @@ const MAX_MINOR_ID: u32 = 0x000f_ffff;
/// The major component of a device ID. /// The major component of a device ID.
/// ///
/// A major ID is a non-zero, 12-bit integer, thus falling in the range of `1..(1u16 << 12)`. /// A major ID is a 12-bit integer, thus falling in the range of `0..(1u16 << 12)`.
///
/// - **0**: Represents an invalid or absent device (used for pseudo filesystems)
/// - **1-4095**: Valid major device numbers
/// ///
/// Reference: <https://elixir.bootlin.com/linux/v6.13/source/include/linux/kdev_t.h#L10>. /// Reference: <https://elixir.bootlin.com/linux/v6.13/source/include/linux/kdev_t.h#L10>.
pub type MajorId = RangedU16<1, MAX_MAJOR_ID>; pub type MajorId = RangedU16<0, MAX_MAJOR_ID>;
/// The minor component of a device ID. /// The minor component of a device ID.
/// ///

View File

@ -239,27 +239,27 @@ impl Inode for RootInode {
} }
fn atime(&self) -> Duration { fn atime(&self) -> Duration {
self.metadata.read().atime self.metadata.read().last_access_at
} }
fn set_atime(&self, time: Duration) { fn set_atime(&self, time: Duration) {
self.metadata.write().atime = time; self.metadata.write().last_access_at = time;
} }
fn mtime(&self) -> Duration { fn mtime(&self) -> Duration {
self.metadata.read().mtime self.metadata.read().last_modify_at
} }
fn set_mtime(&self, time: Duration) { fn set_mtime(&self, time: Duration) {
self.metadata.write().mtime = time; self.metadata.write().last_modify_at = time;
} }
fn ctime(&self) -> Duration { fn ctime(&self) -> Duration {
self.metadata.read().ctime self.metadata.read().last_meta_change_at
} }
fn set_ctime(&self, time: Duration) { fn set_ctime(&self, time: Duration) {
self.metadata.write().ctime = time; self.metadata.write().last_meta_change_at = time;
} }
fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>> { fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>> {

View File

@ -121,27 +121,27 @@ impl Inode for Ptmx {
} }
fn atime(&self) -> Duration { fn atime(&self) -> Duration {
self.metadata.read().atime self.metadata.read().last_access_at
} }
fn set_atime(&self, time: Duration) { fn set_atime(&self, time: Duration) {
self.metadata.write().atime = time; self.metadata.write().last_access_at = time;
} }
fn mtime(&self) -> Duration { fn mtime(&self) -> Duration {
self.metadata.read().mtime self.metadata.read().last_modify_at
} }
fn set_mtime(&self, time: Duration) { fn set_mtime(&self, time: Duration) {
self.metadata.write().mtime = time; self.metadata.write().last_modify_at = time;
} }
fn ctime(&self) -> Duration { fn ctime(&self) -> Duration {
self.metadata.read().ctime self.metadata.read().last_meta_change_at
} }
fn set_ctime(&self, time: Duration) { fn set_ctime(&self, time: Duration) {
self.metadata.write().ctime = time; self.metadata.write().last_meta_change_at = time;
} }
fn fs(&self) -> Arc<dyn FileSystem> { fn fs(&self) -> Arc<dyn FileSystem> {

View File

@ -120,27 +120,27 @@ impl Inode for PtySlaveInode {
} }
fn atime(&self) -> Duration { fn atime(&self) -> Duration {
self.metadata.read().atime self.metadata.read().last_access_at
} }
fn set_atime(&self, time: Duration) { fn set_atime(&self, time: Duration) {
self.metadata.write().atime = time; self.metadata.write().last_access_at = time;
} }
fn mtime(&self) -> Duration { fn mtime(&self) -> Duration {
self.metadata.read().mtime self.metadata.read().last_modify_at
} }
fn set_mtime(&self, time: Duration) { fn set_mtime(&self, time: Duration) {
self.metadata.write().mtime = time; self.metadata.write().last_modify_at = time;
} }
fn ctime(&self) -> Duration { fn ctime(&self) -> Duration {
self.metadata.read().ctime self.metadata.read().last_meta_change_at
} }
fn set_ctime(&self, time: Duration) { fn set_ctime(&self, time: Duration) {
self.metadata.write().ctime = time; self.metadata.write().last_meta_change_at = time;
} }
fn fs(&self) -> Arc<dyn FileSystem> { fn fs(&self) -> Arc<dyn FileSystem> {

View File

@ -12,6 +12,7 @@ use aster_block::{
bio::{BioDirection, BioSegment, BioWaiter}, bio::{BioDirection, BioSegment, BioWaiter},
id::{Bid, BlockId}, id::{Bid, BlockId},
}; };
use device_id::DeviceId;
use ostd::mm::{Segment, VmIo, io_util::HasVmReaderWriter}; use ostd::mm::{Segment, VmIo, io_util::HasVmReaderWriter};
use super::{ use super::{
@ -1358,21 +1359,20 @@ impl Inode for ExfatInode {
}; };
Metadata { Metadata {
dev: 0,
ino: inner.ino, ino: inner.ino,
size: inner.size, size: inner.size,
blk_size, optimal_block_size: blk_size,
blocks: inner.size.div_ceil(blk_size), nr_sectors_allocated: inner.size.div_ceil(blk_size),
atime: inner.atime.as_duration().unwrap_or_default(), last_access_at: inner.atime.as_duration().unwrap_or_default(),
mtime: inner.mtime.as_duration().unwrap_or_default(), last_modify_at: inner.mtime.as_duration().unwrap_or_default(),
ctime: inner.ctime.as_duration().unwrap_or_default(), last_meta_change_at: inner.ctime.as_duration().unwrap_or_default(),
type_: inner.inode_type, type_: inner.inode_type,
mode: inner.make_mode(), mode: inner.make_mode(),
nlinks, nr_hard_links: nlinks,
uid: Uid::new(inner.fs().mount_option().fs_uid as u32), uid: Uid::new(inner.fs().mount_option().fs_uid as u32),
gid: Gid::new(inner.fs().mount_option().fs_gid as u32), gid: Gid::new(inner.fs().mount_option().fs_gid as u32),
//real device container_dev_id: DeviceId::none(), // FIXME: placeholder
rdev: 0, self_dev_id: None,
} }
} }

View File

@ -6,6 +6,7 @@
use alloc::{borrow::ToOwned, rc::Rc}; use alloc::{borrow::ToOwned, rc::Rc};
use core::sync::atomic::{AtomicUsize, Ordering}; use core::sync::atomic::{AtomicUsize, Ordering};
use device_id::DeviceId;
use inherit_methods_macro::inherit_methods; use inherit_methods_macro::inherit_methods;
use ostd::{const_assert, mm::io_util::HasVmReaderWriter}; use ostd::{const_assert, mm::io_util::HasVmReaderWriter};
@ -106,20 +107,24 @@ impl Inode {
let inner = self.inner.read(); let inner = self.inner.read();
let id = self.fs.upgrade().unwrap().block_device().id(); let id = self.fs.upgrade().unwrap().block_device().id();
Metadata { Metadata {
dev: id.as_encoded_u64(),
ino: self.ino() as _, ino: self.ino() as _,
size: inner.file_size() as _, size: inner.file_size() as _,
blk_size: BLOCK_SIZE, optimal_block_size: BLOCK_SIZE,
blocks: inner.blocks_count() as _, nr_sectors_allocated: inner.blocks_count() as _,
atime: inner.atime(), last_access_at: inner.atime(),
mtime: inner.mtime(), last_modify_at: inner.mtime(),
ctime: inner.ctime(), last_meta_change_at: inner.ctime(),
type_: self.type_, type_: self.type_,
mode: InodeMode::from(inner.file_perm()), mode: InodeMode::from(inner.file_perm()),
nlinks: inner.hard_links() as _, nr_hard_links: inner.hard_links() as _,
uid: Uid::new(inner.uid()), uid: Uid::new(inner.uid()),
gid: Gid::new(inner.gid()), gid: Gid::new(inner.gid()),
rdev: self.device_id(), container_dev_id: id,
self_dev_id: if self.device_id() != 0 {
DeviceId::from_encoded_u64(self.device_id())
} else {
None
},
} }
} }

View File

@ -34,6 +34,7 @@ use crate::{
}; };
pub fn init() { pub fn init() {
device_id::init();
registry::init(); registry::init();
sysfs::init(); sysfs::init();

View File

@ -371,7 +371,7 @@ impl DirDentry<'_> {
dir_inode.unlink(name)?; dir_inode.unlink(name)?;
let nlinks = child_inode.metadata().nlinks; let nlinks = child_inode.metadata().nr_hard_links;
fs::notify::on_link_count(&child_inode); fs::notify::on_link_count(&child_inode);
if nlinks == 0 { if nlinks == 0 {
// FIXME: `DELETE_SELF` should be generated after closing the last FD. // FIXME: `DELETE_SELF` should be generated after closing the last FD.
@ -422,7 +422,7 @@ impl DirDentry<'_> {
dir_inode.rmdir(name)?; dir_inode.rmdir(name)?;
let nlinks = child_inode.metadata().nlinks; let nlinks = child_inode.metadata().nr_hard_links;
if nlinks == 0 { if nlinks == 0 {
// FIXME: `DELETE_SELF` should be generated after closing the last FD. // FIXME: `DELETE_SELF` should be generated after closing the last FD.
fs::notify::on_inode_removed(&child_inode); fs::notify::on_inode_removed(&child_inode);

View File

@ -58,27 +58,27 @@ impl Common {
} }
pub fn atime(&self) -> Duration { pub fn atime(&self) -> Duration {
self.metadata.read().atime self.metadata.read().last_access_at
} }
pub fn set_atime(&self, time: Duration) { pub fn set_atime(&self, time: Duration) {
self.metadata.write().atime = time; self.metadata.write().last_access_at = time;
} }
pub fn mtime(&self) -> Duration { pub fn mtime(&self) -> Duration {
self.metadata.read().mtime self.metadata.read().last_modify_at
} }
pub fn set_mtime(&self, time: Duration) { pub fn set_mtime(&self, time: Duration) {
self.metadata.write().mtime = time; self.metadata.write().last_modify_at = time;
} }
pub fn ctime(&self) -> Duration { pub fn ctime(&self) -> Duration {
self.metadata.read().ctime self.metadata.read().last_meta_change_at
} }
pub fn set_ctime(&self, time: Duration) { pub fn set_ctime(&self, time: Duration) {
self.metadata.write().ctime = time; self.metadata.write().last_meta_change_at = time;
} }
pub fn mode(&self) -> Result<InodeMode> { pub fn mode(&self) -> Result<InodeMode> {

View File

@ -6,6 +6,7 @@ use core::{
time::Duration, time::Duration,
}; };
use device_id::DeviceId;
use spin::Once; use spin::Once;
use super::utils::{Extension, InodeIo, StatusFlags}; use super::utils::{Extension, InodeIo, StatusFlags};
@ -372,20 +373,20 @@ impl PseudoInode {
let type_ = InodeType::from(type_); let type_ = InodeType::from(type_);
let metadata = Metadata { let metadata = Metadata {
dev: 0,
ino, ino,
size: 0, size: 0,
blk_size: aster_block::BLOCK_SIZE, optimal_block_size: aster_block::BLOCK_SIZE,
blocks: 0, nr_sectors_allocated: 0,
atime: now, last_access_at: now,
mtime: now, last_modify_at: now,
ctime: now, last_meta_change_at: now,
type_, type_,
mode, mode,
nlinks: 1, nr_hard_links: 1,
uid, uid,
gid, gid,
rdev: 0, container_dev_id: DeviceId::none(), // FIXME: placeholder
self_dev_id: None,
}; };
PseudoInode { PseudoInode {
@ -462,7 +463,7 @@ impl Inode for PseudoInode {
let mut meta = self.metadata.lock(); let mut meta = self.metadata.lock();
meta.mode = mode; meta.mode = mode;
meta.ctime = now(); meta.last_meta_change_at = now();
Ok(()) Ok(())
} }
@ -473,7 +474,7 @@ impl Inode for PseudoInode {
fn set_owner(&self, uid: Uid) -> Result<()> { fn set_owner(&self, uid: Uid) -> Result<()> {
let mut meta = self.metadata.lock(); let mut meta = self.metadata.lock();
meta.uid = uid; meta.uid = uid;
meta.ctime = now(); meta.last_meta_change_at = now();
Ok(()) Ok(())
} }
@ -484,32 +485,32 @@ impl Inode for PseudoInode {
fn set_group(&self, gid: Gid) -> Result<()> { fn set_group(&self, gid: Gid) -> Result<()> {
let mut meta = self.metadata.lock(); let mut meta = self.metadata.lock();
meta.gid = gid; meta.gid = gid;
meta.ctime = now(); meta.last_meta_change_at = now();
Ok(()) Ok(())
} }
fn atime(&self) -> Duration { fn atime(&self) -> Duration {
self.metadata.lock().atime self.metadata.lock().last_access_at
} }
fn set_atime(&self, time: Duration) { fn set_atime(&self, time: Duration) {
self.metadata.lock().atime = time; self.metadata.lock().last_access_at = time;
} }
fn mtime(&self) -> Duration { fn mtime(&self) -> Duration {
self.metadata.lock().mtime self.metadata.lock().last_modify_at
} }
fn set_mtime(&self, time: Duration) { fn set_mtime(&self, time: Duration) {
self.metadata.lock().mtime = time; self.metadata.lock().last_modify_at = time;
} }
fn ctime(&self) -> Duration { fn ctime(&self) -> Duration {
self.metadata.lock().ctime self.metadata.lock().last_meta_change_at
} }
fn set_ctime(&self, time: Duration) { fn set_ctime(&self, time: Duration) {
self.metadata.lock().ctime = time; self.metadata.lock().last_meta_change_at = time;
} }
fn open( fn open(

View File

@ -1170,20 +1170,24 @@ impl Inode for RamInode {
let rdev = self.inner.device_id().unwrap_or(0); let rdev = self.inner.device_id().unwrap_or(0);
let inode_metadata = self.metadata.lock(); let inode_metadata = self.metadata.lock();
Metadata { Metadata {
dev: 0,
ino: self.ino as _, ino: self.ino as _,
size: inode_metadata.size, size: inode_metadata.size,
blk_size: BLOCK_SIZE, optimal_block_size: BLOCK_SIZE,
blocks: inode_metadata.blocks, nr_sectors_allocated: inode_metadata.blocks,
atime: inode_metadata.atime, last_access_at: inode_metadata.atime,
mtime: inode_metadata.mtime, last_modify_at: inode_metadata.mtime,
ctime: inode_metadata.ctime, last_meta_change_at: inode_metadata.ctime,
type_: self.typ, type_: self.typ,
mode: inode_metadata.mode, mode: inode_metadata.mode,
nlinks: inode_metadata.nlinks, nr_hard_links: inode_metadata.nlinks,
uid: inode_metadata.uid, uid: inode_metadata.uid,
gid: inode_metadata.gid, gid: inode_metadata.gid,
rdev, container_dev_id: DeviceId::none(), // FIXME: placeholder
self_dev_id: if rdev == 0 {
None
} else {
DeviceId::from_encoded_u64(rdev)
},
} }
} }

View File

@ -6,6 +6,7 @@ use alloc::boxed::ThinBox;
use core::time::Duration; use core::time::Duration;
use core2::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult, Write}; use core2::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult, Write};
use device_id::DeviceId;
use ostd::task::Task; use ostd::task::Task;
use spin::Once; use spin::Once;
@ -124,101 +125,177 @@ impl From<AccessMode> for Permission {
} }
} }
/// File metadata, providing detailed information about an inode.
///
/// Asterinas's type-safe counterparts for Linux's `struct stat`.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Metadata { pub struct Metadata {
pub dev: u64, /// The inode number, which uniquely identifies the file within the filesystem.
///
/// Corresponds to `st_ino`.
pub ino: u64, pub ino: u64,
/// The size of the inode.
///
/// The interpretation depends on `inode_type`:
/// - **Regular File**: The total length of the file content.
/// - **Directory**: The size of the directory's internal table (usually a multiple of block size).
/// - **Symbolic Link**: The length of the target pathname.
/// - **Device/Socket/FIFO**: Usually zero.
///
/// Corresponds to `st_size`.
pub size: usize, pub size: usize,
pub blk_size: usize,
pub blocks: usize, /// The optimal block size for filesystem I/O operations.
pub atime: Duration, ///
pub mtime: Duration, /// Corresponds to `st_blksize`.
pub ctime: Duration, pub optimal_block_size: usize,
/// Number of 512-byte sectors allocated for the inode on disk.
///
/// Corresponds to `st_blocks`.
///
/// This represents physical usage.
/// For sparse files (those having holes), `size` is greater than this field.
/// For files with preallocated blocks (`FALLOC_FL_KEEP_SIZE`),
/// `size` is smaller than this field.
pub nr_sectors_allocated: usize,
/// The timestamp of the last access to the inode's data.
///
/// Corresponds to `st_atime`.
pub last_access_at: Duration,
/// The timestamp of the last modification to the inode's content.
///
/// Corresponds to `st_mtime`.
pub last_modify_at: Duration,
/// The timestamp of the last change to the inode's metadata.
///
/// This is updated when permissions, ownership, or link count change,
/// not just when the inode content is modified.
///
/// Corresponds to `st_ctime`.
pub last_meta_change_at: Duration,
/// The type of the inode (e.g., regular file, directory, symlink).
///
/// Derived from the file type bits of `st_mode` (using the `S_IFMT` mask).
pub type_: InodeType, pub type_: InodeType,
/// The inode mode, representing access permissions.
///
/// Derived from the permission bits of `st_mode`.
pub mode: InodeMode, pub mode: InodeMode,
pub nlinks: usize,
/// The number of hard links pointing to this inode.
///
/// Corresponds to `st_nlink`.
pub nr_hard_links: usize,
/// The User ID (UID) of the inode's owner.
///
/// Corresponds to `st_uid`.
pub uid: Uid, pub uid: Uid,
/// The Group ID (GID) of the inode's owner.
///
/// Corresponds to `st_gid`.
pub gid: Gid, pub gid: Gid,
pub rdev: u64,
/// The ID of the device containing the inode.
///
/// For persisted files, this device could be a on-disk partition or a logical volume (with RAID).
/// For pseudo files (e.g., those on sockfs), this device is also "pseudo".
///
/// Corresponds to `st_dev`.
pub container_dev_id: DeviceId,
/// The device ID of the inode itself, if this inode represents a special device file (character or block).
///
/// Corresponds to `st_rdev`.
pub self_dev_id: Option<DeviceId>,
} }
impl Metadata { impl Metadata {
pub fn new_dir(ino: u64, mode: InodeMode, blk_size: usize) -> Self { pub fn new_dir(ino: u64, mode: InodeMode, blk_size: usize) -> Self {
let now = RealTimeCoarseClock::get().read_time(); let now = RealTimeCoarseClock::get().read_time();
Self { Self {
dev: 0,
ino, ino,
size: 2, size: 2,
blk_size, optimal_block_size: blk_size,
blocks: 1, nr_sectors_allocated: 1,
atime: now, last_access_at: now,
mtime: now, last_modify_at: now,
ctime: now, last_meta_change_at: now,
type_: InodeType::Dir, type_: InodeType::Dir,
mode, mode,
nlinks: 2, nr_hard_links: 2,
uid: Uid::new_root(), uid: Uid::new_root(),
gid: Gid::new_root(), gid: Gid::new_root(),
rdev: 0, container_dev_id: DeviceId::none(), // FIXME: placeholder
self_dev_id: None,
} }
} }
pub fn new_file(ino: u64, mode: InodeMode, blk_size: usize) -> Self { pub fn new_file(ino: u64, mode: InodeMode, blk_size: usize) -> Self {
let now = RealTimeCoarseClock::get().read_time(); let now = RealTimeCoarseClock::get().read_time();
Self { Self {
dev: 0,
ino, ino,
size: 0, size: 0,
blk_size, optimal_block_size: blk_size,
blocks: 0, nr_sectors_allocated: 0,
atime: now, last_access_at: now,
mtime: now, last_modify_at: now,
ctime: now, last_meta_change_at: now,
type_: InodeType::File, type_: InodeType::File,
mode, mode,
nlinks: 1, nr_hard_links: 1,
uid: Uid::new_root(), uid: Uid::new_root(),
gid: Gid::new_root(), gid: Gid::new_root(),
rdev: 0, container_dev_id: DeviceId::none(), // FIXME: placeholder
self_dev_id: None,
} }
} }
pub fn new_symlink(ino: u64, mode: InodeMode, blk_size: usize) -> Self { pub fn new_symlink(ino: u64, mode: InodeMode, blk_size: usize) -> Self {
let now = RealTimeCoarseClock::get().read_time(); let now = RealTimeCoarseClock::get().read_time();
Self { Self {
dev: 0,
ino, ino,
size: 0, size: 0,
blk_size, optimal_block_size: blk_size,
blocks: 0, nr_sectors_allocated: 0,
atime: now, last_access_at: now,
mtime: now, last_modify_at: now,
ctime: now, last_meta_change_at: now,
type_: InodeType::SymLink, type_: InodeType::SymLink,
mode, mode,
nlinks: 1, nr_hard_links: 1,
uid: Uid::new_root(), uid: Uid::new_root(),
gid: Gid::new_root(), gid: Gid::new_root(),
rdev: 0, container_dev_id: DeviceId::none(), // FIXME: placeholder
self_dev_id: None,
} }
} }
pub fn new_device(ino: u64, mode: InodeMode, blk_size: usize, device: &dyn Device) -> Self { pub fn new_device(ino: u64, mode: InodeMode, blk_size: usize, device: &dyn Device) -> Self {
let now = RealTimeCoarseClock::get().read_time(); let now = RealTimeCoarseClock::get().read_time();
Self { Self {
dev: 0,
ino, ino,
size: 0, size: 0,
blk_size, optimal_block_size: blk_size,
blocks: 0, nr_sectors_allocated: 0,
atime: now, last_access_at: now,
mtime: now, last_modify_at: now,
ctime: now, last_meta_change_at: now,
type_: InodeType::from(device.type_()), type_: InodeType::from(device.type_()),
mode, mode,
nlinks: 1, nr_hard_links: 1,
uid: Uid::new_root(), uid: Uid::new_root(),
gid: Gid::new_root(), gid: Gid::new_root(),
rdev: device.id().as_encoded_u64(), container_dev_id: DeviceId::none(), // FIXME: placeholder
self_dev_id: Some(device.id()),
} }
} }
} }

View File

@ -12,6 +12,7 @@ use core::time::Duration;
use aster_systree::{ use aster_systree::{
SysAttr, SysBranchNode, SysNode, SysNodeId, SysNodeType, SysObj, SysStr, SysSymlink, SysAttr, SysBranchNode, SysNode, SysNodeId, SysNodeType, SysObj, SysStr, SysSymlink,
}; };
use device_id::DeviceId;
use super::Extension; use super::Extension;
use crate::{ use crate::{
@ -74,21 +75,21 @@ pub(in crate::fs) trait SysTreeInodeTy: Send + Sync + 'static {
fn new_metadata(ino: u64, type_: InodeType) -> Metadata { fn new_metadata(ino: u64, type_: InodeType) -> Metadata {
let now = RealTimeCoarseClock::get().read_time(); let now = RealTimeCoarseClock::get().read_time();
Metadata { Metadata {
dev: 0,
ino, ino,
size: 0, size: 0,
blk_size: 1024, optimal_block_size: 1024,
blocks: 0, nr_sectors_allocated: 0,
atime: now, last_access_at: now,
mtime: now, last_modify_at: now,
ctime: now, last_meta_change_at: now,
type_, type_,
// The mode field in metadata will not be used // The mode field in metadata will not be used
mode: mkmod!(a=), mode: mkmod!(a=),
nlinks: 1, nr_hard_links: 1,
uid: Uid::new_root(), uid: Uid::new_root(),
gid: Gid::new_root(), gid: Gid::new_root(),
rdev: 0, container_dev_id: DeviceId::none(), // FIXME: placeholder
self_dev_id: None,
} }
} }
@ -361,19 +362,19 @@ impl<KInode: SysTreeInodeTy + Send + Sync + 'static> Inode for KInode {
} }
default fn atime(&self) -> Duration { default fn atime(&self) -> Duration {
self.metadata().atime self.metadata().last_access_at
} }
default fn set_atime(&self, _time: Duration) {} default fn set_atime(&self, _time: Duration) {}
default fn mtime(&self) -> Duration { default fn mtime(&self) -> Duration {
self.metadata().mtime self.metadata().last_modify_at
} }
default fn set_mtime(&self, _time: Duration) {} default fn set_mtime(&self, _time: Duration) {}
default fn ctime(&self) -> Duration { default fn ctime(&self) -> Duration {
self.metadata().ctime self.metadata().last_meta_change_at
} }
default fn set_ctime(&self, _time: Duration) {} default fn set_ctime(&self, _time: Duration) {}

View File

@ -1,7 +1,5 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
use device_id::DeviceId;
use super::SyscallReturn; use super::SyscallReturn;
use crate::{ use crate::{
fs::{ fs::{
@ -240,7 +238,7 @@ fn get_fs(
return_errno_with_message!(Errno::ENODEV, "the path is not a device file"); return_errno_with_message!(Errno::ENODEV, "the path is not a device file");
} }
let id = DeviceId::from_encoded_u64(path.metadata().rdev); let id = path.metadata().self_dev_id;
let device = id.and_then(aster_block::lookup); let device = id.and_then(aster_block::lookup);
if device.is_none() { if device.is_none() {
return_errno_with_message!(Errno::ENODEV, "the device is not found"); return_errno_with_message!(Errno::ENODEV, "the device is not found");

View File

@ -175,19 +175,19 @@ struct Stat {
impl From<Metadata> for Stat { impl From<Metadata> for Stat {
fn from(info: Metadata) -> Self { fn from(info: Metadata) -> Self {
Self { Self {
st_dev: info.dev, st_dev: info.container_dev_id.as_encoded_u64(),
st_ino: info.ino, st_ino: info.ino,
st_nlink: info.nlinks as _, st_nlink: info.nr_hard_links as _,
st_mode: info.type_ as u32 | info.mode.bits() as u32, st_mode: info.type_ as u32 | info.mode.bits() as u32,
st_uid: info.uid.into(), st_uid: info.uid.into(),
st_gid: info.gid.into(), st_gid: info.gid.into(),
st_rdev: info.rdev, st_rdev: info.self_dev_id.map_or(0, |id| id.as_encoded_u64()),
st_size: info.size as i64, st_size: info.size as i64,
st_blksize: info.blk_size as _, st_blksize: info.optimal_block_size as _,
st_blocks: (info.blocks * (info.blk_size / 512)) as i64, st_blocks: info.nr_sectors_allocated as _,
st_atime: info.atime.into(), st_atime: info.last_access_at.into(),
st_mtime: info.mtime.into(), st_mtime: info.last_modify_at.into(),
st_ctime: info.ctime.into(), st_ctime: info.last_meta_change_at.into(),
..Default::default() ..Default::default()
} }
} }

View File

@ -128,8 +128,10 @@ impl Statx {
fn new(path: &Path) -> Self { fn new(path: &Path) -> Self {
let info = path.metadata(); let info = path.metadata();
let (stx_dev_major, stx_dev_minor) = device_id::decode_device_numbers(info.dev); let (stx_dev_major, stx_dev_minor) =
let (stx_rdev_major, stx_rdev_minor) = device_id::decode_device_numbers(info.rdev); device_id::decode_device_numbers(info.container_dev_id.as_encoded_u64());
let (stx_rdev_major, stx_rdev_minor) =
device_id::decode_device_numbers(info.self_dev_id.map_or(0, |id| id.as_encoded_u64()));
// TODO: Support more `stx_attributes` flags. // TODO: Support more `stx_attributes` flags.
let stx_attributes_mask = STATX_ATTR_MOUNT_ROOT; let stx_attributes_mask = STATX_ATTR_MOUNT_ROOT;
@ -146,21 +148,21 @@ impl Statx {
Self { Self {
// FIXME: All zero fields below are dummy implementations that need to be improved in the future. // FIXME: All zero fields below are dummy implementations that need to be improved in the future.
stx_mask, stx_mask,
stx_blksize: info.blk_size as u32, stx_blksize: info.optimal_block_size as u32,
stx_attributes, stx_attributes,
stx_nlink: info.nlinks as u32, stx_nlink: info.nr_hard_links as u32,
stx_uid: info.uid.into(), stx_uid: info.uid.into(),
stx_gid: info.gid.into(), stx_gid: info.gid.into(),
stx_mode: info.type_ as u16 | info.mode.bits(), stx_mode: info.type_ as u16 | info.mode.bits(),
__spare0: [0; 1], __spare0: [0; 1],
stx_ino: info.ino, stx_ino: info.ino,
stx_size: info.size as u64, stx_size: info.size as u64,
stx_blocks: (info.blocks * (info.blk_size / 512)) as u64, stx_blocks: (info.nr_sectors_allocated * (info.optimal_block_size / 512)) as u64,
stx_attributes_mask, stx_attributes_mask,
stx_atime: StatxTimestamp::from(info.atime), stx_atime: StatxTimestamp::from(info.last_access_at),
stx_btime: StatxTimestamp::from(info.atime), stx_btime: StatxTimestamp::from(info.last_access_at),
stx_ctime: StatxTimestamp::from(info.ctime), stx_ctime: StatxTimestamp::from(info.last_meta_change_at),
stx_mtime: StatxTimestamp::from(info.ctime), stx_mtime: StatxTimestamp::from(info.last_meta_change_at),
stx_rdev_major, stx_rdev_major,
stx_rdev_minor, stx_rdev_minor,
stx_dev_major, stx_dev_major,

View File

@ -242,7 +242,9 @@ impl VmMapping {
let offset = self.vmo().map(|vmo| vmo.offset).unwrap_or(0); let offset = self.vmo().map(|vmo| vmo.offset).unwrap_or(0);
let (dev_major, dev_minor) = self let (dev_major, dev_minor) = self
.inode() .inode()
.map(|inode| device_id::decode_device_numbers(inode.metadata().dev)) .map(|inode| {
device_id::decode_device_numbers(inode.metadata().container_dev_id.as_encoded_u64())
})
.unwrap_or((0, 0)); .unwrap_or((0, 0));
let ino = self.inode().map(|inode| inode.ino()).unwrap_or(0); let ino = self.inode().map(|inode| inode.ino()).unwrap_or(0);