* [PATCH RFC 3/3] bcachefs: introduce Rust module implementation
@ 2024-02-07 5:58 Thomas Bertschinger
2024-02-07 6:07 ` Kent Overstreet
2024-02-07 6:58 ` Trevor Gross
0 siblings, 2 replies; 3+ messages in thread
From: Thomas Bertschinger @ 2024-02-07 5:58 UTC (permalink / raw)
To: rust-for-linux, linux-bcachefs, linux-fsdevel, kent.overstreet,
bfoster, ojeda, alex.gaynor, wedsonaf
Cc: Thomas Bertschinger
This patch uses the bcachefs bindgen framework to introduce a Rust
implementation of the module entry and exit functions. With this change,
bcachefs is now a Rust kernel module (that calls C functions to do most
of its work).
This is only if CONFIG_BCACHEFS_RUST is defined; the C implementation of
the module init and exit code is left around so that bcachefs remains
usable in kernels compiled without Rust support.
Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
---
fs/bcachefs/Makefile | 3 ++
fs/bcachefs/bcachefs.h | 5 ++
fs/bcachefs/bcachefs_module.rs | 66 ++++++++++++++++++++++++++
fs/bcachefs/bindgen_parameters | 13 ++++-
fs/bcachefs/bindings/bindings_helper.h | 4 ++
fs/bcachefs/bindings/mod.rs | 2 +
fs/bcachefs/super.c | 31 ++++++++++--
7 files changed, 120 insertions(+), 4 deletions(-)
create mode 100644 fs/bcachefs/bcachefs_module.rs
diff --git a/fs/bcachefs/Makefile b/fs/bcachefs/Makefile
index 3f209511149c..252810a4d9a0 100644
--- a/fs/bcachefs/Makefile
+++ b/fs/bcachefs/Makefile
@@ -89,8 +89,11 @@ bcachefs-y := \
varint.o \
xattr.o
+bcachefs-$(CONFIG_BCACHEFS_RUST) += bcachefs_module.o
always-$(CONFIG_BCACHEFS_RUST) += bindings/bcachefs_generated.rs
+$(obj)/bcachefs_module.o: $(src)/bindings/bcachefs_generated.rs
+
$(obj)/bindings/bcachefs_generated.rs: private bindgen_target_flags = \
$(shell grep -Ev '^#|^$$' $(srctree)/$(src)/bindgen_parameters)
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h
index b80c6c9efd8c..3a777592bff4 100644
--- a/fs/bcachefs/bcachefs.h
+++ b/fs/bcachefs/bcachefs.h
@@ -1252,4 +1252,9 @@ static inline struct stdio_redirect *bch2_fs_stdio_redirect(struct bch_fs *c)
#define BKEY_PADDED_ONSTACK(key, pad) \
struct { struct bkey_i key; __u64 key ## _pad[pad]; }
+#ifdef CONFIG_BCACHEFS_RUST
+int bch2_kset_init(void);
+void bch2_kset_exit(void);
+#endif
+
#endif /* _BCACHEFS_H */
diff --git a/fs/bcachefs/bcachefs_module.rs b/fs/bcachefs/bcachefs_module.rs
new file mode 100644
index 000000000000..8db2de8139bc
--- /dev/null
+++ b/fs/bcachefs/bcachefs_module.rs
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! bcachefs
+//!
+//! Rust kernel module for bcachefs.
+
+pub mod bindings;
+
+use kernel::prelude::*;
+
+use crate::bindings::*;
+
+module! {
+ type: Bcachefs,
+ name: "bcachefs",
+ author: "Kent Overstreet <kent.overstreet@gmail.com>",
+ description: "bcachefs filesystem",
+ license: "GPL",
+}
+
+struct Bcachefs;
+
+impl kernel::Module for Bcachefs {
+ #[link_section = ".init.text"]
+ fn init(_module: &'static ThisModule) -> Result<Self> {
+ // SAFETY: this block registers the bcachefs services with the kernel. After succesful
+ // registration, all such services are guaranteed by the kernel to exist as long as the
+ // driver is loaded. In the event of any failure in the registration, all registered
+ // services are unregistered.
+ unsafe {
+ bch2_bkey_pack_test();
+
+ if bch2_kset_init() != 0
+ || bch2_btree_key_cache_init() != 0
+ || bch2_chardev_init() != 0
+ || bch2_vfs_init() != 0
+ || bch2_debug_init() != 0
+ {
+ __drop();
+ return Err(ENOMEM);
+ }
+ }
+
+ Ok(Bcachefs)
+ }
+}
+
+fn __drop() {
+ // SAFETY: The kernel does not allow cleanup_module() (which results in
+ // drop()) to be called unless there are no users of the filesystem.
+ // The *_exit() functions only free data that they confirm is allocated, so
+ // this is safe to call even if the module's init() function did not finish.
+ unsafe {
+ bch2_debug_exit();
+ bch2_vfs_exit();
+ bch2_chardev_exit();
+ bch2_btree_key_cache_exit();
+ bch2_kset_exit();
+ }
+}
+
+impl Drop for Bcachefs {
+ fn drop(&mut self) {
+ __drop();
+ }
+}
diff --git a/fs/bcachefs/bindgen_parameters b/fs/bcachefs/bindgen_parameters
index 547212bebd6e..96a63e3a2cc3 100644
--- a/fs/bcachefs/bindgen_parameters
+++ b/fs/bcachefs/bindgen_parameters
@@ -1,5 +1,16 @@
# SPDX-License-Identifier: GPL-2.0
---allowlist-function ''
+--allowlist-function bch2_bkey_pack_test
+--allowlist-function bch2_kset_init
+--allowlist-function bch2_btree_key_cache_init
+--allowlist-function bch2_chardev_init
+--allowlist-function bch2_vfs_init
+--allowlist-function bch2_debug_init
+--allowlist-function bch2_debug_exit
+--allowlist-function bch2_vfs_exit
+--allowlist-function bch2_chardev_exit
+--allowlist-function bch2_btree_key_cache_exit
+--allowlist-function bch2_kset_exit
+
--allowlist-type ''
--allowlist-var ''
diff --git a/fs/bcachefs/bindings/bindings_helper.h b/fs/bcachefs/bindings/bindings_helper.h
index f8bef3676f71..8cf3c35e8ca1 100644
--- a/fs/bcachefs/bindings/bindings_helper.h
+++ b/fs/bcachefs/bindings/bindings_helper.h
@@ -1,3 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include "../bcachefs.h"
+#include "../btree_key_cache.h"
+#include "../chardev.h"
+#include "../fs.h"
+#include "../debug.h"
diff --git a/fs/bcachefs/bindings/mod.rs b/fs/bcachefs/bindings/mod.rs
index 19a3ae3c63c6..d1c3bbbd7b5a 100644
--- a/fs/bcachefs/bindings/mod.rs
+++ b/fs/bcachefs/bindings/mod.rs
@@ -1,3 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
+#![allow(missing_docs)]
+
include!("bcachefs_generated.rs");
diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c
index da8697c79a97..343c4bc6e81c 100644
--- a/fs/bcachefs/super.c
+++ b/fs/bcachefs/super.c
@@ -69,9 +69,12 @@
#include <linux/sysfs.h>
#include <crypto/hash.h>
+#ifndef CONFIG_BCACHEFS_RUST
+/* when enabled, the Rust module exports these modinfo attributes */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kent Overstreet <kent.overstreet@gmail.com>");
MODULE_DESCRIPTION("bcachefs filesystem");
+#endif
MODULE_SOFTDEP("pre: crc32c");
MODULE_SOFTDEP("pre: crc64");
MODULE_SOFTDEP("pre: sha256");
@@ -2082,6 +2085,7 @@ struct bch_fs *bch2_fs_open(char * const *devices, unsigned nr_devices,
/* Global interfaces/init */
+#ifndef CONFIG_BCACHEFS_RUST
static void bcachefs_exit(void)
{
bch2_debug_exit();
@@ -2109,6 +2113,30 @@ static int __init bcachefs_init(void)
return -ENOMEM;
}
+module_exit(bcachefs_exit);
+module_init(bcachefs_init);
+
+#else /* CONFIG_BCACHEFS_RUST */
+/*
+ * bch2_kset_init() and bch2_kset_exit() are wrappers around the kset functions
+ * to be called from the Rust module init and exit because there is not
+ * currently a Rust API for ksets. If/when a Rust API is provided, these
+ * wrappers can be removed and the Rust kernel module can use that directly.
+ */
+int __init bch2_kset_init(void)
+{
+ bcachefs_kset = kset_create_and_add("bcachefs", NULL, fs_kobj);
+
+ return !bcachefs_kset;
+}
+
+void bch2_kset_exit(void)
+{
+ if (bcachefs_kset)
+ kset_unregister(bcachefs_kset);
+}
+#endif
+
#define BCH_DEBUG_PARAM(name, description) \
bool bch2_##name; \
module_param_named(name, bch2_##name, bool, 0644); \
@@ -2119,6 +2147,3 @@ BCH_DEBUG_PARAMS()
__maybe_unused
static unsigned bch2_metadata_version = bcachefs_metadata_version_current;
module_param_named(version, bch2_metadata_version, uint, 0400);
-
-module_exit(bcachefs_exit);
-module_init(bcachefs_init);
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH RFC 3/3] bcachefs: introduce Rust module implementation
2024-02-07 5:58 [PATCH RFC 3/3] bcachefs: introduce Rust module implementation Thomas Bertschinger
@ 2024-02-07 6:07 ` Kent Overstreet
2024-02-07 6:58 ` Trevor Gross
1 sibling, 0 replies; 3+ messages in thread
From: Kent Overstreet @ 2024-02-07 6:07 UTC (permalink / raw)
To: Thomas Bertschinger
Cc: rust-for-linux, linux-bcachefs, linux-fsdevel, bfoster, ojeda,
alex.gaynor, wedsonaf
On Tue, Feb 06, 2024 at 10:58:45PM -0700, Thomas Bertschinger wrote:
> This patch uses the bcachefs bindgen framework to introduce a Rust
> implementation of the module entry and exit functions. With this change,
> bcachefs is now a Rust kernel module (that calls C functions to do most
> of its work).
>
> This is only if CONFIG_BCACHEFS_RUST is defined; the C implementation of
> the module init and exit code is left around so that bcachefs remains
> usable in kernels compiled without Rust support.
so the module_init in Rust is an interesting test case, but - not much
point in checking it in if we're not deleting code on the C side.
Instead, have you looked at pulling the btree transaction layer bindings
from -tools into the kernel? That was going to be my starting point;
once we've got that there's a lot of code we'll be able to rewrite in
Rust piecmeal (fsck, debugs, alloc_background.c - anything that
primarily interacts with the transaction layer).
>
> Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
> ---
> fs/bcachefs/Makefile | 3 ++
> fs/bcachefs/bcachefs.h | 5 ++
> fs/bcachefs/bcachefs_module.rs | 66 ++++++++++++++++++++++++++
> fs/bcachefs/bindgen_parameters | 13 ++++-
> fs/bcachefs/bindings/bindings_helper.h | 4 ++
> fs/bcachefs/bindings/mod.rs | 2 +
> fs/bcachefs/super.c | 31 ++++++++++--
> 7 files changed, 120 insertions(+), 4 deletions(-)
> create mode 100644 fs/bcachefs/bcachefs_module.rs
>
> diff --git a/fs/bcachefs/Makefile b/fs/bcachefs/Makefile
> index 3f209511149c..252810a4d9a0 100644
> --- a/fs/bcachefs/Makefile
> +++ b/fs/bcachefs/Makefile
> @@ -89,8 +89,11 @@ bcachefs-y := \
> varint.o \
> xattr.o
>
> +bcachefs-$(CONFIG_BCACHEFS_RUST) += bcachefs_module.o
> always-$(CONFIG_BCACHEFS_RUST) += bindings/bcachefs_generated.rs
>
> +$(obj)/bcachefs_module.o: $(src)/bindings/bcachefs_generated.rs
> +
> $(obj)/bindings/bcachefs_generated.rs: private bindgen_target_flags = \
> $(shell grep -Ev '^#|^$$' $(srctree)/$(src)/bindgen_parameters)
>
> diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h
> index b80c6c9efd8c..3a777592bff4 100644
> --- a/fs/bcachefs/bcachefs.h
> +++ b/fs/bcachefs/bcachefs.h
> @@ -1252,4 +1252,9 @@ static inline struct stdio_redirect *bch2_fs_stdio_redirect(struct bch_fs *c)
> #define BKEY_PADDED_ONSTACK(key, pad) \
> struct { struct bkey_i key; __u64 key ## _pad[pad]; }
>
> +#ifdef CONFIG_BCACHEFS_RUST
> +int bch2_kset_init(void);
> +void bch2_kset_exit(void);
> +#endif
> +
> #endif /* _BCACHEFS_H */
> diff --git a/fs/bcachefs/bcachefs_module.rs b/fs/bcachefs/bcachefs_module.rs
> new file mode 100644
> index 000000000000..8db2de8139bc
> --- /dev/null
> +++ b/fs/bcachefs/bcachefs_module.rs
> @@ -0,0 +1,66 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! bcachefs
> +//!
> +//! Rust kernel module for bcachefs.
> +
> +pub mod bindings;
> +
> +use kernel::prelude::*;
> +
> +use crate::bindings::*;
> +
> +module! {
> + type: Bcachefs,
> + name: "bcachefs",
> + author: "Kent Overstreet <kent.overstreet@gmail.com>",
> + description: "bcachefs filesystem",
> + license: "GPL",
> +}
> +
> +struct Bcachefs;
> +
> +impl kernel::Module for Bcachefs {
> + #[link_section = ".init.text"]
> + fn init(_module: &'static ThisModule) -> Result<Self> {
> + // SAFETY: this block registers the bcachefs services with the kernel. After succesful
> + // registration, all such services are guaranteed by the kernel to exist as long as the
> + // driver is loaded. In the event of any failure in the registration, all registered
> + // services are unregistered.
> + unsafe {
> + bch2_bkey_pack_test();
> +
> + if bch2_kset_init() != 0
> + || bch2_btree_key_cache_init() != 0
> + || bch2_chardev_init() != 0
> + || bch2_vfs_init() != 0
> + || bch2_debug_init() != 0
> + {
> + __drop();
> + return Err(ENOMEM);
> + }
> + }
> +
> + Ok(Bcachefs)
> + }
> +}
> +
> +fn __drop() {
> + // SAFETY: The kernel does not allow cleanup_module() (which results in
> + // drop()) to be called unless there are no users of the filesystem.
> + // The *_exit() functions only free data that they confirm is allocated, so
> + // this is safe to call even if the module's init() function did not finish.
> + unsafe {
> + bch2_debug_exit();
> + bch2_vfs_exit();
> + bch2_chardev_exit();
> + bch2_btree_key_cache_exit();
> + bch2_kset_exit();
> + }
> +}
> +
> +impl Drop for Bcachefs {
> + fn drop(&mut self) {
> + __drop();
> + }
> +}
> diff --git a/fs/bcachefs/bindgen_parameters b/fs/bcachefs/bindgen_parameters
> index 547212bebd6e..96a63e3a2cc3 100644
> --- a/fs/bcachefs/bindgen_parameters
> +++ b/fs/bcachefs/bindgen_parameters
> @@ -1,5 +1,16 @@
> # SPDX-License-Identifier: GPL-2.0
>
> ---allowlist-function ''
> +--allowlist-function bch2_bkey_pack_test
> +--allowlist-function bch2_kset_init
> +--allowlist-function bch2_btree_key_cache_init
> +--allowlist-function bch2_chardev_init
> +--allowlist-function bch2_vfs_init
> +--allowlist-function bch2_debug_init
> +--allowlist-function bch2_debug_exit
> +--allowlist-function bch2_vfs_exit
> +--allowlist-function bch2_chardev_exit
> +--allowlist-function bch2_btree_key_cache_exit
> +--allowlist-function bch2_kset_exit
> +
> --allowlist-type ''
> --allowlist-var ''
> diff --git a/fs/bcachefs/bindings/bindings_helper.h b/fs/bcachefs/bindings/bindings_helper.h
> index f8bef3676f71..8cf3c35e8ca1 100644
> --- a/fs/bcachefs/bindings/bindings_helper.h
> +++ b/fs/bcachefs/bindings/bindings_helper.h
> @@ -1,3 +1,7 @@
> /* SPDX-License-Identifier: GPL-2.0 */
>
> #include "../bcachefs.h"
> +#include "../btree_key_cache.h"
> +#include "../chardev.h"
> +#include "../fs.h"
> +#include "../debug.h"
> diff --git a/fs/bcachefs/bindings/mod.rs b/fs/bcachefs/bindings/mod.rs
> index 19a3ae3c63c6..d1c3bbbd7b5a 100644
> --- a/fs/bcachefs/bindings/mod.rs
> +++ b/fs/bcachefs/bindings/mod.rs
> @@ -1,3 +1,5 @@
> // SPDX-License-Identifier: GPL-2.0
>
> +#![allow(missing_docs)]
> +
> include!("bcachefs_generated.rs");
> diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c
> index da8697c79a97..343c4bc6e81c 100644
> --- a/fs/bcachefs/super.c
> +++ b/fs/bcachefs/super.c
> @@ -69,9 +69,12 @@
> #include <linux/sysfs.h>
> #include <crypto/hash.h>
>
> +#ifndef CONFIG_BCACHEFS_RUST
> +/* when enabled, the Rust module exports these modinfo attributes */
> MODULE_LICENSE("GPL");
> MODULE_AUTHOR("Kent Overstreet <kent.overstreet@gmail.com>");
> MODULE_DESCRIPTION("bcachefs filesystem");
> +#endif
> MODULE_SOFTDEP("pre: crc32c");
> MODULE_SOFTDEP("pre: crc64");
> MODULE_SOFTDEP("pre: sha256");
> @@ -2082,6 +2085,7 @@ struct bch_fs *bch2_fs_open(char * const *devices, unsigned nr_devices,
>
> /* Global interfaces/init */
>
> +#ifndef CONFIG_BCACHEFS_RUST
> static void bcachefs_exit(void)
> {
> bch2_debug_exit();
> @@ -2109,6 +2113,30 @@ static int __init bcachefs_init(void)
> return -ENOMEM;
> }
>
> +module_exit(bcachefs_exit);
> +module_init(bcachefs_init);
> +
> +#else /* CONFIG_BCACHEFS_RUST */
> +/*
> + * bch2_kset_init() and bch2_kset_exit() are wrappers around the kset functions
> + * to be called from the Rust module init and exit because there is not
> + * currently a Rust API for ksets. If/when a Rust API is provided, these
> + * wrappers can be removed and the Rust kernel module can use that directly.
> + */
> +int __init bch2_kset_init(void)
> +{
> + bcachefs_kset = kset_create_and_add("bcachefs", NULL, fs_kobj);
> +
> + return !bcachefs_kset;
> +}
> +
> +void bch2_kset_exit(void)
> +{
> + if (bcachefs_kset)
> + kset_unregister(bcachefs_kset);
> +}
> +#endif
> +
> #define BCH_DEBUG_PARAM(name, description) \
> bool bch2_##name; \
> module_param_named(name, bch2_##name, bool, 0644); \
> @@ -2119,6 +2147,3 @@ BCH_DEBUG_PARAMS()
> __maybe_unused
> static unsigned bch2_metadata_version = bcachefs_metadata_version_current;
> module_param_named(version, bch2_metadata_version, uint, 0400);
> -
> -module_exit(bcachefs_exit);
> -module_init(bcachefs_init);
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH RFC 3/3] bcachefs: introduce Rust module implementation
2024-02-07 5:58 [PATCH RFC 3/3] bcachefs: introduce Rust module implementation Thomas Bertschinger
2024-02-07 6:07 ` Kent Overstreet
@ 2024-02-07 6:58 ` Trevor Gross
1 sibling, 0 replies; 3+ messages in thread
From: Trevor Gross @ 2024-02-07 6:58 UTC (permalink / raw)
To: Thomas Bertschinger
Cc: rust-for-linux, linux-bcachefs, linux-fsdevel, kent.overstreet,
bfoster, ojeda, alex.gaynor, wedsonaf
On Wed, Feb 7, 2024 at 12:59 AM Thomas Bertschinger
<tahbertschinger@gmail.com> wrote:
>
> This patch uses the bcachefs bindgen framework to introduce a Rust
> implementation of the module entry and exit functions. With this change,
> bcachefs is now a Rust kernel module (that calls C functions to do most
> of its work).
>
> This is only if CONFIG_BCACHEFS_RUST is defined; the C implementation of
> the module init and exit code is left around so that bcachefs remains
> usable in kernels compiled without Rust support.
>
> Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
> ---
>
> [...]
>
> diff --git a/fs/bcachefs/bcachefs_module.rs b/fs/bcachefs/bcachefs_module.rs
> new file mode 100644
> index 000000000000..8db2de8139bc
> --- /dev/null
> +++ b/fs/bcachefs/bcachefs_module.rs
> @@ -0,0 +1,66 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! bcachefs
> +//!
> +//! Rust kernel module for bcachefs.
> +
> +pub mod bindings;
> +
> +use kernel::prelude::*;
> +
> +use crate::bindings::*;
Most in-tree code uses the `bindings::` prefix when referencing C to
make extern calls clear, rather than doing the glob import. I think we
probably want to keep this style.
> +module! {
> + type: Bcachefs,
> + name: "bcachefs",
> + author: "Kent Overstreet <kent.overstreet@gmail.com>",
> + description: "bcachefs filesystem",
> + license: "GPL",
> +}
> +
> +struct Bcachefs;
> +
> +impl kernel::Module for Bcachefs {
> + #[link_section = ".init.text"]
Is the attribute still needed if this lands?
https://lore.kernel.org/rust-for-linux/20240206153806.567055-1-tahbertschinger@gmail.com/T/#u
> + fn init(_module: &'static ThisModule) -> Result<Self> {
> + // SAFETY: this block registers the bcachefs services with the kernel. After succesful
> + // registration, all such services are guaranteed by the kernel to exist as long as the
> + // driver is loaded. In the event of any failure in the registration, all registered
> + // services are unregistered.
> + unsafe {
> + bch2_bkey_pack_test();
> +
> + if bch2_kset_init() != 0
> + || bch2_btree_key_cache_init() != 0
> + || bch2_chardev_init() != 0
> + || bch2_vfs_init() != 0
> + || bch2_debug_init() != 0
> + {
> + __drop();
> + return Err(ENOMEM);
Do these init functions ever return anything more descriptive than
ENOMEM that should be returned instead? Maybe not worth changing if
the next phase will let you `?` the results.
> + }
> + }
> +
> + Ok(Bcachefs)
> + }
> +}
> +
> +fn __drop() {
Something like `drop_impl` or `unregister` is probably more in line
with naming, dunder is really only used when something
unstable/generated needs to be made public.
> [...]
Cool to see the ball rolling on this :)
- Trevor
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2024-02-07 6:58 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-07 5:58 [PATCH RFC 3/3] bcachefs: introduce Rust module implementation Thomas Bertschinger
2024-02-07 6:07 ` Kent Overstreet
2024-02-07 6:58 ` Trevor Gross
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).