Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to CoercePointee macro, with examples #1130

Draft
wants to merge 1 commit into
base: rust-next
Choose a base branch
from

Conversation

dingxiangfei2009
Copy link

@dingxiangfei2009 dingxiangfei2009 commented Nov 20, 2024

Target audience: first timers to build kernel with Rust support

This patch demonstrates the new capability from the current Rust Nightly, which now supports the #[derive(CoercePointee)] macro to derive the key trait implementations, in place of use of unstable language features such as Unsize and DispatchFromDyn.

An illustrative example is attached for more details in the Rust sample kernel module.

How to test this

As usual, you shall follow the guide to set up the toolchain: https://docs.kernel.org/rust/quick-start.html. This demonstration can be executed through virtualization. In this case, during configuration through make LLVM=1 menuconfig, be sure to select Enable Paravirtualization code and KVM Guest support under Processor type and features/Linux guest support; also select Printing Macros as modularised under Kernel hacking/Sample kernel code/Rust samples. Initiate build with make LLVM=1 optionally with -j for parallelism.

Meanwhile, you will need busybox from https://www.busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox. I am running a x86_64 box, so the demo uses qemu-system-x86_64 as the emulator. I will use the usr/gen_init_cpio script for generating the initramfs image initram.img. Here is the description I used.

dir     /bin                                          0755 0 0
dir     /sys                                          0755 0 0
dir     /dev                                          0755 0 0
file    /bin/busybox  <path to busybox>                         0755 0 0
slink   /bin/sh       /bin/busybox                    0755 0 0
slink   /bin/mount    /bin/busybox                    0755 0 0
slink   /bin/insmod   /bin/busybox                    0755 0 0
slink   /bin/rmmod    /bin/busybox                    0755 0 0
slink   /bin/cut      /bin/busybox                    0755 0 0
slink   /bin/cat      /bin/busybox                    0755 0 0
slink   /bin/cd       /bin/busybox                    0755 0 0
slink   /bin/ls       /bin/busybox                    0755 0 0
file    /init         init                            0755 0 0
file    /rust_print.ko <path to linux>/linux/samples/rust/rust_print.ko 0755 0 0

I used this command to launch the emulation and it dropped to a shell.

qemu-system-x86_64 \
    -kernel arch/x86_64/boot/bzImage \
    -initrd <path to initram.img> \
    -M pc \
    -m 4G \
    -cpu Cascadelake-Server \
    -smp 4 \
    -nographic \
    -vga none \
    -no-reboot \
    -accel kvm \
    -append 'console=ttyS0'

In the shell I executed insmod rust_print.ko.

What would you see

Upon successful launch, a quick insmod rust_print.ko will generate some kernel log. You may watch out for the following log stanza, especially the lines containing the text Arc<dyn Display>.

...
[   36.255440] rust_print: "hello, world"
[   36.255627] rust_print: [samples/rust/rust_print.rs:35:5] c = "hello, world"
[   36.256245] rust_print: Arc<dyn Display> says 42
[   36.256267] rust_print: Arc<dyn Display> says hello, world
[   36.256579] rust_print: "hello, world"
...

TODO(@wieDasDing): work on the patch epilogue a bit more

Comment on lines 444 to 460
// This is to allow coercion from `ListArc<T>` to `ListArc<U>` if `T` can be converted to the
// dynamically-sized type (DST) `U`.
impl<T, U, const ID: u64> core::ops::CoerceUnsized<ListArc<U, ID>> for ListArc<T, ID>
where
T: ListArcSafe<ID> + Unsize<U> + ?Sized,
U: ListArcSafe<ID> + ?Sized,
{
}

