Skip to content

Commit 639409a

Browse files
committed
Merge tag 'wq-for-6.7-rust-bindings' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
Pull workqueue rust bindings from Tejun Heo: "Add rust bindings to allow rust code to schedule work items on workqueues. While the current bindings don't cover all of the workqueue API, it provides enough for basic usage and can be expanded as needed" * tag 'wq-for-6.7-rust-bindings' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq: rust: workqueue: add examples rust: workqueue: add `try_spawn` helper method rust: workqueue: implement `WorkItemPointer` for pointer types rust: workqueue: add helper for defining work_struct fields rust: workqueue: define built-in queues rust: workqueue: add low-level workqueue bindings rust: sync: add `Arc::{from_raw, into_raw}`
2 parents 455cdcb + 15b286d commit 639409a

File tree

6 files changed

+741
-3
lines changed

6 files changed

+741
-3
lines changed

rust/bindings/bindings_helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/refcount.h>
1313
#include <linux/wait.h>
1414
#include <linux/sched.h>
15+
#include <linux/workqueue.h>
1516

1617
/* `bindgen` gets confused at certain things. */
1718
const size_t BINDINGS_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN;

rust/helpers.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/sched/signal.h>
3131
#include <linux/spinlock.h>
3232
#include <linux/wait.h>
33+
#include <linux/workqueue.h>
3334

3435
__noreturn void rust_helper_BUG(void)
3536
{
@@ -144,6 +145,18 @@ struct kunit *rust_helper_kunit_get_current_test(void)
144145
}
145146
EXPORT_SYMBOL_GPL(rust_helper_kunit_get_current_test);
146147

148+
void rust_helper_init_work_with_key(struct work_struct *work, work_func_t func,
149+
bool onstack, const char *name,
150+
struct lock_class_key *key)
151+
{
152+
__init_work(work, onstack);
153+
work->data = (atomic_long_t)WORK_DATA_INIT();
154+
lockdep_init_map(&work->lockdep_map, name, key, 0);
155+
INIT_LIST_HEAD(&work->entry);
156+
work->func = func;
157+
}
158+
EXPORT_SYMBOL_GPL(rust_helper_init_work_with_key);
159+
147160
/*
148161
* `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can
149162
* use it in contexts where Rust expects a `usize` like slice (array) indices.

rust/kernel/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#![feature(coerce_unsized)]
1717
#![feature(dispatch_from_dyn)]
1818
#![feature(new_uninit)]
19+
#![feature(offset_of)]
20+
#![feature(ptr_metadata)]
1921
#![feature(receiver_trait)]
2022
#![feature(unsize)]
2123

@@ -45,6 +47,7 @@ pub mod str;
4547
pub mod sync;
4648
pub mod task;
4749
pub mod types;
50+
pub mod workqueue;
4851

4952
#[doc(hidden)]
5053
pub use bindings;

rust/kernel/sync/arc.rs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ use crate::{
2424
};
2525
use alloc::boxed::Box;
2626
use core::{
27-
alloc::AllocError,
27+
alloc::{AllocError, Layout},
2828
fmt,
2929
marker::{PhantomData, Unsize},
3030
mem::{ManuallyDrop, MaybeUninit},
3131
ops::{Deref, DerefMut},
3232
pin::Pin,
33-
ptr::NonNull,
33+
ptr::{NonNull, Pointee},
3434
};
3535
use macros::pin_data;
3636

@@ -215,6 +215,48 @@ impl<T: ?Sized> Arc<T> {
215215
}
216216
}
217217

218+
/// Convert the [`Arc`] into a raw pointer.
219+
///
220+
/// The raw pointer has ownership of the refcount that this Arc object owned.
221+
pub fn into_raw(self) -> *const T {
222+
let ptr = self.ptr.as_ptr();
223+
core::mem::forget(self);
224+
// SAFETY: The pointer is valid.
225+
unsafe { core::ptr::addr_of!((*ptr).data) }
226+
}
227+
228+
/// Recreates an [`Arc`] instance previously deconstructed via [`Arc::into_raw`].
229+
///
230+
/// # Safety
231+
///
232+
/// `ptr` must have been returned by a previous call to [`Arc::into_raw`]. Additionally, it
233+
/// must not be called more than once for each previous call to [`Arc::into_raw`].
234+
pub unsafe fn from_raw(ptr: *const T) -> Self {
235+
let refcount_layout = Layout::new::<bindings::refcount_t>();
236+
// SAFETY: The caller guarantees that the pointer is valid.
237+
let val_layout = Layout::for_value(unsafe { &*ptr });
238+
// SAFETY: We're computing the layout of a real struct that existed when compiling this
239+
// binary, so its layout is not so large that it can trigger arithmetic overflow.
240+
let val_offset = unsafe { refcount_layout.extend(val_layout).unwrap_unchecked().1 };
241+
242+
let metadata: <T as Pointee>::Metadata = core::ptr::metadata(ptr);
243+
// SAFETY: The metadata of `T` and `ArcInner<T>` is the same because `ArcInner` is a struct
244+
// with `T` as its last field.
245+
//
246+
// This is documented at:
247+
// <https://doc.rust-lang.org/std/ptr/trait.Pointee.html>.
248+
let metadata: <ArcInner<T> as Pointee>::Metadata =
249+
unsafe { core::mem::transmute_copy(&metadata) };
250+
// SAFETY: The pointer is in-bounds of an allocation both before and after offsetting the
251+
// pointer, since it originates from a previous call to `Arc::into_raw` and is still valid.
252+
let ptr = unsafe { (ptr as *mut u8).sub(val_offset) as *mut () };
253+
let ptr = core::ptr::from_raw_parts_mut(ptr, metadata);
254+
255+
// SAFETY: By the safety requirements we know that `ptr` came from `Arc::into_raw`, so the
256+
// reference count held then will be owned by the new `Arc` object.
257+
unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) }
258+
}
259+
218260
/// Returns an [`ArcBorrow`] from the given [`Arc`].
219261
///
220262
/// This is useful when the argument of a function call is an [`ArcBorrow`] (e.g., in a method

0 commit comments

Comments
 (0)