Split pseudofs.rs into several modules

This commit is contained in:
Jianfeng Jiang 2026-02-09 06:41:07 +00:00
parent f4102e7db4
commit 9c99e782ed
5 changed files with 297 additions and 228 deletions

View File

@ -0,0 +1,74 @@
// SPDX-License-Identifier: MPL-2.0
use spin::Once;
use crate::{
fs::{
path::{Mount, Path},
pseudofs::{PseudoFs, PseudoInodeType},
utils::{Inode, mkmod},
},
prelude::*,
process::{Gid, Uid},
};
pub struct AnonInodeFs {
_private: (),
}
impl AnonInodeFs {
/// Returns the singleton instance of the anonymous inode file system.
fn singleton() -> &'static Arc<PseudoFs> {
static ANON_INODEFS: Once<Arc<PseudoFs>> = Once::new();
PseudoFs::singleton(&ANON_INODEFS, "anon_inodefs", ANON_INODEFS_MAGIC)
}
/// Creates a pseudo `Path` for the shared inode.
pub fn new_path(name_fn: fn(&dyn Inode) -> String) -> Path {
Path::new_pseudo(
Self::mount_node().clone(),
Self::shared_inode().clone(),
name_fn,
)
}
/// Returns the pseudo mount node of the anonymous inode file system.
pub fn mount_node() -> &'static Arc<Mount> {
static ANON_INODEFS_MOUNT: Once<Arc<Mount>> = Once::new();
ANON_INODEFS_MOUNT.call_once(|| Mount::new_pseudo(Self::singleton().clone()))
}
/// Returns the shared inode of the anonymous inode file system singleton.
//
// Some members of anon_inodefs (such as epollfd, eventfd, timerfd, etc.) share
// the same inode. The sharing is not only within the same category (e.g., two
// epollfds share the same inode) but also across different categories (e.g.,
// an epollfd and a timerfd share the same inode). Even across namespaces, this
// inode is still shared. Although this Linux behavior is a bit odd, we keep it
// for compatibility.
//
// A small subset of members in anon_inodefs (i.e., userfaultfd, io_uring, and
// kvm_guest_memfd) have their own dedicated inodes. We need to support creating
// independent inodes within anon_inodefs for them in the future.
//
// Reference: <https://elixir.bootlin.com/linux/v6.16.5/source/fs/anon_inodes.c#L153-L164>
pub fn shared_inode() -> &'static Arc<dyn Inode> {
static SHARED_INODE: Once<Arc<dyn Inode>> = Once::new();
SHARED_INODE.call_once(|| {
let shared_inode = Self::singleton().alloc_inode(
PseudoInodeType::AnonInode,
mkmod!(u+rw),
Uid::new_root(),
Gid::new_root(),
);
Arc::new(shared_inode)
})
}
}
// Reference: <https://elixir.bootlin.com/linux/v6.16.5/source/include/uapi/linux/magic.h#L93>
const ANON_INODEFS_MAGIC: u64 = 0x09041934;

View File

