linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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>
Cc: Kent Overstreet <kent.overstreet@gmail.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	linux-fsdevel@vger.kernel.org, rust-for-linux@vger.kernel.org,
	Wedson Almeida Filho <walmeida@microsoft.com>
Subject: [RFC PATCH 04/19] rust: fs: introduce `FileSystem::super_params`
Date: Wed, 18 Oct 2023 09:25:03 -0300	[thread overview]
Message-ID: <20231018122518.128049-5-wedsonaf@gmail.com> (raw)
In-Reply-To: <20231018122518.128049-1-wedsonaf@gmail.com>

From: Wedson Almeida Filho <walmeida@microsoft.com>

Allow Rust file systems to initialise superblocks, which allows them
to be mounted (though they are still empty).

Some scaffolding code is added to create an empty directory as the root.
It is replaced by proper inode creation in a subsequent patch in this
series.

Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
---
 rust/bindings/bindings_helper.h |   5 +
 rust/bindings/lib.rs            |   4 +
 rust/kernel/fs.rs               | 176 ++++++++++++++++++++++++++++++--
 samples/rust/rust_rofs.rs       |  10 ++
 4 files changed, 189 insertions(+), 6 deletions(-)

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 9c23037b33d0..ca1898ce9527 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -9,6 +9,7 @@
 #include <kunit/test.h>
 #include <linux/errname.h>
 #include <linux/fs.h>
+#include <linux/fs_context.h>
 #include <linux/slab.h>
 #include <linux/refcount.h>
 #include <linux/wait.h>
@@ -22,3 +23,7 @@ const gfp_t BINDINGS___GFP_ZERO = __GFP_ZERO;
 const slab_flags_t BINDINGS_SLAB_RECLAIM_ACCOUNT = SLAB_RECLAIM_ACCOUNT;
 const slab_flags_t BINDINGS_SLAB_MEM_SPREAD = SLAB_MEM_SPREAD;
 const slab_flags_t BINDINGS_SLAB_ACCOUNT = SLAB_ACCOUNT;
+
+const unsigned long BINDINGS_SB_RDONLY = SB_RDONLY;
+
+const loff_t BINDINGS_MAX_LFS_FILESIZE = MAX_LFS_FILESIZE;
diff --git a/rust/bindings/lib.rs b/rust/bindings/lib.rs
index 6a8c6cd17e45..426915d3fb57 100644
--- a/rust/bindings/lib.rs
+++ b/rust/bindings/lib.rs
@@ -55,3 +55,7 @@ mod bindings_helper {
 pub const SLAB_RECLAIM_ACCOUNT: slab_flags_t = BINDINGS_SLAB_RECLAIM_ACCOUNT;
 pub const SLAB_MEM_SPREAD: slab_flags_t = BINDINGS_SLAB_MEM_SPREAD;
 pub const SLAB_ACCOUNT: slab_flags_t = BINDINGS_SLAB_ACCOUNT;
+
+pub const SB_RDONLY: core::ffi::c_ulong = BINDINGS_SB_RDONLY;
+
+pub const MAX_LFS_FILESIZE: loff_t = BINDINGS_MAX_LFS_FILESIZE;
diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs
index 1df54c234101..31cf643aaded 100644
--- a/rust/kernel/fs.rs
+++ b/rust/kernel/fs.rs
@@ -6,16 +6,22 @@
 //!
 //! C headers: [`include/linux/fs.h`](../../include/linux/fs.h)
 
-use crate::error::{code::*, from_result, to_result, Error};
+use crate::error::{code::*, from_result, to_result, Error, Result};
 use crate::types::Opaque;
 use crate::{bindings, init::PinInit, str::CStr, try_pin_init, ThisModule};
 use core::{marker::PhantomData, marker::PhantomPinned, pin::Pin};
 use macros::{pin_data, pinned_drop};
 
+/// Maximum size of an inode.
+pub const MAX_LFS_FILESIZE: i64 = bindings::MAX_LFS_FILESIZE;
+
 /// A file system type.
 pub trait FileSystem {
     /// The name of the file system type.
     const NAME: &'static CStr;
+
+    /// Returns the parameters to initialise a super block.
+    fn super_params(sb: &NewSuperBlock<Self>) -> Result<SuperParams>;
 }
 
 /// A registration of a file system.
@@ -49,7 +55,7 @@ pub fn new<T: FileSystem + ?Sized>(module: &'static ThisModule) -> impl PinInit<
                 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.init_fs_context = Some(Self::init_fs_context_callback::<T>);
                 fs.kill_sb = Some(Self::kill_sb_callback);
                 fs.fs_flags = 0;
 
@@ -60,13 +66,22 @@ pub fn new<T: FileSystem + ?Sized>(module: &'static ThisModule) -> impl PinInit<
         })
     }
 
