All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ariel Miculas <amiculas@cisco.com>
To: rust-for-linux@vger.kernel.org
Cc: Wedson Almeida Filho <wedsonaf@google.com>
Subject: [PATCH 06/80] rust: allow fs driver to initialise new superblocks
Date: Fri,  9 Jun 2023 09:30:04 +0300	[thread overview]
Message-ID: <20230609063118.24852-7-amiculas@cisco.com> (raw)
In-Reply-To: <20230609063118.24852-1-amiculas@cisco.com>

From: Wedson Almeida Filho <wedsonaf@google.com>

They are also allowed to specify the type of superblock keying.

With this change, drivers get a new callback, `fill_super`, that they
need to implement to initialise new superblocks.

In subsequent commits, they'll be able to populate the root with
entries, but for now it's empty.

Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
---
 rust/kernel/fs.rs       | 406 ++++++++++++++++++++++++++++++++--------
 rust/kernel/fs/param.rs |  17 +-
 samples/rust/rust_fs.rs |  14 +-
 3 files changed, 357 insertions(+), 80 deletions(-)

diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs
index e68b67b8adb0..fb4a814e1fc8 100644
--- a/rust/kernel/fs.rs
+++ b/rust/kernel/fs.rs
@@ -7,11 +7,31 @@
 use crate::{bindings, error::code::*, str::CStr, ThisModule};
 use crate::error::{to_result, from_kernel_result, Error, Result};
 use crate::types::{AlwaysRefCounted, ForeignOwnable, ScopeGuard};
-use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin, ptr};
+use core::{cell::UnsafeCell, marker::PhantomData, marker::PhantomPinned, pin::Pin, ptr};
 use macros::vtable;
 
 pub mod param;
 
+/// Type of superblock keying.
+///
+/// It determines how C's `fs_context_operations::get_tree` is implemented.
+pub enum Super {
+    /// Only one such superblock may exist.
+    Single,
+
+    /// As [`Super::Single`], but reconfigure if it exists.
+    SingleReconf,
+
+    /// Superblocks with different data pointers may exist.
+    Keyed,
+
+    /// Multiple independent superblocks may exist.
+    Independent,
+
+    /// Uses a block device.
+    BlockDev,
+}
+
 /// A file system context.
 ///
 /// It is used to gather configuration to then mount or reconfigure a file system.
@@ -48,6 +68,16 @@ fn parse_monolithic<'a>(
     ) -> Result<Option<&'a mut [u8]>> {
         Ok(None)
     }
+
+    /// Returns the superblock data to be used by this file system context.
+    ///
+    /// This is only needed when [`Type::SUPER_TYPE`] is [`Super::Keyed`], otherwise it is never
+    /// called. In the former case, when the fs is being mounted, an existing superblock is reused
+    /// if one can be found with the same data as the returned value; otherwise a new superblock is
+    /// created.
+    fn tree_key(_data: &mut Self::Data) -> Result<T::Data> {
+        Err(ENOTSUPP)
+    }
 }
 
 struct Tables<T: Type + ?Sized>(T);