@ -1,23 +1,25 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
use alloc::format;
use core::{ use core::{
sync::atomic::{AtomicU64, Ordering}, sync::atomic::{AtomicU64, Ordering},
time::Duration, time::Duration,
}; };
pub use anon_inode_fs::AnonInodeFs;
pub use pidfdfs::PidfdFs;
pub(super) use pipefs::PipeFs;
use pipefs::PipeFsType;
pub use sockfs::SockFs;
use sockfs::SockFsType;
use spin::Once; use spin::Once;
use super::utils::{Extension, InodeIo, StatusFlags}; use super::utils::{Extension, InodeIo, StatusFlags};
use crate::{ use crate::{
fs::{ fs::{
inode_handle::FileIo, inode_handle::FileIo,
path::{Mount, Path},
pipe::AnonPipeInode,
registry::{FsProperties, FsType},
utils::{ utils::{
AccessMode, FileSystem, FsEventSubscriberStats, FsFlags, Inode, InodeMode, InodeType, AccessMode, FileSystem, FsEventSubscriberStats, Inode, InodeMode, InodeType, Metadata,
Metadata, NAME_MAX, SuperBlock, mkmod, NAME_MAX, SuperBlock, mkmod,
}, },
}, },
prelude::*, prelude::*,
@ -25,6 +27,11 @@ use crate::{
time::clocks::RealTimeCoarseClock, time::clocks::RealTimeCoarseClock,
}; };
mod anon_inode_fs;
mod pidfdfs;
mod pipefs;
mod sockfs;
/// A pseudo file system that manages pseudo inodes, such as pipe inodes and socket inodes. /// A pseudo file system that manages pseudo inodes, such as pipe inodes and socket inodes.
pub struct PseudoFs { pub struct PseudoFs {
name: &'static str, name: &'static str,
@ -98,170 +105,6 @@ impl PseudoFs {
} }
} }
pub(super) struct PipeFs {
_private: (),
}
impl PipeFs {
/// Returns the singleton instance of the anonymous pipe file system.
pub(super) fn singleton() -> &'static Arc<PseudoFs> {
static PIPEFS: Once<Arc<PseudoFs>> = Once::new();
PseudoFs::singleton(&PIPEFS, "pipefs", PIPEFS_MAGIC)
}
/// Creates a pseudo `Path` for an anonymous pipe.
pub(super) fn new_path(pipe_inode: Arc<AnonPipeInode>) -> Path {
Path::new_pseudo(Self::mount_node().clone(), pipe_inode, |inode| {
format!("pipe:[{}]", inode.ino())
})
}
/// Returns the pseudo mount node of the pipe file system.
fn mount_node() -> &'static Arc<Mount> {
static PIPEFS_MOUNT: Once<Arc<Mount>> = Once::new();
PIPEFS_MOUNT.call_once(|| Mount::new_pseudo(Self::singleton().clone()))
}
}
pub struct SockFs {
_private: (),
}
impl SockFs {
/// Returns the singleton instance of the socket file system.
pub fn singleton() -> &'static Arc<PseudoFs> {
static SOCKFS: Once<Arc<PseudoFs>> = Once::new();
PseudoFs::singleton(&SOCKFS, "sockfs", SOCKFS_MAGIC)
}
/// Creates a pseudo `Path` for a socket.
pub fn new_path() -> Path {
let socket_inode = Arc::new(Self::singleton().alloc_inode(
PseudoInodeType::Socket,
mkmod!(a+rwx),
Uid::new_root(),
Gid::new_root(),
));
Path::new_pseudo(Self::mount_node().clone(), socket_inode, |inode| {
format!("socket:[{}]", inode.ino())
})
}
/// Returns the pseudo mount node of the socket file system.
pub fn mount_node() -> &'static Arc<Mount> {
static SOCKFS_MOUNT: Once<Arc<Mount>> = Once::new();
SOCKFS_MOUNT.call_once(|| Mount::new_pseudo(Self::singleton().clone()))
}
}
pub struct AnonInodeFs {
_private: (),
}
impl AnonInodeFs {
/// Returns the singleton instance of the anonymous inode file system.
fn singleton() -> &'static Arc<PseudoFs> {
static ANON_INODEFS: Once<Arc<PseudoFs>> = Once::new();
PseudoFs::singleton(&ANON_INODEFS, "anon_inodefs", ANON_INODEFS_MAGIC)
}
/// Creates a pseudo `Path` for the shared inode.
pub fn new_path(name_fn: fn(&dyn Inode) -> String) -> Path {
Path::new_pseudo(
Self::mount_node().clone(),
Self::shared_inode().clone(),
name_fn,
)
}
/// Returns the pseudo mount node of the anonymous inode file system.
pub fn mount_node() -> &'static Arc<Mount> {
static ANON_INODEFS_MOUNT: Once<Arc<Mount>> = Once::new();
ANON_INODEFS_MOUNT.call_once(|| Mount::new_pseudo(Self::singleton().clone()))
}
/// Returns the shared inode of the anonymous inode file system singleton.
//
// Some members of anon_inodefs (such as epollfd, eventfd, timerfd, etc.) share
// the same inode. The sharing is not only within the same category (e.g., two
// epollfds share the same inode) but also across different categories (e.g.,
// an epollfd and a timerfd share the same inode). Even across namespaces, this
// inode is still shared. Although this Linux behavior is a bit odd, we keep it
// for compatibility.
//
// A small subset of members in anon_inodefs (i.e., userfaultfd, io_uring, and
// kvm_guest_memfd) have their own dedicated inodes. We need to support creating
// independent inodes within anon_inodefs for them in the future.
//
// Reference: <https://elixir.bootlin.com/linux/v6.16.5/source/fs/anon_inodes.c#L153-L164>
pub fn shared_inode() -> &'static Arc<dyn Inode> {
static SHARED_INODE: Once<Arc<dyn Inode>> = Once::new();
SHARED_INODE.call_once(|| {
let shared_inode = Self::singleton().alloc_inode(
PseudoInodeType::AnonInode,
mkmod!(u+rw),
Uid::new_root(),
Gid::new_root(),
);
Arc::new(shared_inode)
})
}
}
pub struct PidfdFs {
_private: (),
}
impl PidfdFs {
/// Returns the singleton instance of the pidfd file system.
pub fn singleton() -> &'static Arc<PseudoFs> {
static PIDFDFS: Once<Arc<PseudoFs>> = Once::new();
PseudoFs::singleton(&PIDFDFS, "pidfdfs", PIDFDFS_MAGIC)
}
/// Creates a pseudo `Path` for a pidfd.
pub fn new_path(name_fn: fn(&dyn Inode) -> String) -> Path {
Path::new_pseudo(
Self::mount_node().clone(),
Self::shared_inode().clone(),
name_fn,
)
}
/// Returns the pseudo mount node of the pidfd file system.
pub fn mount_node() -> &'static Arc<Mount> {
static PIDFDFS_MOUNT: Once<Arc<Mount>> = Once::new();
PIDFDFS_MOUNT.call_once(|| Mount::new_pseudo(Self::singleton().clone()))
}
/// Returns the shared inode of the pidfd file system.
pub fn shared_inode() -> &'static Arc<dyn Inode> {
static SHARED_INODE: Once<Arc<dyn Inode>> = Once::new();
SHARED_INODE.call_once(|| {
let pidfd_inode = Self::singleton().alloc_inode(
PseudoInodeType::Pidfd,
mkmod!(u+rwx),
Uid::new_root(),
Gid::new_root(),
);
Arc::new(pidfd_inode)
})
}
}
pub(super) fn init() { pub(super) fn init() {
super::registry::register(&PipeFsType).unwrap(); super::registry::register(&PipeFsType).unwrap();
super::registry::register(&SockFsType).unwrap(); super::registry::register(&SockFsType).unwrap();
@ -269,66 +112,8 @@ pub(super) fn init() {
// Reference: <https://elixir.bootlin.com/linux/v6.16.5/A/ident/anon_inode_fs_type> // Reference: <https://elixir.bootlin.com/linux/v6.16.5/A/ident/anon_inode_fs_type>
} }
pub(super) struct PipeFsType;
impl FsType for PipeFsType {
fn name(&self) -> &'static str {
"pipefs"
}
fn properties(&self) -> FsProperties {
FsProperties::empty()
}
fn create(
&self,
_flags: FsFlags,
_args: Option<CString>,
_disk: Option<Arc<dyn aster_block::BlockDevice>>,
) -> Result<Arc<dyn FileSystem>> {
return_errno_with_message!(Errno::EINVAL, "pipefs cannot be mounted");
}
fn sysnode(&self) -> Option<Arc<dyn aster_systree::SysNode>> {
None
}
}
pub(super) struct SockFsType;
impl FsType for SockFsType {
fn name(&self) -> &'static str {
"sockfs"
}
fn properties(&self) -> FsProperties {
FsProperties::empty()
}
fn create(
&self,
_flags: FsFlags,
_args: Option<CString>,
_disk: Option<Arc<dyn aster_block::BlockDevice>>,
) -> Result<Arc<dyn FileSystem>> {
return_errno_with_message!(Errno::EINVAL, "sockfs cannot be mounted");
}
fn sysnode(&self) -> Option<Arc<dyn aster_systree::SysNode>> {
None
}
}
/// Root Inode ID. /// Root Inode ID.
const ROOT_INO: u64 = 1; const ROOT_INO: u64 = 1;
// Reference: <https://elixir.bootlin.com/linux/v6.16.5/source/include/uapi/linux/magic.h#L87>
const PIPEFS_MAGIC: u64 = 0x50495045;
// Reference: <https://elixir.bootlin.com/linux/v6.16.5/source/include/uapi/linux/magic.h#L89>
const SOCKFS_MAGIC: u64 = 0x534F434B;
// Reference: <https://elixir.bootlin.com/linux/v6.16.5/source/include/uapi/linux/magic.h#L93>
const ANON_INODEFS_MAGIC: u64 = 0x09041934;
// Reference: <https://elixir.bootlin.com/linux/v6.16.5/source/include/uapi/linux/magic.h#L105>
const PIDFDFS_MAGIC: u64 = 0x50494446;
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PseudoInodeType { pub enum PseudoInodeType {

View File

@ -0,0 +1,61 @@
// SPDX-License-Identifier: MPL-2.0
use spin::Once;
use crate::{
fs::{
path::{Mount, Path},
pseudofs::{PseudoFs, PseudoInodeType},
utils::{Inode, mkmod},
},
prelude::*,
process::{Gid, Uid},
};
pub struct PidfdFs {
_private: (),
}
impl PidfdFs {
/// Returns the singleton instance of the pidfd file system.
pub fn singleton() -> &'static Arc<PseudoFs> {
static PIDFDFS: Once<Arc<PseudoFs>> = Once::new();
PseudoFs::singleton(&PIDFDFS, "pidfdfs", PIDFDFS_MAGIC)
}
/// Creates a pseudo `Path` for a pidfd.
pub fn new_path(name_fn: fn(&dyn Inode) -> String) -> Path {
Path::new_pseudo(
Self::mount_node().clone(),
Self::shared_inode().clone(),
name_fn,
)
}
/// Returns the pseudo mount node of the pidfd file system.
pub fn mount_node() -> &'static Arc<Mount> {
static PIDFDFS_MOUNT: Once<Arc<Mount>> = Once::new();
PIDFDFS_MOUNT.call_once(|| Mount::new_pseudo(Self::singleton().clone()))
}
/// Returns the shared inode of the pidfd file system.
pub fn shared_inode() -> &'static Arc<dyn Inode> {
static SHARED_INODE: Once<Arc<dyn Inode>> = Once::new();
SHARED_INODE.call_once(|| {
let pidfd_inode = Self::singleton().alloc_inode(
PseudoInodeType::Pidfd,
mkmod!(u+rwx),
Uid::new_root(),
Gid::new_root(),
);
Arc::new(pidfd_inode)
})
}
}
// Reference: <https://elixir.bootlin.com/linux/v6.16.5/source/include/uapi/linux/magic.h#L105>
const PIDFDFS_MAGIC: u64 = 0x50494446;

