Skip to content

Commit

Permalink
Merge tag 'wq-for-6.7-rust-bindings' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…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}`
  • Loading branch information
torvalds committed Oct 31, 2023
2 parents 455cdcb + 15b286d commit 639409a
Show file tree
Hide file tree
Showing 6 changed files with 741 additions and 3 deletions.
1 change: 1 addition & 0 deletions rust/bindings/bindings_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <linux/refcount.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/workqueue.h>

/* `bindgen` gets confused at certain things. */
const size_t BINDINGS_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN;
Expand Down
13 changes: 13 additions & 0 deletions rust/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <linux/sched/signal.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/workqueue.h>

__noreturn void rust_helper_BUG(void)
{
Expand Down Expand Up @@ -144,6 +145,18 @@ struct kunit *rust_helper_kunit_get_current_test(void)
}
EXPORT_SYMBOL_GPL(rust_helper_kunit_get_current_test);

void rust_helper_init_work_with_key(struct work_struct *work, work_func_t func,
bool onstack, const char *name,
struct lock_class_key *key)
{
__init_work(work, onstack);
work->data = (atomic_long_t)WORK_DATA_INIT();
lockdep_init_map(&work->lockdep_map, name, key, 0);
INIT_LIST_HEAD(&work->entry);
work->func = func;
}
EXPORT_SYMBOL_GPL(rust_helper_init_work_with_key);

/*
* `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can
* use it in contexts where Rust expects a `usize` like slice (array) indices.
Expand Down
3 changes: 3 additions & 0 deletions rust/kernel/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#![feature(coerce_unsized)]
#![feature(dispatch_from_dyn)]
#![feature(new_uninit)]
#![feature(offset_of)]
#![feature(ptr_metadata)]
#![feature(receiver_trait)]
#![feature(unsize)]

Expand Down Expand Up @@ -45,6 +47,7 @@ pub mod str;
pub mod sync;
pub mod task;
pub mod types;
pub mod workqueue;

#[doc(hidden)]
pub use bindings;
Expand Down
46 changes: 44 additions & 2 deletions rust/kernel/sync/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ use crate::{
};
use alloc::boxed::Box;
use core::{
alloc::AllocError,
alloc::{AllocError, Layout},
fmt,
marker::{PhantomData, Unsize},
mem::{ManuallyDrop, MaybeUninit},
ops::{Deref, DerefMut},
pin::Pin,
ptr::NonNull,
ptr::{NonNull, Pointee},
};
use macros::pin_data;

Expand Down Expand Up @@ -215,6 +215,48 @@ impl<T: ?Sized> Arc<T> {
}
}

/// Convert the [`Arc`] into a raw pointer.
///
/// The raw pointer has ownership of the refcount that this Arc object owned.
pub fn into_raw(self) -> *const T {
let ptr = self.ptr.as_ptr();
core::mem::forget(self);
// SAFETY: The pointer is valid.
unsafe { core::ptr::addr_of!((*ptr).data) }
}

/// Recreates an [`Arc`] instance previously deconstructed via [`Arc::into_raw`].
///
/// # Safety
///
/// `ptr` must have been returned by a previous call to [`Arc::into_raw`]. Additionally, it
/// must not be called more than once for each previous call to [`Arc::into_raw`].
pub unsafe fn from_raw(ptr: *const T) -> Self {
let refcount_layout = Layout::new::<bindings::refcount_t>();
// SAFETY: The caller guarantees that the pointer is valid.
let val_layout = Layout::for_value(unsafe { &*ptr });
// SAFETY: We're computing the layout of a real struct that existed when compiling this
// binary, so its layout is not so large that it can trigger arithmetic overflow.
let val_offset = unsafe { refcount_layout.extend(val_layout).unwrap_unchecked().1 };

let metadata: <T as Pointee>::Metadata = core::ptr::metadata(ptr);
// SAFETY: The metadata of `T` and `ArcInner<T>` is the same because `ArcInner` is a struct
// with `T` as its last field.
//
// This is documented at:
// <https://doc.rust-lang.org/std/ptr/trait.Pointee.html>.
let metadata: <ArcInner<T> as Pointee>::Metadata =
unsafe { core::mem::transmute_copy(&metadata) };
// SAFETY: The pointer is in-bounds of an allocation both before and after offsetting the
// pointer, since it originates from a previous call to `Arc::into_raw` and is still valid.
let ptr = unsafe { (ptr as *mut u8).sub(val_offset) as *mut () };
let ptr = core::ptr::from_raw_parts_mut(ptr, metadata);

// SAFETY: By the safety requirements we know that `ptr` came from `Arc::into_raw`, so the
// reference count held then will be owned by the new `Arc` object.
unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) }
}

/// Returns an [`ArcBorrow`] from the given [`Arc`].
///
/// This is useful when the argument of a function call is an [`ArcBorrow`] (e.g., in a method
Expand Down
Loading

0 comments on commit 639409a

Please sign in to comment.