@@ -67,12 +97,22 @@ impl<T: Type + ?Sized> Tables<T> {
 
     unsafe extern "C" fn free_callback(fc: *mut bindings::fs_context) {
         // SAFETY: The callback contract guarantees that `fc` is valid.
-        let ptr = unsafe { (*fc).fs_private };
+        let fc = unsafe { &*fc };
+
+        let ptr = fc.fs_private;
         if !ptr.is_null() {
             // SAFETY: `fs_private` was initialised with the result of a `to_pointer` call in
             // `init_fs_context_callback`, so it's ok to call `from_foreign` here.
             unsafe { <T::Context as Context<T>>::Data::from_foreign(ptr) };
         }
+
+        let ptr = fc.s_fs_info;
+        if !ptr.is_null() {
+            // SAFETY: `s_fs_info` may be initialised with the result of a `to_pointer` call in
+            // `get_tree_callback` when keyed superblocks are used (`get_tree_keyed` sets it), so
+            // it's ok to call `from_foreign` here.
+            unsafe { T::Data::from_foreign(ptr) };
+        }
     }
 
     unsafe extern "C" fn parse_param_callback(
@@ -84,8 +124,8 @@ impl<T: Type + ?Sized> Tables<T> {
             let ptr = unsafe { (*fc).fs_private };
 
             // SAFETY: The value of `ptr` (coming from `fs_private` was initialised in
-            // `init_fs_context_callback` to the result of an `into_pointer` call. Since the
-            // context is valid, `from_pointer` wasn't called yet, so `ptr` is valid. Additionally,
+            // `init_fs_context_callback` to the result of an `into_foreign` call. Since the
+            // context is valid, `from_foreign` wasn't called yet, so `ptr` is valid. Additionally,
             // the callback contract guarantees that callbacks are serialised, so it is ok to
             // mutably reference it.
             let mut data =
@@ -126,73 +166,91 @@ impl<T: Type + ?Sized> Tables<T> {
 
     unsafe extern "C" fn fill_super_callback(
         sb_ptr: *mut bindings::super_block,
-        _fc: *mut bindings::fs_context,
+        fc: *mut bindings::fs_context,
     ) -> core::ffi::c_int {
         from_kernel_result! {
-            // The following is temporary code to create the root inode and dentry. It will be
-            // replaced with calls to Rust code.
-
-            // SAFETY: The callback contract guarantees that `sb_ptr` is the only pointer to a
-            // newly-allocated superblock, so it is safe to mutably reference it.
-            let sb = unsafe { &mut *sb_ptr };
-
-            sb.s_maxbytes = bindings::MAX_LFS_FILESIZE;
-            sb.s_blocksize = crate::PAGE_SIZE as _;
-            sb.s_blocksize_bits = bindings::PAGE_SHIFT as _;
-            sb.s_magic = T::MAGIC as _;
-            sb.s_op = &Tables::<T>::SUPER_BLOCK;
-            sb.s_time_gran = 1;
-
-            // Create and initialise the root inode.
-
-            // SAFETY: `sb` was just created initialised, so it is safe pass it to `new_inode`.
-            let inode = unsafe { bindings::new_inode(sb) };
-            if inode.is_null() {
-                return Err(ENOMEM);
-            }
-
-            {
-                // 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 };
-
-                // SAFETY: `current_time` requires that `inode.sb` be valid, which is the case here
-                // since we allocated the inode through the superblock.
-                let time = unsafe { bindings::current_time(inode) };
-                inode.i_ino = 1;
-                inode.i_mode = (bindings::S_IFDIR | 0o755) as _;
-                inode.i_mtime = time;
-                inode.i_atime = time;
-                inode.i_ctime = time;
-
-                // 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: `inode` is valid for write.
-                unsafe { bindings::set_nlink(inode, 2) };
-            }
-
-            // 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);
-            }
+            // SAFETY: The callback contract guarantees that `fc` is valid. It also guarantees that
+            // the callbacks are serialised for a given `fc`, so it is safe to mutably dereference
+            // it.
+            let fc = unsafe { &mut *fc };
+            let ptr = core::mem::replace(&mut fc.fs_private, ptr::null_mut());
 
-            sb.s_root = dentry;
+            // SAFETY: The value of `ptr` (coming from `fs_private` was initialised in
+            // `init_fs_context_callback` to the result of an `into_foreign` call. The context is
+            // being used to initialise a superblock, so we took over `ptr` (`fs_private` is set to
+            // null now) and call `from_foreign` below.
+            let data =
+                unsafe { <<T::Context as Context<T>>::Data as ForeignOwnable>::from_foreign(ptr) };
+
+            // SAFETY: The callback contract guarantees that `sb_ptr` is a unique pointer to a
+            // newly-created superblock.
+            let newsb = unsafe { NewSuperBlock::new(sb_ptr) };
+            T::fill_super(data, newsb)?;
             Ok(0)
         }
     }
 
     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)) }
