From nobody Sun Feb 8 07:08:33 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A072AC77B7E for ; Thu, 1 Jun 2023 13:50:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232935AbjFANu5 (ORCPT ); Thu, 1 Jun 2023 09:50:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48850 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230222AbjFANux (ORCPT ); Thu, 1 Jun 2023 09:50:53 -0400 Received: from mail-ej1-x649.google.com (mail-ej1-x649.google.com [IPv6:2a00:1450:4864:20::649]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EE884129 for ; Thu, 1 Jun 2023 06:50:51 -0700 (PDT) Received: by mail-ej1-x649.google.com with SMTP id a640c23a62f3a-94a348facbbso65753966b.1 for ; Thu, 01 Jun 2023 06:50:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1685627450; x=1688219450; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=FuSvyE3H/lsB/N9LBubh06h32izpsOqcuowYerHxhqc=; b=FyvVJlD2CGIUJvNbQZbNEYbMCpjM2wfkXCGCXQdGdxbllqs61y+dOimrUiXITslDnr L0xzV3vfgwdACLzxRZt2w/DUr0I0hVp38FptQFQB6p9HI8WTeYEqxuLkrzz5udg311TU P31I2p4lYUs39xALew33gD26gaTMk5tNQ6oSCPSJoYX0pP5ep3b5P0RNsM1r1kT4n/fe iI4kk5O3HoJfozo7oHD16yShr/tg4SPDVzuEmF1fYUSe19h8vKIorMgbuPFZHd/uKeEN 9035Iz0htSCg+0b9FgqdQzj12QUgODRxB+tsT3VI3//m07btmf13UfCNEU/ZNeURTvpq Knhw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685627450; x=1688219450; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=FuSvyE3H/lsB/N9LBubh06h32izpsOqcuowYerHxhqc=; b=PphalykoE+g5objEglB5to6coQbd1WH/nF5j+JplrZ6IjNDtF30j2nNV7VPcODTt9t IOzLIFhyspTCpHaSrJXW9yM3ZZTyWXCR/IvmzmAibI1TMCWm90VsXsUNWCJrqCS3IGU2 98gQnd16N6hJ/DmoAivcf6eFnu4D7uo5VUt5OyDIZ7J3smAvIfmrWjlhXLCMGhT89FMn LetAArXQyRA6nHpsk9bCSnW9lh1+yaAncXlp+fci8MNbhM++fBxVv2xaMtXPe8TNK5JX vhsWKFqgz1snlCVQStlJLd4jPd80VcG8DIpnpj7fW/H6yvQwhZjuumZbOgIrCGM+IInc EcXA== X-Gm-Message-State: AC+VfDyEmreYFa+HYOnjp/C8Jvwv98XVNhEqnYAhXUcgeEQn6Hud6O4d KFBgLPhs+oxB3AnX8M5KezCAwPxCbav98aY= X-Google-Smtp-Source: ACHHUZ6TR3gcEhy6cUHWUaknBY4LOpR/0VQfiptgYOtwdk6sQS7UXBw3mwnxPT2zlqGTkevpuGugbzKDFTYvcnc= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a17:907:270c:b0:96f:ddeb:9e8c with SMTP id w12-20020a170907270c00b0096fddeb9e8cmr3366915ejk.6.1685627450568; Thu, 01 Jun 2023 06:50:50 -0700 (PDT) Date: Thu, 1 Jun 2023 13:49:39 +0000 In-Reply-To: <20230601134946.3887870-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230601134946.3887870-1-aliceryhl@google.com> X-Mailer: git-send-email 2.41.0.rc0.172.g3f132b7071-goog Message-ID: <20230601134946.3887870-2-aliceryhl@google.com> Subject: [PATCH v2 1/8] rust: workqueue: add low-level workqueue bindings From: Alice Ryhl To: rust-for-linux@vger.kernel.org Cc: Miguel Ojeda , Wedson Almeida Filho , Tejun Heo , Lai Jiangshan , Alex Gaynor , Boqun Feng , Gary Guo , "=?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?=" , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Define basic low-level bindings to a kernel workqueue. The API defined here can only be used unsafely. Later commits will provide safe wrappers. Co-developed-by: Gary Guo Signed-off-by: Gary Guo Signed-off-by: Alice Ryhl Reviewed-by: Andreas Hindborg (Samsung) Reviewed-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo --- rust/bindings/bindings_helper.h | 1 + rust/kernel/lib.rs | 1 + rust/kernel/workqueue.rs | 107 ++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 rust/kernel/workqueue.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 50e7a76d5455..ae2e8f018268 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -10,6 +10,7 @@ #include #include #include +#include =20 /* `bindgen` gets confused at certain things. */ const gfp_t BINDINGS_GFP_KERNEL =3D GFP_KERNEL; diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 85b261209977..eaded02ffb01 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -43,6 +43,7 @@ pub mod sync; pub mod task; pub mod types; +pub mod workqueue; =20 #[doc(hidden)] pub use bindings; diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs new file mode 100644 index 000000000000..9c630840039b --- /dev/null +++ b/rust/kernel/workqueue.rs @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Work queues. +//! +//! C header: [`include/linux/workqueue.h`](../../../../include/linux/work= queue.h) + +use crate::{bindings, types::Opaque}; + +/// A kernel work queue. +/// +/// Wraps the kernel's C `struct workqueue_struct`. +/// +/// It allows work items to be queued to run on thread pools managed by th= e kernel. Several are +/// always available, for example, `system`, `system_highpri`, `system_lon= g`, etc. +#[repr(transparent)] +pub struct Queue(Opaque); + +// SAFETY: Kernel workqueues are usable from any thread. +unsafe impl Send for Queue {} +unsafe impl Sync for Queue {} + +impl Queue { + /// Use the provided `struct workqueue_struct` with Rust. + /// + /// # Safety + /// + /// The caller must ensure that the provided raw pointer is not dangli= ng, that it points at a + /// valid workqueue, and that it remains valid until the end of 'a. + pub unsafe fn from_raw<'a>(ptr: *const bindings::workqueue_struct) -> = &'a Queue { + // SAFETY: The `Queue` type is `#[repr(transparent)]`, so the poin= ter cast is valid. The + // caller promises that the pointer is not dangling. + unsafe { &*(ptr as *const Queue) } + } + + /// Enqueues a work item. + /// + /// This may fail if the work item is already enqueued in a workqueue. + /// + /// The work item will be submitted using `WORK_CPU_UNBOUND`. + pub fn enqueue(&self, w: W) -> W::EnqueueOutput + where + W: RawWorkItem + Send + 'static, + { + let queue_ptr =3D self.0.get(); + + // SAFETY: We only return `false` if the `work_struct` is already = in a workqueue. The other + // `__enqueue` requirements are not relevant since `W` is `Send` a= nd static. + // + // The call to `bindings::queue_work_on` will dereference the prov= ided raw pointer, which + // is ok because `__enqueue` guarantees that the pointer is valid = for the duration of this + // closure. + // + // Furthermore, if the C workqueue code accesses the pointer after= this call to + // `__enqueue`, then the work item was successfully enqueued, and = `bindings::queue_work_on` + // will have returned true. In this case, `__enqueue` promises tha= t the raw pointer will + // stay valid until we call the function pointer in the `work_stru= ct`, so the access is ok. + unsafe { + w.__enqueue(move |work_ptr| { + bindings::queue_work_on(bindings::WORK_CPU_UNBOUND as _, q= ueue_ptr, work_ptr) + }) + } + } +} + +/// A raw work item. +/// +/// This is the low-level trait that is designed for being as general as p= ossible. +/// +/// The `ID` parameter to this trait exists so that a single type can prov= ide multiple +/// implementations of this trait. For example, if a struct has multiple `= work_struct` fields, then +/// you will implement this trait once for each field, using a different i= d for each field. The +/// actual value of the id is not important as long as you use different i= ds for different fields +/// of the same struct. (Fields of different structs need not use differen= t ids.) +/// +/// Note that the id is used only to select the right method to call durin= g compilation. It wont be +/// part of the final executable. +/// +/// # Safety +/// +/// Implementers must ensure that any pointers passed to a `queue_work_on`= closure by `__enqueue` +/// remain valid for the duration specified in the documentation for `__en= queue`. +pub unsafe trait RawWorkItem { + /// The return type of [`Queue::enqueue`]. + type EnqueueOutput; + + /// Enqueues this work item on a queue using the provided `queue_work_= on` method. + /// + /// # Guarantees + /// + /// If this method calls the provided closure, then the raw pointer is= guaranteed to point at a + /// valid `work_struct` for the duration of the call to the closure. I= f the closure returns + /// true, then it is further guaranteed that the pointer remains valid= until someone calls the + /// function pointer stored in the `work_struct`. + /// + /// # Safety + /// + /// The provided closure may only return `false` if the `work_struct` = is already in a workqueue. + /// + /// If the work item type is annotated with any lifetimes, then you mu= st not call the function + /// pointer after any such lifetime expires. (Never calling the functi= on pointer is okay.) + /// + /// If the work item type is not [`Send`], then the function pointer m= ust be called on the same + /// thread as the call to `__enqueue`. + unsafe fn __enqueue(self, queue_work_on: F) -> Self::EnqueueOutput + where + F: FnOnce(*mut bindings::work_struct) -> bool; +} --=20 2.41.0.rc0.172.g3f132b7071-goog From nobody Sun Feb 8 07:08:33 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 98BBFC77B7E for ; Thu, 1 Jun 2023 13:51:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233287AbjFANvU (ORCPT ); Thu, 1 Jun 2023 09:51:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49162 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233267AbjFANvR (ORCPT ); Thu, 1 Jun 2023 09:51:17 -0400 Received: from mail-ed1-x549.google.com (mail-ed1-x549.google.com [IPv6:2a00:1450:4864:20::549]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4F7D21AD for ; Thu, 1 Jun 2023 06:51:11 -0700 (PDT) Received: by mail-ed1-x549.google.com with SMTP id 4fb4d7f45d1cf-514b05895f7so783241a12.0 for ; Thu, 01 Jun 2023 06:51:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1685627470; x=1688219470; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=CFWZiTMzRcsx84Z5SYXbngPTfzR7GjN80EhCOaRTPas=; b=6U1LmEILAkXt1ykhx/Ehu4FX/iB1ojm/m3YZhZZkMXOJ1AUeWEH2jlJbqb665k/3Zl UyRA+zunWEjQTWb6+7BglNY3ssL/IdWy8mC00gdGNfPYWvpX92UeVIpgmBeIVWJ7dWlg zA9q4amy/WFWI5coaOYgwbUHvE17fLTDf3pxodr/okPUFMqLBlKBIn36kKRjcDOmY/tm mTIKZ8119pOSw08AkUN26fS9yvv4y6RVrmd22szoQMDHDN5qguhwAG5ZeSbKzcNoZ8tk +dVRxL08TvQCZ+aWANc8BUah0e4E0MRnbTZid/0ie+ioPBhISLnEadvuBGWRLZhe/nWc CmDw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685627470; x=1688219470; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=CFWZiTMzRcsx84Z5SYXbngPTfzR7GjN80EhCOaRTPas=; b=gdPdXHwz+76fK41CG0nVn3AchzuExG28B0YhjqZoOOI65m7/sYd/V+CHbuE/FaHfmv vVhhnNdTq1qzU5PNoFkcMYUQ2ewwOx5xkKHcDyUMg2/NPFXw3c1pTBwMz18fMkLOnL7y weehT+k0LBvYb8UaG88nUpqqzg227fi3ikT8P3agpSyLL6BQ6dbRu3/uW3iwSGbtwOsZ CbkOe3WibQk2vuyh3Q82x6yIKnHdNoif+wIHAhuimk9WhbcHJ7e7YR/wJKRhVo/C5pYG 8PxQnv1eANA/7DOi+z+5JLdvA3GDy/v2LI6TYeFP2c0e/rvVxqZVZuG23IQ23H3hJ/DB LruA== X-Gm-Message-State: AC+VfDyfCrX4MpK0CZNSwNC4L0SMhktyjY0XkHWpEdC70rBFIdbBAXBq OTVSFjXXGYkcileIEtzMwbzjsoA/UqfaHqs= X-Google-Smtp-Source: ACHHUZ7ST9mZi4kYui3d3gUljsAefg4w47aEs4JF/TBbtRVokn5rwijE56vtX4t1Q6J90rRBY+JFA2F75r1jcsw= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a17:906:9bc3:b0:947:f975:cc09 with SMTP id de3-20020a1709069bc300b00947f975cc09mr2209092ejc.1.1685627469897; Thu, 01 Jun 2023 06:51:09 -0700 (PDT) Date: Thu, 1 Jun 2023 13:49:40 +0000 In-Reply-To: <20230601134946.3887870-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230601134946.3887870-1-aliceryhl@google.com> X-Mailer: git-send-email 2.41.0.rc0.172.g3f132b7071-goog Message-ID: <20230601134946.3887870-3-aliceryhl@google.com> Subject: [PATCH v2 2/8] rust: add offset_of! macro From: Alice Ryhl To: rust-for-linux@vger.kernel.org Cc: Miguel Ojeda , Wedson Almeida Filho , Tejun Heo , Lai Jiangshan , Alex Gaynor , Boqun Feng , Gary Guo , "=?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?=" , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev, Wedson Almeida Filho , Martin Rodriguez Reboredo Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Wedson Almeida Filho This macro is used to compute the offset of a field in a struct. This commit enables an unstable feature that is necessary for using the macro in a constant. However, this is not a problem as the macro will become available from the Rust standard library soon [1]. The unstable feature can be disabled again once that happens. The macro in this patch does not support sub-fields. That is, you cannot write `offset_of!(MyStruct, field.sub_field)` to get the offset of `sub_field` with `field`'s type being a struct with a field called `sub_field`. This is because `field` might be a `Box`, which means that you would be trying to compute the offset to something in an entirely different allocation. There's no easy way to fix the current macro to support subfields, but the version being added to the standard library should support it, so the limitation is temporary and not a big deal. Link: https://github.com/rust-lang/rust/issues/106655 [1] Signed-off-by: Wedson Almeida Filho Co-developed-by: Alice Ryhl Signed-off-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Benno Lossin Reviewed-by: Gary Guo --- rust/kernel/lib.rs | 35 +++++++++++++++++++++++++++++++++++ scripts/Makefile.build | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index eaded02ffb01..7ea777b731e6 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -14,6 +14,7 @@ #![no_std] #![feature(allocator_api)] #![feature(coerce_unsized)] +#![feature(const_refs_to_cell)] #![feature(dispatch_from_dyn)] #![feature(new_uninit)] #![feature(receiver_trait)] @@ -98,3 +99,37 @@ fn panic(info: &core::panic::PanicInfo<'_>) -> ! { // instead of `!`. See . loop {} } + +/// Calculates the offset of a field from the beginning of the struct it b= elongs to. +/// +/// # Examples +/// +/// ``` +/// #[repr(C)] +/// struct Test { +/// a: u64, +/// b: u32, +/// } +/// +/// assert_eq!(kernel::offset_of!(Test, b), 8); +/// ``` +#[macro_export] +macro_rules! offset_of { + ($type:path, $field:ident) =3D> {{ + let $type { $field: _, .. }; + let tmp =3D ::core::mem::MaybeUninit::<$type>::uninit(); + let outer =3D tmp.as_ptr(); + // To avoid warnings when nesting `unsafe` blocks. + #[allow(unused_unsafe)] + // SAFETY: The pointer is valid and aligned, just not initialised;= `addr_of` ensures that + // we don't actually read from `outer` (which would be UB) nor cre= ate an intermediate + // reference. + let inner =3D unsafe { ::core::ptr::addr_of!((*outer).$field) } as= *const u8; + // To avoid warnings when nesting `unsafe` blocks. + #[allow(unused_unsafe)] + // SAFETY: The two pointers are within the same allocation block. + unsafe { + inner.offset_from(outer as *const u8) as usize + } + }}; +} diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 78175231c969..819510694769 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -277,7 +277,7 @@ $(obj)/%.lst: $(src)/%.c FORCE # Compile Rust sources (.rs) # ------------------------------------------------------------------------= --- =20 -rust_allowed_features :=3D new_uninit +rust_allowed_features :=3D const_refs_to_cell,new_uninit =20 rust_common_cmd =3D \ RUST_MODFILE=3D$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \ --=20 2.41.0.rc0.172.g3f132b7071-goog From nobody Sun Feb 8 07:08:33 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DC062C77B7E for ; Thu, 1 Jun 2023 13:53:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233397AbjFANxV (ORCPT ); Thu, 1 Jun 2023 09:53:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50594 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229866AbjFANxT (ORCPT ); Thu, 1 Jun 2023 09:53:19 -0400 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 00E97119 for ; Thu, 1 Jun 2023 06:53:17 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id 3f1490d57ef6-bacd408046cso1313040276.3 for ; Thu, 01 Jun 2023 06:53:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1685627597; x=1688219597; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=emM0vnYZP8ovSB9/0L28X7xu1W1tC2o+UTrpcckUn6I=; b=xiQpeTApD8EOPRLGvqOEbGnwk5VdgbS481DnQDIEFxEdsz/On6iBdKRYTdwC4GSgKB ph6LBgaidNw+WGSeSHFktPPsUZz32+fyRaDVJAIFfZN/e98wVfiftPu+6Uks3ZrG/Wbm qYQSoWdlUuUSFuYtP5XYH42+XrgljkWS1ibSt+8a48D1yXNfxUsbCgVXQcRA1QlmnIjo DJdJK+53Kf/Rf7wXCzRaWFXdwIBLvTbOxI3Iofy7tLQ5FmIGaCokuy9i65leoDsK3Jb1 vHup+pJUEoS+DZOCrHTg5fJDr1NpU8/R+Ig1RUYXj7GDgRTXdO1bvBdOXfCNqJXcUIMb lzXA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685627597; x=1688219597; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=emM0vnYZP8ovSB9/0L28X7xu1W1tC2o+UTrpcckUn6I=; b=CY31pES92B2l8WBq3ocb1nVUa7yUGARnUfJg0s4f8jZDj3miMboTQQe/rA7znpdVfN m+OK7qHuq7oSuH+nnlN4VOyWa51ML+u689lxiPzBoqdQ+KAQyY5S97unJBRPoV8YEo6b GJ9ABsOG4e/0A6EeICY07XQNCH/tWrkGaGoV7fL2YhXEIJIe2f/9RqmNVgGmpzP4mSAg J6CbQW5u4Duc34RCnqiAPlUDjGRmE3eSa/wgZ1HpM6IVwY1l5zpSayy4Xtb994BAZbHj HIMynEXA9k8iInj6XzURw5iNjQSc0bcmlg510PzkzmDzUlcHlsY7lKEpPj3O+ERh7TwD JdbA== X-Gm-Message-State: AC+VfDxDEPKWVHQXyZoO0Nfj/DkVWBzbI3DPDrkNw0NTMmoVc7bmqE30 MvIIwd2raHcFdKqO2lagw/GjrTQtb0x+EYc= X-Google-Smtp-Source: ACHHUZ6D9pKmfatjre8+3n+W1GuZF8ZhsQLF+BiTz9FLkUqyRuqeWMNbDcq1x6MUBFd9q5UdZjwDyQhhHBy0eaU= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a05:6902:a8e:b0:b1d:5061:98e3 with SMTP id cd14-20020a0569020a8e00b00b1d506198e3mr5275183ybb.6.1685627597196; Thu, 01 Jun 2023 06:53:17 -0700 (PDT) Date: Thu, 1 Jun 2023 13:49:41 +0000 In-Reply-To: <20230601134946.3887870-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230601134946.3887870-1-aliceryhl@google.com> X-Mailer: git-send-email 2.41.0.rc0.172.g3f132b7071-goog Message-ID: <20230601134946.3887870-4-aliceryhl@google.com> Subject: [PATCH v2 3/8] rust: sync: add `Arc::{from_raw, into_raw}` From: Alice Ryhl To: rust-for-linux@vger.kernel.org Cc: Miguel Ojeda , Wedson Almeida Filho , Tejun Heo , Lai Jiangshan , Alex Gaynor , Boqun Feng , Gary Guo , "=?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?=" , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev, Wedson Almeida Filho , Martin Rodriguez Reboredo Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Wedson Almeida Filho These methods can be used to turn an `Arc` into a raw pointer and back, in a way that preserves the metadata for fat pointers. This is done using the unstable ptr_metadata feature [1]. However, it could also be done using the unstable pointer_byte_offsets feature [2], which is likely to have a shorter path to stabilization than ptr_metadata. Link: https://github.com/rust-lang/rust/issues/81513 [1] Link: https://github.com/rust-lang/rust/issues/96283 [2] Signed-off-by: Wedson Almeida Filho Co-developed-by: Alice Ryhl Signed-off-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Benno Lossin Reviewed-by: Gary Guo --- rust/kernel/lib.rs | 1 + rust/kernel/sync/arc.rs | 42 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 7ea777b731e6..ad9142928fb1 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -17,6 +17,7 @@ #![feature(const_refs_to_cell)] #![feature(dispatch_from_dyn)] #![feature(new_uninit)] +#![feature(ptr_metadata)] #![feature(receiver_trait)] #![feature(unsize)] =20 diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index a89843cacaad..684be9f73aca 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -24,7 +24,7 @@ }; use alloc::boxed::Box; use core::{ - alloc::AllocError, + alloc::{AllocError, Layout}, fmt, marker::{PhantomData, Unsize}, mem::{ManuallyDrop, MaybeUninit}, @@ -212,6 +212,46 @@ unsafe fn from_inner(inner: NonNull>) -> S= elf { } } =20 + /// 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 =3D 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`]. + /// + /// This code relies on the `repr(C)` layout of structs as described in + /// . + /// + /// # Safety + /// + /// `ptr` must have been returned by a previous call to [`Arc::into_ra= w`]. Additionally, it + /// can only be called once for each previous call to [`Arc::into_raw`= ]. + pub unsafe fn from_raw(ptr: *const T) -> Self { + let refcount_layout =3D Layout::new::(); + // SAFETY: The caller guarantees that the pointer is valid. + let val_layout =3D unsafe { Layout::for_value(&*ptr) }; + // SAFETY: We're computing the layout of a real struct that existe= d when compiling this + // binary, so its layout is not so large that it can trigger arith= metic overflow. + let val_offset =3D unsafe { refcount_layout.extend(val_layout).unw= rap_unchecked().1 }; + + // This preserves the metadata in the pointer, if any. + // + // Note that `*const T` and `*const ArcInner` have the same met= adata as documented at + // . + let metadata =3D core::ptr::metadata(ptr as *const ArcInner); + let ptr =3D (ptr as *mut u8).wrapping_sub(val_offset) as *mut (); + let ptr =3D 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 [`ArcBor= row`] (e.g., in a method --=20 2.41.0.rc0.172.g3f132b7071-goog From nobody Sun Feb 8 07:08:33 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 911C5C7EE23 for ; Thu, 1 Jun 2023 13:54:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233483AbjFANyE (ORCPT ); Thu, 1 Jun 2023 09:54:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50916 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233016AbjFANyB (ORCPT ); Thu, 1 Jun 2023 09:54:01 -0400 Received: from mail-ed1-x54a.google.com (mail-ed1-x54a.google.com [IPv6:2a00:1450:4864:20::54a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6778B13D for ; Thu, 1 Jun 2023 06:53:59 -0700 (PDT) Received: by mail-ed1-x54a.google.com with SMTP id 4fb4d7f45d1cf-514b3b99882so706683a12.2 for ; Thu, 01 Jun 2023 06:53:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1685627638; x=1688219638; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=kFZgiOUIu+kFD/tH5EFpQqSQN/mWPzP02CS5RCs3B9M=; b=MkzWTGF98V5rWGyl2PEut0MvVD60T25TsJG+nP3EJ0G5Xj9HN/47MO2rJK4nSC8lAD TJvZCwvsHZnHGDFiPXqerEKpexrbHyZ5jkHFur0RTDUcpye/mtH04woakV0u/oTzddFi ErxxJN1cTn+2gjmPjvFwUQd+aIbjKx6adZhQgUS1rFmnHk5ewCWxnCRVk26Do8jsKsXm kwmrZ5wO4mULuKacNSxdAF+hTBRIKHsiOx0dgijn4mDotI5LaPFPj1fzFl3IlRL5TpXy 0qtu9up5ITib15C7+Z77VR0cIS8sBssQbXFZkrc6NmoyqwmKOmd2IQqBo5uEGjolxxCB Nc2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685627638; x=1688219638; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=kFZgiOUIu+kFD/tH5EFpQqSQN/mWPzP02CS5RCs3B9M=; b=gZh0+JwUIU1KaUqHYgSw6AFokJMqdfcKHBuhpP2FAX9ps1/u5PUOvyc8CdA0zTQEL8 iM/WV+XNDEdL+jCA9MCfA+K7MrxNdSAR1GgdW47kvo9+6VV5OjqcYsSv15pbUC8dP+OK 5iT3R4uY9v+44u9KYzYQTDe/W2StoA1mRm3JSZVXthJVvpS1TrLOWQQF9DpufEOwYwyL 2govK78S5HoAXvJSxmt7ISPpHvSRo0qB/J6sjigBLc24CGJK+VCUxvuJb7GxMK+1Lt7J IYDlR0jixU8PFk72E/gyiJGMlubDwlaZGWToupKtj7uvBwDyy61TmFCsKWqitZUe+Cu2 TujA== X-Gm-Message-State: AC+VfDwof9xGA7G3SV5BN80v5+7Dy0KjQgnsw2k6ej5sOttHGtVxWJis CPFZ6bN2J4ozxBEk1GXjZxilNNwg1/C4ulQ= X-Google-Smtp-Source: ACHHUZ5xOb/B9cybQJo26BFDnCaofuwbd/HT1NJPNXV66I9mRscvFL3xGEVBJJEYGaMR9X34vY8CcFElhSj10Ww= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a50:f692:0:b0:510:b4dc:165a with SMTP id d18-20020a50f692000000b00510b4dc165amr3036075edn.5.1685627637870; Thu, 01 Jun 2023 06:53:57 -0700 (PDT) Date: Thu, 1 Jun 2023 13:49:42 +0000 In-Reply-To: <20230601134946.3887870-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230601134946.3887870-1-aliceryhl@google.com> X-Mailer: git-send-email 2.41.0.rc0.172.g3f132b7071-goog Message-ID: <20230601134946.3887870-5-aliceryhl@google.com> Subject: [PATCH v2 4/8] rust: workqueue: define built-in queues From: Alice Ryhl To: rust-for-linux@vger.kernel.org Cc: Miguel Ojeda , Wedson Almeida Filho , Tejun Heo , Lai Jiangshan , Alex Gaynor , Boqun Feng , Gary Guo , "=?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?=" , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev, Wedson Almeida Filho , Martin Rodriguez Reboredo Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Wedson Almeida Filho We provide these methods because it lets us access these queues from Rust without using unsafe code. These methods return `&'static Queue`. References annotated with the 'static lifetime are used when the referent will stay alive forever. That is ok for these queues because they are global variables and cannot be destroyed. Signed-off-by: Wedson Almeida Filho Co-developed-by: Alice Ryhl Signed-off-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Andreas Hindborg (Samsung) Reviewed-by: Benno Lossin Reviewed-by: Gary Guo --- rust/kernel/workqueue.rs | 65 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index 9c630840039b..e37820f253f6 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -105,3 +105,68 @@ unsafe fn __enqueue(self, queue_work_on: F) -> Self= ::EnqueueOutput where F: FnOnce(*mut bindings::work_struct) -> bool; } + +/// Returns the system work queue (`system_wq`). +/// +/// It is the one used by `schedule[_delayed]_work[_on]()`. Multi-CPU mult= i-threaded. There are +/// users which expect relatively short queue flush time. +/// +/// Callers shouldn't queue work items which can run for too long. +pub fn system() -> &'static Queue { + // SAFETY: `system_wq` is a C global, always available. + unsafe { Queue::from_raw(bindings::system_wq) } +} + +/// Returns the system high-priority work queue (`system_highpri_wq`). +/// +/// It is similar to the one returned by [`system`] but for work items whi= ch require higher +/// scheduling priority. +pub fn system_highpri() -> &'static Queue { + // SAFETY: `system_highpri_wq` is a C global, always available. + unsafe { Queue::from_raw(bindings::system_highpri_wq) } +} + +/// Returns the system work queue for potentially long-running work items = (`system_long_wq`). +/// +/// It is similar to the one returned by [`system`] but may host long runn= ing work items. Queue +/// flushing might take relatively long. +pub fn system_long() -> &'static Queue { + // SAFETY: `system_long_wq` is a C global, always available. + unsafe { Queue::from_raw(bindings::system_long_wq) } +} + +/// Returns the system unbound work queue (`system_unbound_wq`). +/// +/// Workers are not bound to any specific CPU, not concurrency managed, an= d all queued work items +/// are executed immediately as long as `max_active` limit is not reached = and resources are +/// available. +pub fn system_unbound() -> &'static Queue { + // SAFETY: `system_unbound_wq` is a C global, always available. + unsafe { Queue::from_raw(bindings::system_unbound_wq) } +} + +/// Returns the system freezable work queue (`system_freezable_wq`). +/// +/// It is equivalent to the one returned by [`system`] except that it's fr= eezable. +pub fn system_freezable() -> &'static Queue { + // SAFETY: `system_freezable_wq` is a C global, always available. + unsafe { Queue::from_raw(bindings::system_freezable_wq) } +} + +/// Returns the system power-efficient work queue (`system_power_efficient= _wq`). +/// +/// It is inclined towards saving power and is converted to "unbound" vari= ants if the +/// `workqueue.power_efficient` kernel parameter is specified; otherwise, = it is similar to the one +/// returned by [`system`]. +pub fn system_power_efficient() -> &'static Queue { + // SAFETY: `system_power_efficient_wq` is a C global, always available. + unsafe { Queue::from_raw(bindings::system_power_efficient_wq) } +} + +/// Returns the system freezable power-efficient work queue (`system_freez= able_power_efficient_wq`). +/// +/// It is similar to the one returned by [`system_power_efficient`] except= that is freezable. +pub fn system_freezable_power_efficient() -> &'static Queue { + // SAFETY: `system_freezable_power_efficient_wq` is a C global, always= available. + unsafe { Queue::from_raw(bindings::system_freezable_power_efficient_wq= ) } +} --=20 2.41.0.rc0.172.g3f132b7071-goog From nobody Sun Feb 8 07:08:33 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6AA09C7EE2A for ; Thu, 1 Jun 2023 13:55:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233530AbjFANzj (ORCPT ); Thu, 1 Jun 2023 09:55:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51432 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233252AbjFANzg (ORCPT ); Thu, 1 Jun 2023 09:55:36 -0400 Received: from mail-ed1-x549.google.com (mail-ed1-x549.google.com [IPv6:2a00:1450:4864:20::549]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C933513D for ; Thu, 1 Jun 2023 06:55:33 -0700 (PDT) Received: by mail-ed1-x549.google.com with SMTP id 4fb4d7f45d1cf-50a16ab50e6so705843a12.0 for ; Thu, 01 Jun 2023 06:55:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1685627732; x=1688219732; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=8uFcGXdbIjrtd3/5CVHZnSQ6TrHuzg4doZPL2ZtyWy4=; b=dxNWQhZAZ2nOkQBAkfySPOKTnAbreN9qU4AiDWVlxtii/UbqsQM/aUA9jDhRqp6JLo FwTHDqhxLsi73PzsHdmIpABgy8T/gAIsqlq530RntQCv4iiVdya5DxEVlexC+Hfaep4M OtFi+J48gNosyuyjFZYtuHgIbaFsvQZ/fuSzCR2yhPws0kdDLPyklwVfI66rVeMgLRxx kkDcX+A27gb4h+0ZLfBpAQU/wZZ4aBwNEwM175nY/aopxaAvlN3gzYRAvCUR5LE8NHYw 7FKLNgEHM2SpjGR0GqsZYve7A36AhAZsE/nWkeoTkl0TyA+pdisntr2zEZST19fayOBU 0Nxw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685627732; x=1688219732; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=8uFcGXdbIjrtd3/5CVHZnSQ6TrHuzg4doZPL2ZtyWy4=; b=E4p7vh+ysDjrd1/x9xygLudb5qHYyol8oB/9hKLay4/Xnf2F2CGde+OpKbvsa+WUXk oblusRopzXAUoL1Rnq/4xWp9L8N2yWWwHEMalRBGVWzruaREAu5EfP4G6uNRaNwmRq0i 3QDL4t+glyJ1x3SiLytnSGlKUkwkUGYAtDI/AVrNbmCA5Gebd5ZwHcFAWMpkE3j4rKN9 HQsVFMTcWZ53Kgq+BpULiL3cqbDi2ljooNdWSAXoR0ivf3xB26eLFeewUP89Mk3P2Ixb Zwy0BIDLzX9d8w+GPtiQ+XXF74BpmovoVJXYaP+BloqXWg6GKTpvDkn3SSMfIL1bX3CH 8Jzw== X-Gm-Message-State: AC+VfDxuMGqiaYsItQu+1eAmwNS2OIzZv8M7CbY6m7ItuU85/FeA7BiV oevr6KDlv+PtfMnbmvqUeLU6+3CXkjcqd4Y= X-Google-Smtp-Source: ACHHUZ78kRIRP501R7FwyLfuyrbMTGlPycodfRCVeinxekvAWOgPTPSMBeXmMszRDpOaabOf3e+/LrMzDNw9rN8= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a50:bace:0:b0:514:8f21:5a0f with SMTP id x72-20020a50bace000000b005148f215a0fmr2787107ede.6.1685627732265; Thu, 01 Jun 2023 06:55:32 -0700 (PDT) Date: Thu, 1 Jun 2023 13:49:43 +0000 In-Reply-To: <20230601134946.3887870-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230601134946.3887870-1-aliceryhl@google.com> X-Mailer: git-send-email 2.41.0.rc0.172.g3f132b7071-goog Message-ID: <20230601134946.3887870-6-aliceryhl@google.com> Subject: [PATCH v2 5/8] rust: workqueue: add helper for defining work_struct fields From: Alice Ryhl To: rust-for-linux@vger.kernel.org Cc: Miguel Ojeda , Wedson Almeida Filho , Tejun Heo , Lai Jiangshan , Alex Gaynor , Boqun Feng , Gary Guo , "=?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?=" , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The main challenge with defining `work_struct` fields is making sure that the function pointer stored in the `work_struct` is appropriate for the work item type it is embedded in. It needs to know the offset of the `work_struct` field being used (even if there are several!) so that it can do a `container_of`, and it needs to know the type of the work item so that it can call into the right user-provided code. All of this needs to happen in a way that provides a safe API to the user, so that users of the workqueue cannot mix up the function pointers. There are three important pieces that are relevant when doing this: * The pointer type. * The work item struct. This is what the pointer points at. * The `work_struct` field. This is a field of the work item struct. This patch introduces a separate trait for each piece. The pointer type is given a `WorkItemPointer` trait, which pointer types need to implement to be usable with the workqueue. This trait will be implemented for `Arc` and `Box` in a later patch in this patchset. Implementing this trait is unsafe because this is where the `container_of` operation happens, but user-code will not need to implement it themselves. The work item struct should then implement the `WorkItem` trait. This trait is where user-code specifies what they want to happen when a work item is executed. It also specifies what the correct pointer type is. Finally, to make the work item struct know the offset of its `work_struct` field, we use a trait called `HasWork`. If a type implements this trait, then the type declares that, at the given offset, there is a field of type `Work`. The trait is marked unsafe because the OFFSET constant must be correct, but we provide an `impl_has_work!` macro that can safely implement `HasWork` on a type. The macro expands to something that only compiles if the specified field really has the type `Work`. It is used like this: ``` struct MyWorkItem { work_field: Work, } impl_has_work! { impl HasWork for MyWorkItem { self.work_field } } ``` Note that since the `Work` type is annotated with an id, you can have several `work_struct` fields by using a different id for each one. Co-developed-by: Gary Guo Signed-off-by: Gary Guo Signed-off-by: Alice Ryhl Reviewed-by: Andreas Hindborg (Samsung) Reviewed-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo --- rust/helpers.c | 8 ++ rust/kernel/workqueue.rs | 219 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 226 insertions(+), 1 deletion(-) diff --git a/rust/helpers.c b/rust/helpers.c index 81e80261d597..7f0c2fe2fbeb 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -26,6 +26,7 @@ #include #include #include +#include =20 __noreturn void rust_helper_BUG(void) { @@ -128,6 +129,13 @@ void rust_helper_put_task_struct(struct task_struct *t) } EXPORT_SYMBOL_GPL(rust_helper_put_task_struct); =20 +void rust_helper___INIT_WORK(struct work_struct *work, work_func_t func, + bool on_stack) +{ + __INIT_WORK(work, func, on_stack); +} +EXPORT_SYMBOL_GPL(rust_helper___INIT_WORK); + /* * We use `bindgen`'s `--size_t-is-usize` option to bind the C `size_t` ty= pe * as the Rust `usize` type, so we can use it in contexts where Rust diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index e37820f253f6..dbf0aab29a85 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -2,9 +2,34 @@ =20 //! Work queues. //! +//! This file has two components: The raw work item API, and the safe work= item API. +//! +//! One pattern that is used in both APIs is the `ID` const generic, which= exists to allow a single +//! type to define multiple `work_struct` fields. This is done by choosing= an id for each field, +//! and using that id to specify which field you wish to use. (The actual = value doesn't matter, as +//! long as you use different values for different fields of the same stru= ct.) Since these IDs are +//! generic, they are used only at compile-time, so they shouldn't exist i= n the final binary. +//! +//! # The raw API +//! +//! The raw API consists of the `RawWorkItem` trait, where the work item n= eeds to provide an +//! arbitrary function that knows how to enqueue the work item. It should = usually not be used +//! directly, but if you want to, you can use it without using the pieces = from the safe API. +//! +//! # The safe API +//! +//! The safe API is used via the `Work` struct and `WorkItem` traits. Furt= hermore, it also includes +//! a trait called `WorkItemPointer`, which is usually not used directly b= y the user. +//! +//! * The `Work` struct is the Rust wrapper for the C `work_struct` type. +//! * The `WorkItem` trait is implemented for structs that can be enqueue= d to a workqueue. +//! * The `WorkItemPointer` trait is implemented for the pointer type tha= t points at a something +//! that implements `WorkItem`. +//! //! C header: [`include/linux/workqueue.h`](../../../../include/linux/work= queue.h) =20 -use crate::{bindings, types::Opaque}; +use crate::{bindings, prelude::*, types::Opaque}; +use core::marker::{PhantomData, PhantomPinned}; =20 /// A kernel work queue. /// @@ -106,6 +131,198 @@ unsafe fn __enqueue(self, queue_work_on: F) -> Sel= f::EnqueueOutput F: FnOnce(*mut bindings::work_struct) -> bool; } =20 +/// Defines the method that should be called directly when a work item is = executed. +/// +/// Typically you would implement [`WorkItem`] instead. The `run` method o= n this trait will +/// usually just perform the appropriate `container_of` translation and th= en call into the `run` +/// method from the [`WorkItem`] trait. +/// +/// This trait is used when the `work_struct` field is defined using the [= `Work`] helper. +/// +/// # Safety +/// +/// Implementers must ensure that [`__enqueue`] uses a `work_struct` initi= alized with the [`run`] +/// method of this trait as the function pointer. +/// +/// [`__enqueue`]: RawWorkItem::__enqueue +/// [`run`]: WorkItemPointer::run +pub unsafe trait WorkItemPointer: RawWorkItem { + /// Run this work item. + /// + /// # Safety + /// + /// The provided `work_struct` pointer must originate from a previous = call to `__enqueue` where + /// the `queue_work_on` closure returned true, and the pointer must st= ill be valid. + unsafe extern "C" fn run(ptr: *mut bindings::work_struct); +} + +/// Defines the method that should be called when this work item is execut= ed. +/// +/// This trait is used when the `work_struct` field is defined using the [= `Work`] helper. +pub trait WorkItem { + /// The pointer type that this struct is wrapped in. This will typical= ly be `Arc` or + /// `Pin>`. + type Pointer: WorkItemPointer; + + /// The method that should be called when this work item is executed. + fn run(this: Self::Pointer); +} + +/// Links for a work item. +/// +/// This struct contains a function pointer to the `run` function from the= [`WorkItemPointer`] +/// trait, and defines the linked list pointers necessary to enqueue a wor= k item in a workqueue. +/// +/// Wraps the kernel's C `struct work_struct`. +/// +/// This is a helper type used to associate a `work_struct` with the [`Wor= kItem`] that uses it. +#[repr(transparent)] +pub struct Work { + work: Opaque, + _pin: PhantomPinned, + _inner: PhantomData, +} + +// SAFETY: Kernel work items are usable from any thread. +// +// We do not need to constrain `T` since the work item does not actually c= ontain a `T`. +unsafe impl Send for Work {} +// SAFETY: Kernel work items are usable from any thread. +// +// We do not need to constrain `T` since the work item does not actually c= ontain a `T`. +unsafe impl Sync for Work {} + +impl Work { + /// Creates a new instance of [`Work`]. + #[inline] + #[allow(clippy::new_ret_no_self)] + pub fn new() -> impl PinInit + where + T: WorkItem, + { + // SAFETY: The `WorkItemPointer` implementation promises that `run= ` can be used as the work + // item function. + unsafe { + kernel::init::pin_init_from_closure(move |slot| { + bindings::__INIT_WORK(Self::raw_get(slot), Some(T::Pointer= ::run), false); + Ok(()) + }) + } + } + + /// Get a pointer to the inner `work_struct`. + /// + /// # Safety + /// + /// The provided pointer must not be dangling and must be properly ali= gned. (But the memory + /// need not be initialized.) + #[inline] + pub unsafe fn raw_get(ptr: *const Self) -> *mut bindings::work_struct { + // SAFETY: The caller promises that the pointer is aligned and not= dangling. + // + // A pointer cast would also be ok due to `#[repr(transparent)]`. = We use `addr_of!` so that + // the compiler does not complain that the `work` field is unused. + unsafe { Opaque::raw_get(core::ptr::addr_of!((*ptr).work)) } + } +} + +/// Declares that a type has a [`Work`] field. +/// +/// # Safety +/// +/// The [`OFFSET`] constant must be the offset of a field in Self of type = [`Work`]. The methods on +/// this trait must have exactly the behavior that the definitions given b= elow have. +/// +/// [`Work`]: Work +/// [`OFFSET`]: HasWork::OFFSET +pub unsafe trait HasWork { + /// The offset of the [`Work`] field. + /// + /// [`Work`]: Work + const OFFSET: usize; + + /// Returns the offset of the [`Work`] field. + /// + /// This method exists because the [`OFFSET`] constant cannot be acces= sed if the type is not Sized. + /// + /// [`Work`]: Work + /// [`OFFSET`]: HasWork::OFFSET + #[inline] + fn get_work_offset(&self) -> usize { + Self::OFFSET + } + + /// Returns a pointer to the [`Work`] field. + /// + /// # Safety + /// + /// The provided pointer must point at a valid struct of type `Self`. + /// + /// [`Work`]: Work + #[inline] + unsafe fn raw_get_work(ptr: *mut Self) -> *mut Work { + // SAFETY: The caller promises that the pointer is valid. + unsafe { (ptr as *mut u8).add(Self::OFFSET) as *mut Work } + } + + /// Returns a pointer to the struct containing the [`Work`] fie= ld. + /// + /// # Safety + /// + /// The pointer must point at a [`Work`] field in a struct of t= ype `Self`. + /// + /// [`Work`]: Work + #[inline] + unsafe fn work_container_of(ptr: *mut Work) -> *mut Self + where + Self: Sized, + { + // SAFETY: The caller promises that the pointer points at a field = of the right type in the + // right kind of struct. + unsafe { (ptr as *mut u8).sub(Self::OFFSET) as *mut Self } + } +} + +/// Used to safely implement the [`HasWork`] trait. +/// +/// # Examples +/// +/// ``` +/// use kernel::sync::Arc; +/// +/// struct MyStruct { +/// work_field: Work, +/// } +/// +/// impl_has_work! { +/// impl HasWork for MyStruct { self.work_field } +/// } +/// ``` +/// +/// [`HasWork`]: HasWork +#[macro_export] +macro_rules! impl_has_work { + ($(impl$(<$($implarg:ident),*>)? + HasWork<$work_type:ty $(, $id:tt)?> + for $self:ident $(<$($selfarg:ident),*>)? + { self.$field:ident } + )*) =3D> {$( + // SAFETY: The implementation of `raw_get_work` only compiles if t= he field has the right + // type. + unsafe impl$(<$($implarg),*>)? $crate::workqueue::HasWork<$work_ty= pe $(, $id)?> for $self $(<$($selfarg),*>)? { + const OFFSET: usize =3D $crate::offset_of!(Self, $field) as us= ize; + + #[inline] + unsafe fn raw_get_work(ptr: *mut Self) -> *mut $crate::workque= ue::Work<$work_type $(, $id)?> { + // SAFETY: The caller promises that the pointer is not dan= gling. + unsafe { + ::core::ptr::addr_of_mut!((*ptr).$field) + } + } + } + )*}; +} + /// Returns the system work queue (`system_wq`). /// /// It is the one used by `schedule[_delayed]_work[_on]()`. Multi-CPU mult= i-threaded. There are --=20 2.41.0.rc0.172.g3f132b7071-goog From nobody Sun Feb 8 07:08:33 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 26D9FC7EE2A for ; Thu, 1 Jun 2023 13:56:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233592AbjFAN4S (ORCPT ); Thu, 1 Jun 2023 09:56:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51950 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232769AbjFAN4P (ORCPT ); Thu, 1 Jun 2023 09:56:15 -0400 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E1E3E129 for ; Thu, 1 Jun 2023 06:56:13 -0700 (PDT) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-565c380565dso22593137b3.1 for ; Thu, 01 Jun 2023 06:56:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1685627773; x=1688219773; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=TyRNG5KT1C+kxxh+8DvNZVfySdIBr+c+luuNQvW24B8=; b=rqoKpkOtbw5E7aZUP5vKjWc3Rud11Cj869FSLBYeNDUpqqAOXnkZIPl7lj5T2v5p7s DmMa94afp5CNZFk1ywR4ew+ffsOd7nOjrFz827+LCZEp8XI49xI9Wdw9RtCEvPkuo8im TbhBhsVdo138vg3Nl4AMaccmsNOCCPZENyu59Kaii+poHD6Mc9UdWgsN3jNMxvyt2W4I y2/H0+6GzKgtGlccHAiV83rBObv6Oqk4nXU9rcSvjnEk0GniwrycnB1qvh3JpmxgcBKs vNmUwJcJLMtZRaxTJ5rpjwixRZNRXubZmOhOpkg300KRq2lF92feTXVc6m+zgHMAsqIc FyaA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685627773; x=1688219773; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=TyRNG5KT1C+kxxh+8DvNZVfySdIBr+c+luuNQvW24B8=; b=Av8fzN6acgq9cqPKg8w5NP7W/jPbdPu86oBTUHO74Vf3sOGtJy7tgkixDikDpMuhNS PltCeeHMTszdkiKw8feSgiPyMqffr4+y1/oVAopS5B0vXs1/OV28kc+cFtPfgUqEbNR2 64pDkwjkE9bfo8pyUeVBKYnqSWINJvzYNQPlqVt8+Cv1P5gWes6e3UAcSC3h5cvX0LIJ cGgV+HHOA3qimD6DdeANSIzV2rvNRZjoYSWA2271Nc40aHtNPEYkygV84Ggc8rPtGzl1 ySNXBMhq00xnWpQRWjAc8NHVZPri2vtNKGbxYvhy/9+01hwfwkCl+Srz94lpj9MWinE5 EYdg== X-Gm-Message-State: AC+VfDyOGNxF2hk76dJER4GeGwKikfpjLujBxaRVSYoz0jGPEv/1OVkL A35TSaYNCGXPJH44Tiv+4JXSz8Vwf49Fgd4= X-Google-Smtp-Source: ACHHUZ5aHph4tvkKB0c6QYrmRqC0Hw9+Se7T+ePGC68o9O2DFJVKozkWFG8onb0G18ETbUursPX9HxukD6gKR/M= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a81:7813:0:b0:561:ec3e:62fd with SMTP id t19-20020a817813000000b00561ec3e62fdmr1402978ywc.5.1685627773081; Thu, 01 Jun 2023 06:56:13 -0700 (PDT) Date: Thu, 1 Jun 2023 13:49:44 +0000 In-Reply-To: <20230601134946.3887870-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230601134946.3887870-1-aliceryhl@google.com> X-Mailer: git-send-email 2.41.0.rc0.172.g3f132b7071-goog Message-ID: <20230601134946.3887870-7-aliceryhl@google.com> Subject: [PATCH v2 6/8] rust: workqueue: implement `WorkItemPointer` for pointer types From: Alice Ryhl To: rust-for-linux@vger.kernel.org Cc: Miguel Ojeda , Wedson Almeida Filho , Tejun Heo , Lai Jiangshan , Alex Gaynor , Boqun Feng , Gary Guo , "=?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?=" , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This implements the `WorkItemPointer` trait for the pointer types that you are likely to use the workqueue with. The `Arc` type is for reference counted objects, and the `Pin>` type is for objects where the caller has exclusive ownership of the object. Co-developed-by: Gary Guo Signed-off-by: Gary Guo Signed-off-by: Alice Ryhl Reviewed-by: Andreas Hindborg (Samsung) Reviewed-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo --- rust/kernel/workqueue.rs | 97 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index dbf0aab29a85..f06a2f036d8b 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -28,8 +28,10 @@ //! //! C header: [`include/linux/workqueue.h`](../../../../include/linux/work= queue.h) =20 -use crate::{bindings, prelude::*, types::Opaque}; +use crate::{bindings, prelude::*, sync::Arc, types::Opaque}; +use alloc::boxed::Box; use core::marker::{PhantomData, PhantomPinned}; +use core::pin::Pin; =20 /// A kernel work queue. /// @@ -323,6 +325,99 @@ unsafe fn raw_get_work(ptr: *mut Self) -> *mut $crate:= :workqueue::Work<$work_typ )*}; } =20 +unsafe impl WorkItemPointer for Arc +where + T: WorkItem, + T: HasWork, +{ + unsafe extern "C" fn run(ptr: *mut bindings::work_struct) { + // SAFETY: The `__enqueue` method always uses a `work_struct` stor= ed in a `Work`. + let ptr =3D ptr as *mut Work; + // SAFETY: This computes the pointer that `__enqueue` got from `Ar= c::into_raw`. + let ptr =3D unsafe { T::work_container_of(ptr) }; + // SAFETY: This pointer comes from `Arc::into_raw` and we've been = given back ownership. + let arc =3D unsafe { Arc::from_raw(ptr) }; + + T::run(arc) + } +} + +unsafe impl RawWorkItem for Arc +where + T: WorkItem, + T: HasWork, +{ + type EnqueueOutput =3D Result<(), Self>; + + unsafe fn __enqueue(self, queue_work_on: F) -> Self::EnqueueOutput + where + F: FnOnce(*mut bindings::work_struct) -> bool, + { + // Casting between const and mut is not a problem as long as the p= ointer is a raw pointer. + let ptr =3D Arc::into_raw(self) as *mut T; + + // SAFETY: Pointers into an `Arc` point at a valid value. + let work_ptr =3D unsafe { T::raw_get_work(ptr) }; + // SAFETY: `raw_get_work` returns a pointer to a valid value. + let work_ptr =3D unsafe { Work::raw_get(work_ptr) }; + + if queue_work_on(work_ptr) { + Ok(()) + } else { + // SAFETY: The work queue has not taken ownership of the point= er. + Err(unsafe { Arc::from_raw(ptr) }) + } + } +} + +unsafe impl WorkItemPointer for Pin> +where + T: WorkItem, + T: HasWork, +{ + unsafe extern "C" fn run(ptr: *mut bindings::work_struct) { + // SAFETY: The `__enqueue` method always uses a `work_struct` stor= ed in a `Work`. + let ptr =3D ptr as *mut Work; + // SAFETY: This computes the pointer that `__enqueue` got from `Ar= c::into_raw`. + let ptr =3D unsafe { T::work_container_of(ptr) }; + // SAFETY: This pointer comes from `Arc::into_raw` and we've been = given back ownership. + let boxed =3D unsafe { Box::from_raw(ptr) }; + // SAFETY: The box was already pinned when it was enqueued. + let pinned =3D unsafe { Pin::new_unchecked(boxed) }; + + T::run(pinned) + } +} + +unsafe impl RawWorkItem for Pin> +where + T: WorkItem, + T: HasWork, +{ + type EnqueueOutput =3D (); + + unsafe fn __enqueue(self, queue_work_on: F) -> Self::EnqueueOutput + where + F: FnOnce(*mut bindings::work_struct) -> bool, + { + // SAFETY: We're not going to move `self` or any of its fields, so= its okay to temporarily + // remove the `Pin` wrapper. + let boxed =3D unsafe { Pin::into_inner_unchecked(self) }; + let ptr =3D Box::into_raw(boxed); + + // SAFETY: Pointers into a `Box` point at a valid value. + let work_ptr =3D unsafe { T::raw_get_work(ptr) }; + // SAFETY: `raw_get_work` returns a pointer to a valid value. + let work_ptr =3D unsafe { Work::raw_get(work_ptr) }; + + if !queue_work_on(work_ptr) { + // SAFETY: This method requires exclusive ownership of the box= , so it cannot be in a + // workqueue. + unsafe { ::core::hint::unreachable_unchecked() } + } + } +} + /// Returns the system work queue (`system_wq`). /// /// It is the one used by `schedule[_delayed]_work[_on]()`. Multi-CPU mult= i-threaded. There are --=20 2.41.0.rc0.172.g3f132b7071-goog From nobody Sun Feb 8 07:08:33 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0DBABC77B7E for ; Thu, 1 Jun 2023 13:56:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233572AbjFAN4y (ORCPT ); Thu, 1 Jun 2023 09:56:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52354 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232769AbjFAN4u (ORCPT ); Thu, 1 Jun 2023 09:56:50 -0400 Received: from mail-ej1-x649.google.com (mail-ej1-x649.google.com [IPv6:2a00:1450:4864:20::649]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5DBAEFC for ; Thu, 1 Jun 2023 06:56:49 -0700 (PDT) Received: by mail-ej1-x649.google.com with SMTP id a640c23a62f3a-96faa650a3fso64714866b.0 for ; Thu, 01 Jun 2023 06:56:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1685627808; x=1688219808; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=vB1KTXT+BDPTSPss1nKfZFCllt9cnJRUrJkIndsk9bQ=; b=ONUw1Bi/LF6RsZlr45Sb+TKYR/o9wrpaSOn2lrXAM6QYiczLPUguB/OtTWl2nFQb/z QHCJFovGIHfcYE7ZKxME4rHu0QrQ4t0lkAsZaKzOuoP35MgMHVzXbqZ9Js6mYq3jSxzW iQhJQID+sbpuY6rX1Kr1tInXmFVQ8bpfhl7KPdzG/3nj30erauVwt9zGGqKaupzxvtkk zJUHWqC/9bRRmif13gTcB23wiU9s0WW2SS+C2rW0b1KB96pBbzxeXvLAmsDK+Q6B9hpm WC4RIxiwCa89hBCrOaMs11hNEoZ8Mf+uzlLbeKiVPw4rmcJHNzBDHeol1J09Swzd8q5c 6l1Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685627808; x=1688219808; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=vB1KTXT+BDPTSPss1nKfZFCllt9cnJRUrJkIndsk9bQ=; b=lo9haCHBe4Rv6oEM9rz/yWuRkLtX4NNucTR/AFkW/YrQljmNPcWujJNGDCKyMJ7x3N 8FyRvbZxSVD/PHo4QmwX8wKZ6abWlrVSwbsnGjaxidjb+QG1L0z5dj7NQ4GuMqh+SSZ5 pRUbgrr+K9Zkdmvy9vkUDoo3G7J14MN7afJSzgpeJhLZ+s2px0nP2NcxLwL/mosJV9rC UwnFBS6yZEusClaDftEJk6DMMwBD5m6CMB50QR7BQJ79IrZzJa2RcD07Wh1aB5Qw1bdm PefQhqNDuCVNzas1OcfoITXD8aT6yH1JRh2Rw5tQ1NtOF/H75muZhYu4oXQ0HGW7a1Ei OVaw== X-Gm-Message-State: AC+VfDyj08R6iOJjfqrMALln2hzWZ8npmxFn2eReu7GES+Kok4krqcWk VeqNKjRBSe8NxmfKsLY9YmroykodpqnVnlI= X-Google-Smtp-Source: ACHHUZ6wvWf7QDEiZpOYRmHr1ZokpvS+ySsWXbKzAtbGtHwYA1ojE0HCynF9ToBu5yxSIkNVCdyZ/ezhgmRDm2s= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a17:907:2cd9:b0:973:867b:399e with SMTP id hg25-20020a1709072cd900b00973867b399emr2256552ejc.4.1685627807883; Thu, 01 Jun 2023 06:56:47 -0700 (PDT) Date: Thu, 1 Jun 2023 13:49:45 +0000 In-Reply-To: <20230601134946.3887870-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230601134946.3887870-1-aliceryhl@google.com> X-Mailer: git-send-email 2.41.0.rc0.172.g3f132b7071-goog Message-ID: <20230601134946.3887870-8-aliceryhl@google.com> Subject: [PATCH v2 7/8] rust: workqueue: add `try_spawn` helper method From: Alice Ryhl To: rust-for-linux@vger.kernel.org Cc: Miguel Ojeda , Wedson Almeida Filho , Tejun Heo , Lai Jiangshan , Alex Gaynor , Boqun Feng , Gary Guo , "=?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?=" , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This adds a convenience method that lets you spawn a closure for execution on a workqueue. This will be the most convenient way to use workqueues, but it is fallible because it needs to allocate memory. Co-developed-by: Gary Guo Signed-off-by: Gary Guo Signed-off-by: Alice Ryhl Reviewed-by: Andreas Hindborg (Samsung) Reviewed-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo --- rust/kernel/workqueue.rs | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index f06a2f036d8b..c302e8b8624b 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -29,6 +29,7 @@ //! C header: [`include/linux/workqueue.h`](../../../../include/linux/work= queue.h) =20 use crate::{bindings, prelude::*, sync::Arc, types::Opaque}; +use alloc::alloc::AllocError; use alloc::boxed::Box; use core::marker::{PhantomData, PhantomPinned}; use core::pin::Pin; @@ -87,6 +88,44 @@ pub fn enqueue(&self, w: W) -> W::Enqu= eueOutput }) } } + + /// Tries to spawn the given function or closure as a work item. + /// + /// This method can fail because it allocates memory to store the work= item. + pub fn try_spawn(&self, func: T) -> Resu= lt<(), AllocError> { + let init =3D pin_init!(ClosureWork { + work <- Work::new(), + func: Some(func), + }); + + self.enqueue(Box::pin_init(init).map_err(|_| AllocError)?); + Ok(()) + } +} + +/// A helper type used in `try_spawn`. +#[pin_data] +struct ClosureWork { + #[pin] + work: Work>, + func: Option, +} + +impl ClosureWork { + fn project(self: Pin<&mut Self>) -> &mut Option { + // SAFETY: The `func` field is not structurally pinned. + unsafe { &mut self.get_unchecked_mut().func } + } +} + +impl WorkItem for ClosureWork { + type Pointer =3D Pin>; + + fn run(mut this: Pin>) { + if let Some(func) =3D this.as_mut().project().take() { + (func)() + } + } } =20 /// A raw work item. @@ -325,6 +364,10 @@ unsafe fn raw_get_work(ptr: *mut Self) -> *mut $crate:= :workqueue::Work<$work_typ )*}; } =20 +impl_has_work! { + impl HasWork for ClosureWork { self.work } +} + unsafe impl WorkItemPointer for Arc where T: WorkItem, --=20 2.41.0.rc0.172.g3f132b7071-goog From nobody Sun Feb 8 07:08:33 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8CDC9C7EE23 for ; Thu, 1 Jun 2023 13:57:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232935AbjFAN5w (ORCPT ); Thu, 1 Jun 2023 09:57:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52738 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232769AbjFAN5t (ORCPT ); Thu, 1 Jun 2023 09:57:49 -0400 Received: from mail-ed1-x54a.google.com (mail-ed1-x54a.google.com [IPv6:2a00:1450:4864:20::54a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C7D66FC for ; Thu, 1 Jun 2023 06:57:48 -0700 (PDT) Received: by mail-ed1-x54a.google.com with SMTP id 4fb4d7f45d1cf-506b21104faso684004a12.1 for ; Thu, 01 Jun 2023 06:57:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1685627867; x=1688219867; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Il50p8nZECxcQJDqUwkg/ZOtCLHgjGH7eHBvIr+OJqA=; b=woEEVeXRdIaNOBTuxaLQGdFXHzH0XEF+niu0dsO9UeJfo1436BCJtmE9PIaMuBm1Gw 2TlWaCgo7du6wZP7cPNRfr2NARZW9QeUN+Kyf/Oo6lnJMqGqm6GXcV5SZ+/8/PFjwFym 1TX75spnYLhrC7D6K6gHyZYI+3ApgUJsV3Gz/G1Oux0qwDrekdin+1Hf2uXbma6agOuy xQdsi5wTSib1B2vfRftoFo/X8JejRIQDj5V8tDbJ6tSX2QeWnIVyIZzqyr9/i/ur/5G1 aC7RuAJ9WiyhVR+6T1jXJDvmY7YeW0blKboqYpu4UoLPr3c77ZS/i6p5z0Yei5sMJm8a WcRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685627867; x=1688219867; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Il50p8nZECxcQJDqUwkg/ZOtCLHgjGH7eHBvIr+OJqA=; b=fN0qtUcnsRGtDD0TCKCaSC2M5fK6yDKvsGpDr4WUZnIeUPj3iVfXjOohoxEuJVqxcd aRiGsqy8lu4DnPqeqOXs28Z0jmtSJkuIi7NRtODjyqf+R3P4B/e2P0RIfYSUjuEFxe8M gpYvK2fPL7g2c8Ymd11JlLu/YwplOr5gDckdz2Ty4B+vvtUptnYdc81zTDVsOoY1YFTu ZfmC0VCtEWgExtnXv4ipBDemIB9He6t/t5EsnLpSNnQMI+w6BiE9l1tERHaIjZX9l4Dr yMfxEX6qSOaj4znHmIoL6Y+hTuuK4gCQdCHTZfZNDBdipwPRg/1Nc+Y+PhoCCMTp7Bqh 4juA== X-Gm-Message-State: AC+VfDzfXQgTS34JsArPPOTA0rXDU/xa6p8zxXlqaa5IibMf2xF+oDhu 1xYxocv+aOuDqDelaC8b7LcMf1R3Ax5Aduk= X-Google-Smtp-Source: ACHHUZ7WvE4QJSoGfg6HWhpos46egMoDrUulcJUiBKGiTAvmV94C08JCqmzQITaMZhMI/RA5MuReTCwzHFong84= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a50:ab09:0:b0:50b:c88a:f7cd with SMTP id s9-20020a50ab09000000b0050bc88af7cdmr2009edc.4.1685627867420; Thu, 01 Jun 2023 06:57:47 -0700 (PDT) Date: Thu, 1 Jun 2023 13:49:46 +0000 In-Reply-To: <20230601134946.3887870-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230601134946.3887870-1-aliceryhl@google.com> X-Mailer: git-send-email 2.41.0.rc0.172.g3f132b7071-goog Message-ID: <20230601134946.3887870-9-aliceryhl@google.com> Subject: [PATCH v2 8/8] rust: workqueue: add examples From: Alice Ryhl To: rust-for-linux@vger.kernel.org Cc: Miguel Ojeda , Wedson Almeida Filho , Tejun Heo , Lai Jiangshan , Alex Gaynor , Boqun Feng , Gary Guo , "=?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?=" , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This adds two examples of how to use the workqueue. The first example shows how to use it when you only have one `work_struct` field, and the second example shows how to use it when you have multiple `work_struct` fields. Signed-off-by: Alice Ryhl Reviewed-by: Andreas Hindborg (Samsung) Reviewed-by: Benno Lossin Reviewed-by: Gary Guo Reviewed-by: Martin Rodriguez Reboredo --- rust/kernel/workqueue.rs | 104 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index c302e8b8624b..cefcf43ff40e 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -26,6 +26,110 @@ //! * The `WorkItemPointer` trait is implemented for the pointer type tha= t points at a something //! that implements `WorkItem`. //! +//! ## Example +//! +//! This example defines a struct that holds an integer and can be schedul= ed on the workqueue. When +//! the struct is executed, it will print the integer. Since there is only= one `work_struct` field, +//! we do not need to specify ids for the fields. +//! +//! ``` +//! use kernel::prelude::*; +//! use kernel::sync::Arc; +//! use kernel::workqueue::{self, Work, WorkItem}; +//! +//! #[pin_data] +//! struct MyStruct { +//! value: i32, +//! #[pin] +//! work: Work, +//! } +//! +//! impl_has_work! { +//! impl HasWork for MyStruct { self.work } +//! } +//! +//! impl MyStruct { +//! fn new(value: i32) -> Result> { +//! Arc::pin_init(pin_init!(MyStruct { +//! value, +//! work <- Work::new(), +//! })) +//! } +//! } +//! +//! impl WorkItem for MyStruct { +//! type Pointer =3D Arc; +//! +//! fn run(this: Arc) { +//! pr_info!("The value is: {}", this.value); +//! } +//! } +//! +//! /// This method will enqueue the struct for execution on the system wo= rkqueue, where its value +//! /// will be printed. +//! fn print_later(val: Arc) { +//! let _ =3D workqueue::system().enqueue(val); +//! } +//! ``` +//! +//! The following example shows how multiple `work_struct` fields can be u= sed: +//! +//! ``` +//! use kernel::prelude::*; +//! use kernel::sync::Arc; +//! use kernel::workqueue::{self, Work, WorkItem}; +//! +//! #[pin_data] +//! struct MyStruct { +//! value_1: i32, +//! value_2: i32, +//! #[pin] +//! work_1: Work, +//! #[pin] +//! work_2: Work, +//! } +//! +//! impl_has_work! { +//! impl HasWork for MyStruct { self.work_1 } +//! impl HasWork for MyStruct { self.work_2 } +//! } +//! +//! impl MyStruct { +//! fn new(value_1: i32, value_2: i32) -> Result> { +//! Arc::pin_init(pin_init!(MyStruct { +//! value_1, +//! value_2, +//! work_1 <- Work::new(), +//! work_2 <- Work::new(), +//! })) +//! } +//! } +//! +//! impl WorkItem<1> for MyStruct { +//! type Pointer =3D Arc; +//! +//! fn run(this: Arc) { +//! pr_info!("The value is: {}", this.value_1); +//! } +//! } +//! +//! impl WorkItem<2> for MyStruct { +//! type Pointer =3D Arc; +//! +//! fn run(this: Arc) { +//! pr_info!("The second value is: {}", this.value_2); +//! } +//! } +//! +//! fn print_1_later(val: Arc) { +//! let _ =3D workqueue::system().enqueue::, 1>(val); +//! } +//! +//! fn print_2_later(val: Arc) { +//! let _ =3D workqueue::system().enqueue::, 2>(val); +//! } +//! ``` +//! //! C header: [`include/linux/workqueue.h`](../../../../include/linux/work= queue.h) =20 use crate::{bindings, prelude::*, sync::Arc, types::Opaque}; --=20 2.41.0.rc0.172.g3f132b7071-goog