Skip to content

Commit ce1f7d9

Browse files
committed
rust: fs: add registration/unregistration of ro file systems
This is just the basics of registering a filesystem and automatically unregistering when the registration instance 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@microsoft.com>
1 parent bbab9fd commit ce1f7d9

4 files changed

Lines changed: 82 additions & 2 deletions

File tree

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