[RFC PATCH v3 10/22] rust: kernel: add an abstraction over vfsmount to allow cloning a new private mount

From: Ariel Miculas
Date: Thu May 16 2024 - 15:09:06 EST


Provide an abstraction over vfsmount so that we can create a new private
mount from Rust code.

PuzzleFS needs a private mount of the PuzzleFS image, so it can access
the chunks from the data store independent of the future changes to the
mount namespace.

Signed-off-by: Ariel Miculas <amiculas@xxxxxxxxx>
---
rust/bindings/bindings_helper.h | 1 +
rust/kernel/lib.rs | 1 +
rust/kernel/mount.rs | 73 +++++++++++++++++++++++++++++++++
3 files changed, 75 insertions(+)
create mode 100644 rust/kernel/mount.rs

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 629fce394dbe..2d87bb9f87c9 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -16,6 +16,7 @@
#include <linux/iomap.h>
#include <linux/jiffies.h>
#include <linux/mdio.h>
+#include <linux/namei.h>
#include <linux/pagemap.h>
#include <linux/phy.h>
#include <linux/refcount.h>
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 445599d4bff6..7f0d89b902ce 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -37,6 +37,7 @@
#[cfg(CONFIG_KUNIT)]
pub mod kunit;
pub mod mem_cache;
+pub mod mount;
#[cfg(CONFIG_NET)]
pub mod net;
pub mod prelude;
diff --git a/rust/kernel/mount.rs b/rust/kernel/mount.rs
new file mode 100644
index 000000000000..50cfe7f7437a
--- /dev/null
+++ b/rust/kernel/mount.rs
@@ -0,0 +1,73 @@
+//! Mount interface
+//!
+//! C headers: [`include/linux/mount.h`](../../../../include/linux/mount.h)
+
+use kernel::bindings;
+use kernel::error::from_err_ptr;
+use kernel::pr_err;
+use kernel::prelude::*;
+use kernel::str::CStr;
+use kernel::types::Opaque;
+
+/// Wraps the kernel's `struct path`.
+#[repr(transparent)]
+pub struct Path(pub(crate) Opaque<bindings::path>);
+
+/// Wraps the kernel's `struct vfsmount`.
+#[repr(transparent)]
+#[derive(Debug)]
+pub struct Vfsmount {
+ vfsmount: *mut bindings::vfsmount,
+}
+
+// SAFETY: No one besides us has the raw pointer, so we can safely transfer Vfsmount to another thread
+unsafe impl Send for Vfsmount {}
+// SAFETY: It's OK to access `Vfsmount` through references from other threads because we're not
+// accessing any properties from the underlying raw pointer
+unsafe impl Sync for Vfsmount {}
+
+impl Vfsmount {
+ /// Create a new private mount clone based on a path name
+ pub fn new_private_mount(path_name: &CStr) -> Result<Self> {
+ let path: Path = Path(Opaque::uninit());
+ // SAFETY: path_name is a &CStr, so it's a valid string pointer; path is an uninitialized
+ // struct stored on the stack and it's ok because kern_path expects an out parameter
+ let err = unsafe {
+ bindings::kern_path(
+ path_name.as_ptr().cast::<i8>(),
+ bindings::LOOKUP_FOLLOW | bindings::LOOKUP_DIRECTORY,
+ path.0.get(),
+ )
+ };
+ if err != 0 {
+ pr_err!("failed to resolve '{}': {}\n", path_name, err);
+ return Err(EINVAL);
+ }
+
+ // SAFETY: path is a struct stored on the stack and it is initialized because the call to
+ // kern_path succeeded
+ let vfsmount = unsafe { from_err_ptr(bindings::clone_private_mount(path.0.get()))? };
+
+ // Don't inherit atime flags
+ // CAST: these flags fit into i32
+ let skip_flags =
+ !(bindings::MNT_NOATIME | bindings::MNT_NODIRATIME | bindings::MNT_RELATIME) as i32;
+ // SAFETY: we called from_err_ptr so it's safe to dereference this pointer
+ unsafe {
+ (*vfsmount).mnt_flags &= skip_flags;
+ }
+ Ok(Self { vfsmount })
+ }
+
+ /// Returns a raw pointer to vfsmount
+ pub fn get(&self) -> *mut bindings::vfsmount {
+ self.vfsmount
+ }
+}
+
+impl Drop for Vfsmount {
+ fn drop(&mut self) {
+ // SAFETY new_private_mount makes sure to return a valid pointer
+ unsafe { bindings::kern_unmount(self.vfsmount) };
+ }
+}
--
2.34.1