Received: by 2002:ab2:6816:0:b0:1f9:5764:f03e with SMTP id t22csp2604836lqo; Mon, 20 May 2024 10:29:52 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCW/nFufRDi3N4jm+LnATf4UlnBts0LJ+vfh3NRjxmSSSFCUtF3cpoghW6ZJii/vN4IzwTa5Map2IjF+5UjWSoA+SDoZhQZdUsD3EZ6jaA== X-Google-Smtp-Source: AGHT+IHNm7Rtnc1gRclRHGDqF9MmdIdAhesjV/aJpeUGKOmycZMLt/powv5QipUPJyb9u3AlQwqz X-Received: by 2002:ac8:57d5:0:b0:43d:f989:edbc with SMTP id d75a77b69052e-43dfdcd7457mr335994131cf.52.1716226191871; Mon, 20 May 2024 10:29:51 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1716226191; cv=pass; d=google.com; s=arc-20160816; b=F/U3xNnJK9y1XWh/ydM35Rk40EaRRUYyH4xQfeaXZkDRhG2ObB7zJiS+YP+4FFUww+ /2RH1mQhGO8UP4TAg+7MpUOqB8fmNOhtpbjFUejBY+Rrw9yLG0rU8+8+efsKJF5kyjTO 7uShsI31XHy/B/Mi3VmgAvDkUSgk2gnYAKjoSTIsPdqR6N9e9hksuypmIN3Wi63X2imc 2xp6ve9mcenUjQ8pREWrnv+jzuJ0lngNJ8npDG25QjhufsLl1E+n9OwlTbyKBj2AkLhH VQvlXHZ1fY64dy8dWvAUl0iWib2331vUjUoZsVb6mwucvpEqmDRw6v/hiMPFLHmK0026 K23g== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=1CsnJXGBZcLyYjfrlAMv2FyBTh8bc+Mt3a3EbW5Rnks=; fh=yoZmTq+bvCljNEZ+SeYiWnN2yd979HFDIh5d2AxJZ90=; b=qjqH727v/1MPx5y8D0suxlSfhCCXDHyXbAMmRRDp1RSqUKZ1DVeUHsHbq1rYx/DC0G 4FEWAG2M3cdlmRL1RW/8xKfSPuZ6XAkOwb0ffGdfy0X4LswRMsi2N1fIkXfhcd+NgXL4 TRidIRacqyY8LY9ANIxsIJozInxFixpyM+j4LoIiS/ljV7gvGS+bmNGgzqT2Ied3stJE VzIK3qDuZaIrsZLP0cSgh4/Mzny+P7nLO8uV3DmwoaCJog8Le6RkFkdHZCOufPojcusK TIcVc1P1sdQ4n35aJR75BR1Dt0J8sxTF0nzhd6IYdo0nEvq0bdLbDSN3SmFblMaz/mMs DY4Q==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=SvzrCzGo; arc=pass (i=1 spf=pass spfdomain=redhat.com dkim=pass dkdomain=redhat.com dmarc=pass fromdomain=redhat.com); spf=pass (google.com: domain of linux-kernel+bounces-184009-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-184009-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [2604:1380:45d1:ec00::1]) by mx.google.com with ESMTPS id d75a77b69052e-43df54b585esi108838951cf.215.2024.05.20.10.29.51 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 May 2024 10:29:51 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-184009-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) client-ip=2604:1380:45d1:ec00::1; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=SvzrCzGo; arc=pass (i=1 spf=pass spfdomain=redhat.com dkim=pass dkdomain=redhat.com dmarc=pass fromdomain=redhat.com); spf=pass (google.com: domain of linux-kernel+bounces-184009-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-184009-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 87F801C21894 for ; Mon, 20 May 2024 17:29:51 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 1BFCE137C3F; Mon, 20 May 2024 17:27:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="SvzrCzGo" Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6877D13A418 for ; Mon, 20 May 2024 17:27:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716226051; cv=none; b=kfS+En8/WnH6wj8oKGTNq19lXa8jopNSlHfHokjEdJUC41t18tAzX9AJYXbvQP2QXoFBX+JC+6phjM3mJdAeom8xpylAJr33KGKrgwsaHGzKVqiT1RutLuVcIenTKTSbruZdXInh9KaPM+f399EGZcqFrhpFcbBp1MYorMvKV04= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716226051; c=relaxed/simple; bh=Pf+OOnuHz5mcZsGqaVhIEIMHurAZcjaBobj/NJHA3CI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MlfV8YKP9TT4wb7nqTJLfgrzw57LTsXxUs73Vw4k03KHqzqjyZHBWrtKEFq862/0IkcnMNRSK9p1xDAH/34tKZSuPxZEGhypruHqpk/P0ii7ZBNVvXb3pavEtqRJo/RqM5avHvY4HSYOAbLlpE8xg3vx11SsJqmGw0JnlvTwqy8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=SvzrCzGo; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716226048; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1CsnJXGBZcLyYjfrlAMv2FyBTh8bc+Mt3a3EbW5Rnks=; b=SvzrCzGo9wb2DXXlFn5leFcfH0Ok8ax85GHnujv3sSaCXzxc3fWYxmyILkAFDSveCfq+iU A1TwcOIIArL8YwJdMh1bPX9pIykLt/VPoZjbgRY8Vvgjt47mvAtXLQmN050AbjHfibPAsx ZR/IFYijSgZl+lY4rhFyrusppqWZlKs= Received: from mail-lj1-f198.google.com (mail-lj1-f198.google.com [209.85.208.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-628-Gp4t6pQcOKab6F_be5iwVg-1; Mon, 20 May 2024 13:27:26 -0400 X-MC-Unique: Gp4t6pQcOKab6F_be5iwVg-1 Received: by mail-lj1-f198.google.com with SMTP id 38308e7fff4ca-2e3208c29abso103894141fa.2 for ; Mon, 20 May 2024 10:27:26 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716226045; x=1716830845; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=1CsnJXGBZcLyYjfrlAMv2FyBTh8bc+Mt3a3EbW5Rnks=; b=TOImeyVpe0RVKgP6uHsnGm3dFCxtc0EjKq+qjHfkexAgQ40uY2ab/tzg3CMDnsT4lo poHTpx5vWzioAn1/qOS0hc5qEG3L9FGKebkvlNUUsvOmHH+2WZD2vAGw4ui8hEToEjtu rJ3vqCBpoD62G9+sTsUxmKxwR9EXIdEI/A/ZGqvZU/tSKDw8c78FiZ+kbnxBBE3PRiYR l/RVYNhRSOxDOEtCS8l79cioWBJcu45hB5qxhBWWlpSXycLK7X/BQKqC+13/oHjTHeb/ WEteUbrKjuuhgL22Bzb9Z3KcK+45NmQAxtlaDjelTd5okTxoUycVj2kvc04dXpjz8Gsy fLYg== X-Forwarded-Encrypted: i=1; AJvYcCUzQwwt4GWLl6FMn6QMhs/0g527GMYmS30/mB2jSkshruuc3ZIeX4A6l86BiW1CdER9T6+e9D9zClVSu6qxRdKGcZy+dBbzV6w/K9RI X-Gm-Message-State: AOJu0YyjYP93EL6J1PHwXhrALob0YepZ8+JAazXqdN+SSEsw/fre15Fi exixOEMHEl4X4tPGPH0Pp5bUP7AUa7BpqTdvPmIr7Ge8PZT0e++fsOMQ6P30rfuG+MuYBFcTjt8 fzHh8+QTF9UnyhC/Ta3ZnClechu74eyYMdVHrZCikKP/ujmsXEI++4Wf9IMwbCA== X-Received: by 2002:a2e:be9f:0:b0:2e3:ba0e:de12 with SMTP id 38308e7fff4ca-2e51ff5cf48mr319538881fa.22.1716226045291; Mon, 20 May 2024 10:27:25 -0700 (PDT) X-Received: by 2002:a2e:be9f:0:b0:2e3:ba0e:de12 with SMTP id 38308e7fff4ca-2e51ff5cf48mr319538611fa.22.1716226044936; Mon, 20 May 2024 10:27:24 -0700 (PDT) Received: from cassiopeiae.. ([2a02:810d:4b3f:ee94:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-42009eda143sm363816305e9.14.2024.05.20.10.27.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 May 2024 10:27:24 -0700 (PDT) From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, bhelgaas@google.com, ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@samsung.com, aliceryhl@google.com, airlied@gmail.com, fujita.tomonori@gmail.com, lina@asahilina.net, pstanner@redhat.com, ajanulgu@redhat.com, lyude@redhat.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, Danilo Krummrich Subject: [RFC PATCH 08/11] rust: add devres abstraction Date: Mon, 20 May 2024 19:25:45 +0200 Message-ID: <20240520172554.182094-9-dakr@redhat.com> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240520172554.182094-1-dakr@redhat.com> References: <20240520172554.182094-1-dakr@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Add a Rust abstraction for the kernel's devres (device resource management) implementation. The Devres type acts as a container to manage the lifetime and accessibility of device bound resources. Therefore it registers a devres callback and revokes access to the resource on invocation. Users of the Devres abstraction can simply free the corresponding resources in their Drop implementation, which is invoked when either the Devres instance goes out of scope or the devres callback leads to the resource being revoked, which implies a call to drop_in_place(). Co-developed-by: Philipp Stanner Signed-off-by: Philipp Stanner Signed-off-by: Danilo Krummrich --- rust/helpers.c | 5 ++ rust/kernel/devres.rs | 151 ++++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 3 files changed, 157 insertions(+) create mode 100644 rust/kernel/devres.rs diff --git a/rust/helpers.c b/rust/helpers.c index 1d3e800140fc..34061eca05a0 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -173,6 +173,11 @@ void rust_helper_rcu_read_unlock(void) EXPORT_SYMBOL_GPL(rust_helper_rcu_read_unlock); /* end rcu */ +int rust_helper_devm_add_action(struct device *dev, void (*action)(void *), void *data) +{ + return devm_add_action(dev, action, data); +} + /* * `bindgen` binds the C `size_t` type as the Rust `usize` type, so we can * use it in contexts where Rust expects a `usize` like slice (array) indices. diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs new file mode 100644 index 000000000000..bf7bd304cd9b --- /dev/null +++ b/rust/kernel/devres.rs @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Devres abstraction +//! +//! [`Devres`] represents an abstraction for the kernel devres (device resource management) +//! implementation. + +use crate::{ + alloc::Flags, + bindings, + device::Device, + error::{Error, Result}, + prelude::*, + revocable::Revocable, + types::ARef, +}; + +use core::ffi::c_void; +use core::ops::Deref; + +#[pin_data] +struct DevresInner { + dev: ARef, + #[pin] + data: Revocable, +} + +/// This abstraction is meant to be used by subsystems to containerize [`Device`] bound resources to +/// manage their lifetime. +/// +/// [`Device`] bound resources should be freed when either the resource goes out of scope or the +/// [`Device`] is unbound respectively, depending on what happens first. +/// +/// To achieve that [`Devres`] registers a devres callback on creation, which is called once the +/// [`Device`] is unbound, revoking access to the encapsulated resource (see also [`Revocable`]). +/// +/// After the [`Devres`] has been unbound it is not possible to access the encapsulated resource +/// anymore. +/// +/// [`Devres`] users should make sure to simply free the corresponding backing resource in `T`'s +/// [`Drop`] implementation. +/// +/// # Example +/// +/// ``` +/// use kernel::devres::Devres; +/// +/// // See also [`pci::Bar`] for a real example. +/// struct IoRemap(IoMem); +/// +/// impl IoRemap { +/// fn new(usize paddr, usize len) -> Result{ +/// // assert success +/// let addr = unsafe { bindings::ioremap(paddr as _); }; +/// let iomem = IoMem::new(addr, len)?; +/// +/// Ok(IoRemap(iomem)) +/// } +/// } +/// +/// impl Drop for IoRemap { +/// fn drop(&mut self) { +/// unsafe { bindings::iounmap(self.0.ioptr as _); }; +/// } +/// } +/// +/// impl Deref for IoRemap { +/// type Target = IoMem; +/// +/// fn deref(&self) -> &Self::Target { +/// &self.0 +/// } +/// } +/// +/// let devres = Devres::new(dev, IoRemap::new(0xBAAAAAAD, 0x4)?, GFP_KERNEL)?; +/// +/// let res = devres.try_access().ok_or(ENXIO)?; +/// res.writel(0xBAD); +/// ``` +/// +pub struct Devres { + inner: Pin>>, + callback: unsafe extern "C" fn(*mut c_void), +} + +impl DevresInner { + fn as_ptr(&self) -> *const DevresInner { + self as *const DevresInner + } + + fn as_cptr(&self) -> *mut c_void { + self.as_ptr() as *mut c_void + } +} + +unsafe extern "C" fn devres_callback(inner: *mut c_void) { + let inner = inner as *const DevresInner; + let inner = unsafe { &*inner }; + + inner.data.revoke(); +} + +impl Devres { + /// Creates a new [`Devres`] instance of the give data. + pub fn new(dev: ARef, data: T, flags: Flags) -> Result { + let callback = devres_callback::; + + let inner = Box::pin_init( + pin_init!( DevresInner { + dev: dev, + data <- Revocable::new(data), + }), + flags, + )?; + + let ret = unsafe { + bindings::devm_add_action(inner.dev.as_raw(), Some(callback), inner.as_cptr()) + }; + + if ret != 0 { + return Err(Error::from_errno(ret)); + } + + // We have to store the exact callback function pointer used with + // `bindings::devm_add_action` for `bindings::devm_remove_action`. There compiler might put + // multiple definitions of `devres_callback` for the same `T` in both the kernel itself + // and modules. Hence, we might see different pointer values depending on whether we look + // at `devres_callback`'s address from `Devres::new` or `Devres::drop`. + Ok(Devres { inner, callback }) + } +} + +impl Deref for Devres { + type Target = Revocable; + + fn deref(&self) -> &Self::Target { + &self.inner.data + } +} + +impl Drop for Devres { + fn drop(&mut self) { + unsafe { + bindings::devm_remove_action( + self.inner.dev.as_raw(), + Some(self.callback), + self.inner.as_cptr(), + ) + } + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index d7d415429517..11645060b444 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -30,6 +30,7 @@ pub mod alloc; mod build_assert; pub mod device; +pub mod devres; pub mod driver; pub mod error; pub mod init; -- 2.45.1