// This is to allow `ListArc<U>` to be dispatched on when `ListArc<T>` can be coerced into
// `ListArc<U>`.
impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc<T, ID>
where
T: ListArcSafe<ID> + Unsize<U> + ?Sized,
U: ListArcSafe<ID> + ?Sized,
{
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't delete these due to support for older rustc releases. Please see this doc for info on conditional compilation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference, our current minimum version is 1.78.0, so you can use that to test.

Copy link
Author

@dingxiangfei2009 dingxiangfei2009 Nov 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will revert those chunks and wrap it with a conditional

@dingxiangfei2009 dingxiangfei2009 force-pushed the coerce-pointee-example branch 2 times, most recently from 27e8103 to 36e9396 Compare November 22, 2024 12:56
@dingxiangfei2009
Copy link
Author

From now I am going to squash the commits a bit and attach proper commit messages. I will run the checks over the commit as per instructions.

@ojeda
Copy link
Member

ojeda commented Nov 22, 2024

I will run the checks over the commit as per instructions.

Sounds great, thanks for doing that -- please also take a look at: https://rust-for-linux.com/contributing#submit-checklist-addendum (i.e. our own list, mostly about running rustfmt, Clippy...).

By the way, for linking to kernel docs, I recommend docs.kernel.org, e.g. the latest version would be at: https://docs.kernel.org/process/submitting-patches.html

@@ -471,13 +479,16 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {
/// obj.as_arc_borrow().use_reference();
/// # Ok::<(), Error>(())
/// ```
#[cfg_attr(CONFIG_RUST_COERCE_POINTEE, repr(transparent))]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be unconditional

Comment on lines 53 to 57
#[cfg(not(CONFIG_RUST_COERCE_POINTEE))]
pr_info!(
"The demonstration for dynamic dispatching through Arc is skipped. "
"To see the print-out from this example, please upgrade your Rust compiler to 1.83.0 or higher.\n"
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this example limited. Does the logic we have pre-1.83 not work for the sample?

Comment on lines 465 to 470
/// `ListArc` is well-behaved so that its dereferencing operation does not mutate.
#[cfg(CONFIG_RUST_COERCE_POINTEE)]
unsafe impl<T: ?Sized + ListArcSafe<ID>, const ID: u64> core::pin::PinCoerceUnsized
for ListArc<T, ID>
{
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need PinCoerceUnsized.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha. Dropped.

Comment on lines 16 to 23
#![cfg_attr(
CONFIG_RUST_COERCE_POINTEE,
feature(derive_coerce_pointee, pin_coerce_unsized_trait)
)]
#![cfg_attr(
not(CONFIG_RUST_COERCE_POINTEE),
feature(coerce_unsized, dispatch_from_dyn, unsize)
)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this format better if we split each feature out on its own line?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have splitted them in the final patch. I will push the results shortly.

Copy link
Collaborator

@Darksonn Darksonn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good and ready for submission. Just one nit:

Comment on lines 26 to 29
#[cfg(CONFIG_RUST_COERCE_POINTEE)]
use core::marker::CoercePointee;
#[cfg(not(CONFIG_RUST_COERCE_POINTEE))]
use core::marker::Unsize;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use full paths for these instead of the imports?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, fully qualified paths looks much better and easier to reason given all the cfg conditional.

Since Rust 1.84.0 the macro `CoercePointee` has
been made public on Nightly, so that it answers
the some usability questions.

If one wants to equip generic types with the
ability to weaken itself and to work with
unsized types with dynamic dispatching.
This feature is useful such that Rust code are
enabled to work with a family of types satisfying
the same protocol or Rust traits, while the same
safety guarantees are still uphold [1].
Examples of this weakening include those from
*[u8; 8]* to *[u8]*, eliding the concrete size of
the array; and a concrete type *T* to *dyn Trait*
where *T* implements the trait or traits *Trait*.

As of date, the exact language features to enable
this type weakening is still under stabilization
effort. Nevertheless, Alice Ryhl has proposed [2]
a very valuable combination of them such that a
user can enable this feature via a procedural
macro `CoercePointee` without much verbosity and
without declaring dependence on the relevant
unstable language features.

Alice has previously filed a patch [3] to
demonstrate the capability of this macro.
This patch provides further updates to incorporate
recent changes to the proposal in [2] and paves
the way for the final stabilization of the
feature in the Rust language.

A minimal demostration code is added to
the *samples/rust/rust_print_main.rs* module.

The use of the macro is now gated behind the
available Rust version *1.83.0*.
The *kernel* crate will still be as functional on
the prior Rust toolchains.

Link: https://doc.rust-lang.org/stable/nomicon/exotic-sizes.html?highlight=dynamic#dynamically-sized-types-dsts [1]
Link: https://rust-lang.github.io/rfcs/3621-derive-smart-pointer.html [2]
Link: https://lore.kernel.org/all/20240823-derive-smart-pointer-v1-1-53769cd37239@google.com/ [3]
Signed-off-by: Xiangfei Ding <dingxiangfei2009@protonmail.ch>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

4 participants