[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20240514131711.379322-6-wedsonaf@gmail.com>
Date: Tue, 14 May 2024 10:16:46 -0300
From: Wedson Almeida Filho <wedsonaf@...il.com>
To: Alexander Viro <viro@...iv.linux.org.uk>,
Christian Brauner <brauner@...nel.org>,
Matthew Wilcox <willy@...radead.org>,
Dave Chinner <david@...morbit.com>
Cc: Kent Overstreet <kent.overstreet@...il.com>,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
linux-fsdevel@...r.kernel.org,
rust-for-linux@...r.kernel.org,
linux-kernel@...r.kernel.org,
Wedson Almeida Filho <walmeida@...rosoft.com>
Subject: [RFC PATCH v2 05/30] rust: fs: introduce `INode<T>`
From: Wedson Almeida Filho <walmeida@...rosoft.com>
Allow Rust file systems to handle typed and ref-counted inodes.
This is in preparation for creating new inodes (for example, to create
the root inode of a new superblock), which comes in the next patch in
the series.
Signed-off-by: Wedson Almeida Filho <walmeida@...rosoft.com>
---
rust/helpers.c | 7 ++++
rust/kernel/block.rs | 9 +++++
rust/kernel/fs.rs | 20 +++++++++++
rust/kernel/fs/inode.rs | 78 +++++++++++++++++++++++++++++++++++++++++
rust/kernel/fs/sb.rs | 15 +++++++-
5 files changed, 128 insertions(+), 1 deletion(-)
create mode 100644 rust/kernel/fs/inode.rs
diff --git a/rust/helpers.c b/rust/helpers.c
index 318e3e85dddd..c697c1c4c9d7 100644
--- a/rust/helpers.c
+++ b/rust/helpers.c
@@ -164,6 +164,13 @@ struct file *rust_helper_get_file(struct file *f)
}
EXPORT_SYMBOL_GPL(rust_helper_get_file);
+
+loff_t rust_helper_i_size_read(const struct inode *inode)
+{
+ return i_size_read(inode);
+}
+EXPORT_SYMBOL_GPL(rust_helper_i_size_read);
+
unsigned long rust_helper_copy_to_user(void __user *to, const void *from,
unsigned long n)
{
diff --git a/rust/kernel/block.rs b/rust/kernel/block.rs
index 38d2a3089ae7..868623d7c873 100644
--- a/rust/kernel/block.rs
+++ b/rust/kernel/block.rs
@@ -5,6 +5,7 @@
//! C headers: [`include/linux/blk_types.h`](../../include/linux/blk_types.h)
use crate::bindings;
+use crate::fs::inode::INode;
use crate::types::Opaque;
/// The type used for indexing onto a disc or disc partition.
@@ -35,4 +36,12 @@ pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::block_device) -> &'a Self
// SAFETY: The safety requirements guarantee that the cast below is ok.
unsafe { &*ptr.cast::<Self>() }
}
+
+ /// Returns the inode associated with this block device.
+ pub fn inode(&self) -> &INode {
+ // SAFETY: `bd_inode` is never reassigned.
+ let ptr = unsafe { (*self.0.get()).bd_inode };
+ // SAFET: `ptr` is valid as long as the block device remains valid as well.
+ unsafe { INode::from_raw(ptr) }
+ }
}
diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs
index 263b4b6186ae..89dcd5537830 100644
--- a/rust/kernel/fs.rs
+++ b/rust/kernel/fs.rs
@@ -13,6 +13,7 @@
use macros::{pin_data, pinned_drop};
use sb::SuperBlock;
+pub mod inode;
pub mod sb;
/// The offset of a file in a file system.
@@ -28,10 +29,29 @@ pub trait FileSystem {
/// The name of the file system type.
const NAME: &'static CStr;
+ /// Determines if an implementation doesn't specify the required types.
+ ///
+ /// This is meant for internal use only.
+ #[doc(hidden)]
+ const IS_UNSPECIFIED: bool = false;
+
/// Initialises the new superblock.
fn fill_super(sb: &mut SuperBlock<Self>) -> Result;
}
+/// A file system that is unspecified.
+///
+/// Attempting to get super-block or inode data from it will result in a build error.
+pub struct UnspecifiedFS;
+
+impl FileSystem for UnspecifiedFS {
+ const NAME: &'static CStr = crate::c_str!("unspecified");
+ const IS_UNSPECIFIED: bool = true;
+ fn fill_super(_: &mut SuperBlock<Self>) -> Result {
+ Err(ENOTSUPP)
+ }
+}
+
/// A registration of a file system.
#[pin_data(PinnedDrop)]
pub struct Registration {
diff --git a/rust/kernel/fs/inode.rs b/rust/kernel/fs/inode.rs
new file mode 100644
index 000000000000..bcb9c8ce59a9
--- /dev/null
+++ b/rust/kernel/fs/inode.rs
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! File system inodes.
+//!
+//! This module allows Rust code to implement inodes.
+//!
+//! C headers: [`include/linux/fs.h`](srctree/include/linux/fs.h)
+
+use super::{sb::SuperBlock, FileSystem, Offset, UnspecifiedFS};
+use crate::bindings;
+use crate::types::{AlwaysRefCounted, Opaque};
+use core::{marker::PhantomData, ptr};
+
+/// The number of an inode.
+pub type Ino = u64;
+
+/// A node (inode) in the file index.
+///
+/// Wraps the kernel's `struct inode`.
+///
+/// # Invariants
+///
+/// Instances of this type are always ref-counted, that is, a call to `ihold` ensures that the
+/// allocation remains valid at least until the matching call to `iput`.
+#[repr(transparent)]
+pub struct INode<T: FileSystem + ?Sized = UnspecifiedFS>(
+ pub(crate) Opaque<bindings::inode>,
+ PhantomData<T>,
+);
+
+impl<T: FileSystem + ?Sized> INode<T> {
+ /// Creates a new inode reference from the given raw pointer.
+ ///
+ /// # Safety
+ ///
+ /// Callers must ensure that:
+ ///
+ /// * `ptr` is valid and remains so for the lifetime of the returned object.
+ /// * `ptr` has the correct file system type, or `T` is [`super::UnspecifiedFS`].
+ #[allow(dead_code)]
+ pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::inode) -> &'a Self {
+ // SAFETY: The safety requirements guarantee that the cast below is ok.
+ unsafe { &*ptr.cast::<Self>() }
+ }
+
+ /// Returns the number of the inode.
+ pub fn ino(&self) -> Ino {
+ // SAFETY: `i_ino` is immutable, and `self` is guaranteed to be valid by the existence of a
+ // shared reference (&self) to it.
+ unsafe { (*self.0.get()).i_ino }
+ }
+
+ /// Returns the super-block that owns the inode.
+ pub fn super_block(&self) -> &SuperBlock<T> {
+ // SAFETY: `i_sb` is immutable, and `self` is guaranteed to be valid by the existence of a
+ // shared reference (&self) to it.
+ unsafe { SuperBlock::from_raw((*self.0.get()).i_sb) }
+ }
+
+ /// Returns the size of the inode contents.
+ pub fn size(&self) -> Offset {
+ // SAFETY: `self` is guaranteed to be valid by the existence of a shared reference.
+ unsafe { bindings::i_size_read(self.0.get()) }
+ }
+}
+
+// SAFETY: The type invariants guarantee that `INode` is always ref-counted.
+unsafe impl<T: FileSystem + ?Sized> AlwaysRefCounted for INode<T> {
+ fn inc_ref(&self) {
+ // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+ unsafe { bindings::ihold(self.0.get()) };
+ }
+
+ unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
+ // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+ unsafe { bindings::iput(obj.as_ref().0.get()) }
+ }
+}
diff --git a/rust/kernel/fs/sb.rs b/rust/kernel/fs/sb.rs
index 113d3c0d8148..f48e0e2695fa 100644
--- a/rust/kernel/fs/sb.rs
+++ b/rust/kernel/fs/sb.rs
@@ -20,6 +20,19 @@ pub struct SuperBlock<T: FileSystem + ?Sized>(
);
impl<T: FileSystem + ?Sized> SuperBlock<T> {
+ /// Creates a new superblock reference from the given raw pointer.
+ ///
+ /// # Safety
+ ///
+ /// Callers must ensure that:
+ ///
+ /// * `ptr` is valid and remains so for the lifetime of the returned object.
+ /// * `ptr` has the correct file system type, or `T` is [`super::UnspecifiedFS`].
+ pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::super_block) -> &'a Self {
+ // SAFETY: The safety requirements guarantee that the cast below is ok.
+ unsafe { &*ptr.cast::<Self>() }
+ }
+
/// Creates a new superblock mutable reference from the given raw pointer.
///
/// # Safety
@@ -27,7 +40,7 @@ impl<T: FileSystem + ?Sized> SuperBlock<T> {
/// Callers must ensure that:
///
/// * `ptr` is valid and remains so for the lifetime of the returned object.
- /// * `ptr` has the correct file system type.
+ /// * `ptr` has the correct file system type, or `T` is [`super::UnspecifiedFS`].
/// * `ptr` is the only active pointer to the superblock.
pub(crate) unsafe fn from_raw_mut<'a>(ptr: *mut bindings::super_block) -> &'a mut Self {
// SAFETY: The safety requirements guarantee that the cast below is ok.
--
2.34.1
Powered by blists - more mailing lists