-    unsafe extern "C" fn init_fs_context_callback(
-        _fc_ptr: *mut bindings::fs_context,
+    unsafe extern "C" fn init_fs_context_callback<T: FileSystem + ?Sized>(
+        fc_ptr: *mut bindings::fs_context,
     ) -> core::ffi::c_int {
-        from_result(|| Err(ENOTSUPP))
+        from_result(|| {
+            // SAFETY: The C callback API guarantees that `fc_ptr` is valid.
+            let fc = unsafe { &mut *fc_ptr };
+            fc.ops = &Tables::<T>::CONTEXT;
+            Ok(0)
+        })
     }
 
-    unsafe extern "C" fn kill_sb_callback(_sb_ptr: *mut bindings::super_block) {}
+    unsafe extern "C" fn kill_sb_callback(sb_ptr: *mut bindings::super_block) {
+        // SAFETY: In `get_tree_callback` we always call `get_tree_nodev`, so `kill_anon_super` is
+        // the appropriate function to call for cleanup.
+        unsafe { bindings::kill_anon_super(sb_ptr) };
+    }
 }
 
 #[pinned_drop]
@@ -79,6 +94,151 @@ fn drop(self: Pin<&mut Self>) {
     }
 }
 
+/// A file system super block.
+///
+/// Wraps the kernel's `struct super_block`.
+#[repr(transparent)]
+pub struct SuperBlock<T: FileSystem + ?Sized>(Opaque<bindings::super_block>, PhantomData<T>);
+
+/// Required superblock parameters.
+///
+/// This is returned by implementations of [`FileSystem::super_params`].
+pub struct SuperParams {
+    /// The magic number of the superblock.
+    pub magic: u32,
+
+    /// The size of a block in powers of 2 (i.e., for a value of `n`, the size is `2^n`).
+    pub blocksize_bits: u8,
+
+    /// Maximum size of a file.
+    ///
+    /// The maximum allowed value is [`MAX_LFS_FILESIZE`].
+    pub maxbytes: i64,
+
+    /// Granularity of c/m/atime in ns (cannot be worse than a second).
+    pub time_gran: u32,
+}
+
+/// A superblock that is still being initialised.
+///
+/// # Invariants
+///
+/// The superblock is a newly-created one and this is the only active pointer to it.
+#[repr(transparent)]
+pub struct NewSuperBlock<T: FileSystem + ?Sized>(bindings::super_block, PhantomData<T>);
+
+struct Tables<T: FileSystem + ?Sized>(T);
+impl<T: FileSystem + ?Sized> Tables<T> {
+    const CONTEXT: bindings::fs_context_operations = bindings::fs_context_operations {
+        free: None,
+        parse_param: None,
+        get_tree: Some(Self::get_tree_callback),
+        reconfigure: None,
+        parse_monolithic: None,
+        dup: None,
+    };
+
+    unsafe extern "C" fn get_tree_callback(fc: *mut bindings::fs_context) -> core::ffi::c_int {
+        // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
+        // the right type and is a valid callback.
+        unsafe { bindings::get_tree_nodev(fc, Some(Self::fill_super_callback)) }
+    }
+
+    unsafe extern "C" fn fill_super_callback(
+        sb_ptr: *mut bindings::super_block,
+        _fc: *mut bindings::fs_context,
+    ) -> core::ffi::c_int {
+        from_result(|| {
+            // SAFETY: The callback contract guarantees that `sb_ptr` is a unique pointer to a
+            // newly-created superblock.
+            let sb = unsafe { &mut *sb_ptr.cast() };
+            let params = T::super_params(sb)?;
+
+            sb.0.s_magic = params.magic as _;
+            sb.0.s_op = &Tables::<T>::SUPER_BLOCK;
+            sb.0.s_maxbytes = params.maxbytes;
+            sb.0.s_time_gran = params.time_gran;
+            sb.0.s_blocksize_bits = params.blocksize_bits;
+            sb.0.s_blocksize = 1;
+            if sb.0.s_blocksize.leading_zeros() < params.blocksize_bits.into() {
+                return Err(EINVAL);
+            }
+            sb.0.s_blocksize = 1 << sb.0.s_blocksize_bits;
+            sb.0.s_flags |= bindings::SB_RDONLY;
+
+            // The following is scaffolding code that will be removed in a subsequent patch. It is
+            // needed to build a root dentry, otherwise core code will BUG().
+            // SAFETY: `sb` is the superblock being initialised, it is valid for read and write.
+            let inode = unsafe { bindings::new_inode(&mut sb.0) };
+            if inode.is_null() {
+                return Err(ENOMEM);
+            }
+
+            // SAFETY: `inode` is valid for write.
+            unsafe { bindings::set_nlink(inode, 2) };
+
+            {
+                // SAFETY: This is a newly-created inode. No other references to it exist, so it is
+                // safe to mutably dereference it.
+                let inode = unsafe { &mut *inode };
+                inode.i_ino = 1;
+                inode.i_mode = (bindings::S_IFDIR | 0o755) as _;
+
+                // SAFETY: `simple_dir_operations` never changes, it's safe to reference it.
+                inode.__bindgen_anon_3.i_fop = unsafe { &bindings::simple_dir_operations };
+
+                // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it.
+                inode.i_op = unsafe { &bindings::simple_dir_inode_operations };
+            }
+
+            // 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 = unsafe { bindings::d_make_root(inode) };
+            if dentry.is_null() {
+                return Err(ENOMEM);
+            }
+
+            sb.0.s_root = dentry;
+
+            Ok(0)
+        })
+    }
+
+    const SUPER_BLOCK: bindings::super_operations = bindings::super_operations {
+        alloc_inode: None,
+        destroy_inode: None,
+        free_inode: None,
+        dirty_inode: None,
+        write_inode: None,
+        drop_inode: None,
+        evict_inode: None,
+        put_super: None,
+        sync_fs: None,
+        freeze_super: None,
+        freeze_fs: None,
+        thaw_super: None,
+        unfreeze_fs: None,
+        statfs: None,
+        remount_fs: None,
+        umount_begin: None,
+        show_options: None,
+        show_devname: None,
+        show_path: None,
+        show_stats: None,
+        #[cfg(CONFIG_QUOTA)]
+        quota_read: None,
+        #[cfg(CONFIG_QUOTA)]
+        quota_write: None,
+        #[cfg(CONFIG_QUOTA)]
+        get_dquots: None,
+        nr_cached_objects: None,
+        free_cached_objects: None,
+        shutdown: None,
+    };
+}
+
 /// Kernel module that exposes a single file system implemented by `T`.
 #[pin_data]
 pub struct Module<T: FileSystem + ?Sized> {
@@ -105,6 +265,7 @@ fn init(module: &'static ThisModule) -> impl PinInit<Self, Error> {
 ///
 /// ```
 /// # mod module_fs_sample {
+/// use kernel::fs::{NewSuperBlock, SuperParams};
 /// use kernel::prelude::*;
 /// use kernel::{c_str, fs};
 ///
@@ -119,6 +280,9 @@ fn init(module: &'static ThisModule) -> impl PinInit<Self, Error> {
 /// struct MyFs;
 /// impl fs::FileSystem for MyFs {
 ///     const NAME: &'static CStr = c_str!("myfs");
+///     fn super_params(_: &NewSuperBlock<Self>) -> Result<SuperParams> {
+///         todo!()
+///     }
 /// }
 /// # }
 /// ```
diff --git a/samples/rust/rust_rofs.rs b/samples/rust/rust_rofs.rs
index 1c00b1da8b94..9878bf88b991 100644
--- a/samples/rust/rust_rofs.rs
+++ b/samples/rust/rust_rofs.rs
@@ -2,6 +2,7 @@
 
 //! Rust read-only file system sample.
 
+use kernel::fs::{NewSuperBlock, SuperParams};
 use kernel::prelude::*;
 use kernel::{c_str, fs};
 
@@ -16,4 +17,13 @@
 struct RoFs;
 impl fs::FileSystem for RoFs {
     const NAME: &'static CStr = c_str!("rust-fs");
+
+    fn super_params(_sb: &NewSuperBlock<Self>) -> Result<SuperParams> {
+        Ok(SuperParams {
+            magic: 0x52555354,
+            blocksize_bits: 12,
+            maxbytes: fs::MAX_LFS_FILESIZE,
+            time_gran: 1,
+        })
+    }
 }
-- 
2.34.1


  parent reply	other threads:[~2023-10-18 12:25 UTC|newest]

Thread overview: 125+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-18 12:24 [RFC PATCH 00/19] Rust abstractions for VFS Wedson Almeida Filho
2023-10-18 12:25 ` [RFC PATCH 01/19] rust: fs: add registration/unregistration of file systems Wedson Almeida Filho
2023-10-18 15:38   ` Benno Lossin
2024-01-10 18:32     ` Wedson Almeida Filho
2024-01-25  9:15       ` Benno Lossin
2023-10-18 12:25 ` [RFC PATCH 02/19] rust: fs: introduce the `module_fs` macro Wedson Almeida Filho
2023-10-18 12:25 ` [RFC PATCH 03/19] samples: rust: add initial ro file system sample Wedson Almeida Filho
2023-10-28 16:18   ` Alice Ryhl
2024-01-10 18:25     ` Wedson Almeida Filho
2023-10-18 12:25 ` Wedson Almeida Filho [this message]
2023-10-18 16:34   ` [RFC PATCH 04/19] rust: fs: introduce `FileSystem::super_params` Benno Lossin
2023-10-28 16:39     ` Alice Ryhl
2023-10-30  8:21       ` Benno Lossin
2023-10-30 21:36         ` Alice Ryhl
2023-10-20 15:04   ` Ariel Miculas (amiculas)
2024-01-03 12:25   ` Andreas Hindborg (Samsung)
2023-10-18 12:25 ` [RFC PATCH 05/19] rust: fs: introduce `INode<T>` Wedson Almeida Filho
2023-10-28 18:00   ` Alice Ryhl
2024-01-03 12:45     ` Andreas Hindborg (Samsung)
2024-01-03 12:54   ` Andreas Hindborg (Samsung)
2024-01-04  5:20     ` Darrick J. Wong
2024-01-04  9:57       ` Andreas Hindborg (Samsung)
2024-01-10  9:45     ` Benno Lossin
2024-01-04  5:14   ` Darrick J. Wong
2024-01-24 18:17     ` Wedson Almeida Filho
2023-10-18 12:25 ` [RFC PATCH 06/19] rust: fs: introduce `FileSystem::init_root` Wedson Almeida Filho
2023-10-19 14:30   ` Benno Lossin
2023-10-20  0:52     ` Boqun Feng
2023-10-21 13:48       ` Benno Lossin
2023-10-21 15:57         ` Boqun Feng
2023-10-21 17:01           ` Matthew Wilcox
2023-10-21 19:33             ` Boqun Feng
2023-10-23  5:29               ` Dave Chinner
2023-10-23 12:55                 ` Wedson Almeida Filho
2023-10-30  2:29                   ` Dave Chinner
2023-10-31 20:49                     ` Wedson Almeida Filho
2023-11-08  4:54                       ` Dave Chinner
2023-11-08  6:15                         ` Wedson Almeida Filho
2023-10-20  0:30   ` Boqun Feng
2023-10-23 12:36     ` Wedson Almeida Filho
2024-01-03 13:29   ` Andreas Hindborg (Samsung)
2024-01-24  4:07     ` Wedson Almeida Filho
2023-10-18 12:25 ` [RFC PATCH 07/19] rust: fs: introduce `FileSystem::read_dir` Wedson Almeida Filho
2023-10-21  8:33   ` Benno Lossin
2024-01-03 14:09   ` Andreas Hindborg (Samsung)
2024-01-21 21:00   ` Askar Safin
2024-01-21 21:51     ` Dave Chinner
2023-10-18 12:25 ` [RFC PATCH 08/19] rust: fs: introduce `FileSystem::lookup` Wedson Almeida Filho
2023-10-18 12:25 ` [RFC PATCH 09/19] rust: folio: introduce basic support for folios Wedson Almeida Filho
2023-10-18 17:17   ` Matthew Wilcox
2023-10-18 18:32     ` Wedson Almeida Filho
2023-10-18 19:21       ` Matthew Wilcox
2023-10-19 13:25         ` Wedson Almeida Filho
2023-10-20  4:11           ` Matthew Wilcox
2023-10-20 15:17             ` Matthew Wilcox
2023-10-23 12:32               ` Wedson Almeida Filho
2023-10-23 10:48             ` Andreas Hindborg (Samsung)
2023-10-23 14:28               ` Matthew Wilcox
2023-10-24 15:04                 ` Ariel Miculas (amiculas)
2023-10-23 12:29             ` Wedson Almeida Filho
2023-10-21  9:21   ` Benno Lossin
2023-10-18 12:25 ` [RFC PATCH 10/19] rust: fs: introduce `FileSystem::read_folio` Wedson Almeida Filho
2023-11-07 22:18   ` Matthew Wilcox
2023-11-07 22:22     ` Al Viro
2023-11-08  0:35       ` Wedson Almeida Filho
2023-11-08  0:56         ` Al Viro
2023-11-08  2:39           ` Wedson Almeida Filho
2023-10-18 12:25 ` [RFC PATCH 11/19] rust: fs: introduce `FileSystem::read_xattr` Wedson Almeida Filho
2023-10-18 13:06   ` Ariel Miculas (amiculas)
2023-10-19 13:35     ` Wedson Almeida Filho
2023-10-18 12:25 ` [RFC PATCH 12/19] rust: fs: introduce `FileSystem::statfs` Wedson Almeida Filho
2024-01-03 14:13   ` Andreas Hindborg (Samsung)
2024-01-04  5:33   ` Darrick J. Wong
2024-01-24  4:24     ` Wedson Almeida Filho
2023-10-18 12:25 ` [RFC PATCH 13/19] rust: fs: introduce more inode types Wedson Almeida Filho
2023-10-18 12:25 ` [RFC PATCH 14/19] rust: fs: add per-superblock data Wedson Almeida Filho
2023-10-25 15:51   ` Ariel Miculas (amiculas)
2023-10-26 13:46   ` Ariel Miculas (amiculas)
2024-01-03 14:16   ` Andreas Hindborg (Samsung)
2023-10-18 12:25 ` [RFC PATCH 15/19] rust: fs: add basic support for fs buffer heads Wedson Almeida Filho
2024-01-03 14:17   ` Andreas Hindborg (Samsung)
2023-10-18 12:25 ` [RFC PATCH 16/19] rust: fs: allow file systems backed by a block device Wedson Almeida Filho
2023-10-21 13:39   ` Benno Lossin
2024-01-24  4:14     ` Wedson Almeida Filho
2024-01-03 14:38   ` Andreas Hindborg (Samsung)
2023-10-18 12:25 ` [RFC PATCH 17/19] rust: fs: allow per-inode data Wedson Almeida Filho
2023-10-21 13:57   ` Benno Lossin
2024-01-03 14:39   ` Andreas Hindborg (Samsung)
2023-10-18 12:25 ` [RFC PATCH 18/19] rust: fs: export file type from mode constants Wedson Almeida Filho
2023-10-18 12:25 ` [RFC PATCH 19/19] tarfs: introduce tar fs Wedson Almeida Filho
2023-10-18 16:57   ` Matthew Wilcox
2023-10-18 17:05     ` Wedson Almeida Filho
2023-10-18 17:20       ` Matthew Wilcox
2023-10-18 18:07         ` Wedson Almeida Filho
2024-01-24  5:05   ` Matthew Wilcox
2024-01-24  5:23     ` Matthew Wilcox
2024-01-24 18:26       ` Wedson Almeida Filho
2024-01-24 21:05         ` Dave Chinner
2024-01-24 21:28           ` Matthew Wilcox
2024-01-24  5:34     ` Gao Xiang
2023-10-18 13:40 ` [RFC PATCH 00/19] Rust abstractions for VFS Ariel Miculas (amiculas)
2023-10-18 17:12   ` Wedson Almeida Filho
2023-10-29 20:31 ` Matthew Wilcox
2023-10-31 20:14   ` Wedson Almeida Filho
2024-01-03 18:02     ` Matthew Wilcox
2024-01-03 19:04       ` Wedson Almeida Filho
2024-01-03 19:53         ` Al Viro
2024-01-03 20:38           ` Kent Overstreet
2024-01-04  1:49         ` Matthew Wilcox
2024-01-09 18:25           ` Wedson Almeida Filho
2024-01-09 19:30             ` Matthew Wilcox
2024-01-03 19:14       ` Kent Overstreet
2024-01-03 20:41         ` Al Viro
2024-01-09 19:13           ` Wedson Almeida Filho
2024-01-09 19:25             ` Matthew Wilcox
2024-01-09 19:32               ` Greg Kroah-Hartman
2024-01-10  7:49                 ` Wedson Almeida Filho
2024-01-10  7:57                   ` Greg Kroah-Hartman
2024-01-10 12:56                   ` Matthew Wilcox
2024-01-09 22:19               ` Dave Chinner
2024-01-10 19:19                 ` Kent Overstreet
2024-01-24 13:08                   ` FUJITA Tomonori
2024-01-24 19:49                     ` Kent Overstreet
2024-01-05  0:04       ` David Howells
2024-01-05 15:54         ` Jarkko Sakkinen

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=20231018122518.128049-5-wedsonaf@gmail.com \
    --to=wedsonaf@gmail.com \
    --cc=brauner@kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=kent.overstreet@gmail.com \
    --cc=linux-fsdevel@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).