Skip to content

Commit 528babd

Browse files
committed
rust: fs: add registration/unregistration of file systems
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 <[email protected]>
1 parent b0bc357 commit 528babd

File tree

4 files changed

+82
-2
lines changed

4 files changed

+82
-2
lines changed

rust/bindings/bindings_helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <kunit/test.h>
1010
#include <linux/errname.h>
11+
#include <linux/fs.h>
1112
#include <linux/slab.h>
1213
#include <linux/refcount.h>
1314
#include <linux/wait.h>

rust/kernel/error.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,6 @@ pub(crate) fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
320320
/// })
321321
/// }
322322
/// ```
323-
// TODO: Remove `dead_code` marker once an in-kernel client is available.
324-
#[allow(dead_code)]
325323
pub(crate) fn from_result<T, F>(f: F) -> T
326324
where
327325
T: From<i16>,

rust/kernel/fs.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Kernel file systems.
4+
//!
5+
//! This module allows Rust code to register new kernel file systems.
6+
//!
7+
//! C headers: [`include/linux/fs.h`](../../include/linux/fs.h)
8+
9+
use crate::error::{code::*, from_result, to_result, Error};
10+
use crate::types::Opaque;
11+
use crate::{bindings, init::PinInit, str::CStr, try_pin_init, ThisModule};
12+
use core::{marker::PhantomPinned, pin::Pin};
13+
use macros::{pin_data, pinned_drop};
14+
15+
/// A file system type.
16+
pub trait FileSystem {
17+
/// The name of the file system type.
18+
const NAME: &'static CStr;
19+
}
20+
21+
/// A registration of a file system.
22+
#[pin_data(PinnedDrop)]
23+
pub struct Registration {
24+
#[pin]
25+
fs: Opaque<bindings::file_system_type>,
26+
#[pin]
27+
_pin: PhantomPinned,
28+
}
29+
30+
// SAFETY: `Registration` doesn't provide any `&self` methods, so it is safe to pass references
31+
// to it around.
32+
unsafe impl Sync for Registration {}
33+
34+
// SAFETY: Both registration and unregistration are implemented in C and safe to be performed
35+
// from any thread, so `Registration` is `Send`.
36+
unsafe impl Send for Registration {}
37+
38+
impl Registration {
39+
/// Creates the initialiser of a new file system registration.
40+
pub fn new<T: FileSystem + ?Sized>(module: &'static ThisModule) -> impl PinInit<Self, Error> {
41+
try_pin_init!(Self {
42+
_pin: PhantomPinned,
43+
fs <- Opaque::try_ffi_init(|fs_ptr: *mut bindings::file_system_type| {
44+
// SAFETY: `try_ffi_init` guarantees that `fs_ptr` is valid for write.
45+
unsafe { fs_ptr.write(bindings::file_system_type::default()) };
46+
47+
// SAFETY: `try_ffi_init` guarantees that `fs_ptr` is valid for write, and it has
48+
// just been initialised above, so it's also valid for read.
49+
let fs = unsafe { &mut *fs_ptr };
50+
fs.owner = module.0;
51+
fs.name = T::NAME.as_char_ptr();
52+
fs.init_fs_context = Some(Self::init_fs_context_callback);
53+
fs.kill_sb = Some(Self::kill_sb_callback);
54+
fs.fs_flags = 0;
55+
56+
// SAFETY: Pointers stored in `fs` are static so will live for as long as the
57+
// registration is active (it is undone in `drop`).
58+
to_result(unsafe { bindings::register_filesystem(fs_ptr) })
59+
}),
60+
})
61+
}
62+
63+
unsafe extern "C" fn init_fs_context_callback(
64+
_fc_ptr: *mut bindings::fs_context,
65+
) -> core::ffi::c_int {
66+
from_result(|| Err(ENOTSUPP))
67+
}
68+
69+
unsafe extern "C" fn kill_sb_callback(_sb_ptr: *mut bindings::super_block) {}
70+
}
71+
72+
#[pinned_drop]
73+
impl PinnedDrop for Registration {
74+
fn drop(self: Pin<&mut Self>) {
75+
// SAFETY: If an instance of `Self` has been successfully created, a call to
76+
// `register_filesystem` has necessarily succeeded. So it's ok to call
77+
// `unregister_filesystem` on the previously registered fs.
78+
unsafe { bindings::unregister_filesystem(self.fs.get()) };
79+
}
80+
}

rust/kernel/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ extern crate self as kernel;
3434
mod allocator;
3535
mod build_assert;
3636
pub mod error;
37+
pub mod fs;
3738
pub mod init;
3839
pub mod ioctl;
3940
#[cfg(CONFIG_KUNIT)]

0 commit comments

Comments
 (0)