+        // N.B. When new types are added below, we may need to update `kill_sb_callback` to ensure
+        // that we're cleaning up properly.
+        match T::SUPER_TYPE {
+            Super::Single => unsafe {
+                // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
+                // the right type and is a valid callback.
+                bindings::get_tree_single(fc, Some(Self::fill_super_callback))
+            },
+            Super::SingleReconf => unsafe {
+                // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
+                // the right type and is a valid callback.
+                bindings::get_tree_single_reconf(fc, Some(Self::fill_super_callback))
+            },
+            Super::Independent => unsafe {
+                // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
+                // the right type and is a valid callback.
+                bindings::get_tree_nodev(fc, Some(Self::fill_super_callback))
+            },
+            Super::BlockDev => unsafe {
+                // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also has
+                // the right type and is a valid callback.
+                bindings::get_tree_bdev(fc, Some(Self::fill_super_callback))
+            },
+            Super::Keyed => {
+                from_kernel_result! {
+                    // SAFETY: `fc` is valid per the callback contract.
+                    let ctx = unsafe { &*fc };
+                    let ptr = ctx.fs_private;
+
+                    // SAFETY: The value of `ptr` (coming from `fs_private` was initialised in
+                    // `init_fs_context_callback` to the result of an `into_foreign` call. Since
+                    // the context is valid, `from_foreign` wasn't called yet, so `ptr` is valid.
+                    // Additionally, the callback contract guarantees that callbacks are
+                    // serialised, so it is ok to mutably reference it.
+                    let mut data = unsafe {
+                        <<T::Context as Context<T>>::Data as ForeignOwnable>::borrow_mut(ptr)
+                    };
+                    let fs_data = T::Context::tree_key(&mut data)?;
+                    let fs_data_ptr = fs_data.into_foreign();
+
+                    // `get_tree_keyed` reassigns `ctx.s_fs_info`, which should be ok because
+                    // nowhere else is it assigned a non-null value. However, we add the assert
+                    // below to ensure that there are no unexpected paths on the C side that may do
+                    // this.
+                    assert_eq!(ctx.s_fs_info, core::ptr::null_mut());
+
+                    // SAFETY: `fc` is valid per the callback contract. `fill_super_callback` also
+                    // has the right type and is a valid callback. Lastly, we just called
+                    // `into_foreign` above, so `fs_data_ptr` is also valid.
+                    to_result(unsafe {
+                        bindings::get_tree_keyed(
+                            fc,
+                            Some(Self::fill_super_callback),
+                            fs_data_ptr as _,
+                        )
+                    })?;
+                    Ok(0)
+                }
+            }
+        }
     }
 
     unsafe extern "C" fn reconfigure_callback(_fc: *mut bindings::fs_context) -> core::ffi::c_int {
@@ -208,8 +266,8 @@ impl<T: Type + ?Sized> Tables<T> {
             let ptr = unsafe { (*fc).fs_private };
 
             // SAFETY: The value of `ptr` (coming from `fs_private` was initialised in
-            // `init_fs_context_callback` to the result of an `into_pointer` call. Since the
-            // context is valid, `from_pointer` wasn't called yet, so `ptr` is valid. Additionally,
+            // `init_fs_context_callback` to the result of an `into_foreign` call. Since the
+            // context is valid, `from_foreign` wasn't called yet, so `ptr` is valid. Additionally,
             // the callback contract guarantees that callbacks are serialised, so it is ok to
             // mutably reference it.
             let mut data =
@@ -270,18 +328,25 @@ pub trait Type {
     /// The context used to build fs configuration before it is mounted or reconfigured.
     type Context: Context<Self> + ?Sized;
 
+    /// Data associated with each file system instance.
+    type Data: ForeignOwnable + Send + Sync = ();
+
+    /// Determines how superblocks for this file system type are keyed.
+    const SUPER_TYPE: Super;
+
     /// The name of the file system type.
     const NAME: &'static CStr;
 
-    /// The magic number associated with the file system.
-    ///
-    /// This is normally one of the values in `include/uapi/linux/magic.h`.
-    const MAGIC: u32;
-
     /// The flags of this file system type.
     ///
     /// It is a combination of the flags in the [`flags`] module.
     const FLAGS: i32;
+
+    /// Initialises a super block for this file system type.
+    fn fill_super(
+        data: <Self::Context as Context<Self>>::Data,
+        sb: NewSuperBlock<'_, Self>,
+    ) -> Result<&SuperBlock<Self>>;
 }
 
 /// File system flags.
@@ -425,14 +490,33 @@ unsafe fn unregister_keys(fs: *mut bindings::file_system_type) {
     }
 
     unsafe extern "C" fn kill_sb_callback<T: Type + ?Sized>(sb_ptr: *mut bindings::super_block) {
-        // SAFETY: We always call `get_tree_nodev` from `get_tree_callback`, so we never have a
-        // device, so it is ok to call the function below. Additionally, the callback contract
-        // guarantees that `sb_ptr` is valid.
-        unsafe { bindings::kill_anon_super(sb_ptr) }
-
-        // SAFETY: The callback contract guarantees that `sb_ptr` is valid, and the `kill_sb`
-        // callback being called implies that the `s_type` is also valid.
-        unsafe { Self::unregister_keys((*sb_ptr).s_type) };
+        if let Super::BlockDev = T::SUPER_TYPE {
+            // SAFETY: When the superblock type is `BlockDev`, we have a block device so it's safe
+            // to call `kill_block_super`. Additionally, the callback contract guarantees that
+            // `sb_ptr` is valid.
+            unsafe { bindings::kill_block_super(sb_ptr) }
+        } else {
+            // SAFETY: We always call a `get_tree_nodev` variant from `get_tree_callback` without a
+            // device when `T::SUPER_TYPE` is not `BlockDev`, so we never have a device in such
+            // cases, therefore it is ok to call the function below. Additionally, the callback
+            // contract guarantees that `sb_ptr` is valid.
+            unsafe { bindings::kill_anon_super(sb_ptr) }
+        }
+
+        // SAFETY: The callback contract guarantees that `sb_ptr` is valid.
+        let sb = unsafe { &*sb_ptr };
+
+        // SAFETY: The `kill_sb` callback being called implies that the `s_type` field is valid.
+        unsafe { Self::unregister_keys(sb.s_type) };
+
+        let ptr = sb.s_fs_info;
+        if !ptr.is_null() {
+            // SAFETY: The only place where `s_fs_info` is assigned is `NewSuperBlock::init`, where
+            // it's initialised with the result of a `to_pointer` call. We checked above that ptr
+            // is non-null because it would be null if we never reached the point where we init the
+            // field.
+            unsafe { T::Data::from_foreign(ptr) };
+        }
     }
 }
 
@@ -446,6 +530,172 @@ fn drop(&mut self) {
     }
 }
 
