From patchwork Wed May 17 20:31:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alice Ryhl X-Patchwork-Id: 95539 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp36651vqo; Wed, 17 May 2023 13:33:07 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4C6igh+ETlvGmLeAl9QHelrcm0HMVPfoBeaUrRHQ6KDPjZVQtOF2ndZV26uYsyuo78fpxb X-Received: by 2002:a05:6a20:2452:b0:105:d55a:ff48 with SMTP id t18-20020a056a20245200b00105d55aff48mr14870190pzc.9.1684355586779; Wed, 17 May 2023 13:33:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1684355586; cv=none; d=google.com; s=arc-20160816; b=B4y9He8pukql8ZI393e+PNrrf2lQ7rrw6DmhcgLs2YLXXQskn8N5l9FTeRsZAyWIkO 2uI+b5OSPKIE/Imkj5uR20Mkcrz6BgZmwrO1eKW7bw9DnPkmbfty+LR2d/WjtCF9XLe+ 0dE6cXrQUYbBoW4Yvt/qgt72ejgMn8Wv91SNMFpIBq63sKfQuoWfFcPdC/XraLhE/T3j bKkFH8a/aN58SGyOIzSASm2TZZxucedeuPAgB14aRCCI+EgZmhUbro0ZH4jBPe9KTQGv mR+bj632OH6ueR3eBkePWXVsjVRU4LVnm0Fs3EyvsFkm5bd0sZYtah2ew99pIiUKDoUr +xwg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=2Q2MUmGAiEMdaaQsAAxoPHDCIZoeH9n1n1GaPuiAfzA=; b=LVz7EW0XJegARC8gfhoKuLR1M0q5lhIeF8m+RzID9PiFyUYSk81XMyx4kOJPR5h0q/ Glz0aH2D8OV4IJkCPMVGCwy5dkwaadiYrByvOTqyGWYT5voCG1gpUM/ReJpfxV28Hmc7 Mi28JeXUIQVhcCOw2CIZLhbh9tnkxiR+x39/mh4zqqZH/X9vy5Je36HuJe3H4IybAMkk PX6P0fJoW6E3c6twdx8T7vHr8oRLMm4WyDkPQ8cY4KmF3mXLa709vtuOlsDFcVL3hdW2 2fw8WU23HsuuLzl2Bq0u7icn5QhE2PKPaNotH3lfz4k2kubpmH7mRrnrI41IM/P/9eRo TWDg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=zKAfePbl; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id t62-20020a638141000000b00518a1800624si22909838pgd.307.2023.05.17.13.32.53; Wed, 17 May 2023 13:33:06 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=zKAfePbl; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229752AbjEQUbe (ORCPT + 99 others); Wed, 17 May 2023 16:31:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56200 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229742AbjEQUbb (ORCPT ); Wed, 17 May 2023 16:31:31 -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 EEDA87AAF for ; Wed, 17 May 2023 13:31:24 -0700 (PDT) Received: by mail-ed1-x54a.google.com with SMTP id 4fb4d7f45d1cf-506a7b4f141so1508065a12.2 for ; Wed, 17 May 2023 13:31:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1684355483; x=1686947483; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=2Q2MUmGAiEMdaaQsAAxoPHDCIZoeH9n1n1GaPuiAfzA=; b=zKAfePblS1nd8XT33ZnJ95+8xGVLMDUS4gyMSoEOyKiGtcCNCMO8kBMGgXG8J58EN5 HBlHGHGxQq2LEu9iNG+/RWs0ZqlG6Ek4QFwFjHg5+7YBUlFGo26Al3txqchhePqZn6Zl uyUTm7AR2QS+S2vtY+gm2LUM+RnnPpXFmn816h8Qw3A4HKo5eNyn1aa9yq/G9Z4VoLGh 8AhujsdNZPagkjKj0YBFqoq+gvCPaAnE8YNM4V3kfXMge+g2bau9E8rXexTcirMqSBKo rFb31MR76JCgHdloKxoYVbWL3y5K/8HEYE0Bzuc64gmIsw+AodoRLJQSWZslY7lWy0RG VIDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684355483; x=1686947483; 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=2Q2MUmGAiEMdaaQsAAxoPHDCIZoeH9n1n1GaPuiAfzA=; b=efb6UEAgM8d5tg2lDUS7mRJbmSvqfLKaIC2ovmnSqSt92z1tTvgyxBm+VihcfUWtT5 wnbs4XIMkaV/q7G+z2+vhOpA5vPXcXIKF3X+Clse2rBTg6ZnTlZf629XdVMnydjcIwnE bEoDbmi+LUQ4XtHF1kLTBMsvKg9vzOB3gDTFiX5D2kSQp9fLqnGCTUQTg1MmUDQCJ7D5 UezKn/bvxCt2cPlF70/NORFQP+MFnkziQLXCpLVjWeFHAAcsRYwPX41Iid7mT+bthIED lCONbf4m1BTmNj6LTcDHPy9lSrjG7cEl3p7N9l/z5xLy4nvM3auANNlhjpGfCoD7oBhK tKXw== X-Gm-Message-State: AC+VfDzryDaO25BWLb5pyPggu3D2kUHl1rVdND3uW6D/3WtxuRAQIPpd RhgfYuhVVXGJ4QbcSqTr3XmtCZ6ljfva6wk= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a50:cd4b:0:b0:504:e957:2926 with SMTP id d11-20020a50cd4b000000b00504e9572926mr1473278edj.1.1684355483536; Wed, 17 May 2023 13:31:23 -0700 (PDT) Date: Wed, 17 May 2023 20:31:13 +0000 In-Reply-To: <20230517203119.3160435-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230517203119.3160435-1-aliceryhl@google.com> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog Message-ID: <20230517203119.3160435-2-aliceryhl@google.com> Subject: [PATCH v1 1/7] 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_Roy_Baron?= " , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED, USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1766174843730270749?= X-GMAIL-MSGID: =?utf-8?q?1766174843730270749?= Define basic low-level bindings to a kernel workqueue. The API defined here can only be used unsafely. Later commits will provide safe wrappers. Signed-off-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo --- rust/kernel/lib.rs | 1 + rust/kernel/workqueue.rs | 99 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 rust/kernel/workqueue.rs diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 676995d4e460..c718524056a6 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -47,6 +47,7 @@ pub mod str; pub mod sync; pub mod task; pub mod types; +pub mod workqueue; #[doc(hidden)] pub use bindings; diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs new file mode 100644 index 000000000000..e66b6b50dfae --- /dev/null +++ b/rust/kernel/workqueue.rs @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Work queues. +//! +//! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.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 the kernel. Several are +/// always available, for example, `system`, `system_highpri`, `system_long`, 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 dangling, 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 pointer 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. + pub fn enqueue(&self, w: T) -> T::EnqueueOutput { + let queue_ptr = self.0.get(); + + // SAFETY: There are two cases. + // + // 1. If `queue_work_on` returns false, then we failed to push the work item to the queue. + // In this case, we don't touch the work item again. + // + // 2. If `queue_work_on` returns true, then we pushed the work item to the queue. The work + // queue will call the function pointer in the `work_struct` at some point in the + // future. We require `T` to be static, so the type has no lifetimes annotated on it. + // We require `T` to be send, so there are no thread-safety issues to take care of. + // + // In either case we follow the safety requirements of `__enqueue`. + unsafe { + w.__enqueue(move |work_ptr| { + bindings::queue_work_on(bindings::WORK_CPU_UNBOUND as _, queue_ptr, work_ptr) + }) + } + } +} + +/// A work item. +/// +/// This is the low-level trait that is designed for being as general as possible. +/// +/// # Safety +/// +/// Implementers must ensure that `__enqueue` behaves as documented. +pub unsafe trait WorkItem { + /// The return type of [`Queue::enqueue`]. + type EnqueueOutput; + + /// Enqueues this work item on a queue using the provided `queue_work_on` method. + /// + /// # Safety + /// + /// Calling this method guarantees that the provided closure will be called with a raw pointer + /// to a `struct work_struct`. The closure should behave in the following way: + /// + /// 1. If the `struct work_struct` cannot be pushed to a workqueue because its already in one, + /// then the closure should return `false`. It may not access the pointer after returning + /// `false`. + /// 2. If the `struct work_struct` is successfully added to a workqueue, then the closure + /// should return `true`. When the workqueue executes the work item, it will do so by + /// calling the function pointer stored in the `struct work_struct`. The work item ensures + /// that the raw pointer remains valid until that happens. + /// + /// This method may not have any other failure cases than the closure returning `false`. The + /// output type should reflect this, but it may also be an infallible type if the work item + /// statically ensures that pushing the `struct work_struct` will succeed. + /// + /// If the work item type is annotated with any lifetimes, then the workqueue must call the + /// function pointer before any such lifetime expires. (Or it may forget the work item and + /// never call the function pointer at all.) + /// + /// If the work item type is not [`Send`], then the work item must be executed 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; +} From patchwork Wed May 17 20:31:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alice Ryhl X-Patchwork-Id: 95544 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp38243vqo; Wed, 17 May 2023 13:36:29 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4Uik61BVKoF2fCAts6H6aHH0poO3sq/eccaMDM8AI8w1dyQRUuL2wWavFwtS0P3LgGUum6 X-Received: by 2002:a17:90b:8d4:b0:24e:5344:9c9d with SMTP id ds20-20020a17090b08d400b0024e53449c9dmr92556pjb.38.1684355788819; Wed, 17 May 2023 13:36:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1684355788; cv=none; d=google.com; s=arc-20160816; b=bDGvKcjHySn5SGFJhBONuE8kcRiAx02YySAFS8Y7U+JX/nPkNImQrYg9G4RCOp1bz8 MtBwTOLJdIeXlQjGZvk34ZWkkCGTB/LBJDNS+5jV5TXOTdQJZrbr9jfMwKT0LeLHW9Rg fF3F2/Da8vyRyO4alYHDyExn4aER4Z6ekPz0U4iPNtg34/QO6k9sxEMLyCnumYzWA1Wg cgQuVStjcCTOzDDNxNo1DStsk2iGdT+1mg1XxwLBqXMiuPK+L3ZJGOhFZxJYTN5gPPHt c5asnv8JjeEoRgFWQeEaoNDKHFbt46yJ72gZQMovnX9Od8MmyDmpxZP1xoKRIcR+zcuP mDgA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=32ue7WltCbe1aj9V+bmg5YyP4ANtZIJoj0Bg0fkgpuM=; b=b/shc2za8QFPMzfrMOywS7CBgO4bwDXdM9OblZ+T6J1ea5lPpdhDyRDoLduCIeK0fq Nck2SeexoRxeBILRxswX7zkMxHJbgkpR1tGnODs+d9r6kbICMJPQfpdDe8m2NAiRw/cu aF/OiqlLBaL4ceUEEi+VD+4mdhXCMaOczypD4RkFx0ASKHpmTX3TLSSVIIis7MbqWoZ7 k5eZ1CYF3mkG5KqLCGX1+VSw/Dqe5YSTNWFNW0HrvU4SgA7+hpeOqZhfGegSdmza22KE YFjuwvANGTAad/PKmONsh2QIk8EFZ23+BmxgfWbAuUsD1C0G81BptujzGf9F7Lf0LL2W VOWQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=RBwReH9o; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id a21-20020a63e855000000b0050f817c6c82si22073125pgk.232.2023.05.17.13.36.03; Wed, 17 May 2023 13:36:28 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=RBwReH9o; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229724AbjEQUba (ORCPT + 99 others); Wed, 17 May 2023 16:31:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56166 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229497AbjEQUb2 (ORCPT ); Wed, 17 May 2023 16:31:28 -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 F3FF87DA3 for ; Wed, 17 May 2023 13:31:26 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id 3f1490d57ef6-ba8217b3d30so1502670276.2 for ; Wed, 17 May 2023 13:31:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1684355486; x=1686947486; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=32ue7WltCbe1aj9V+bmg5YyP4ANtZIJoj0Bg0fkgpuM=; b=RBwReH9ogtwVoE1XQ/ZI6UfWivhfBXI3WmrFbmj7DoEuSLsn8C1nmPiQsBycA+2F43 62buFxLbt/L8aBnfdSpk2jL6Nw7xsYt+5rZnyqeCudDzwy/Nx1sPcTQM0R/OoQOW+zsL oGBOurlBS6d9N5xkh7hwEjNk77U0euEAONsRWMRySBg3+XH0WhdK9tms5MnFg9qttraz HO1bLTR98+8tyOkgi9P84RD+c5JBS5CuIzVRZltEVWkxtTx3wZsdq03GOa6unp6OQ05q QyLTOQyAnjJ+pdcGBsZLcPNnBcb0PPIAyGbWw0aiAQtLUU8KbW6DNenHPCUxrsxUtyi0 Hqwg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684355486; x=1686947486; 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=32ue7WltCbe1aj9V+bmg5YyP4ANtZIJoj0Bg0fkgpuM=; b=QaWY31EpWMJF0Gmu2S5Nx26EFW7szFM8w6cdYCGOWjKfMDi89/zPsZZcaNjnHMcXsZ vWrQgpfcNzdXNqwPY4zHa2ydddf4r6Lhoa8fMiDB5eft0FiTrPcV5hKD2llyT/Mx2wcv j1BXdVLm/WwfVtVCOpcL2tICT1JAiBRpfAJMAliLrRYC+gT+/WiyUDQws8C6mFgxvalO OqZ1Nzd/fLsJinnAVWyAmbCkxESrHDZjlg+LD7qsja9XI3F/nyC6pj+2HHK7pcnAiXYJ W0MVIiFPyri2gwnT/eKA0Uqjs6DoUFNXWYNbUJt/nBX/L0P7tZo221+sWvusgdSCA6SX Qlrw== X-Gm-Message-State: AC+VfDxcmMDrX+NFas41nKjQzl/48S714umf4pFSlugaWLEyyx9bB+vI 7SgX61ByI8iH0Hzycz7fVQp1i1sd/09xOoU= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a25:182:0:b0:ba8:58c8:38f7 with SMTP id 124-20020a250182000000b00ba858c838f7mr2038208ybb.11.1684355486248; Wed, 17 May 2023 13:31:26 -0700 (PDT) Date: Wed, 17 May 2023 20:31:14 +0000 In-Reply-To: <20230517203119.3160435-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230517203119.3160435-1-aliceryhl@google.com> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog Message-ID: <20230517203119.3160435-3-aliceryhl@google.com> Subject: [PATCH v1 2/7] 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_Roy_Baron?= " , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED, USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1766175055574848924?= X-GMAIL-MSGID: =?utf-8?q?1766175055574848924?= From: Wedson Almeida Filho This macro is used to compute the offset of a field in a struct. This commit enables two unstable features that are 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 features 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 --- 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 c718524056a6..cdf9fe999328 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -14,6 +14,8 @@ #![no_std] #![feature(allocator_api)] #![feature(coerce_unsized)] +#![feature(const_ptr_offset_from)] +#![feature(const_refs_to_cell)] #![feature(core_ffi_c)] #![feature(dispatch_from_dyn)] #![feature(explicit_generic_args_with_impl_trait)] @@ -102,3 +104,36 @@ fn panic(info: &core::panic::PanicInfo<'_>) -> ! { // instead of `!`. See . loop {} } + +/// Calculates the offset of a field from the beginning of the struct it belongs 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:ty, $field:ident) => {{ + let tmp = ::core::mem::MaybeUninit::<$type>::uninit(); + let outer = 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 create an intermediate + // reference. + let inner = 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 9f94fc83f086..ec583d13dde2 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -277,7 +277,7 @@ $(obj)/%.lst: $(src)/%.c FORCE # Compile Rust sources (.rs) # --------------------------------------------------------------------------- -rust_allowed_features := core_ffi_c,explicit_generic_args_with_impl_trait,new_uninit,pin_macro +rust_allowed_features := const_ptr_offset_from,const_refs_to_cell,core_ffi_c,explicit_generic_args_with_impl_trait,new_uninit,pin_macro rust_common_cmd = \ RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \ From patchwork Wed May 17 20:31:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alice Ryhl X-Patchwork-Id: 95545 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp38883vqo; Wed, 17 May 2023 13:37:55 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7osEJUWcq/AgIKrMNSvK40T6SYmImVwdhxTeU7AfsPZbiPPLWgY07AsjM7F5hmPfhyYC6a X-Received: by 2002:a05:6a00:a05:b0:64c:c5f9:152a with SMTP id p5-20020a056a000a0500b0064cc5f9152amr1392166pfh.23.1684355875052; Wed, 17 May 2023 13:37:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1684355875; cv=none; d=google.com; s=arc-20160816; b=XLYZImySQ4bvFhvh3C4KEpUukiSxNd/4StSnFb3FlqnjrY+EDm6Z33f50bsoJfr7x4 4fxViR9cf+Uau3ejf9o4WZwau4WsGoBqJ1GS8IooDAp2opdAIthfIDeCN3O9frchmicc GUEUoI+UxDB0sHlcyvBh2lmKiDv/T0+teGW+hjngo6Px2Et10r8IZlv+/Hsfz2t74JwM jSUVQGGk4pfQDHYKLKfCxMKRZx/QRmiJ0Fk4uBXE2GnvUIK1tM4h0bd6GUvvup7D+tb7 26OA8Hytp7AM6Z9VOaurhJOqJsZ/LlVCIiP07Ma4noXLmcG9rcOf2i5V9L2lwi3Gej06 GSTA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=1m2NIZThmeCBayz0liS/tGETC/9gj7ELeSxPKaC6Yh8=; b=ZMixPLuyRSuvpd/ZybEl3FivnVpiMLUkMQaB90UB6x23pEOY/E1QJFoDx+nlH3etmi AGwG/m7mjZo5utjJQkGZfrJrqk7FdV3fP0S9ceor/SPlmYuH1jyA5Y5L7mbUi9GMNKt/ 7c4Dm4W1gweuayYihg/ofWrSxmPspih/KomG0NQi79wW4PhcZkrIiWQCbGrOehRnFedb j+PsICfN9TAIMmB8jQwvko7eOwg72z5yD04mfe150JRlZxz4kAe7hhJDXNmpIHGdUwec W9mEa0sR5O6a7HWd0cGezrE19NDzIe+/INPMxxdzFj9FOm7FZOTK1Ky5xkPZ+ElsKYC0 j3Rg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b="BnGU93/l"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id m12-20020a633f0c000000b00528a60ab393si21662381pga.314.2023.05.17.13.37.14; Wed, 17 May 2023 13:37:55 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b="BnGU93/l"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229785AbjEQUbl (ORCPT + 99 others); Wed, 17 May 2023 16:31:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56204 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229514AbjEQUbc (ORCPT ); Wed, 17 May 2023 16:31:32 -0400 Received: from mail-ej1-x64a.google.com (mail-ej1-x64a.google.com [IPv6:2a00:1450:4864:20::64a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4203F30DE for ; Wed, 17 May 2023 13:31:30 -0700 (PDT) Received: by mail-ej1-x64a.google.com with SMTP id a640c23a62f3a-969f24626fbso68332766b.0 for ; Wed, 17 May 2023 13:31:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1684355489; x=1686947489; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=1m2NIZThmeCBayz0liS/tGETC/9gj7ELeSxPKaC6Yh8=; b=BnGU93/l6zgPX74n1BWhPYto1+DmrAaRJmje1ktjtxvvMVe5/ufxtkwfhHuGWoWdhk sTD0ze0cB+pBIMUh0eC20QGkHMtXngl1qheah8sXtY3xJUm4p2C/jy+3agGa/nXWMaBI cjXQYFgEMFGWjq0AK5WF2hb3rxsDq2qWXzEhoziYVq2kaalDDx9UX4nj4NQFwlvAumU+ X8d+B3yeLFzGBO3Z8qQeVsV6ID5+4q96aaX8eg1fnDPAsOkB3kNDdNSo2o+kmZH4J8aw 91bpLwB4E7EfRot8PStAuoblk4n4X2GSjicq/7i8QVuKgUhHDcQKGNJycsRIbr49laKs oJ7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684355489; x=1686947489; 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=1m2NIZThmeCBayz0liS/tGETC/9gj7ELeSxPKaC6Yh8=; b=Zl71juEiWgWapMieElwxyxvVlTgo7rZXGmSnDEl5iVUZUtXdGaJ0J8wium9eKnvjJG l8WIx8E+Y3+NYHhEDMO/JVB66nrlztT+q48BR5WxYF/2jh0RQPfYVSZBdZmLSWZEr5Nc pww5aVjUiac5OGx9EIs5vG0djJ6WUaIzm95Kku7G5cLi0mZ3Tc7kWQpD3n1G7eoO3RcE Yq85DoQVOkz7yNTdIxOtrByHjwC19OxQH3R24ApRTq4wHMfPbSLtNfHBJndSpW9HH1JG 7JwVs8neLGmiMSNeO38kZX3p/DbCGdZTg5uRF7VmjyIp0WNgg1OCeovMfmWeu6/KArk3 TYhA== X-Gm-Message-State: AC+VfDwxCnQWukm2fhCOSsmlU2PCqGADf9kO6U3gMSsIpj9DlMBSx9Pp /RyHxkWmBGaeM5NCnG9a8zaXCFsgoOFsjTU= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a17:907:2bf5:b0:94e:dcd5:2429 with SMTP id gv53-20020a1709072bf500b0094edcd52429mr1413196ejc.3.1684355488912; Wed, 17 May 2023 13:31:28 -0700 (PDT) Date: Wed, 17 May 2023 20:31:15 +0000 In-Reply-To: <20230517203119.3160435-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230517203119.3160435-1-aliceryhl@google.com> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog Message-ID: <20230517203119.3160435-4-aliceryhl@google.com> Subject: [PATCH v1 3/7] 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_Roy_Baron?= " , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED, USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1766175146251007014?= X-GMAIL-MSGID: =?utf-8?q?1766175146251007014?= 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 --- rust/kernel/lib.rs | 1 + rust/kernel/sync/arc.rs | 44 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index cdf9fe999328..82854c86e65d 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -22,6 +22,7 @@ #![feature(generic_associated_types)] #![feature(new_uninit)] #![feature(pin_macro)] +#![feature(ptr_metadata)] #![feature(receiver_trait)] #![feature(unsize)] diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index e6d206242465..7c55a9178dfb 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -210,6 +210,50 @@ impl Arc { } } + /// 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`]. + /// + /// 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_raw`]. Additionally, it + /// can only be called once for each previous call to [`Arc::into_raw`]. + pub unsafe fn from_raw(ptr: *const T) -> Self { + // SAFETY: The safety requirement ensures that the pointer is valid. + let val_align = core::mem::align_of_val(unsafe { &*ptr }); + let refcount_size = core::mem::size_of::>(); + + // Use the `repr(C)` algorithm to compute the offset of `data` in `ArcInner`. + // + // Pseudo-code for the `#[repr(C)]` algorithm can be found here: + // + let mut val_offset = refcount_size; + let val_misalign = val_offset % val_align; + if val_misalign > 0 { + val_offset += val_align - val_misalign; + } + + // This preserves the metadata in the pointer, if any. + let metadata = core::ptr::metadata(ptr as *const ArcInner); + let ptr = (ptr as *mut u8).wrapping_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 From patchwork Wed May 17 20:31:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alice Ryhl X-Patchwork-Id: 95540 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp36799vqo; Wed, 17 May 2023 13:33:22 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ5lQImf94WmmlV4BAaCHOro2fsnlCL1RC7SijqrP3+N2uc7TyxdcZJptql8l6AL0oN9pNgC X-Received: by 2002:a17:902:8482:b0:1a6:3799:ec2a with SMTP id c2-20020a170902848200b001a63799ec2amr49701plo.35.1684355602366; Wed, 17 May 2023 13:33:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1684355602; cv=none; d=google.com; s=arc-20160816; b=j+ppd2F6OywCR25M8QAZNnY5mnLtCVdB7iBEUPR3SMAlr2zjfmFQeVhdcM5622Mvsk edO0Ushr+rYe1Fjka0qflXfDIo7Aj4/DLRMu8pbf4JdPtxFNkkOySBEdkGkZDuMCESc+ T5aftMMItXyU1r+JlxiQA8dZEiTU8jvjYsZSKKbvTzfB5BWjDdc3mN5SdgCgNdx5CpPC VnEEJWR0svpqpAThK939KQEwmbaYs7fw3bV1K6YZZYE9om7tWdm62/fFyUIf3ElX7kaU UmiJ/m3sk+McMoEjIQUkKkxWcugccXl5mMiwYVPAfD6bbmbIta11ikYpDJUUo2SUtwq1 qPHw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=aOsrinT2/iaeBb0WCg7wbvs+eW6FJ9BpP6VKG3yyBao=; b=InuBUUSNY0h2VJrpsAqop9UrsKtVQPe48fQDkCpI+MENP0HugKhpiQ1FaENnbZ1X54 QTTEW13ybPI1Pyaegut75UYh7yjYpMch2ft4/khxNKEWmklf4njfkUCzNkO9PADwPDH0 YmBOqyV83f9fRmFgBaLYN9LV6OwlAiIfvSw4tnDYx65dCbyC1JI+GKjKJ4m9SUehwTH4 +U2neKHqBNRKVdMdapRXDcoyS93qzLYM8Re8n/JmDYegmRmRl2Yg7eRpFKuDvWh5icQX Oywru87tf/HK7r8hY+0Z4tofI9rKednc1FgJt17ZG5poAdy4UUFqVT0g/bLxPWqLPqpC vk9w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=H6PERSAk; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id c17-20020a170902d49100b0019b090e497esi23065539plg.298.2023.05.17.13.33.10; Wed, 17 May 2023 13:33:22 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=H6PERSAk; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229826AbjEQUbr (ORCPT + 99 others); Wed, 17 May 2023 16:31:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56332 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229767AbjEQUbf (ORCPT ); Wed, 17 May 2023 16:31:35 -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 058FC9037 for ; Wed, 17 May 2023 13:31:33 -0700 (PDT) Received: by mail-ed1-x549.google.com with SMTP id 4fb4d7f45d1cf-50bc456a94dso1283225a12.1 for ; Wed, 17 May 2023 13:31:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1684355491; x=1686947491; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=aOsrinT2/iaeBb0WCg7wbvs+eW6FJ9BpP6VKG3yyBao=; b=H6PERSAkTTYE2cWlo4VM3SlqSWM7x5pxRQ0xuWDg3VOBNyhF2hvGKULDhDPgLi2z3g B6Z0eUxWVpg5g5oXZLmaug777isU03Z+nfEJ5ms9qAPmuVNsFW1fc8qMU7nD99034pQy JBR5MzZlyYJrWwX4d7Pd79YdlG1fLg6EbSOgLlcg8D+RArG3dkHGoOpFv7Or62NCvRzf ULBHvzIUC6W1xuBIfvCrqHqTKetHK8rZJFGSh+P0Z8yHzoPYw5anwwjpuCKLIgGlnJaH caRHHNXst0n42JTDJdFiZhG2I1wLxulOebTtWnSeGO+dGTMUCBk6ViszJYZzaZ9AxwrI enWA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684355491; x=1686947491; 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=aOsrinT2/iaeBb0WCg7wbvs+eW6FJ9BpP6VKG3yyBao=; b=Z8obwwZ7PrcoKcgeE4UG8PMyK7B/Q+KLfqxr4fxD6ZX5likCybDPRRHqW1OK+OBu9b XkR8ZF6snzxUPe5Qxn1pa6ZvXy73IxG2TZ4ftw0YBPWlHM1zFG+zx32D+Of2JlJw2Xed zFrmygeZzBBktPxfyL8WGu+EKLMzAGSmhsJ6zg++ur2qATNYpPViUmmV9Va/4S63rdeh Fy9zaw4bFQn2sbcfwZTpwX3NjsD8EiAo7raV2GQa27D3480C6nXWU8ndDyE1EgCXkoFF PYzw4xq3fZpVwxPEm4dWskrzgDwLHfAlSWJdnQSrPH2PIJ1zHXEmkH8pT0LXD6OG8sNd Edxg== X-Gm-Message-State: AC+VfDzBp+nQwDAlV1WOP6CeF6b1Crb1EBLsEQm/ovhHIMfgsq16DNRI FJkX17lg1492FQOTwANY6F5sm6njELInyeM= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a50:f610:0:b0:50b:d648:a963 with SMTP id c16-20020a50f610000000b0050bd648a963mr1508053edn.6.1684355491066; Wed, 17 May 2023 13:31:31 -0700 (PDT) Date: Wed, 17 May 2023 20:31:16 +0000 In-Reply-To: <20230517203119.3160435-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230517203119.3160435-1-aliceryhl@google.com> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog Message-ID: <20230517203119.3160435-5-aliceryhl@google.com> Subject: [PATCH v1 4/7] 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_Roy_Baron?= " , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED, USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1766174859861432240?= X-GMAIL-MSGID: =?utf-8?q?1766174859861432240?= 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 --- rust/kernel/workqueue.rs | 65 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index e66b6b50dfae..22205d3bda72 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -97,3 +97,68 @@ pub unsafe trait WorkItem { 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 multi-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 which 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 running 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, and 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 freezable. +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" variants 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_freezable_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) } +} From patchwork Wed May 17 20:31:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alice Ryhl X-Patchwork-Id: 95541 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp37005vqo; Wed, 17 May 2023 13:33:50 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7A7jGyfa4k8dVAs11SbxCNFBaXdGYVWV/5SHohk2khwcWx1Y5LgMWYxqUzuebvVsKZfWCW X-Received: by 2002:a05:6a00:179e:b0:63b:854c:e0f6 with SMTP id s30-20020a056a00179e00b0063b854ce0f6mr1372121pfg.21.1684355630241; Wed, 17 May 2023 13:33:50 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1684355630; cv=none; d=google.com; s=arc-20160816; b=FtxnnHOU2cNrQGLy0/6FHNFtfBSAOSmbc0N37P25kW8L0XqWc7TBT99mrLdIpr3Q/q kqCbYX16wyuD/DKu4PLu0sEFksKmTj5IRVfG1+fdLv0EpN43gTRd+b8jB5kuTau5vvn4 y+m5bCmXSG5dtM6i80diJwEuMj9miTjPNAhTf9js9XeYQ7tEUtifYhz6j4usloxtEyGJ oh3/7YtX7FhsPuGRLPtp6y9674Gllir2bLigmthMpiFRkem2qrYyg0SZ9ml8kK5hJA3b GGdIdLcp+zpIATvPERwOO4WBKRQ8yu84Eus+Wvgev8DTiwZqMozzLhCl/Ym1AoXXtrIS FUjg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=/ed87iA39b46/wbybn6KAMFj/986EKOHM/Dtt+HZtew=; b=OGQMMEnJui0U9pTMSQomNSXNhSqji70pThbDuMqjJ4UHQWtVDUPgxwHkARzSEKZ8zi RmSkk02ckheMINO33d6lP+PneYDjdGYZpt3DslBYtFvj8AQB+uPafl7V/exTqfTTYP3C kJMzPquLY6iP5ZINZHI5n583IlDS579ic+mFPkYkbuNtwE7lJtRfDzWng5G6+3CnCm7v NRyaQIyLDyJUao69upHytoZHo8AGJbJXxHsE6AXKx9gQ1wgUCrWrr9T/xv8TLQ6JSgD3 QZZ7nqUpn6Qn8NIJWq36fxA0u4xNA+T2+3KbAA/CTUpIsvfKGk7cojSKB2O5CrW3jWHK 94MQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b="nXa/1h2A"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id m12-20020a633f0c000000b00528a60ab393si21662381pga.314.2023.05.17.13.33.38; Wed, 17 May 2023 13:33:50 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b="nXa/1h2A"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229814AbjEQUbu (ORCPT + 99 others); Wed, 17 May 2023 16:31:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56882 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229792AbjEQUbq (ORCPT ); Wed, 17 May 2023 16:31:46 -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 22BDF7D91 for ; Wed, 17 May 2023 13:31:35 -0700 (PDT) Received: by mail-ed1-x54a.google.com with SMTP id 4fb4d7f45d1cf-50bc88edf7eso1239329a12.2 for ; Wed, 17 May 2023 13:31:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1684355493; x=1686947493; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=/ed87iA39b46/wbybn6KAMFj/986EKOHM/Dtt+HZtew=; b=nXa/1h2AGviWC4V/Xefyq0aHpIWoGu8VQkwlrEvRjpoLHDtlcGW8h0bJUrizBgt3B8 /LDdZMVr02UYquwmjhEobVQydx7CWgdO8mSMpx3mGUUrr46nRkOpmYY2MO41xI19ZBzt iHlRD56GyICHxUfGCxwOcCTSxBmMpqw8cSVG7MciW8Bjwh7mPT1MRjIFNekKYU3F5XnJ k9NX+qxB62RlnpdM0W17Nzx6Yv0mdX/dAwsL6oJqm40cOXjIq1VX8tJsobMHMJW1otPx q84k2Sou+Y0dbYVilH+urESzPX3rlWz2anjgsXwt4UmO0KOi5qu5kd1PIyIhGBMC6LZw wKjA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684355493; x=1686947493; 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=/ed87iA39b46/wbybn6KAMFj/986EKOHM/Dtt+HZtew=; b=OsFnEWUqJjM/AMyJISRqXj1hOQA4PaJp1PTO8Q8NXyt6e1x3MntHKm58LCk+XLNPa1 QGEAewb/a/ETvaid3KEUM/Sd532sTeGgpxUbYBc4Oavff8nc/nwRAvbH1fOfrBSsJVpw DVP9ZimyniO8TWhi91OvKWq3U838d14JWE3+kLug6TxvKzLo/SHWUKt9xBWwtcmSWjlE EU4KvlrzkIi8EZIOB96COPUt4Y4U9BjUdA91TKnZkpOb8Urq/YV94wqe1r4XMzV1fJcE wgeK1jO64+uDCFNIBaM93pKdTWEmI3/oByvp8pseCjGeGjtIG2xvMYFcGZZ1L6ENPVRh c59w== X-Gm-Message-State: AC+VfDxPRT4hDSnm2pv/WHx8n+f/dHwmOa4aK/Z7th0ngF7PJt3ysk1l HPNQe4aHzSkAGertqjciUjSNsOXLYvWeMp4= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a50:aa9d:0:b0:510:d8d6:93c9 with SMTP id q29-20020a50aa9d000000b00510d8d693c9mr837868edc.0.1684355493654; Wed, 17 May 2023 13:31:33 -0700 (PDT) Date: Wed, 17 May 2023 20:31:17 +0000 In-Reply-To: <20230517203119.3160435-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230517203119.3160435-1-aliceryhl@google.com> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog Message-ID: <20230517203119.3160435-6-aliceryhl@google.com> Subject: [PATCH v1 5/7] 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_Roy_Baron?= " , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED, USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1766174889476239927?= X-GMAIL-MSGID: =?utf-8?q?1766174889476239927?= 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. This commit will use traits so that they know about each other according to the following cycle: * The pointer type. It knows the type of the work item struct. * The work item struct. It knows the offset of its `work_struct` field. * The `work_struct` field. It knows the pointer type. There's nothing special about making the pointer type know the type of the struct it points at. Pointers generally always know that information. However, making the `work_struct` field know about the pointer type is less commonly seen. This is done by using a generic parameter: the `work_struct` field will have the type `Work`, where T will be the pointer type in use. The pointer type is required to implement the `WorkItemAdapter` trait, which defines the function pointer to store in the `work_struct` field. The `Work` type guarantees that the `work_struct` inside it uses `::run` as its function pointer. 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 } } ``` So to summarize, given a pointer to an allocation containing a work item, you can use the `HasWork` trait to offset the pointer to the `work_struct` field. The function pointer in the `work_struct` field is guaranteed to be a function that knows what the original pointer type was, and using that information, it can undo the offset operation by looking up what the offset was via the `HasWork` trait. This design supports work items with multiple `work_struct` fields by using different pointer types. For example, you might define structs like these: ``` struct MyPointer1(Arc); struct MyPointer2(Arc); struct MyWorkItem { work1: Work, work2: Work, } ``` Then, the wrapper structs `MyPointer1` and `MyPointer2` will take the role as the pointer type. By using one or the other, you tell the workqueue which `work_struct` field to use. This pattern is called the "newtype" pattern. Signed-off-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo --- rust/helpers.c | 8 ++ rust/kernel/workqueue.rs | 183 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 190 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 __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); +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` type * 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 22205d3bda72..7509618af252 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -4,7 +4,8 @@ //! //! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h) -use crate::{bindings, types::Opaque}; +use crate::{bindings, prelude::*, types::Opaque}; +use core::marker::{PhantomData, PhantomPinned}; /// A kernel work queue. /// @@ -98,6 +99,186 @@ pub unsafe trait WorkItem { F: FnOnce(*mut bindings::work_struct) -> bool; } +/// Defines the method that should be called when a work item is executed. +/// +/// 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` initialized with the [`run`] +/// method of this trait as the function pointer. +/// +/// [`__enqueue`]: WorkItem::__enqueue +/// [`run`]: WorkItemAdapter::run +pub unsafe trait WorkItemAdapter: WorkItem { + /// Run this work item. + /// + /// # Safety + /// + /// Must only be called via the function pointer that [`__enqueue`] provides to the + /// `queue_work_on` closure, and only as described in the documentation of `queue_work_on`. + /// + /// [`__enqueue`]: WorkItem::__enqueue + unsafe extern "C" fn run(ptr: *mut bindings::work_struct); +} + +/// Links for a work item. +/// +/// This struct contains a function pointer to the `T::run` function from the [`WorkItemAdapter`] +/// trait, and defines the linked list pointers necessary to enqueue a work 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 [`WorkItemAdapter`] that uses +/// it. +#[repr(transparent)] +pub struct Work { + work: Opaque, + _pin: PhantomPinned, + _adapter: PhantomData, +} + +// SAFETY: Kernel work items are usable from any thread. +// +// We do not need to constrain `T` since the work item does not actually contain 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 contain 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: WorkItemAdapter, + { + // SAFETY: The `WorkItemAdapter` implementation promises that `T::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::run), false); + Ok(()) + }) + } + } + + /// Get a pointer to the inner `work_struct`. + /// + /// # Safety + /// + /// The provided pointer must not be dangling. (But it 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 valid. + // + // A pointer cast would also be ok due to `#[repr(transparent)]`. We use `addr_of!` so that + // the compiler does not complain that `work` 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 below 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 accessed 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 pointer must not be dangling. (But the memory need not be initialized.) + /// + /// [`Work`]: Work + #[inline] + unsafe fn raw_get_work(ptr: *mut Self) -> *mut Work + where + Self: Sized, + { + // SAFETY: The caller promises that the pointer is not dangling. + unsafe { (ptr as *mut u8).add(Self::OFFSET) as *mut Work } + } + + /// Returns a pointer to the struct containing the [`Work`] field. + /// + /// # Safety + /// + /// The pointer must not be dangling. (But the memory need not be initialized.) + /// + /// [`Work`]: Work + #[inline] + unsafe fn work_container_of(ptr: *mut Work) -> *mut Self + where + Self: Sized, + { + // SAFETY: The caller promises that the pointer is not dangling. + 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> + for $self:ident $(<$($selfarg:ident),*>)? + { self.$field:ident } + )*) => {$( + // SAFETY: The implementation of `raw_get_work` only compiles if the field has the right + // type. + unsafe impl$(<$($implarg),*>)? $crate::workqueue::HasWork<$work_type> for $self $(<$($selfarg),*>)? { + const OFFSET: usize = $crate::offset_of!(Self, $field) as usize; + + #[inline] + unsafe fn raw_get_work(ptr: *mut Self) -> *mut $crate::workqueue::Work<$work_type> { + // SAFETY: The caller promises that the pointer is not dangling. + 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 multi-threaded. There are From patchwork Wed May 17 20:31:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alice Ryhl X-Patchwork-Id: 95542 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp37119vqo; Wed, 17 May 2023 13:34:05 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4h9muXmPGYjMsXeTtMs22LK7P3AxBmLYxvJzMH0bnGg1auHA34U7GqzShjITjTQd8zb9nS X-Received: by 2002:a05:6a21:9999:b0:100:c8ed:c207 with SMTP id ve25-20020a056a21999900b00100c8edc207mr46069830pzb.39.1684355644751; Wed, 17 May 2023 13:34:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1684355644; cv=none; d=google.com; s=arc-20160816; b=YUmSrnFndvP27Id4vtxRWz/ClqDE33AfsEZLUkukUJeCRmLb5uo4PAKifCYTtQBJkV 6ZrEGhLZUnSu6wwuO1gikRluoZyLAgU6pK+faKIsWyRuNHoJg1FkcgrZsWtUUA3WviJ5 pTElx5B/7+QKxBFZg1NcZEe8vJAoHVSqCcGJQuywcBc8KQD6v0QO7skzhVUD8oNyS4cT 4JV7RxiVLG31tWfD/iCssRpdh80XB8CSdnpJWrfUggYdJrCQDKQOvIKXj6ldzuHIYXkK cBEf99QR7Tkdsr5vdNy1JzWHnrY7S5v86pHBfcJG6CEUNBvWXjDb0TaWEZwkDwZoS5EI 5wdg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=fgvSQEdS5WExED0wIm07QH2swg26Pv/48bDvBCAkvT4=; b=JaoF+5Fy35ZXADYCkN1VQmFwSl0aXI/b0iPTfXoRPXZeKfcJIC8vkfRnPEDVALdZVi Fz1p63wBdwdpN+cO4fTQGg9sK5p1d49wYmBlxFgDIR3ZqRKlQsv6tSvCT8vxCFaT6ZEp pGBwURXAH6QGgEtS0HGTnG6vNoC90SCcrmUfTB1oLGej0CO43ZA2i/wZT52wXooDv+8W PlI7A6UQcXQ0o3NFiT2nmzy26joBEg72KxOtd8u8z1QIuwFT85YgFOVJ53HAtZtLz3Tg wWx832+axkMbF/sdnB7pdDjPTZxN+/rUa3/vQ2QPg0tVuL0iiDBMoxgwYMEUZarL5veg i8yw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=maslnMdS; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id t62-20020a638141000000b00518a1800624si22909838pgd.307.2023.05.17.13.33.52; Wed, 17 May 2023 13:34:04 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=maslnMdS; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229877AbjEQUbx (ORCPT + 99 others); Wed, 17 May 2023 16:31:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56940 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229807AbjEQUbq (ORCPT ); Wed, 17 May 2023 16:31:46 -0400 Received: from mail-ej1-x64a.google.com (mail-ej1-x64a.google.com [IPv6:2a00:1450:4864:20::64a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 97F637AA9 for ; Wed, 17 May 2023 13:31:37 -0700 (PDT) Received: by mail-ej1-x64a.google.com with SMTP id a640c23a62f3a-9662fbb79b3so136303866b.0 for ; Wed, 17 May 2023 13:31:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1684355496; x=1686947496; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=fgvSQEdS5WExED0wIm07QH2swg26Pv/48bDvBCAkvT4=; b=maslnMdSIs3sxQ2nroKBfN5UKh7kzcmPZXZKPZDG1mkKjMNiq6Sx3RzKw8XFHAGe8n k3L3evQ/vtn8IacWG3XJzNd3ZOCiYjPUvMND8SKlIZIqq+vCf7BNkYCXgdmUs0g5kPVU d/Le0ssyJh4Qjjsn+BSRp/efSWewRGUBrPjvyG2/rayWOXYLwdbdLCoa5e4ybdYOmH4w yj27QUvsyLFi1cMCuK4Lo3P7ovUq8+2rHG/Zk1MnPBV6fs3TlGhGROs3nCeC59C7yH4f nVr/1CgiWZ0VdY/fJCmgJsisAiB8JlHKt6vTHrXTBZ+RaGeYu6jYNhR/3GcuckYueYEI pD2Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684355496; x=1686947496; 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=fgvSQEdS5WExED0wIm07QH2swg26Pv/48bDvBCAkvT4=; b=fO/DrkEbosB8WwZ68r3dyCbSyvI/pdRLJtZyZ+N90c1RUO0QxTaC2CHWh/xrdMuVYM SAUpDzku86DczRxMa6hpKa1S8ONZxDfUDm5JBbG1pGn+MxAh9g6CNTPyE3pdKzO0RHLj +euOvnq0iQ2rPHJARYHcU+5PZUdXSFk2ue3emmmTJbT1nbXilX3QwUavsHoKtCSLuIaq z6eDY/EJrWGVJermouwqtZUeoPPqAvP3dEibPPr5k3+s+ViGbyf4tM7TNkj0ddw3XQRN IfvR0UAPe2s0e6A7wV96qufDUdNFd4uoJFzXV5DOdSjeSiI2D4j1rZRXDTDuDq4sfj99 uMkw== X-Gm-Message-State: AC+VfDzpkzLhu9Mgm2D9m2dD0B3p0Yg13GMhTC3KF1bKhNcSIu1rQhPO /K675wNRWjVLjxaB6ZAS4cUoxPwb28FeP18= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a17:907:75c3:b0:94a:4c68:c1aa with SMTP id jl3-20020a17090775c300b0094a4c68c1aamr16788766ejc.7.1684355496096; Wed, 17 May 2023 13:31:36 -0700 (PDT) Date: Wed, 17 May 2023 20:31:18 +0000 In-Reply-To: <20230517203119.3160435-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230517203119.3160435-1-aliceryhl@google.com> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog Message-ID: <20230517203119.3160435-7-aliceryhl@google.com> Subject: [PATCH v1 6/7] rust: workqueue: add safe API to workqueue 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_Roy_Baron?= " , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED, USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1766174904451964809?= X-GMAIL-MSGID: =?utf-8?q?1766174904451964809?= This commit introduces `ArcWorkItem`, `BoxWorkItem`, and `define_work_adapter_newtype!` that make it possible to use the workqueue without any unsafe code whatsoever. The `ArcWorkItem` and `BoxWorkItem` traits are used when a struct has a single `work_struct` field. The `define_work_adapter_newtype!` macro is used when a struct has multiple `work_struct` fields. For each `work_struct` field, a newtype struct is defined that wraps `Arc`, and pushing an instance of the newtype to a workqueue will enqueue it using the associated `work_struct` field. The newtypes are matched with `work_struct` fields by having the T in `Work` be the newtype. Signed-off-by: Alice Ryhl --- rust/kernel/workqueue.rs | 332 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 331 insertions(+), 1 deletion(-) diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index 7509618af252..007005ddcaf0 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -4,8 +4,9 @@ //! //! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h) -use crate::{bindings, prelude::*, types::Opaque}; +use crate::{bindings, prelude::*, sync::Arc, types::Opaque}; use core::marker::{PhantomData, PhantomPinned}; +use core::result::Result; /// A kernel work queue. /// @@ -279,6 +280,335 @@ macro_rules! impl_has_work { )*}; } +/// Declares that [`Arc`] should implement [`WorkItem`]. +/// +/// # Examples +/// +/// The example below will make [`Arc`] implement the [`WorkItem`] trait so that you can +/// enqueue it in a workqueue. +/// +/// ``` +/// use kernel::sync::Arc; +/// +/// struct MyStruct { +/// work_field: Work>, +/// } +/// +/// kernel::impl_has_work! { +/// impl HasWork> for MyStruct { self.work_field } +/// } +/// +/// impl ArcWorkItem for MyStruct { +/// fn run(self: Arc) { +/// pr_info!("Executing MyStruct on a workqueue."); +/// } +/// } +/// ``` +/// +/// [`Arc`]: crate::sync::Arc +/// [`Arc`]: crate::sync::Arc +pub trait ArcWorkItem { + /// Called when this work item is executed. + fn run(self: Arc); +} + +unsafe impl WorkItem for Arc +where + T: ArcWorkItem + HasWork + ?Sized, +{ + type EnqueueOutput = Result<(), Self>; + + unsafe fn __enqueue(self, queue_work_on: F) -> Self::EnqueueOutput + where + F: FnOnce(*mut bindings::work_struct) -> bool, + { + let ptr = Arc::into_raw(self); + + // Using `get_work_offset` here for object-safety. + // + // SAFETY: The pointer is valid since we just got it from `into_raw`. + let off = unsafe { (&*ptr).get_work_offset() }; + + // SAFETY: The `HasWork` impl promises that this offset gives us a field of type + // `Work` in the same allocation. + let work_ptr = unsafe { (ptr as *const u8).add(off) as *const Work }; + // SAFETY: The pointer is not dangling. + let work_ptr = unsafe { Work::raw_get(work_ptr) }; + + match (queue_work_on)(work_ptr) { + true => Ok(()), + // SAFETY: The work queue has not taken ownership of the pointer. + false => Err(unsafe { Arc::from_raw(ptr) }), + } + } +} + +// Let `Work>` be usable with types that are `ArcWorkItem`. +// +// We do not allow unsized types here. The `Work>` field should always specify the actual +// concrete type stored in the `Arc`. +// +// SAFETY: The `Work>` field must be initialized with this `run` method because the `Work` +// struct prevents you from initializing it in any other way. The `__enqueue` trait uses the +// same `Work>` field because `HasWork` promises to always return the same field. +unsafe impl WorkItemAdapter for Arc +where + T: ArcWorkItem + HasWork + Sized, +{ + unsafe extern "C" fn run(ptr: *mut bindings::work_struct) { + // SAFETY: The `__enqueue` method always uses a `work_struct` stored in a `Work`. + let ptr = ptr as *mut Work; + // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`. + let ptr = unsafe { T::work_container_of(ptr) }; + // SAFETY: This pointer comes from `Arc::into_raw` and we've been given back ownership. + let arc = unsafe { Arc::from_raw(ptr) }; + + arc.run(); + } +} + +/// Declares that [`Pin`]`<`[`Box`]`>` should implement [`WorkItem`]. +/// +/// # Examples +/// +/// The example below will make [`Pin`]`<`[`Box`]`>` implement the [`WorkItem`] trait so +/// that you can enqueue it in a workqueue. +/// +/// ``` +/// struct MyStruct { +/// work_field: Work>>, +/// } +/// +/// kernel::impl_has_work! { +/// impl HasWork>> for MyStruct { self.work_field } +/// } +/// +/// impl BoxWorkItem for MyStruct { +/// fn run(self: Pin>) { +/// pr_info!("Executing MyStruct on a workqueue."); +/// } +/// } +/// ``` +/// +/// [`Box`]: alloc::boxed::Box +/// [`Pin`]: core::pin::Pin +pub trait BoxWorkItem { + /// Called when this work item is executed. + fn run(self: Pin>); +} + +unsafe impl WorkItem for Pin> +where + T: BoxWorkItem + HasWork + ?Sized, +{ + // When a box is in a workqueue, the workqueue has exclusive ownership of the box. Therefore, + // it's not possible to enqueue a box while it is in a workqueue. + type EnqueueOutput = (); + + unsafe fn __enqueue(self, queue_work_on: F) + where + F: FnOnce(*mut bindings::work_struct) -> bool, + { + // SAFETY: We will not used the contents in an unpinned manner. + let ptr = unsafe { Box::into_raw(Pin::into_inner_unchecked(self)) }; + + // Using `get_work_offset` here for object-safety. + // + // SAFETY: The pointer is valid since we just got it from `into_raw`. + let off = unsafe { (&*ptr).get_work_offset() }; + + // SAFETY: The `HasWork` impl promises that this offset gives us a field of type + // `Work` in the same allocation. + let work_ptr = unsafe { (ptr as *mut u8).add(off) as *mut Work }; + // SAFETY: The pointer is not dangling. + let work_ptr = unsafe { Work::raw_get(work_ptr) }; + + match (queue_work_on)(work_ptr) { + true => {} + // SAFETY: This method requires exclusive ownership of the box, so it cannot be in a + // workqueue. + false => unsafe { core::hint::unreachable_unchecked() }, + } + } +} + +// Let `Work>>` be usable with types that are `BoxWorkItem`. +// +// We do not allow unsized types here. The `Work>>` field should always specify the actual +// concrete type stored in the `Box`. +// +// SAFETY: The `Work>>` field must be initialized with this run method because the `Work` +// struct prevents you from initializing it in any other way. The `__enqueue` trait uses the +// same `Work>>` field because `HasWork` promises to always return the same field. +unsafe impl WorkItemAdapter for Pin> +where + T: BoxWorkItem + HasWork + Sized, +{ + unsafe extern "C" fn run(ptr: *mut bindings::work_struct) { + // SAFETY: The `__enqueue` method always uses a `work_struct` stored in a `Work`. + let ptr = ptr as *mut Work; + // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`. + let ptr = unsafe { T::work_container_of(ptr) }; + // SAFETY: This pointer comes from `Box::into_raw` and we've been given back ownership. + // The box was originally pinned, so pinning it again is ok. + let boxed = unsafe { Pin::new_unchecked(Box::from_raw(ptr)) }; + + boxed.run(); + } +} + +/// Helper macro for structs with several `Work` fields that can be in several queues at once. +/// +/// For each `Work` field in your type `T`, a newtype struct that wraps an `Arc` or +/// `Pin>` should be defined. +/// +/// # Examples +/// +/// ``` +/// struct MyStruct { +/// work1: Work, +/// work2: Work, +/// } +/// +/// impl_has_work! { +/// impl HasWork for MyStruct { self.work1 } +/// impl HasWork for MyStruct { self.work2 } +/// } +/// +/// define_work_adapter_newtype! { +/// struct MyStructWork1(Arc); +/// struct MyStructWork2(Arc); +/// } +/// +/// impl MyStructWork1 { +/// fn run(self) { +/// // ... +/// } +/// } +/// +/// impl MyStructWork2 { +/// fn run(self) { +/// // ... +/// } +/// } +/// ``` +/// +/// This will let you push a `MyStructWork1(arc)` or `MyStructWork2(arc)` to a work queue. The [`Arc`] +/// can be in two work queues at the same time, and the `run` method on the wrapper type is called +/// when the work item is called. +/// +/// [`Arc`]: crate::sync::Arc +#[macro_export] +macro_rules! define_work_adapter_newtype { + ( + $(#[$outer:meta])* + $pub:vis struct $name:ident( + $(#[$innermeta:meta])* + $fpub:vis Arc<$inner:ty> $(,)? + ); + $($rest:tt)* + ) => { + $(#[$outer])* + $pub struct $name($(#[$innermeta])* $fpub $crate::sync::Arc<$inner>); + + unsafe impl $crate::workqueue::WorkItem for $name { + type EnqueueOutput = ::core::result::Result<(), $name>; + + unsafe fn __enqueue(self, queue_work_on: F) -> Self::EnqueueOutput + where + F: ::core::ops::FnOnce(*mut $crate::bindings::work_struct) -> bool, + { + let ptr = $crate::sync::Arc::into_raw(self.0); + + // SAFETY: The pointer is not dangling since we just got it from Arc::into_raw. + let work_ptr = unsafe { <$inner as $crate::workqueue::HasWork::<$name>>::raw_get_work(ptr.cast_mut()) }; + + // SAFETY: The pointer is not dangling. + let work_ptr = unsafe { $crate::workqueue::Work::raw_get(work_ptr) }; + + match (queue_work_on)(work_ptr) { + true => Ok(()), + // SAFETY: The work queue has not taken ownership of the pointer. + false => Err($name(unsafe { $crate::sync::Arc::from_raw(ptr) })), + } + } + } + + unsafe impl $crate::workqueue::WorkItemAdapter for $name { + unsafe extern "C" fn run(ptr: *mut $crate::bindings::work_struct) { + // SAFETY: The `__enqueue` method always uses a `work_struct` stored in a `Work`. + let ptr = ptr as *mut $crate::workqueue::Work; + // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`. + let ptr = unsafe { <$inner as $crate::workqueue::HasWork::<$name>>::work_container_of(ptr) }; + // SAFETY: This pointer comes from `Arc::into_raw` and we've been given back ownership. + let arc = unsafe { $crate::sync::Arc::from_raw(ptr) }; + + $name::run($name(arc)); + } + } + + define_work_adapter_newtype! { $($rest)* } + }; + + ( + $(#[$outer:meta])* + $pub:vis struct $name:ident( + $(#[$innermeta:meta])* + $fpub:vis Pin> $(,)? + ); + $($rest:tt)* + ) => { + $(#[$outer])* + $pub struct $name($(#[$innermeta])* $fpub ::core::pin::Pin<::alloc::boxed::Box<$inner>>); + + unsafe impl $crate::workqueue::WorkItem for $name { + type EnqueueOutput = (); + + unsafe fn __enqueue(self, queue_work_on: F) + where + F: ::core::ops::FnOnce(*mut $crate::bindings::work_struct) -> bool, + { + // SAFETY: We will not used the contents in an unpinned manner. + let boxed = unsafe { ::core::pin::Pin::into_inner_unchecked(self.0) }; + let ptr = ::alloc::boxed::Box::into_raw(boxed); + + // SAFETY: The pointer is not dangling since we just got it from Box::into_raw. + let work_ptr = unsafe { <$inner as $crate::workqueue::HasWork::<$name>>::raw_get_work(ptr) }; + + // SAFETY: The pointer is not dangling. + let work_ptr = unsafe { $crate::workqueue::Work::raw_get(work_ptr) }; + + match (queue_work_on)(work_ptr) { + true => {}, + // SAFETY: This method requires exclusive ownership of the box, so it cannot be in a + // workqueue. + false => unsafe { ::core::hint::unreachable_unchecked() }, + } + } + } + + unsafe impl $crate::workqueue::WorkItemAdapter for $name { + unsafe extern "C" fn run(ptr: *mut $crate::bindings::work_struct) { + // SAFETY: The `__enqueue` method always uses a `work_struct` stored in a `Work`. + let ptr = ptr as *mut $crate::workqueue::Work; + // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`. + let ptr = unsafe { <$inner as $crate::workqueue::HasWork::<$name>>::work_container_of(ptr) }; + // SAFETY: This pointer comes from `Box::into_raw` and we've been given back ownership. + let boxed = unsafe { ::alloc::boxed::Box::from_raw(ptr) }; + // SAFETY: The box was originally pinned, so pinning it again is ok. + let boxed = unsafe { ::core::pin::Pin::new_unchecked(boxed) }; + + $name::run($name(boxed)); + } + } + + define_work_adapter_newtype! { $($rest)* } + }; + + // After processing the last definition, we call ourselves with no input. + () => {}; +} + /// Returns the system work queue (`system_wq`). /// /// It is the one used by `schedule[_delayed]_work[_on]()`. Multi-CPU multi-threaded. There are From patchwork Wed May 17 20:31:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alice Ryhl X-Patchwork-Id: 95543 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp37265vqo; Wed, 17 May 2023 13:34:21 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ6NLm1xnV2VdyPL6mj5cwd0lPVw8NNRT+Vpz2tWcDyoMAliir9UCMx50poOazG/3D3v7bPR X-Received: by 2002:a17:902:c410:b0:1ab:2034:26da with SMTP id k16-20020a170902c41000b001ab203426damr34263plk.51.1684355661575; Wed, 17 May 2023 13:34:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1684355661; cv=none; d=google.com; s=arc-20160816; b=TAP9GrT6EV5aBLCtGRXrBwr+2crILtmZJ970TbwbKlhWuJ+NYAtk4G7aBc33S0D5WG R5HqYfJ+itrEP8jqp2T/Tl3MjGlpMBVsf7lAibqRgZ6Ec5kh/OEclBsLN/RQLzcm1etL Xz5/HdT1T231J0NUJo79moPH09NA5z92ZzjaFGEQMhzkInq0bK/x0t3EmNyHK8Jnvk1n Xqmf/H3ELgt8Bi0e3V/auVyN+yqItcr+1jOsTVU28EgyKNh0tGJUy6xnZJJYi9Ao4EI2 nZkatUvceMBWtO3sw39OFmTlA2lSC4GpUsgpBFiInkNi3RR9Nicn668nWhnNwJeUgqbz DCxA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=jLXiUUyXZrTzMck4adUmLD4E9Fc4RhEDENIXEJkaNoM=; b=fgxdEWQM5l8HADmHNrN7KdFFPYAful+Vw7kBcrm7mZM7/bfVDc6mp4WlR304XaZ1z5 Wb7ZUxWWorz00c0hiHtKXlccCn3ONBGEqy9P4vCfQrpd4VIe6kS2fHT1/4u8HIow7sw5 g+AEBrXM+oibRIpaXd66v6VbPPuW+gicpwvEWDWOtnsX8+3hcDpqJyToydyFZCDJ4uUt /BGJHdUkiO5otC1pddd30WM67PVHZCpfsh8jDRRjirwF5c7f5wZ9lJKAY3ZA38EGoIDG 8AtfLao5gU7KewykFC1VEmMS+CLeZnB25GlD6m8clpxin8vHWyT4EfhwSpjPuZ0ZaOzu kSkA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=znudaE6I; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id c17-20020a170902d49100b0019b090e497esi23065539plg.298.2023.05.17.13.34.08; Wed, 17 May 2023 13:34:21 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=znudaE6I; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229882AbjEQUb7 (ORCPT + 99 others); Wed, 17 May 2023 16:31:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56910 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229829AbjEQUbr (ORCPT ); Wed, 17 May 2023 16:31:47 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ACFA29ED1 for ; Wed, 17 May 2023 13:31:39 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-ba2526a8918so2080886276.1 for ; Wed, 17 May 2023 13:31:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1684355498; x=1686947498; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=jLXiUUyXZrTzMck4adUmLD4E9Fc4RhEDENIXEJkaNoM=; b=znudaE6IMsPT1uZOZAWZvlBQ4z18gWvrpr8fQ4zqjHZn7//aWo6ZQ16KmYAioUALok 80CFBTCmDmR4fNUzZUBj27X6ZgckRry3Fu5AZp45GYmXV2veHpWjjyrtCSQoQqXfFt1B 4Ij33s7K67FQEiNQAKgTwoZzNOk6K5OasuA+WzfFmKEab16aipOvC9AC4a0oMtyQ6k7d 0k7oZtWs6TculeG1g/RbFchNLUWoLMWBAR5qgp3kvjsBryBPOkhTeRwWPYYZyfgxVK1t k9AxgpmoHL+5TCJq+1CuAf/e7QXSrYKn7oaL9C7P43K27eB9YFHabF88nKM/ykhEAczq 6k0Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684355498; x=1686947498; 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=jLXiUUyXZrTzMck4adUmLD4E9Fc4RhEDENIXEJkaNoM=; b=K8hHTwfyWIxauhLpxaamRzqk9tm0ixKHSXhkSziifubEmuJD3fZc2jJKuQ0RpztBGG Va400BwcA4IoKi2epqhY8b4c9JypzXApiF9krYS0HADNxTCTR6TLo0FYAwr2+WJ656wm BNTOc827PFx/diNw9euZx6i+QePXx6Y+VXtVWElgvBfYLKWi3vliVXmhKm2iz0wGVg4U eVjTM9xEhq48W4vPCbWfc3WfGJSaftLP6/FbhBC/3OKAaWYxJFe2W8krii0JgYrDvZzI gEbH1QRNlmFEaTNMLiXfASPDobz8BI++/ljNd7TfX6dox6E7zNDiYIy9LWieVvInSSFO JB9g== X-Gm-Message-State: AC+VfDzaxri4ag2XgD74N0YVMeSbN6+Q1WCTqEEQxieRzQGs55Kw+ap1 joYWqlztKibRQDXRo5sxBl9LqtB6OVcukl4= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a25:9309:0:b0:ba8:2e79:c193 with SMTP id f9-20020a259309000000b00ba82e79c193mr2630490ybo.12.1684355498779; Wed, 17 May 2023 13:31:38 -0700 (PDT) Date: Wed, 17 May 2023 20:31:19 +0000 In-Reply-To: <20230517203119.3160435-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230517203119.3160435-1-aliceryhl@google.com> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog Message-ID: <20230517203119.3160435-8-aliceryhl@google.com> Subject: [PATCH v1 7/7] 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_Roy_Baron?= " , Benno Lossin , Alice Ryhl , linux-kernel@vger.kernel.org, patches@lists.linux.dev X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_PDS_OTHER_BAD_TLD,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1766174922103618054?= X-GMAIL-MSGID: =?utf-8?q?1766174922103618054?= 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. Signed-off-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo --- rust/kernel/workqueue.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index 007005ddcaf0..303b72efd95f 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -57,6 +57,42 @@ impl Queue { }) } } + + /// 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) -> Result { + let init = pin_init!(ClosureWork { + work <- Work::new(), + func: Some(func), + }); + + self.enqueue(Box::pin_init(init)?); + 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 BoxWorkItem for ClosureWork { + fn run(mut self: Pin>) { + if let Some(func) = self.as_mut().project().take() { + (func)() + } + } } /// A work item. @@ -280,6 +316,10 @@ macro_rules! impl_has_work { )*}; } +impl_has_work! { + impl HasWork>> for ClosureWork { self.work } +} + /// Declares that [`Arc`] should implement [`WorkItem`]. /// /// # Examples