Skip to content

Commit d6657ee

Browse files
authored
Merge pull request #812 from wedsonaf/not-mountable
rust: add ability to register a file system
2 parents ec966c7 + 117b428 commit d6657ee

File tree

4 files changed

+153
-2
lines changed

4 files changed

+153
-2
lines changed

rust/kernel/fs.rs

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,119 @@
44
//!
55
//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h)
66
7-
use crate::{bindings, AlwaysRefCounted};
8-
use core::{cell::UnsafeCell, ptr};
7+
use crate::{bindings, error::code::*, str::CStr, to_result, AlwaysRefCounted, Result, ThisModule};
8+
use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin, ptr};
9+
10+
/// A file system type.
11+
pub trait Type {
12+
/// The name of the file system type.
13+
const NAME: &'static CStr;
14+
15+
/// The flags of this file system type.
16+
///
17+
/// It is a combination of the flags in the [`flags`] module.
18+
const FLAGS: i32;
19+
}
20+
21+
/// File system flags.
22+
pub mod flags {
23+
use crate::bindings;
24+
25+
/// The file system requires a device.
26+
pub const REQUIRES_DEV: i32 = bindings::FS_REQUIRES_DEV as _;
27+
28+
/// The options provided when mounting are in binary form.
29+
pub const BINARY_MOUNTDATA: i32 = bindings::FS_BINARY_MOUNTDATA as _;
30+
31+
/// The file system has a subtype. It is extracted from the name and passed in as a parameter.
32+
pub const HAS_SUBTYPE: i32 = bindings::FS_HAS_SUBTYPE as _;
33+
34+
/// The file system can be mounted by userns root.
35+
pub const USERNS_MOUNT: i32 = bindings::FS_USERNS_MOUNT as _;
36+
37+
/// Disables fanotify permission events.
38+
pub const DISALLOW_NOTIFY_PERM: i32 = bindings::FS_DISALLOW_NOTIFY_PERM as _;
39+
40+
/// The file system has been updated to handle vfs idmappings.
41+
pub const ALLOW_IDMAP: i32 = bindings::FS_ALLOW_IDMAP as _;
42+
43+
/// The file systen will handle `d_move` during `rename` internally.
44+
pub const RENAME_DOES_D_MOVE: i32 = bindings::FS_RENAME_DOES_D_MOVE as _;
45+
}
46+
47+
/// A file system registration.
48+
#[derive(Default)]
49+
pub struct Registration {
50+
is_registered: bool,
51+
fs: UnsafeCell<bindings::file_system_type>,
52+
_pin: PhantomPinned,
53+
}
54+
55+
// SAFETY: `Registration` doesn't really provide any `&self` methods, so it is safe to pass
56+
// references to it around.
57+
unsafe impl Sync for Registration {}
58+
59+
// SAFETY: Both registration and unregistration are implemented in C and safe to be performed from
60+
// any thread, so `Registration` is `Send`.
61+
unsafe impl Send for Registration {}
62+
63+
impl Registration {
64+
/// Creates a new file system registration.
65+
///
66+
/// It is not visible or accessible yet. A successful call to [`Registration::register`] needs
67+
/// to be made before users can mount it.
68+
pub fn new() -> Self {
69+
Self {
70+
is_registered: false,
71+
fs: UnsafeCell::new(bindings::file_system_type::default()),
72+
_pin: PhantomPinned,
73+
}
74+
}
75+
76+
/// Registers a file system so that it can be mounted by users.
77+
///
78+
/// The file system is described by the [`Type`] argument.
79+
///
80+
/// It is automatically unregistered when the registration is dropped.
81+
pub fn register<T: Type>(self: Pin<&mut Self>, module: &'static ThisModule) -> Result {
82+
// SAFETY: We never move out of `this`.
83+
let this = unsafe { self.get_unchecked_mut() };
84+
85+
if this.is_registered {
86+
return Err(EINVAL);
87+
}
88+
89+
let mut fs = this.fs.get_mut();
90+
fs.owner = module.0;
91+
fs.name = T::NAME.as_char_ptr();
92+
fs.fs_flags = T::FLAGS;
93+
fs.init_fs_context = Some(Self::init_fs_context_callback::<T>);
94+
fs.kill_sb = Some(Self::kill_sb_callback::<T>);
95+
// SAFETY: Pointers stored in `fs` are either static so will live for as long as the
96+
// registration is active (it is undone in `drop`).
97+
to_result(unsafe { bindings::register_filesystem(this.fs.get()) })?;
98+
this.is_registered = true;
99+
Ok(())
100+
}
101+
102+
unsafe extern "C" fn init_fs_context_callback<T: Type>(
103+
_fc_ptr: *mut bindings::fs_context,
104+
) -> core::ffi::c_int {
105+
EINVAL.to_kernel_errno()
106+
}
107+
108+
unsafe extern "C" fn kill_sb_callback<T: Type>(_sb_ptr: *mut bindings::super_block) {}
109+
}
110+
111+
impl Drop for Registration {
112+
fn drop(&mut self) {
113+
if self.is_registered {
114+
// SAFETY: When `is_registered` is `true`, a previous call to `register_filesystem` has
115+
// succeeded, so it is safe to unregister here.
116+
unsafe { bindings::unregister_filesystem(self.fs.get()) };
117+
}
118+
}
119+
}
9120

10121
/// Wraps the kernel's `struct inode`.
11122
///

samples/rust/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@ config SAMPLE_RUST_PLATFORM
118118
To compile this as a module, choose M here:
119119
the module will be called rust_platform.
120120

121+
config SAMPLE_RUST_FS
122+
tristate "File system"
123+
help
124+
This option builds the Rust file system sample.
125+
126+
To compile this as a module, choose M here:
127+
the module will be called rust_fs.
128+
121129
If unsure, say N.
122130

123131
config SAMPLE_RUST_NETFILTER

samples/rust/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ obj-$(CONFIG_SAMPLE_RUST_RANDOM) += rust_random.o
1313
obj-$(CONFIG_SAMPLE_RUST_PLATFORM) += rust_platform.o
1414
obj-$(CONFIG_SAMPLE_RUST_NETFILTER) += rust_netfilter.o
1515
obj-$(CONFIG_SAMPLE_RUST_ECHO_SERVER) += rust_echo_server.o
16+
obj-$(CONFIG_SAMPLE_RUST_FS) += rust_fs.o
1617

1718
subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS) += hostprogs

samples/rust/rust_fs.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Rust file system sample.
4+
5+
use kernel::prelude::*;
6+
use kernel::{c_str, fs};
7+
8+
module! {
9+
type: FsModule,
10+
name: b"rust_fs",
11+
author: b"Rust for Linux Contributors",
12+
license: b"GPL",
13+
}
14+
15+
struct RustFs;
16+
impl fs::Type for RustFs {
17+
const NAME: &'static CStr = c_str!("rustfs");
18+
const FLAGS: i32 = fs::flags::USERNS_MOUNT;
19+
}
20+
21+
struct FsModule {
22+
_fs: Pin<Box<fs::Registration>>,
23+
}
24+
25+
impl kernel::Module for FsModule {
26+
fn init(_name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
27+
let mut reg = Pin::from(Box::try_new(fs::Registration::new())?);
28+
reg.as_mut().register::<RustFs>(module)?;
29+
Ok(Self { _fs: reg })
30+
}
31+
}

0 commit comments

Comments
 (0)