View File

@ -0,0 +1,71 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::format;
use spin::Once;
use crate::{
fs::{
path::{Mount, Path},
pipe::AnonPipeInode,
pseudofs::PseudoFs,
registry::{FsProperties, FsType},
utils::{FileSystem, FsFlags},
},
prelude::*,
};
pub(in crate::fs) struct PipeFs {
_private: (),
}
impl PipeFs {
/// Returns the singleton instance of the anonymous pipe file system.
pub(in crate::fs) fn singleton() -> &'static Arc<PseudoFs> {
static PIPEFS: Once<Arc<PseudoFs>> = Once::new();
PseudoFs::singleton(&PIPEFS, "pipefs", PIPEFS_MAGIC)
}
/// Creates a pseudo `Path` for an anonymous pipe.
pub(in crate::fs) fn new_path(pipe_inode: Arc<AnonPipeInode>) -> Path {
Path::new_pseudo(Self::mount_node().clone(), pipe_inode, |inode| {
format!("pipe:[{}]", inode.ino())
})
}
/// Returns the pseudo mount node of the pipe file system.
fn mount_node() -> &'static Arc<Mount> {
static PIPEFS_MOUNT: Once<Arc<Mount>> = Once::new();
PIPEFS_MOUNT.call_once(|| Mount::new_pseudo(Self::singleton().clone()))
}
}
pub(super) struct PipeFsType;
impl FsType for PipeFsType {
fn name(&self) -> &'static str {
"pipefs"
}
fn properties(&self) -> FsProperties {
FsProperties::empty()
}
fn create(
&self,
_flags: FsFlags,
_args: Option<CString>,
_disk: Option<Arc<dyn aster_block::BlockDevice>>,
) -> Result<Arc<dyn FileSystem>> {
return_errno_with_message!(Errno::EINVAL, "pipefs cannot be mounted");
}
fn sysnode(&self) -> Option<Arc<dyn aster_systree::SysNode>> {
None
}
}
// Reference: <https://elixir.bootlin.com/linux/v6.16.5/source/include/uapi/linux/magic.h#L87>
const PIPEFS_MAGIC: u64 = 0x50495045;

