Skip to content

Commit

Permalink
refactor(vfs): move to its own directory
Browse files Browse the repository at this point in the history
  • Loading branch information
llenotre committed Aug 25, 2024
1 parent 60d5616 commit ec5c9d6
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 210 deletions.
2 changes: 1 addition & 1 deletion kernel/src/file/buffer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub mod pipe;
pub mod socket;

use crate::{
file::{blocking::WaitQueue, fs::NodeOps, FileLocation, Stat},
file::{fs::NodeOps, wait_queue::WaitQueue, FileLocation, Stat},
syscall::ioctl::Request,
};
use core::{alloc::AllocError, any::Any, ffi::c_void};
Expand Down
2 changes: 1 addition & 1 deletion kernel/src/file/buffer/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

use super::BufferOps;
use crate::{
file::{blocking::WaitQueue, fs::NodeOps, FileLocation, FileType, Stat},
file::{fs::NodeOps, wait_queue::WaitQueue, FileLocation, FileType, Stat},
net::{osi, SocketDesc, SocketDomain, SocketType},
};
use core::{
Expand Down
3 changes: 2 additions & 1 deletion kernel/src/file/fs/proc/proc_dir/mounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
use crate::{
file::{
fs::{proc::get_proc_owner, NodeOps},
mountpoint, FileLocation, FileType, Stat,
vfs::mountpoint,
FileLocation, FileType, Stat,
},
format_content,
process::pid::Pid,
Expand Down
82 changes: 0 additions & 82 deletions kernel/src/file/mapping.rs

This file was deleted.

11 changes: 6 additions & 5 deletions kernel/src/file/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,14 @@
//! The root filesystem is passed to the kernel as an argument on boot.
//! Other filesystems are mounted into subdirectories.

pub mod blocking;
pub mod buffer;
pub mod fd;
pub mod fs;
pub mod mapping;
pub mod mountpoint;
pub mod path;
pub mod perm;
pub mod util;
pub mod vfs;
pub mod wait_queue;

use crate::{
device,
Expand All @@ -43,7 +41,6 @@ use crate::{
fs::{Filesystem, NodeOps},
path::PathBuf,
perm::{Gid, Uid},
vfs::Node,
},
syscall::ioctl,
time::{
Expand All @@ -53,7 +50,6 @@ use crate::{
},
};
use core::{any::Any, ffi::c_void, intrinsics::unlikely, ops::Deref};
use mountpoint::{MountPoint, MountSource};
use perm::AccessProfile;
use utils::{
boxed::Box,
Expand All @@ -64,6 +60,11 @@ use utils::{
ptr::{arc::Arc, cow::Cow},
TryClone,
};
use vfs::{
mountpoint,
mountpoint::{MountPoint, MountSource},
node::Node,
};

/// A filesystem node ID.
///
Expand Down
107 changes: 8 additions & 99 deletions kernel/src/file/vfs.rs → kernel/src/file/vfs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,22 @@
//! To manipulate files, the VFS should be used instead of
//! calling the filesystems' directly.

pub mod mountpoint;
pub mod node;

use super::{
mountpoint,
path::{Component, Path},
perm,
perm::{AccessProfile, S_ISVTX},
FileLocation, FileType, Stat,
};
use crate::{
file::{fs::NodeOps, path::PathBuf},
limits,
process::Process,
};
use crate::{file::path::PathBuf, limits, process::Process};
use core::{
borrow::Borrow,
hash::{Hash, Hasher},
};
use node::Node;
use utils::{
boxed::Box,
collections::{hashmap::HashSet, string::String, vec::Vec},
errno,
errno::EResult,
Expand All @@ -47,95 +45,6 @@ use utils::{
vec,
};

/// A filesystem node, cached by the VFS.
#[derive(Debug)]
pub struct Node {
/// The location of the file on a filesystem.
pub location: FileLocation,
/// Handle for node operations.
pub ops: Box<dyn NodeOps>,
}

impl Node {
/// Releases the node, removing it from the disk if this is the last reference to it.
pub fn release(this: Arc<Self>) -> EResult<()> {
// Lock to avoid race condition later
let mut used_nodes = USED_NODES.lock();
// current instance + the one in `USED_NODE` = `2`
if Arc::strong_count(&this) > 2 {
return Ok(());
}
used_nodes.remove(&this.location);
// The reference count is now `1`
let Some(node) = Arc::into_inner(this) else {
// TODO log?
return Ok(());
};
// If there is no hard link left to the node, remove it
let stat = node.ops.get_stat(&node.location)?;
if stat.nlink == 0 {
node.ops.remove_file(&node.location)?;
}
Ok(())
}
}

/// An entry in the nodes cache.
///
/// The [`Hash`] and [`PartialEq`] traits are forwarded to the entry's location.
#[derive(Debug)]
struct NodeEntry(Arc<Node>);

impl Borrow<FileLocation> for NodeEntry {
fn borrow(&self) -> &FileLocation {
&self.0.location
}
}

impl Eq for NodeEntry {}

impl PartialEq for NodeEntry {
fn eq(&self, other: &Self) -> bool {
self.0.location.eq(&other.0.location)
}
}

impl Hash for NodeEntry {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.location.hash(state)
}
}

/// The list of nodes current in use.
static USED_NODES: Mutex<HashSet<NodeEntry>> = Mutex::new(HashSet::new());

/// Looks in the nodes cache for the node with the given location. If not in cache, the node is
/// created and inserted.
///
/// If the node to be added in cache is a mountpoint `location` and `ops` are modified accordingly.
fn get_node(mut location: FileLocation, mut ops: Box<dyn NodeOps>) -> EResult<Arc<Node>> {
let mut used_nodes = USED_NODES.lock();
let node = used_nodes.get(&location).map(|e| e.0.clone());
match node {
Some(node) => Ok(node),
// The node is not in cache. Insert it
None => {
// If this is a mountpoint, jump to its root
if let Some(mp) = mountpoint::from_location(&location) {
location = mp.get_root_location();
ops = mp.fs.node_from_inode(location.inode)?;
}
// Create and insert node
let node = Arc::new(Node {
location,
ops,
})?;
used_nodes.insert(NodeEntry(node.clone()))?;
Ok(node)
}
}
}

/// A child of a VFS entry.
///
/// The [`Hash`] and [`PartialEq`] traits are forwarded to the entry's name.
Expand Down Expand Up @@ -230,7 +139,7 @@ impl Entry {
Ok(buf)
}

/// Returns an iterator of entries, starting from `this`, to the root of the VFS.
/// Returns the absolute path to reach the entry.
pub fn get_path(this: Arc<Self>) -> EResult<PathBuf> {
let mut buf = vec![0u8; limits::PATH_MAX]?;
let mut off = limits::PATH_MAX;
Expand Down Expand Up @@ -390,7 +299,7 @@ fn resolve_entry(lookup_dir: &Arc<Entry>, name: &[u8]) -> EResult<Option<Arc<Ent
mountpoint_id: lookup_dir.node.location.mountpoint_id,
inode: entry.inode,
};
let node = get_node(location, ops)?;
let node = node::get(location, ops)?;
// Create entry and insert in parent
let ent = Arc::new(Entry {
name: String::try_from(name)?,
Expand Down Expand Up @@ -642,7 +551,7 @@ pub fn create_file(
mountpoint_id: parent.node.location.mountpoint_id,
inode,
};
let node = get_node(location, ops)?;
let node = node::get(location, ops)?;
// Create entry and insert it in parent
let entry = Arc::new(Entry {
name: String::try_from(name)?,
Expand Down
31 changes: 18 additions & 13 deletions kernel/src/file/mountpoint.rs → kernel/src/file/vfs/mountpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,25 @@

//! A mount point is a directory in which a filesystem is mounted.

use super::{
fs,
fs::{Filesystem, FilesystemType},
path::{Path, PathBuf},
vfs, FileLocation, FileType,
};
use crate::{
device,
device::{DeviceID, DeviceType},
file::vfs::ResolutionSettings,
file::{
fs,
fs::{Filesystem, FilesystemType},
path::{Path, PathBuf},
vfs,
vfs::ResolutionSettings,
FileLocation, FileType,
},
};
use core::fmt;
use utils::{
collections::{hashmap::HashMap, string::String},
errno,
errno::{AllocResult, EResult},
lock::Mutex,
ptr::arc::{Arc, Weak},
ptr::arc::Arc,
TryClone,
};

Expand Down Expand Up @@ -133,7 +134,7 @@ impl fmt::Display for MountSource {
}

/// The list of loaded filesystems associated with their respective sources.
static FILESYSTEMS: Mutex<HashMap<MountSource, Weak<dyn Filesystem>>> = Mutex::new(HashMap::new());
static FILESYSTEMS: Mutex<HashMap<MountSource, Arc<dyn Filesystem>>> = Mutex::new(HashMap::new());

/// Loads a filesystem.
///
Expand Down Expand Up @@ -170,15 +171,15 @@ fn load_fs(
let fs = fs_type.load_filesystem(io, path, readonly)?;
// Insert new filesystem into filesystems list
let mut filesystems = FILESYSTEMS.lock();
filesystems.insert(source, Arc::downgrade(&fs))?;
filesystems.insert(source, fs.clone())?;
Ok(fs)
}

/// Returns the loaded filesystem with the given source `source`.
///
/// If the filesystem isn't loaded, the function returns `None`.
pub fn get_fs(source: &MountSource) -> Option<Arc<dyn Filesystem>> {
FILESYSTEMS.lock().get(source).and_then(Weak::upgrade)
FILESYSTEMS.lock().get(source).cloned()
}

/// A mount point, allowing to attach a filesystem to a directory on the VFS.
Expand Down Expand Up @@ -259,8 +260,12 @@ impl Drop for MountPoint {
let Some(fs) = filesystems.get(&self.source) else {
return;
};
// Remove the associated filesystem if this was the last reference to it
if fs.upgrade().is_none() {
/*
* Remove the associated filesystem if this was the last reference to it.
*
* the current instance + FILESYSTEMS = `2`
*/
if Arc::strong_count(fs) <= 2 {
filesystems.remove(&self.source);
}
}
Expand Down
Loading

0 comments on commit ec5c9d6

Please sign in to comment.