From: Wedson Almeida Filho <wedsonaf@gmail.com>
To: Alexander Viro <viro@zeniv.linux.org.uk>,
Christian Brauner <brauner@kernel.org>,
Matthew Wilcox <willy@infradead.org>,
Dave Chinner <david@fromorbit.com>
Cc: Kent Overstreet <kent.overstreet@gmail.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
linux-fsdevel@vger.kernel.org, rust-for-linux@vger.kernel.org,
linux-kernel@vger.kernel.org,
Wedson Almeida Filho <walmeida@microsoft.com>
Subject: [RFC PATCH v2 06/30] rust: fs: introduce `DEntry<T>`
Date: Tue, 14 May 2024 10:16:47 -0300 [thread overview]
Message-ID: <20240514131711.379322-7-wedsonaf@gmail.com> (raw)
In-Reply-To: <20240514131711.379322-1-wedsonaf@gmail.com>
From: Wedson Almeida Filho <walmeida@microsoft.com>
Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
---
rust/helpers.c | 6 ++
rust/kernel/error.rs | 2 -
rust/kernel/fs.rs | 1 +
rust/kernel/fs/dentry.rs | 137 +++++++++++++++++++++++++++++++++++++++
4 files changed, 144 insertions(+), 2 deletions(-)
create mode 100644 rust/kernel/fs/dentry.rs
diff --git a/rust/helpers.c b/rust/helpers.c
index c697c1c4c9d7..c7fe6917251e 100644
--- a/rust/helpers.c
+++ b/rust/helpers.c
@@ -165,6 +165,12 @@ struct file *rust_helper_get_file(struct file *f)
EXPORT_SYMBOL_GPL(rust_helper_get_file);
+struct dentry *rust_helper_dget(struct dentry *dentry)
+{
+ return dget(dentry);
+}
+EXPORT_SYMBOL_GPL(rust_helper_dget);
+
loff_t rust_helper_i_size_read(const struct inode *inode)
{
return i_size_read(inode);
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index f4fa2847e210..bb13bd4a7fa6 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -261,8 +261,6 @@ pub fn to_result(err: core::ffi::c_int) -> Result {
/// from_err_ptr(unsafe { bindings::devm_platform_ioremap_resource(pdev.to_ptr(), index) })
/// }
/// ```
-// TODO: Remove `dead_code` marker once an in-kernel client is available.
-#[allow(dead_code)]
pub(crate) fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
// CAST: Casting a pointer to `*const core::ffi::c_void` is always valid.
let const_ptr: *const core::ffi::c_void = ptr.cast();
diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs
index 89dcd5537830..4f07da71e1ec 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 dentry;
pub mod inode;
pub mod sb;
diff --git a/rust/kernel/fs/dentry.rs b/rust/kernel/fs/dentry.rs
new file mode 100644
index 000000000000..6a36a48cd28b
--- /dev/null
+++ b/rust/kernel/fs/dentry.rs
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! File system directory entries.
+//!
+//! This module allows Rust code to use dentries.
+//!
+//! C headers: [`include/linux/dcache.h`](srctree/include/linux/dcache.h)
+
+use super::{inode::INode, FileSystem, SuperBlock};
+use crate::bindings;
+use crate::error::{code::*, from_err_ptr, Result};
+use crate::types::{ARef, AlwaysRefCounted, Opaque};
+use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref, ptr};
+
+/// A directory entry.
+///
+/// Wraps the kernel's `struct dentry`.
+///
+/// # Invariants
+///
+/// Instances of this type are always ref-counted, that is, a call to `dget` ensures that the
+/// allocation remains valid at least until the matching call to `dput`.
+#[repr(transparent)]
+pub struct DEntry<T: FileSystem + ?Sized>(pub(crate) Opaque<bindings::dentry>, PhantomData<T>);
+
+// SAFETY: The type invariants guarantee that `DEntry` is always ref-counted.
+unsafe impl<T: FileSystem + ?Sized> AlwaysRefCounted for DEntry<T> {
+ fn inc_ref(&self) {
+ // SAFETY: The existence of a shared reference means that the refcount is nonzero.
+ unsafe { bindings::dget(self.0.get()) };
+ }
+
+ unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
+ // SAFETY: The safety requirements guarantee that the refcount is nonzero.
+ unsafe { bindings::dput(obj.as_ref().0.get()) }
+ }
+}
+
+impl<T: FileSystem + ?Sized> DEntry<T> {
+ /// Creates a new [`DEntry`] from a raw C pointer.
+ ///
+ /// # Safety
+ ///
+ /// * `ptr` must be valid for at least the lifetime of the returned reference.
+ /// * `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::dentry) -> &'a Self {
+ // SAFETY: The safety requirements guarantee that the reference is and remains valid.
+ unsafe { &*ptr.cast::<Self>() }
+ }
+
+ /// Returns the superblock of the dentry.
+ pub fn super_block(&self) -> &SuperBlock<T> {
+ // `d_sb` is immutable, so it's safe to read it.
+ unsafe { SuperBlock::from_raw((*self.0.get()).d_sb) }
+ }
+}
+
+/// A dentry that is known to be unhashed.
+pub struct Unhashed<'a, T: FileSystem + ?Sized>(pub(crate) &'a DEntry<T>);
+
+impl<T: FileSystem + ?Sized> Unhashed<'_, T> {
+ /// Splices a disconnected dentry into the tree if one exists.
+ pub fn splice_alias(self, inode: Option<ARef<INode<T>>>) -> Result<Option<ARef<DEntry<T>>>> {
+ let inode_ptr = if let Some(i) = inode {
+ // Reject inode if it belongs to a different superblock.
+ if !ptr::eq(i.super_block(), self.0.super_block()) {
+ return Err(EINVAL);
+ }
+
+ ManuallyDrop::new(i).0.get()
+ } else {
+ ptr::null_mut()
+ };
+
+ // SAFETY: Both inode and dentry are known to be valid.
+ let ptr = from_err_ptr(unsafe { bindings::d_splice_alias(inode_ptr, self.0 .0.get()) })?;
+
+ // SAFETY: The C API guarantees that if a dentry is returned, the refcount has been
+ // incremented.
+ Ok(ptr::NonNull::new(ptr).map(|v| unsafe { ARef::from_raw(v.cast::<DEntry<T>>()) }))
+ }
+
+ /// Returns the name of the dentry.
+ ///
+ /// Being unhashed guarantees that the name won't change.
+ pub fn name(&self) -> &[u8] {
+ // SAFETY: The name is immutable, so it is ok to read it.
+ let name = unsafe { &*ptr::addr_of!((*self.0 .0.get()).d_name) };
+
+ // This ensures that a `u32` is representable in `usize`. If it isn't, we'll get a build
+ // break.
+ const _: usize = 0xffffffff;
+
+ // SAFETY: The union is just allow an easy way to get the `hash` and `len` at once. `len`
+ // is always valid.
+ let len = unsafe { name.__bindgen_anon_1.__bindgen_anon_1.len } as usize;
+
+ // SAFETY: The name is immutable, so it is ok to read it.
+ unsafe { core::slice::from_raw_parts(name.name, len) }
+ }
+}
+
+impl<T: FileSystem + ?Sized> Deref for Unhashed<'_, T> {
+ type Target = DEntry<T>;
+
+ fn deref(&self) -> &Self::Target {
+ self.0
+ }
+}
+
+/// A dentry that is meant to be used as the root of a file system.
+pub struct Root<T: FileSystem + ?Sized>(ARef<DEntry<T>>);
+
+impl<T: FileSystem + ?Sized> Root<T> {
+ /// Creates a root dentry.
+ pub fn try_new(inode: ARef<INode<T>>) -> Result<Root<T>> {
+ // SAFETY: `d_make_root` requires that `inode` be valid and referenced, which is the
+ // case for this call.
+ //
+ // It takes over the inode, even on failure, so we don't need to clean it up.
+ let dentry_ptr = unsafe { bindings::d_make_root(ManuallyDrop::new(inode).0.get()) };
+ let dentry = ptr::NonNull::new(dentry_ptr).ok_or(ENOMEM)?;
+
+ // SAFETY: `dentry` is valid and referenced. It reference ownership is transferred to
+ // `ARef`.
+ Ok(Root(unsafe { ARef::from_raw(dentry.cast::<DEntry<T>>()) }))
+ }
+}
+
+impl<T: FileSystem + ?Sized> Deref for Root<T> {
+ type Target = DEntry<T>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
--
2.34.1
next prev parent reply other threads:[~2024-05-14 13:17 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-14 13:16 [RFC PATCH v2 00/30] Rust abstractions for VFS Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 01/30] rust: fs: add registration/unregistration of file systems Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 02/30] rust: fs: introduce the `module_fs` macro Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 03/30] samples: rust: add initial ro file system sample Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 04/30] rust: fs: introduce `FileSystem::fill_super` Wedson Almeida Filho
2024-05-20 19:38 ` Darrick J. Wong
2024-05-14 13:16 ` [RFC PATCH v2 05/30] rust: fs: introduce `INode<T>` Wedson Almeida Filho
2024-05-14 13:16 ` Wedson Almeida Filho [this message]
2024-05-14 13:16 ` [RFC PATCH v2 07/30] rust: fs: introduce `FileSystem::init_root` Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 08/30] rust: file: move `kernel::file` to `kernel::fs::file` Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 09/30] rust: fs: generalise `File` for different file systems Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 10/30] rust: fs: add empty file operations Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 11/30] rust: fs: introduce `file::Operations::read_dir` Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 12/30] rust: fs: introduce `file::Operations::seek` Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 13/30] rust: fs: introduce `file::Operations::read` Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 14/30] rust: fs: add empty inode operations Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 15/30] rust: fs: introduce `inode::Operations::lookup` Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 16/30] rust: folio: introduce basic support for folios Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 17/30] rust: fs: add empty address space operations Wedson Almeida Filho
2024-05-14 13:16 ` [RFC PATCH v2 18/30] rust: fs: introduce `address_space::Operations::read_folio` Wedson Almeida Filho
2024-05-14 13:17 ` [RFC PATCH v2 19/30] rust: fs: introduce `FileSystem::read_xattr` Wedson Almeida Filho
2024-05-14 13:17 ` [RFC PATCH v2 20/30] rust: fs: introduce `FileSystem::statfs` Wedson Almeida Filho
2024-05-14 13:17 ` [RFC PATCH v2 21/30] rust: fs: introduce more inode types Wedson Almeida Filho
2024-05-14 13:17 ` [RFC PATCH v2 22/30] rust: fs: add per-superblock data Wedson Almeida Filho
2024-05-14 13:17 ` [RFC PATCH v2 23/30] rust: fs: allow file systems backed by a block device Wedson Almeida Filho
2024-05-14 13:17 ` [RFC PATCH v2 24/30] rust: fs: allow per-inode data Wedson Almeida Filho
2024-05-14 13:17 ` [RFC PATCH v2 25/30] rust: fs: export file type from mode constants Wedson Almeida Filho
2024-05-14 13:17 ` [RFC PATCH v2 26/30] rust: fs: allow populating i_lnk Wedson Almeida Filho
2024-05-14 13:17 ` [RFC PATCH v2 27/30] rust: fs: add `iomap` module Wedson Almeida Filho
2024-05-20 19:32 ` Darrick J. Wong
2024-05-14 13:17 ` [RFC PATCH v2 28/30] rust: fs: add memalloc_nofs support Wedson Almeida Filho
2024-05-14 13:17 ` [RFC PATCH v2 29/30] tarfs: introduce tar fs Wedson Almeida Filho
2024-05-14 13:17 ` [RFC PATCH v2 30/30] WIP: fs: ext2: add rust ro ext2 implementation Wedson Almeida Filho
2024-05-20 20:01 ` Darrick J. Wong
2024-05-31 14:34 ` [RFC PATCH v2 00/30] Rust abstractions for VFS Danilo Krummrich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240514131711.379322-7-wedsonaf@gmail.com \
--to=wedsonaf@gmail.com \
--cc=brauner@kernel.org \
--cc=david@fromorbit.com \
--cc=gregkh@linuxfoundation.org \
--cc=kent.overstreet@gmail.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=viro@zeniv.linux.org.uk \
--cc=walmeida@microsoft.com \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.