View File

@ -0,0 +1,78 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::format;
use spin::Once;
use crate::{
fs::{
path::{Mount, Path},
pseudofs::{PseudoFs, PseudoInodeType},
registry::{FsProperties, FsType},
utils::{FileSystem, FsFlags, mkmod},
},
prelude::*,
process::{Gid, Uid},
};
pub struct SockFs {
_private: (),
}
impl SockFs {
/// Returns the singleton instance of the socket file system.
pub fn singleton() -> &'static Arc<PseudoFs> {
static SOCKFS: Once<Arc<PseudoFs>> = Once::new();
PseudoFs::singleton(&SOCKFS, "sockfs", SOCKFS_MAGIC)
}
/// Creates a pseudo `Path` for a socket.
pub fn new_path() -> Path {
let socket_inode = Arc::new(Self::singleton().alloc_inode(
PseudoInodeType::Socket,
mkmod!(a+rwx),
Uid::new_root(),
Gid::new_root(),
));
Path::new_pseudo(Self::mount_node().clone(), socket_inode, |inode| {
format!("socket:[{}]", inode.ino())
})
}
/// Returns the pseudo mount node of the socket file system.
pub fn mount_node() -> &'static Arc<Mount> {
static SOCKFS_MOUNT: Once<Arc<Mount>> = Once::new();
SOCKFS_MOUNT.call_once(|| Mount::new_pseudo(Self::singleton().clone()))
}
}
pub(super) struct SockFsType;
impl FsType for SockFsType {
fn name(&self) -> &'static str {
"sockfs"
}
fn properties(&self) -> FsProperties {
FsProperties::empty()
}
fn create(
&self,
_flags: FsFlags,
_args: Option<CString>,
_disk: Option<Arc<dyn aster_block::BlockDevice>>,
) -> Result<Arc<dyn FileSystem>> {
return_errno_with_message!(Errno::EINVAL, "sockfs cannot be mounted");
}
fn sysnode(&self) -> Option<Arc<dyn aster_systree::SysNode>> {
None
}
}
// Reference: <https://elixir.bootlin.com/linux/v6.16.5/source/include/uapi/linux/magic.h#L89>
const SOCKFS_MAGIC: u64 = 0x534F434B;