+/// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init`] needs to be called
+/// eventually.
+pub struct NeedsInit;
+
+/// State of [`NewSuperBlock`] that indicates that [`NewSuperBlock::init_root`] needs to be called
+/// eventually.
+pub struct NeedsRoot;
+
+/// Required superblock parameters.
+///
+/// This is used in [`NewSuperBlock::init`].
+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.
+    pub maxbytes: i64,
+
+    /// Granularity of c/m/atime in ns (cannot be worse than a second).
+    pub time_gran: u32,
+}
+
+impl SuperParams {
+    /// Default value for instances of [`SuperParams`].
+    pub const DEFAULT: Self = Self {
+        magic: 0,
+        blocksize_bits: crate::PAGE_SIZE as _,
+        maxbytes: bindings::MAX_LFS_FILESIZE,
+        time_gran: 1,
+    };
+}
+
+/// A superblock that is still being initialised.
+///
+/// It uses type states to ensure that callers use the right sequence of calls.
+///
+/// # Invariants
+///
+/// The superblock is a newly-created one and this is the only active pointer to it.
+pub struct NewSuperBlock<'a, T: Type + ?Sized, S = NeedsInit> {
+    sb: *mut bindings::super_block,
+    _p: PhantomData<(&'a T, S)>,
+}
+
+impl<'a, T: Type + ?Sized> NewSuperBlock<'a, T, NeedsInit> {
+    /// Creates a new instance of [`NewSuperBlock`].
+    ///
+    /// # Safety
+    ///
+    /// `sb` must point to a newly-created superblock and it must be the only active pointer to it.
+    unsafe fn new(sb: *mut bindings::super_block) -> Self {
+        // INVARIANT: The invariants are satisfied by the safety requirements of this function.
+        Self {
+            sb,
+            _p: PhantomData,
+        }
+    }
+
+    /// Initialises the superblock so that it transitions to the [`NeedsRoot`] type state.
+    pub fn init(
+        self,
+        data: T::Data,
+        params: &SuperParams,
+    ) -> Result<NewSuperBlock<'a, T, NeedsRoot>> {
+        // SAFETY: The type invariant guarantees that `self.sb` is the only pointer to a
+        // newly-allocated superblock, so it is safe to mutably reference it.
+        let sb = unsafe { &mut *self.sb };
+
+        sb.s_magic = params.magic as _;
+        sb.s_op = &Tables::<T>::SUPER_BLOCK;
+        sb.s_maxbytes = params.maxbytes;
+        sb.s_time_gran = params.time_gran;
+        sb.s_blocksize_bits = params.blocksize_bits;
+        sb.s_blocksize = 1;
+        if sb.s_blocksize.leading_zeros() < params.blocksize_bits.into() {
+            return Err(EINVAL);
+        }
+        sb.s_blocksize = 1 << sb.s_blocksize_bits;
+
+        // Keyed file systems already have `s_fs_info` initialised.
+        let info = data.into_foreign() as *mut _;
+        if let Super::Keyed = T::SUPER_TYPE {
+            // SAFETY: We just called `into_foreign` above.
+            unsafe { T::Data::from_foreign(info) };
+
+            if sb.s_fs_info != info {
+                return Err(EINVAL);
+            }
+        } else {
+            sb.s_fs_info = info;
+        }
+
+        Ok(NewSuperBlock {
+            sb: self.sb,
+            _p: PhantomData,
+        })
+    }
+}
+
+impl<'a, T: Type + ?Sized> NewSuperBlock<'a, T, NeedsRoot> {
+    /// Initialises the root of the superblock.
+    pub fn init_root(self) -> Result<&'a SuperBlock<T>> {
+        // The following is temporary code to create the root inode and dentry. It will be replaced
+        // once we allow inodes and dentries to be created directly from Rust code.
+
+        // SAFETY: `sb` is initialised (`NeedsRoot` typestate implies it), so it is safe to pass it
+        // to `new_inode`.
+        let inode = unsafe { bindings::new_inode(self.sb) };
+        if inode.is_null() {
+            return Err(ENOMEM);
+        }
+
+        {
+            // 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 };
+
+            // SAFETY: `current_time` requires that `inode.sb` be valid, which is the case here
+            // since we allocated the inode through the superblock.
+            let time = unsafe { bindings::current_time(inode) };
+            inode.i_ino = 1;
+            inode.i_mode = (bindings::S_IFDIR | 0o755) as _;
+            inode.i_mtime = time;
+            inode.i_atime = time;
+            inode.i_ctime = time;
+
+            // 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: `inode` is valid for write.
+            unsafe { bindings::set_nlink(inode, 2) };
+        }
+
+        // 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);
+        }
+
+        // SAFETY: The typestate guarantees that `self.sb` is valid.
+        unsafe { (*self.sb).s_root = dentry };
+
+        // SAFETY: The typestate guarantees that `self.sb` is initialised and we just finished
+        // setting its root, so it's a fully ready superblock.
+        Ok(unsafe { &mut *self.sb.cast() })
+    }
+}
+
+/// A file system super block.
+///
+/// Wraps the kernel's `struct super_block`.
+#[repr(transparent)]
+pub struct SuperBlock<T: Type + ?Sized>(
+    pub(crate) UnsafeCell<bindings::super_block>,
+    PhantomData<T>,
+);
+
 /// Wraps the kernel's `struct inode`.
 ///
 /// # Invariants
