Skip to content

Commit 2e5f4f3

Browse files
y86-devojeda
authored andcommitted
rust: pin-init: add miscellaneous files from the user-space version
Add readme and contribution guidelines of the user-space version of pin-init. Signed-off-by: Benno Lossin <[email protected]> Reviewed-by: Fiona Behrens <[email protected]> Reviewed-by: Andreas Hindborg <[email protected]> Tested-by: Andreas Hindborg <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Miguel Ojeda <[email protected]>
1 parent a9fa3a9 commit 2e5f4f3

File tree

2 files changed

+300
-0
lines changed

2 files changed

+300
-0
lines changed

rust/pin-init/CONTRIBUTING.md

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Contributing to `pin-init`
2+
3+
Thanks for showing interest in contributing to `pin-init`! This document outlines the guidelines for
4+
contributing to `pin-init`.
5+
6+
All contributions are double-licensed under Apache 2.0 and MIT. You can find the respective licenses
7+
in the `LICENSE-APACHE` and `LICENSE-MIT` files.
8+
9+
## Non-Code Contributions
10+
11+
### Bug Reports
12+
13+
For any type of bug report, please submit an issue using the bug report issue template.
14+
15+
If the issue is a soundness issue, please privately report it as a security vulnerability via the
16+
GitHub web interface.
17+
18+
### Feature Requests
19+
20+
If you have any feature requests, please submit an issue using the feature request issue template.
21+
22+
### Questions and Getting Help
23+
24+
You can ask questions in the Discussions page of the GitHub repository. If you're encountering
25+
problems or just have questions related to `pin-init` in the Linux kernel, you can also ask your
26+
questions in the [Rust-for-Linux Zulip](https://rust-for-linux.zulipchat.com/) or see
27+
<https://rust-for-linux.com/contact>.
28+
29+
## Contributing Code
30+
31+
### Linux Kernel
32+
33+
`pin-init` is used by the Linux kernel and all commits are synchronized to it. For this reason, the
34+
same requirements for commits apply to `pin-init`. See [the kernel's documentation] for details. The
35+
rest of this document will also cover some of the rules listed there and additional ones.
36+
37+
[the kernel's documentation]: https://docs.kernel.org/process/submitting-patches.html
38+
39+
Contributions to `pin-init` ideally go through the [GitHub repository], because that repository runs
40+
a CI with lots of tests not present in the kernel. However, patches are also accepted (though not
41+
preferred). Do note that there are some files that are only present in the GitHub repository such as
42+
tests, licenses and cargo related files. Making changes to them can only happen via GitHub.
43+
44+
[GitHub repository]: https://github.com/Rust-for-Linux/pin-init
45+
46+
### Commit Style
47+
48+
Everything must compile without errors or warnings and all tests must pass after **every commit**.
49+
This is important for bisection and also required by the kernel.
50+
51+
Each commit should be a single, logically cohesive change. Of course it's best to keep the changes
52+
small and digestible, but logically linked changes should be made in the same commit. For example,
53+
when fixing typos, create a single commit that fixes all of them instead of one commit per typo.
54+
55+
Commits must have a meaningful commit title. Commits with changes to files in the `internal`
56+
directory should have a title prefixed with `internal:`. The commit message should explain the
57+
change and its rationale. You also have to add your `Signed-off-by` tag, see [Developer's
58+
Certificate of Origin]. This has to be done for both mailing list submissions as well as GitHub
59+
submissions.
60+
61+
[Developer's Certificate of Origin]: https://docs.kernel.org/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin
62+
63+
Any changes made to public APIs must be documented not only in the commit message, but also in the
64+
`CHANGELOG.md` file. This is especially important for breaking changes, as those warrant a major
65+
version bump.
66+
67+
If you make changes to the top-level crate documentation, you also need to update the `README.md`
68+
via `cargo rdme`.
69+
70+
Some of these rules can be ignored if the change is done solely to files that are not present in the
71+
kernel version of this library. Those files are documented in the `sync-kernel.sh` script at the
72+
very bottom in the `--exclude` flag given to the `git am` command.

rust/pin-init/README.md

+228
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
[![Crates.io](https://img.shields.io/crates/v/pin-init.svg)](https://crates.io/crates/pin-init)
2+
[![Documentation](https://docs.rs/pin-init/badge.svg)](https://docs.rs/pin-init/)
3+
[![Dependency status](https://deps.rs/repo/github/Rust-for-Linux/pin-init/status.svg)](https://deps.rs/repo/github/Rust-for-Linux/pin-init)
4+
![License](https://img.shields.io/crates/l/pin-init)
5+
[![Toolchain](https://img.shields.io/badge/toolchain-nightly-red)](#nightly-only)
6+
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/Rust-for-Linux/pin-init/test.yml)
7+
# `pin-init`
8+
9+
<!-- cargo-rdme start -->
10+
11+
Library to safely and fallibly initialize pinned `struct`s using in-place constructors.
12+
13+
[Pinning][pinning] is Rust's way of ensuring data does not move.
14+
15+
It also allows in-place initialization of big `struct`s that would otherwise produce a stack
16+
overflow.
17+
18+
This library's main use-case is in [Rust-for-Linux]. Although this version can be used
19+
standalone.
20+
21+
There are cases when you want to in-place initialize a struct. For example when it is very big
22+
and moving it from the stack is not an option, because it is bigger than the stack itself.
23+
Another reason would be that you need the address of the object to initialize it. This stands
24+
in direct conflict with Rust's normal process of first initializing an object and then moving
25+
it into it's final memory location. For more information, see
26+
<https://rust-for-linux.com/the-safe-pinned-initialization-problem>.
27+
28+
This library allows you to do in-place initialization safely.
29+
30+
### Nightly Needed for `alloc` feature
31+
32+
This library requires the [`allocator_api` unstable feature] when the `alloc` feature is
33+
enabled and thus this feature can only be used with a nightly compiler. When enabling the
34+
`alloc` feature, the user will be required to activate `allocator_api` as well.
35+
36+
[`allocator_api` unstable feature]: https://doc.rust-lang.org/nightly/unstable-book/library-features/allocator-api.html
37+
38+
The feature is enabled by default, thus by default `pin-init` will require a nightly compiler.
39+
However, using the crate on stable compilers is possible by disabling `alloc`. In practice this
40+
will require the `std` feature, because stable compilers have neither `Box` nor `Arc` in no-std
41+
mode.
42+
43+
## Overview
44+
45+
To initialize a `struct` with an in-place constructor you will need two things:
46+
- an in-place constructor,
47+
- a memory location that can hold your `struct` (this can be the [stack], an [`Arc<T>`],
48+
[`Box<T>`] or any other smart pointer that supports this library).
49+
50+
To get an in-place constructor there are generally three options:
51+
- directly creating an in-place constructor using the [`pin_init!`] macro,
52+
- a custom function/macro returning an in-place constructor provided by someone else,
53+
- using the unsafe function [`pin_init_from_closure()`] to manually create an initializer.
54+
55+
Aside from pinned initialization, this library also supports in-place construction without
56+
pinning, the macros/types/functions are generally named like the pinned variants without the
57+
`pin_` prefix.
58+
59+
## Examples
60+
61+
Throughout the examples we will often make use of the `CMutex` type which can be found in
62+
`../examples/mutex.rs`. It is essentially a userland rebuild of the `struct mutex` type from
63+
the Linux kernel. It also uses a wait list and a basic spinlock. Importantly the wait list
64+
requires it to be pinned to be locked and thus is a prime candidate for using this library.
65+
66+
### Using the [`pin_init!`] macro
67+
68+
If you want to use [`PinInit`], then you will have to annotate your `struct` with
69+
`#[`[`pin_data`]`]`. It is a macro that uses `#[pin]` as a marker for
70+
[structurally pinned fields]. After doing this, you can then create an in-place constructor via
71+
[`pin_init!`]. The syntax is almost the same as normal `struct` initializers. The difference is
72+
that you need to write `<-` instead of `:` for fields that you want to initialize in-place.
73+
74+
```rust
75+
use pin_init::{pin_data, pin_init, InPlaceInit};
76+
77+
#[pin_data]
78+
struct Foo {
79+
#[pin]
80+
a: CMutex<usize>,
81+
b: u32,
82+
}
83+
84+
let foo = pin_init!(Foo {
85+
a <- CMutex::new(42),
86+
b: 24,
87+
});
88+
```
89+
90+
`foo` now is of the type [`impl PinInit<Foo>`]. We can now use any smart pointer that we like
91+
(or just the stack) to actually initialize a `Foo`:
92+
93+
```rust
94+
let foo: Result<Pin<Box<Foo>>, AllocError> = Box::pin_init(foo);
95+
```
96+
97+
For more information see the [`pin_init!`] macro.
98+
99+
### Using a custom function/macro that returns an initializer
100+
101+
Many types that use this library supply a function/macro that returns an initializer, because
102+
the above method only works for types where you can access the fields.
103+
104+
```rust
105+
let mtx: Result<Pin<Arc<CMutex<usize>>>, _> = Arc::pin_init(CMutex::new(42));
106+
```
107+
108+
To declare an init macro/function you just return an [`impl PinInit<T, E>`]:
109+
110+
```rust
111+
#[pin_data]
112+
struct DriverData {
113+
#[pin]
114+
status: CMutex<i32>,
115+
buffer: Box<[u8; 1_000_000]>,
116+
}
117+
118+
impl DriverData {
119+
fn new() -> impl PinInit<Self, Error> {
120+
try_pin_init!(Self {
121+
status <- CMutex::new(0),
122+
buffer: Box::init(pin_init::zeroed())?,
123+
}? Error)
124+
}
125+
}
126+
```
127+
128+
### Manual creation of an initializer
129+
130+
Often when working with primitives the previous approaches are not sufficient. That is where
131+
[`pin_init_from_closure()`] comes in. This `unsafe` function allows you to create a
132+
[`impl PinInit<T, E>`] directly from a closure. Of course you have to ensure that the closure
133+
actually does the initialization in the correct way. Here are the things to look out for
134+
(we are calling the parameter to the closure `slot`):
135+
- when the closure returns `Ok(())`, then it has completed the initialization successfully, so
136+
`slot` now contains a valid bit pattern for the type `T`,
137+
- when the closure returns `Err(e)`, then the caller may deallocate the memory at `slot`, so
138+
you need to take care to clean up anything if your initialization fails mid-way,
139+
- you may assume that `slot` will stay pinned even after the closure returns until `drop` of
140+
`slot` gets called.
141+
142+
```rust
143+
use pin_init::{pin_data, pinned_drop, PinInit, PinnedDrop, pin_init_from_closure};
144+
use core::{
145+
ptr::addr_of_mut,
146+
marker::PhantomPinned,
147+
cell::UnsafeCell,
148+
pin::Pin,
149+
mem::MaybeUninit,
150+
};
151+
mod bindings {
152+
#[repr(C)]
153+
pub struct foo {
154+
/* fields from C ... */
155+
}
156+
extern "C" {
157+
pub fn init_foo(ptr: *mut foo);
158+
pub fn destroy_foo(ptr: *mut foo);
159+
#[must_use = "you must check the error return code"]
160+
pub fn enable_foo(ptr: *mut foo, flags: u32) -> i32;
161+
}
162+
}
163+
164+
/// # Invariants
165+
///
166+
/// `foo` is always initialized
167+
#[pin_data(PinnedDrop)]
168+
pub struct RawFoo {
169+
#[pin]
170+
_p: PhantomPinned,
171+
#[pin]
172+
foo: UnsafeCell<MaybeUninit<bindings::foo>>,
173+
}
174+
175+
impl RawFoo {
176+
pub fn new(flags: u32) -> impl PinInit<Self, i32> {
177+
// SAFETY:
178+
// - when the closure returns `Ok(())`, then it has successfully initialized and
179+
// enabled `foo`,
180+
// - when it returns `Err(e)`, then it has cleaned up before
181+
unsafe {
182+
pin_init_from_closure(move |slot: *mut Self| {
183+
// `slot` contains uninit memory, avoid creating a reference.
184+
let foo = addr_of_mut!((*slot).foo);
185+
let foo = UnsafeCell::raw_get(foo).cast::<bindings::foo>();
186+
187+
// Initialize the `foo`
188+
bindings::init_foo(foo);
189+
190+
// Try to enable it.
191+
let err = bindings::enable_foo(foo, flags);
192+
if err != 0 {
193+
// Enabling has failed, first clean up the foo and then return the error.
194+
bindings::destroy_foo(foo);
195+
Err(err)
196+
} else {
197+
// All fields of `RawFoo` have been initialized, since `_p` is a ZST.
198+
Ok(())
199+
}
200+
})
201+
}
202+
}
203+
}
204+
205+
#[pinned_drop]
206+
impl PinnedDrop for RawFoo {
207+
fn drop(self: Pin<&mut Self>) {
208+
// SAFETY: Since `foo` is initialized, destroying is safe.
209+
unsafe { bindings::destroy_foo(self.foo.get().cast::<bindings::foo>()) };
210+
}
211+
}
212+
```
213+
214+
For more information on how to use [`pin_init_from_closure()`], take a look at the uses inside
215+
the `kernel` crate. The [`sync`] module is a good starting point.
216+
217+
[`sync`]: https://rust.docs.kernel.org/kernel/sync/index.html
218+
[pinning]: https://doc.rust-lang.org/std/pin/index.html
219+
[structurally pinned fields]: https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field
220+
[stack]: https://docs.rs/pin-init/latest/pin_init/macro.stack_pin_init.html
221+
[`Arc<T>`]: https://doc.rust-lang.org/stable/alloc/sync/struct.Arc.html
222+
[`Box<T>`]: https://doc.rust-lang.org/stable/alloc/boxed/struct.Box.html
223+
[`impl PinInit<Foo>`]: https://docs.rs/pin-init/latest/pin_init/trait.PinInit.html
224+
[`impl PinInit<T, E>`]: https://docs.rs/pin-init/latest/pin_init/trait.PinInit.html
225+
[`impl Init<T, E>`]: https://docs.rs/pin-init/latest/pin_init/trait.Init.html
226+
[Rust-for-Linux]: https://rust-for-linux.com/
227+
228+
<!-- cargo-rdme end -->

0 commit comments

Comments
 (0)