[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20240514131711.379322-2-wedsonaf@gmail.com>
Date: Tue, 14 May 2024 10:16:42 -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 01/30] rust: fs: add registration/unregistration of file systems
From: Wedson Almeida Filho <walmeida@...rosoft.com>
Allow basic registration and unregistration of Rust file system types.
Unregistration happens automatically when a registration variable is
dropped (e.g., when it goes out of scope).
File systems registered this way are visible in `/proc/filesystems` but
cannot be mounted yet because `init_fs_context` fails.
Signed-off-by: Wedson Almeida Filho <walmeida@...rosoft.com>
---
rust/kernel/error.rs | 2 --
rust/kernel/fs.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++
rust/kernel/lib.rs | 1 +
3 files changed, 76 insertions(+), 2 deletions(-)
create mode 100644 rust/kernel/fs.rs
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index b248a4c22fb4..f4fa2847e210 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -308,8 +308,6 @@ pub(crate) fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
/// })
/// }
/// ```
-// TODO: Remove `dead_code` marker once an in-kernel client is available.
-#[allow(dead_code)]
pub(crate) fn from_result<T, F>(f: F) -> T
where
T: From<i16>,
diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs
new file mode 100644
index 000000000000..cc1ed7ed2f54
--- /dev/null
+++ b/rust/kernel/fs.rs
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel file systems.
+//!
+//! This module allows Rust code to register new kernel file systems.
+//!
+//! C headers: [`include/linux/fs.h`](srctree/include/linux/fs.h)
+
+use crate::error::{code::*, from_result, to_result, Error};
+use crate::types::Opaque;
+use crate::{bindings, init::PinInit, str::CStr, try_pin_init, ThisModule};
+use core::{ffi, pin::Pin};
+use macros::{pin_data, pinned_drop};
+
+/// A file system type.
+pub trait FileSystem {
+ /// The name of the file system type.
+ const NAME: &'static CStr;
+}
+
+/// A registration of a file system.
+#[pin_data(PinnedDrop)]
+pub struct Registration {
+ #[pin]
+ fs: Opaque<bindings::file_system_type>,
+}
+
+// SAFETY: `Registration` doesn't provide any `&self` methods, so it is safe to pass references
+// to it around.
+unsafe impl Sync for Registration {}
+
+// SAFETY: Both registration and unregistration are implemented in C and safe to be performed
+// from any thread, so `Registration` is `Send`.
+unsafe impl Send for Registration {}
+
+impl Registration {
+ /// Creates the initialiser of a new file system registration.
+ pub fn new<T: FileSystem + ?Sized>(module: &'static ThisModule) -> impl PinInit<Self, Error> {
+ try_pin_init!(Self {
+ fs <- Opaque::try_ffi_init(|fs_ptr: *mut bindings::file_system_type| {
+ // SAFETY: `try_ffi_init` guarantees that `fs_ptr` is valid for write.
+ unsafe { fs_ptr.write(bindings::file_system_type::default()) };
+
+ // SAFETY: `try_ffi_init` guarantees that `fs_ptr` is valid for write, and it has
+ // just been initialised above, so it's also valid for read.
+ let fs = unsafe { &mut *fs_ptr };
+ fs.owner = module.0;
+ fs.name = T::NAME.as_char_ptr();
+ fs.init_fs_context = Some(Self::init_fs_context_callback);
+ fs.kill_sb = Some(Self::kill_sb_callback);
+ fs.fs_flags = 0;
+
+ // SAFETY: Pointers stored in `fs` are static so will live for as long as the
+ // registration is active (it is undone in `drop`).
+ to_result(unsafe { bindings::register_filesystem(fs_ptr) })
+ }),
+ })
+ }
+
+ unsafe extern "C" fn init_fs_context_callback(_fc: *mut bindings::fs_context) -> ffi::c_int {
+ from_result(|| Err(ENOTSUPP))
+ }
+
+ unsafe extern "C" fn kill_sb_callback(_sb_ptr: *mut bindings::super_block) {}
+}
+
+#[pinned_drop]
+impl PinnedDrop for Registration {
+ fn drop(self: Pin<&mut Self>) {
+ // SAFETY: If an instance of `Self` has been successfully created, a call to
+ // `register_filesystem` has necessarily succeeded. So it's ok to call
+ // `unregister_filesystem` on the previously registered fs.
+ unsafe { bindings::unregister_filesystem(self.fs.get()) };
+ }
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 4b629aa94735..e664f80b8141 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -31,6 +31,7 @@
mod build_assert;
pub mod error;
pub mod file;
+pub mod fs;
pub mod init;
pub mod ioctl;
#[cfg(CONFIG_KUNIT)]
--
2.34.1
Powered by blists - more mailing lists