diff --git a/rust/kernel/fs/param.rs b/rust/kernel/fs/param.rs
index f0b4393b6b67..44b4e895a1eb 100644
--- a/rust/kernel/fs/param.rs
+++ b/rust/kernel/fs/param.rs
@@ -487,9 +487,24 @@ macro_rules! count_brace_items {
 ///
 /// # impl fs::Type for Example {
 /// #    type Context = Self;
+/// #    const SUPER_TYPE: fs::Super = fs::Super::Independent;
 /// #    const NAME: &'static CStr = c_str!("example");
 /// #    const FLAGS: i32 = 0;
-/// #    const MAGIC: u32 = 0x6578616d;
+/// #
+/// #    fn fill_super<'a>(
+/// #        _data: Box<State>,
+/// #        sb: fs::NewSuperBlock<'_, Self>,
+/// #    ) -> Result<&fs::SuperBlock<Self>> {
+/// #        let sb = sb.init(
+/// #            (),
+/// #            &fs::SuperParams {
+/// #                magic: 0x6578616d,
+/// #                ..fs::SuperParams::DEFAULT
+/// #            },
+/// #        )?;
+/// #        let sb = sb.init_root()?;
+/// #        Ok(sb)
+/// #    }
 /// # }
 /// ```
 #[macro_export]
diff --git a/samples/rust/rust_fs.rs b/samples/rust/rust_fs.rs
index acaa603b0bb2..5d8880d5830b 100644
--- a/samples/rust/rust_fs.rs
+++ b/samples/rust/rust_fs.rs
@@ -41,9 +41,21 @@ fn try_new() -> Result {
 
 impl fs::Type for RustFs {
     type Context = Self;
+    const SUPER_TYPE: fs::Super = fs::Super::Independent;
     const NAME: &'static CStr = c_str!("rustfs");
     const FLAGS: i32 = fs::flags::USERNS_MOUNT;
-    const MAGIC: u32 = 0x72757374;
+
+    fn fill_super(_data: (), sb: fs::NewSuperBlock<'_, Self>) -> Result<&fs::SuperBlock<Self>> {
+        let sb = sb.init(
+            (),
+            &fs::SuperParams {
+                magic: 0x72757374,
+                ..fs::SuperParams::DEFAULT
+            },
+        )?;
+        let sb = sb.init_root()?;
+        Ok(sb)
+    }
 }
 
 struct FsModule {
-- 
2.40.1


  parent reply	other threads:[~2023-06-09  6:55 UTC|newest]

Thread overview: 135+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-09  6:29 [RFC PATCH 00/80] Rust PuzzleFS filesystem driver Ariel Miculas
2023-06-09  6:29 ` [PATCH 01/80] rust: add definitions for ref-counted inodes and dentries Ariel Miculas
2023-06-09  6:30 ` [PATCH 02/80] rust: add ability to register a file system Ariel Miculas
2023-06-09  9:23   ` Miguel Ojeda
2023-06-09  6:30 ` [PATCH 03/80] rust: define fs context Ariel Miculas
2023-06-09  6:30 ` [PATCH 04/80] rust: add support for file system parameters Ariel Miculas
2023-06-09  6:30 ` [PATCH 05/80] rust: kernel: add libraries required by the filesystem abstractions Ariel Miculas
2023-06-09  9:46   ` Miguel Ojeda
2023-06-09  6:30 ` Ariel Miculas [this message]
2023-06-09  6:30 ` [PATCH 07/80] rust: add `module_fs` macro Ariel Miculas
2023-06-09  6:30 ` [PATCH 08/80] WIP: rust: allow fs to be populated Ariel Miculas
2023-06-09  6:30 ` [PATCH 09/80] rust: kernel: backport the delay module from the rust branch Ariel Miculas
2023-06-09  9:29   ` Miguel Ojeda
2023-06-09  6:30 ` [PATCH 10/80] rust: kernel: add container_of macro Ariel Miculas
2023-06-09  6:30 ` [PATCH 11/80] rust: kernel: add offset_of macro Ariel Miculas
2023-06-09  6:30 ` [PATCH 12/80] drop: Add crate::pr_warn declaration Ariel Miculas
2023-06-09  9:29   ` Miguel Ojeda
2023-06-09 10:46     ` Ariel Miculas (amiculas)
2023-06-09  6:30 ` [PATCH 13/80] rust: kernel: rename from_kernel_errno to from_errno Ariel Miculas
2023-06-09  9:56   ` Miguel Ojeda
2023-06-09  6:30 ` [PATCH 14/80] rust: kernel: Rename from_pointer to from_foreing and into_pointer to into_foreign Ariel Miculas
2023-06-09  9:57   ` Miguel Ojeda
2023-06-09  6:30 ` [PATCH 15/80] rust: kernel: add count_paren_items macro, needed by define_fs_params macro Ariel Miculas
2023-06-09  6:30 ` [PATCH 16/80] rust: helpers: add missing rust helper 'alloc_pages' Ariel Miculas
2023-06-09  9:57   ` Miguel Ojeda
2023-06-09  6:30 ` [PATCH 17/80] kernel: configs: add qemu-busybox-min.config Ariel Miculas
2023-06-09  9:39   ` Miguel Ojeda
2023-06-09  6:30 ` [PATCH 18/80] rust: kernel: format the rust code Ariel Miculas
2023-06-09  9:21   ` Miguel Ojeda
2023-06-09  6:30 ` [PATCH 19/80] samples: puzzlefs: add initial puzzlefs sample, copied from rust_fs.rs Ariel Miculas
2023-06-09  6:30 ` [PATCH 20/80] kernel: configs: enable rust samples in rust.config Ariel Miculas
2023-06-09  9:25   ` Miguel Ojeda
2023-06-09  6:30 ` [PATCH 22/80] rust: proc-macro2: add SPDX License Identifiers Ariel Miculas
2023-06-09  6:30 ` [PATCH 23/80] rust: proc-macro2: remove `unicode_ident` dependency Ariel Miculas
2023-06-09  6:30 ` [PATCH 24/80] rust: quote: import crate Ariel Miculas
2023-06-09  6:30 ` [PATCH 25/80] rust: quote: add SPDX License Identifiers Ariel Miculas
2023-06-09  6:30 ` [PATCH 27/80] rust: syn: " Ariel Miculas
2023-06-09  6:30 ` [PATCH 28/80] rust: syn: remove `unicode-ident` dependency Ariel Miculas
2023-06-09  6:30 ` [PATCH 30/80] rust: serde: add `no_fp_fmt_parse` support Ariel Miculas
2023-06-09  6:30 ` [PATCH 31/80] rust: serde: add SPDX License Identifiers Ariel Miculas
2023-06-10  0:19   ` Kent Overstreet
2023-06-10  6:43     ` Greg KH
2023-06-10 13:18       ` Kent Overstreet
2023-06-10 15:28         ` Greg KH
2023-06-10  0:25   ` Kent Overstreet
2023-06-10  9:04     ` Andreas Hindborg (Samsung)
2023-06-10 13:20       ` Kent Overstreet
2023-06-12  8:56         ` Ariel Miculas
2023-06-10  9:33     ` Miguel Ojeda
2023-06-12 11:58     ` Ariel Miculas
2023-06-15 15:05     ` Ariel Miculas
2023-06-17 16:04       ` Kent Overstreet
2023-06-09  6:30 ` [PATCH 33/80] rust: serde_derive: " Ariel Miculas
2023-06-09  6:30 ` [PATCH 34/80] rust: Kbuild: enable `proc-macro2`, `quote`, `syn`, `serde` and `serde_derive` Ariel Miculas
2023-06-09  6:30 ` [PATCH 35/80] rust: test `serde` support Ariel Miculas
2023-06-09  6:30 ` [PATCH 36/80] Add SAMPLE_RUST_SERDE in rust.config Ariel Miculas
2023-06-09  6:30 ` [PATCH 37/80] rust: kernel: fix compile errors after rebase to rust-next Ariel Miculas
2023-06-09  9:38   ` Miguel Ojeda
2023-06-09  6:30 ` [PATCH 39/80] rust: serde_cbor: add SPDX License Identifiers Ariel Miculas
2023-06-09  6:30 ` [PATCH 40/80] rust: serde_cbor: add no_fp_fmt_parse support Ariel Miculas
2023-06-09  6:30 ` [PATCH 41/80] rust: Kbuild: enable serde_cbor Ariel Miculas
2023-06-09 10:21   ` Miguel Ojeda
2023-06-09  6:30 ` [PATCH 42/80] samples: rust: add cbor serialize/deserialize example Ariel Miculas
2023-06-09  6:30 ` [PATCH 43/80] rust: serde_cbor: add support for serde_cbor's from_slice method by using a custom alloc_kernel feature Ariel Miculas
2023-06-09  9:55   ` Miguel Ojeda
2023-06-09  6:30 ` [PATCH 44/80] rust: serde: add support for deserializing Vec with kernel_alloc feature Ariel Miculas
2023-06-09 10:10   ` Miguel Ojeda
2023-06-09  6:30 ` [PATCH 45/80] rust: file: Replace UnsafeCell with Opaque for File Ariel Miculas
2023-06-09  6:30 ` [PATCH 46/80] rust: kernel: implement fmt::Debug for CString Ariel Miculas
2023-06-09  6:30 ` [PATCH 47/80] samples: puzzlefs: rename RustFs to PuzzleFs Ariel Miculas
2023-06-09  6:30 ` [PATCH 48/80] samples: puzzlefs: add basic deserializing support for the puzzlefs metadata Ariel Miculas
2023-06-09  6:30 ` [PATCH 49/80] rust: file: present the filesystem context to the open function Ariel Miculas
2023-06-09  6:30 ` [PATCH 50/80] rust: kernel: add an abstraction over vfsmount to allow cloning a new private mount Ariel Miculas
2023-06-09  6:30 ` [PATCH 51/80] rust: file: add from_path, from_path_in_root_mnt and read_with_offset methods to File Ariel Miculas
2023-06-09  6:30 ` [PATCH 52/80] samples: puzzlefs: pass the Vfsmount structure from open to read and return the contents of the data file inside /home/puzzlefs_oci Ariel Miculas
2023-06-09  6:30 ` [PATCH 53/80] rust: file: move from_path, from_path_in_root_mnt and read_with_offset methods to a RegularFile newtype Ariel Miculas
2023-06-09  6:30 ` [PATCH 54/80] rust: file: ensure RegularFile can only create regular files Ariel Miculas
2023-06-09  6:30 ` [PATCH 55/80] rust: file: add get_pos method to RegularFile Ariel Miculas
2023-06-09  6:30 ` [PATCH 56/80] rust: file: add methods read_to_end, get_file_size and update_pos " Ariel Miculas
2023-06-09  6:30 ` [PATCH 57/80] rust: file: define a minimal Read trait and implement it for RegularFile Ariel Miculas
2023-06-09  6:30 ` [PATCH 58/80] samples: puzzlefs: add cbor_get_array_size method Ariel Miculas
2023-06-09  6:30 ` [PATCH 59/80] samples: puzzlefs: add KernelError to WireFormatError and implement From conversion Ariel Miculas
2023-06-09  6:30 ` [PATCH 60/80] samples: puzzlefs: implement new for MetadataBlob Ariel Miculas
2023-06-09  6:30 ` [PATCH 61/80] samples: puzzlefs: build puzzlefs into the kernel, thus avoiding the need to export rust symbols Ariel Miculas
2023-06-09  6:31 ` [PATCH 62/80] rust: alloc: add try_clone for Vec<T> Ariel Miculas
2023-06-09  6:31 ` [PATCH 63/80] rust: alloc: add from_iter_fallible " Ariel Miculas
2023-06-09 10:06   ` Miguel Ojeda
2023-06-09  6:31 ` [PATCH 64/80] samples: puzzlefs: implement to_errno and from_errno for WireFormatError Ariel Miculas
2023-06-09  6:31 ` [PATCH 65/80] samples: puzzlefs: add TryReserveError (and from conversion) to WireFormatError Ariel Miculas
2023-06-09  6:31 ` [PATCH 66/80] samples: puzzlefs: add higher level inode related functionality Ariel Miculas
2023-06-09  6:31 ` [PATCH 67/80] samples: puzzlefs: populate the directory entries with the inodes from the puzzlefs metadata file Ariel Miculas
2023-06-09  6:31 ` [PATCH 68/80] rust: hex: import crate Ariel Miculas
2023-06-09  6:31 ` [PATCH 69/80] rust: hex: add SPDX license identifiers Ariel Miculas
2023-06-09  6:31 ` [PATCH 70/80] rust: Kbuild: enable `hex` Ariel Miculas
2023-06-09  6:31 ` [PATCH 71/80] rust: hex: implement FromHex trait and hex::decode using a custom kernel_alloc feature Ariel Miculas
2023-06-09  6:31 ` [PATCH 72/80] rust: hex: add encode_hex_iter and encode_hex_upper_iter methods Ariel Miculas
2023-06-09  6:31 ` [PATCH 73/80] rust: puzzlefs: add HexError to WireFormatError and implement the From conversion Ariel Miculas
2023-06-09  6:31 ` [PATCH 74/80] rust: puzzlefs: display the error value for WireFormatError::KernelError Ariel Miculas
2023-06-09  6:31 ` [PATCH 75/80] samples: puzzlefs: add Rootfs and Digest structs to types.rs Ariel Miculas
2023-06-09  6:31 ` [PATCH 76/80] samples: puzzlefs: implement the conversion from WireFormatError to kernel::error::Error Ariel Miculas
2023-06-09  6:31 ` [PATCH 77/80] rust: puzzlefs: read the puzzlefs image manifest instead of an individual metadata layer Ariel Miculas
2023-06-09  6:31 ` [PATCH 78/80] rust: puzzlefs: rename PuzzleFs to PuzzleFsModule to avoid confusion with the PuzzleFS struct Ariel Miculas
2023-06-09  6:31 ` [PATCH 79/80] rust: puzzlefs: add support for reading files Ariel Miculas
2023-06-09  6:31 ` [PATCH 80/80] rust: puzzlefs: add oci_root_dir and image_manifest filesystem parameters Ariel Miculas
2023-06-09 10:26 ` [RFC PATCH 00/80] Rust PuzzleFS filesystem driver Miguel Ojeda
2023-06-09 10:36 ` Christian Brauner
2023-06-09 11:22   ` Ariel Miculas (amiculas)
2023-06-09 11:45     ` Christian Brauner
2023-06-09 12:03       ` Ariel Miculas (amiculas)
2023-06-09 12:56         ` Gao Xiang
2023-06-09 12:07       ` Miguel Ojeda
2023-06-09 12:11         ` Ariel Miculas (amiculas)
2023-06-09 12:21           ` Greg KH
2023-06-09 13:05         ` Alice Ryhl
2023-06-09 12:20       ` Colin Walters
2023-06-09 12:42         ` Christian Brauner
2023-06-09 17:28           ` Serge Hallyn
2023-06-09 13:45         ` Ariel Miculas (amiculas)
2023-06-09 17:10           ` Trilok Soni
2023-06-09 17:16             ` Ariel Miculas (amiculas)
2023-06-09 17:41               ` Miguel Ojeda
2023-06-09 18:49                 ` James Bottomley
2023-06-09 19:08                   ` Miguel Ojeda
2023-06-09 19:11                   ` Ariel Miculas
2023-06-09 20:01                     ` James Bottomley
2023-06-10  9:34                     ` Miguel Ojeda
2023-06-09 18:43               ` James Bottomley
2023-06-09 18:59                 ` Ariel Miculas (amiculas)
2023-06-09 19:20                   ` Ariel Miculas
2023-06-09 19:45                     ` Trilok Soni
2023-06-09 19:53                   ` Alice Ryhl
2023-06-09 11:42   ` Miguel Ojeda
2023-06-09 23:52   ` Kent Overstreet
2023-06-10  9:40     ` Miguel Ojeda
2023-06-10  0:09 ` Kent Overstreet

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=20230609063118.24852-7-amiculas@cisco.com \
    --to=amiculas@cisco.com \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=wedsonaf@google.com \
    /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.