From patchwork Fri Feb 7 13:58:24 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamir Duberstein X-Patchwork-Id: 13965030 X-Patchwork-Delegate: bhelgaas@google.com Received: from mail-qk1-f172.google.com (mail-qk1-f172.google.com [209.85.222.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 48EA61F76BD; Fri, 7 Feb 2025 13:58:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738936732; cv=none; b=iKa+sMylBHeS9684Jh1LTvp1SnmkSxNAB/zS2ThDsdvAfIc406jATQzCqYcZTtekCxQTRjiMxZ3k90gUuiVnp9eKdle93gCha/63KJDG6z5uNcrT1WwEtUdZLEUoW/fNSZybqbVT3eVOVscOmc6EUAcwPtIUXlV5sKlFTNQt3To= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738936732; c=relaxed/simple; bh=U+Qc9yDzlFcfSbcLQ8+EjkelL/BGK5QZfWUtRfyC07w=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=raSeSXfZXHmFgiFCH61kNUb+LN57TsM4gNtYhQDMY9OpsukNzgDtDdJRfurU9BvT7MsCYGed5Ky4zqWAPFCus4BcrjOb940BPl2j6pOyXT/Drhr8UG1JXLo2adcy7fzVUZ+8aouqRYS+Jtjgnm8T1Rurz4stNg+i5pLqK7LPJuk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ja+rTEGt; arc=none smtp.client-ip=209.85.222.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ja+rTEGt" Received: by mail-qk1-f172.google.com with SMTP id af79cd13be357-7bcf32a6582so188826085a.1; Fri, 07 Feb 2025 05:58:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1738936730; x=1739541530; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=iVCZw/m2XLPWza3hqEAZhBT+UfWA+IsYv3mZHv/oOJc=; b=ja+rTEGtkrxVEVe0ekX5lOJqEx5U+1g8xsJsNJ5c6CtxTzUDg0c87jX6wM94PvvQp3 /sOzUxWN+va6jyUtvkqOgwk99cguAx1M47Js0BD5EjLypzmCBIshBkdk57tWSVNfa0XQ G6aI1T61qNpTMCX4OcHsDNnFpWC/0AfBcRhE24gsZpusETuu54IFRoC1vU1sK1CS+RKA p+7MgA0BUjN4QkEtD+W1hxHpASug9LfIc6iJCboNwtC1vqtaAH55xr7PDl1dqdTIRdMq IDPo3C9oZsWDr1rUaLpO2No/00CNGZ7lhrviA82T1P0AdqzG1KEyR/4YJCJOBhrizuIB 9mbg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738936730; x=1739541530; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=iVCZw/m2XLPWza3hqEAZhBT+UfWA+IsYv3mZHv/oOJc=; b=kPkSa2wAro4NlSvZVIK98Ieo8dZcuX9vKBLkE1Ds4KT4yFkhQBZYZxD+EW+u4MDvhT JKc7tao6OHtm05C0OkuoZ2Wu9lkJUTtJ6vNDVi0mFVBW4+07S8AyLbcm3AsTuJ3+5H+f BWV07lENcfJP6//satflAVzPljLx/xGbbC3p/M3n+l2b8CplTwEcnl8Uxl9nlorpxSNR K38yy/kaaA0XBsiV0kcXVVq7BHjGoWehuSaLO4hhuN2RcZsvG0Xon2/O/onFWElPWYaN XO102rq5EfXl7xyXX201setqrYpCtwkvuCFPOof56coYl0D4YAmSUXuk0tq5AJTUfSh+ K1Cg== X-Forwarded-Encrypted: i=1; AJvYcCWGOxrgtxuMfNDz4VT94TQn9OpiTqjkHdbFxcCIeBtbMFIGKo/92u9rVMOz4EXQLkCqz7/7nU9noUuqbnjpeFs=@vger.kernel.org, AJvYcCWqOqaiH5pk6RufhAMTF6mkbR+tuPtRzizQpOCw/DqD7Y7ST8DAyt5PoT/5+hFgDPKYLLAUK17zpvAi1lNF@vger.kernel.org, AJvYcCXxF97A9Mi7i7FRuufRv8M5Iq2Hfn/w4e3/JFUrPVuIKU3ZM9uFLghrjRbRL7nDoU1d52m0SQIxTClmQJuQ@vger.kernel.org, AJvYcCXys4sSCo5au/rWdhEGAktLc2jcd178JLN5be4dsduDi2AcaD0dEMcNZkCp37iuyi3+vL6FagJB3jjg@vger.kernel.org X-Gm-Message-State: AOJu0YwxRVmRpS0quvRGkPhMQHMkP8u6oCTK5vkW5pwrik5AtARP5P05 jnVW57Tgwdgf9qiHRoj6dvwL37osgLbtyfk1nuICGDr/3aSPzvxM X-Gm-Gg: ASbGnct/JJNvEUN+D0azm5INb6EY5F1Ckrs4OddVjosLdLTvLFPuCjybVkXQ87jpgb8 KkugF06F7/whN3Mq0CuJnkql/E9CHvfHGp8wY/zwxciRjNVV7CXUKZTuO8T+mSRUYZdQgxxem5V 2KAUEquRmk3IXq+wVQoGq6cQphArg0hc9H3ITBJ+oxlXKpCfuRU18rbtCEh7mvi8kNuqww49mBM 3RiTxe8+w3qvnpobzXwnDd4e5nHorn21TPZDz07R0gfSk0vm8SdSKhrV8/bo9JrMIgdFsNKjIh+ 3klOx5YQvCcqyDFdQBMBhtqxFRewajc3FO8= X-Google-Smtp-Source: AGHT+IGmLVkr5MZzrT5HfwPcZT9faF46dg2WAfvnxPktSkECPMwgcRbLtUhoPVu2iNld0LYucSIViw== X-Received: by 2002:a05:620a:270c:b0:7b6:dc4f:8879 with SMTP id af79cd13be357-7c047c97716mr601107285a.47.1738936730013; Fri, 07 Feb 2025 05:58:50 -0800 (PST) Received: from [192.168.1.159] ([2600:4041:5be7:7c00:fb:aded:686f:8a03]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7c041e11d19sm191919685a.52.2025.02.07.05.58.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 05:58:49 -0800 (PST) From: Tamir Duberstein Date: Fri, 07 Feb 2025 08:58:24 -0500 Subject: [PATCH v16 1/4] rust: remove redundant `as _` casts Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250207-rust-xarray-bindings-v16-1-256b0cf936bd@gmail.com> References: <20250207-rust-xarray-bindings-v16-0-256b0cf936bd@gmail.com> In-Reply-To: <20250207-rust-xarray-bindings-v16-0-256b0cf936bd@gmail.com> To: Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Matthew Wilcox , Bjorn Helgaas , Greg Kroah-Hartman , "Rafael J. Wysocki" , Tamir Duberstein , FUJITA Tomonori , "Rob Herring (Arm)" Cc: =?utf-8?q?Ma=C3=ADra_Canal?= , Asahi Lina , rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org X-Mailer: b4 0.15-dev Remove redundant casts added in commit 1bd8b6b2c5d3 ("rust: pci: add basic PCI device / driver abstractions") and commit 683a63befc73 ("rust: platform: add basic platform device / driver abstractions") While I'm churning this line, move the `.into_foreign()` call to its own statement to avoid churn in the next commit which adds a `.cast()` call. Fixes: 1bd8b6b2c5d3 ("rust: pci: add basic PCI device / driver abstractions") Fixes: 683a63befc73 ("rust: platform: add basic platform device / driver abstractions") Signed-off-by: Tamir Duberstein --- rust/kernel/pci.rs | 3 ++- rust/kernel/platform.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 4c98b5b9aa1e..6c3bc14b42ad 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -72,10 +72,11 @@ extern "C" fn probe_callback( match T::probe(&mut pdev, info) { Ok(data) => { + let data = data.into_foreign(); // Let the `struct pci_dev` own a reference of the driver's private data. // SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a // `struct pci_dev`. - unsafe { bindings::pci_set_drvdata(pdev.as_raw(), data.into_foreign() as _) }; + unsafe { bindings::pci_set_drvdata(pdev.as_raw(), data) }; } Err(err) => return Error::to_errno(err), } diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 50e6b0421813..dea104563fa9 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -63,10 +63,11 @@ extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ff let info = ::id_info(pdev.as_ref()); match T::probe(&mut pdev, info) { Ok(data) => { + let data = data.into_foreign(); // Let the `struct platform_device` own a reference of the driver's private data. // SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a // `struct platform_device`. - unsafe { bindings::platform_set_drvdata(pdev.as_raw(), data.into_foreign() as _) }; + unsafe { bindings::platform_set_drvdata(pdev.as_raw(), data) }; } Err(err) => return Error::to_errno(err), } From patchwork Fri Feb 7 13:58:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamir Duberstein X-Patchwork-Id: 13965031 X-Patchwork-Delegate: bhelgaas@google.com Received: from mail-qk1-f178.google.com (mail-qk1-f178.google.com [209.85.222.178]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7A1E3217677; Fri, 7 Feb 2025 13:58:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738936736; cv=none; b=GoSetGRAnbWPT8EVCpSmFMbymWB4C6tWWUPh+vXHTuM4biUbLSh0/zfHqnGjl1+3Q2tcYRDTABB2fobZ7t67gvQ8tjAMRsRYPnpuWNiRoVeZ8Xh7tGFNivSDpDQ+a5EiPfdFPHWPilwsovSI1Nf+R88LQfXG5V+noQyQa8fYID8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738936736; c=relaxed/simple; bh=cu7D2/Qs6KXy57zpFyny/6cGYI1MldqmQ+blXbEdjJE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=IZlotaDvGnr3F0IwZX8EkB4xyzkW4TC+BQCdl+8VnmDkKM95DInLdy4QvUSmbWypckUHPeUdM1V2TqcpqKP3Wz54zsQT5k2SZ9EzhnclQ6lz9QQ0HyoXZ0k4uV6eG7439QPClwvv89oyecKkM4QXudSX/ocoN3pWqMm4Tc6ThB0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=g9VKshG2; arc=none smtp.client-ip=209.85.222.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="g9VKshG2" Received: by mail-qk1-f178.google.com with SMTP id af79cd13be357-7b8618be68bso186084585a.3; Fri, 07 Feb 2025 05:58:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1738936733; x=1739541533; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=wk48mehN2EwmM7wL9qjrdY9UE3XSglPAw8iFr6BiKdo=; b=g9VKshG28Rz8SNPzAi1uYCClFNczoJiVj/mwCswO8yfkwmlj4b/2xA2u6ZwYT/TO/N m2ZBPSjVQq2AtqV7P61iNwGf4ievju8UbG53Jm+wpB4YAbRnuUrBES0wkKq2YLPuRQJL hdp0kHeGbb91SiL2coAUzG4xzu3lSZ33trp/zTZstEWVHV3VKutISH+7qdp656cbci5e 4kdzeXaDrPYbHPo3ZAFLd5OHtKzVdoxecTpEKrCQf5aBbYoGUhYyLLsSa8p1KgLa3qM0 BTmqLAozpLL0J2LcKf0aED4jR9sHtqgEDDkYvJdOnhZ9KusV9oeIBxh+KZcXtmFvjXIg o0AA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738936733; x=1739541533; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=wk48mehN2EwmM7wL9qjrdY9UE3XSglPAw8iFr6BiKdo=; b=k/cx6k1xzEjS5IChsPVzpAw2Tvf6i9vNz3494rWaHgzGz0uHOZVkYzpzH1IhddEVj2 gH3fE+e7fqvK933FmNjwHRgVAoOWuq/kUfxq5lkAGEQEgt1Ekr3enGQv7qhDJyvCA/Na KBC44VzhTAKLLrcipMGv+DhLDtMe3ic1zPyNFWpdnRlYIRj4JiUThSi26ED3mxSabKP/ d61XlShg8Z72vFaGY1ybhi7BzQbdQbYzWieJ2/CY+S91KQFWCfX9JWKQrNEYdDvxQYEP 9B5SwlY1azTy71ZfSF3uOPjIv4tMw5y1mLPP4t7xf8fzZJ4LTZQB0iAvlGCqWevdIYQ6 tF7Q== X-Forwarded-Encrypted: i=1; AJvYcCUSG/ptcfWY9iTuy2ngztCLXDEU7AolCmltgB61K3Qs0UFpvPpsCuD7Kx9PrIt0OqLr1LyTn4Hda4/eGL2o@vger.kernel.org, AJvYcCUwlHieDBpNywzzx/nhfJKexM9JysnhI+/S0iRRBe25MJgZ36dtVRtl+7KFEHqTH7RZ8kqzqx46ujUuCe9T@vger.kernel.org, AJvYcCVgcRKhNyIC/GiiL+y2Vz5BGgvUsqvJEEjlvzn2lWLKu5pLGa/iV3LFfFPPZxaQq2cyQq8QutZ5JFKea1z3KIo=@vger.kernel.org, AJvYcCXgR02GtYi8ZCql5sbHdrdg4gkdw+rzI6XRW7FMlTIqeuJAkwo1/NoDc6kjSQZu9p3tRz5u0hUH6U3Y@vger.kernel.org X-Gm-Message-State: AOJu0YxOGakmUd2LS7avgQVp2c9XJV73zZfLc0PvNzNhLTvywbyrWSEZ GpR4Kn4tvZ39tW9BmjxXztlddPKp/NM9bPT87XllqoCN0TpwslOP X-Gm-Gg: ASbGncsktt5xapFC7FyktWM733lUKovM80C4cC1+yxLVDHLExbfLkwsCaP4Azqu5FIP IWIv0L+Bnknx4khobrOGPwHMQmWXyYZCWgXbWmsoZMUdjjPeybKrYnL8+E0sTK7rr9nOu6+weZb b8VzZQ+BSiFoOdo7l6nnS8edhc677pitwel/6h7EihXnn1cOi8YGNrZ30qUrw8rh8/XoqZCxiz5 6Zhxu1nixN2sG1SF1+iWVqF6p3Vgk1BXJ4jO+9BKtUHjcoVVkb1aKboiUV85WLbjdZpvLVBNmnN z+mNhjk59LChuBE+oYtR6+KmtOu3AAdpCK8= X-Google-Smtp-Source: AGHT+IEYr2VH2zbdoE4S3LObPk2XDspgJuoqbJJGa+H8Wc8SaHuHLa2q7r/bd4B35qRRaMb+9/HDpg== X-Received: by 2002:a05:620a:2848:b0:7b6:6e7c:8efc with SMTP id af79cd13be357-7c047c78558mr502039185a.44.1738936733071; Fri, 07 Feb 2025 05:58:53 -0800 (PST) Received: from [192.168.1.159] ([2600:4041:5be7:7c00:fb:aded:686f:8a03]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7c041e11d19sm191919685a.52.2025.02.07.05.58.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 05:58:51 -0800 (PST) From: Tamir Duberstein Date: Fri, 07 Feb 2025 08:58:25 -0500 Subject: [PATCH v16 2/4] rust: types: add `ForeignOwnable::PointedTo` Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250207-rust-xarray-bindings-v16-2-256b0cf936bd@gmail.com> References: <20250207-rust-xarray-bindings-v16-0-256b0cf936bd@gmail.com> In-Reply-To: <20250207-rust-xarray-bindings-v16-0-256b0cf936bd@gmail.com> To: Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Matthew Wilcox , Bjorn Helgaas , Greg Kroah-Hartman , "Rafael J. Wysocki" , Tamir Duberstein , FUJITA Tomonori , "Rob Herring (Arm)" Cc: =?utf-8?q?Ma=C3=ADra_Canal?= , Asahi Lina , rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, Fiona Behrens X-Mailer: b4 0.15-dev Allow implementors to specify the foreign pointer type; this exposes information about the pointed-to type such as its alignment. This requires the trait to be `unsafe` since it is now possible for implementors to break soundness by returning a misaligned pointer. Encoding the pointer type in the trait (and avoiding pointer casts) allows the compiler to check that implementors return the correct pointer type. This is preferable to directly encoding the alignment in the trait using a constant as the compiler would be unable to check it. Reviewed-by: Alice Ryhl Reviewed-by: Andreas Hindborg Reviewed-by: Fiona Behrens Signed-off-by: Tamir Duberstein --- rust/kernel/alloc/kbox.rs | 38 ++++++++++++++++++++------------------ rust/kernel/miscdevice.rs | 7 ++++++- rust/kernel/pci.rs | 2 ++ rust/kernel/platform.rs | 2 ++ rust/kernel/sync/arc.rs | 21 ++++++++++++--------- rust/kernel/types.rs | 46 +++++++++++++++++++++++++++++++--------------- 6 files changed, 73 insertions(+), 43 deletions(-) diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index cb4ebea3b074..55529832db54 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -349,68 +349,70 @@ fn try_init(init: impl Init, flags: Flags) -> Result } } -impl ForeignOwnable for Box +// SAFETY: The `into_foreign` function returns a pointer that is well-aligned. +unsafe impl ForeignOwnable for Box where A: Allocator, { + type PointedTo = T; type Borrowed<'a> = &'a T; type BorrowedMut<'a> = &'a mut T; - fn into_foreign(self) -> *mut crate::ffi::c_void { - Box::into_raw(self).cast() + fn into_foreign(self) -> *mut Self::PointedTo { + Box::into_raw(self) } - unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - unsafe { Box::from_raw(ptr.cast()) } + unsafe { Box::from_raw(ptr) } } - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> &'a T { + unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> &'a T { // SAFETY: The safety requirements of this method ensure that the object remains alive and // immutable for the duration of 'a. - unsafe { &*ptr.cast() } + unsafe { &*ptr } } - unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> &'a mut T { - let ptr = ptr.cast(); + unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> &'a mut T { // SAFETY: The safety requirements of this method ensure that the pointer is valid and that // nothing else will access the value for the duration of 'a. unsafe { &mut *ptr } } } -impl ForeignOwnable for Pin> +// SAFETY: The `into_foreign` function returns a pointer that is well-aligned. +unsafe impl ForeignOwnable for Pin> where A: Allocator, { + type PointedTo = T; type Borrowed<'a> = Pin<&'a T>; type BorrowedMut<'a> = Pin<&'a mut T>; - fn into_foreign(self) -> *mut crate::ffi::c_void { + fn into_foreign(self) -> *mut Self::PointedTo { // SAFETY: We are still treating the box as pinned. - Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }).cast() + Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }) } - unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - unsafe { Pin::new_unchecked(Box::from_raw(ptr.cast())) } + unsafe { Pin::new_unchecked(Box::from_raw(ptr)) } } - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Pin<&'a T> { + unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> Pin<&'a T> { // SAFETY: The safety requirements for this function ensure that the object is still alive, // so it is safe to dereference the raw pointer. // The safety requirements of `from_foreign` also ensure that the object remains alive for // the lifetime of the returned value. - let r = unsafe { &*ptr.cast() }; + let r = unsafe { &*ptr }; // SAFETY: This pointer originates from a `Pin>`. unsafe { Pin::new_unchecked(r) } } - unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> Pin<&'a mut T> { - let ptr = ptr.cast(); + unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> Pin<&'a mut T> { // SAFETY: The safety requirements for this function ensure that the object is still alive, // so it is safe to dereference the raw pointer. // The safety requirements of `from_foreign` also ensure that the object remains alive for diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index e14433b2ab9d..f1a081dd64c7 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -225,13 +225,15 @@ impl VtableHelper { Ok(ptr) => ptr, Err(err) => return err.to_errno(), }; + let ptr = ptr.into_foreign(); + let ptr = ptr.cast(); // This overwrites the private data with the value specified by the user, changing the type of // this file's private data. All future accesses to the private data is performed by other // fops_* methods in this file, which all correctly cast the private data to the new type. // // SAFETY: The open call of a file can access the private data. - unsafe { (*raw_file).private_data = ptr.into_foreign() }; + unsafe { (*raw_file).private_data = ptr }; 0 } @@ -246,6 +248,7 @@ impl VtableHelper { ) -> c_int { // SAFETY: The release call of a file owns the private data. let private = unsafe { (*file).private_data }; + let private = private.cast(); // SAFETY: The release call of a file owns the private data. let ptr = unsafe { ::from_foreign(private) }; @@ -267,6 +270,7 @@ impl VtableHelper { ) -> c_long { // SAFETY: The ioctl call of a file can access the private data. let private = unsafe { (*file).private_data }; + let private = private.cast(); // SAFETY: Ioctl calls can borrow the private data of the file. let device = unsafe { ::borrow(private) }; @@ -316,6 +320,7 @@ impl VtableHelper { ) { // SAFETY: The release call of a file owns the private data. let private = unsafe { (*file).private_data }; + let private = private.cast(); // SAFETY: Ioctl calls can borrow the private data of the file. let device = unsafe { ::borrow(private) }; // SAFETY: diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 6c3bc14b42ad..eb25fabbff9c 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -73,6 +73,7 @@ extern "C" fn probe_callback( match T::probe(&mut pdev, info) { Ok(data) => { let data = data.into_foreign(); + let data = data.cast(); // Let the `struct pci_dev` own a reference of the driver's private data. // SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a // `struct pci_dev`. @@ -88,6 +89,7 @@ extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) { // SAFETY: The PCI bus only ever calls the remove callback with a valid pointer to a // `struct pci_dev`. let ptr = unsafe { bindings::pci_get_drvdata(pdev) }; + let ptr = ptr.cast(); // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index dea104563fa9..53764cb7f804 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -64,6 +64,7 @@ extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ff match T::probe(&mut pdev, info) { Ok(data) => { let data = data.into_foreign(); + let data = data.cast(); // Let the `struct platform_device` own a reference of the driver's private data. // SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a // `struct platform_device`. @@ -78,6 +79,7 @@ extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ff extern "C" fn remove_callback(pdev: *mut bindings::platform_device) { // SAFETY: `pdev` is a valid pointer to a `struct platform_device`. let ptr = unsafe { bindings::platform_get_drvdata(pdev) }; + let ptr = ptr.cast(); // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 3cefda7a4372..dfe4abf82c25 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -140,9 +140,10 @@ pub struct Arc { _p: PhantomData>, } +#[doc(hidden)] #[pin_data] #[repr(C)] -struct ArcInner { +pub struct ArcInner { refcount: Opaque, data: T, } @@ -342,18 +343,20 @@ pub fn into_unique_or_drop(self) -> Option>> { } } -impl ForeignOwnable for Arc { +// SAFETY: The `into_foreign` function returns a pointer that is well-aligned. +unsafe impl ForeignOwnable for Arc { + type PointedTo = ArcInner; type Borrowed<'a> = ArcBorrow<'a, T>; type BorrowedMut<'a> = Self::Borrowed<'a>; - fn into_foreign(self) -> *mut crate::ffi::c_void { - ManuallyDrop::new(self).ptr.as_ptr().cast() + fn into_foreign(self) -> *mut Self::PointedTo { + ManuallyDrop::new(self).ptr.as_ptr() } - unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - let inner = unsafe { NonNull::new_unchecked(ptr.cast::>()) }; + let inner = unsafe { NonNull::new_unchecked(ptr) }; // SAFETY: By the safety requirement of this function, we know that `ptr` came from // a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and @@ -361,17 +364,17 @@ unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { unsafe { Self::from_inner(inner) } } - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T> { + unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> ArcBorrow<'a, T> { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - let inner = unsafe { NonNull::new_unchecked(ptr.cast::>()) }; + let inner = unsafe { NonNull::new_unchecked(ptr) }; // SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive // for the lifetime of the returned value. unsafe { ArcBorrow::new(inner) } } - unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T> { + unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> ArcBorrow<'a, T> { // SAFETY: The safety requirements for `borrow_mut` are a superset of the safety // requirements for `borrow`. unsafe { Self::borrow(ptr) } diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 2bbaab83b9d6..55ddd50e8aaa 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -18,7 +18,19 @@ /// /// This trait is meant to be used in cases when Rust objects are stored in C objects and /// eventually "freed" back to Rust. -pub trait ForeignOwnable: Sized { +/// +/// # Safety +/// +/// Implementers must ensure that [`into_foreign`] returns a pointer which meets the alignment +/// requirements of [`PointedTo`]. +/// +/// [`into_foreign`]: Self::into_foreign +/// [`PointedTo`]: Self::PointedTo +pub unsafe trait ForeignOwnable: Sized { + /// Type used when the value is foreign-owned. In practical terms only defines the alignment of + /// the pointer. + type PointedTo; + /// Type used to immutably borrow a value that is currently foreign-owned. type Borrowed<'a>; @@ -27,16 +39,18 @@ pub trait ForeignOwnable: Sized { /// Converts a Rust-owned object to a foreign-owned one. /// - /// The foreign representation is a pointer to void. There are no guarantees for this pointer. - /// For example, it might be invalid, dangling or pointing to uninitialized memory. Using it in - /// any way except for [`from_foreign`], [`try_from_foreign`], [`borrow`], or [`borrow_mut`] can - /// result in undefined behavior. + /// # Guarantees + /// + /// The return value is guaranteed to be well-aligned, but there are no other guarantees for + /// this pointer. For example, it might be null, dangling, or point to uninitialized memory. + /// Using it in any way except for [`ForeignOwnable::from_foreign`], [`ForeignOwnable::borrow`], + /// [`ForeignOwnable::try_from_foreign`] can result in undefined behavior. /// /// [`from_foreign`]: Self::from_foreign /// [`try_from_foreign`]: Self::try_from_foreign /// [`borrow`]: Self::borrow /// [`borrow_mut`]: Self::borrow_mut - fn into_foreign(self) -> *mut crate::ffi::c_void; + fn into_foreign(self) -> *mut Self::PointedTo; /// Converts a foreign-owned object back to a Rust-owned one. /// @@ -46,7 +60,7 @@ pub trait ForeignOwnable: Sized { /// must not be passed to `from_foreign` more than once. /// /// [`into_foreign`]: Self::into_foreign - unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self; + unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self; /// Tries to convert a foreign-owned object back to a Rust-owned one. /// @@ -58,7 +72,7 @@ pub trait ForeignOwnable: Sized { /// `ptr` must either be null or satisfy the safety requirements for [`from_foreign`]. /// /// [`from_foreign`]: Self::from_foreign - unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_void) -> Option { + unsafe fn try_from_foreign(ptr: *mut Self::PointedTo) -> Option { if ptr.is_null() { None } else { @@ -81,7 +95,7 @@ unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_void) -> Option { /// /// [`into_foreign`]: Self::into_foreign /// [`from_foreign`]: Self::from_foreign - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Self::Borrowed<'a>; + unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> Self::Borrowed<'a>; /// Borrows a foreign-owned object mutably. /// @@ -109,21 +123,23 @@ unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_void) -> Option { /// [`from_foreign`]: Self::from_foreign /// [`borrow`]: Self::borrow /// [`Arc`]: crate::sync::Arc - unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> Self::BorrowedMut<'a>; + unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> Self::BorrowedMut<'a>; } -impl ForeignOwnable for () { +// SAFETY: The `into_foreign` function returns a pointer that is dangling, but well-aligned. +unsafe impl ForeignOwnable for () { + type PointedTo = (); type Borrowed<'a> = (); type BorrowedMut<'a> = (); - fn into_foreign(self) -> *mut crate::ffi::c_void { + fn into_foreign(self) -> *mut Self::PointedTo { core::ptr::NonNull::dangling().as_ptr() } - unsafe fn from_foreign(_: *mut crate::ffi::c_void) -> Self {} + unsafe fn from_foreign(_: *mut Self::PointedTo) -> Self {} - unsafe fn borrow<'a>(_: *mut crate::ffi::c_void) -> Self::Borrowed<'a> {} - unsafe fn borrow_mut<'a>(_: *mut crate::ffi::c_void) -> Self::BorrowedMut<'a> {} + unsafe fn borrow<'a>(_: *mut Self::PointedTo) -> Self::Borrowed<'a> {} + unsafe fn borrow_mut<'a>(_: *mut Self::PointedTo) -> Self::BorrowedMut<'a> {} } /// Runs a cleanup function/closure when dropped. From patchwork Fri Feb 7 13:58:26 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tamir Duberstein X-Patchwork-Id: 13965032 X-Patchwork-Delegate: bhelgaas@google.com Received: from mail-qk1-f182.google.com (mail-qk1-f182.google.com [209.85.222.182]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9C8E121E0BA; Fri, 7 Feb 2025 13:58:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738936738; cv=none; b=RzskNluetzsqgViI1UKVe9gQXkZvyyK2naAX3iC5UX0RnF+GkqQvkm6lVKa0xigL+hCHtLabDGFObfIfrfqdm6THMoEEzdMEwoYPeY6C7GrFBa9ALzN4er8AVWJoty4moROv1OsQVeY32DzHLPGJUnaeA+0DBLoE9HCMLeRvOHE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738936738; c=relaxed/simple; bh=wR8pnBtDUB2DEgdGV6lmunID6mIemgcIxyviNi6lWwU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UN1n5kSH0/feArd+XACCkCtRCCOZ9vuFyHpw67WHfD/3a5sTj9bzjJtJ+Y85on7TZ99u5loxCf3BBH815OWTqzxrfO1vD3BTYuAwYBHmhCC8Gt8KGQlLcn37cvjp8N9/JQWr6zBy4/RBcspUVKetwIY6P7/ayrTtCwfelEZCFns= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Z6ehmUwY; arc=none smtp.client-ip=209.85.222.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Z6ehmUwY" Received: by mail-qk1-f182.google.com with SMTP id af79cd13be357-7b6f19a6c04so179713985a.0; Fri, 07 Feb 2025 05:58:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1738936735; x=1739541535; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=g9E79CmCNh8SvzUJ4fLJra60rwytht1fQr8WNIy+YYw=; b=Z6ehmUwYmVMV+wTUXjg+i2tNPB1ZIH0HX7IyuVmhNtF37e46BDRyK6X31xoowT6Z3m K08JsiFX+docKvcq8ivH0jcCEiWtNcoenfKOHCw78+J9VRfzfGEy/jevp1oE1pJ8D7Ub VM+wB1WjQ9C6dkN9PFs7lzi72xRUoV4qjDgO9pKOsryNHfKUWQf52b+CMjTqZ6vurfsr qp41TyXy2Han6nYrrsdD8IIlCjPMECLzjjrdlDokHitTUoqVjLROeZ/Y4mfOVkiJW7cP 1B6criEQonGq8UYIjyvWaBKdxAkiQabuiak9EVyNHcGnW31+CDc6GUst9woMqNYvuFq1 70bQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738936735; x=1739541535; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=g9E79CmCNh8SvzUJ4fLJra60rwytht1fQr8WNIy+YYw=; b=nd2gf+zrU+mOc8m/eTBfZ5K3Yu8tn8vI6elasVpUGJyWuuzbCps9oNfLEE9msVL02c aMaiLahoGnyi1ujPpDRxfoYIZIKTURSbobiJbJMKD0nVAKtG68/iuwz3xJwc8NTr8QkI MdYQxTz0eCjBgvwiEbp0Dlxj53wCL+xNL+jUwu4sV8ruKSm0vtjXhvNydqHItX08qFii wtKTybsfsS7kPDatDfObuldPOigy0T9VRI6ZZWYz3sNWLDmjXjYBJk8wsI4t49QNC5QA P7PGIJ8rDeIwFsh8TY2q1CWnIujSeSkAmsAgJKSwXOqH1WltSRcd4obao1xeUdcyjwXr ID2Q== X-Forwarded-Encrypted: i=1; AJvYcCUAqiHq9bl9DOoogumOBVLYTsAhqRDlTPTZV2n3EVLjB4+Cn61cBS1+ZPTp2E8FNJq3F/jyIUmhVy7Z0iMT+t0=@vger.kernel.org, AJvYcCVjkJJ/vsfJjDiNnWqMHfjDw4/EzTtAzerNcoHqUQPXTi5HOXpvCE+aCZAZk/H1REBDifs2Cjrazj1lyNe4@vger.kernel.org, AJvYcCWLLTQtMDevrS8ZnKhrpWzVdibQjpuJY7d2gTBsm5lZ4aARzxb0hM+vol/Vq6p2hpi9VjH05oEgVYzT@vger.kernel.org, AJvYcCWx+wuTjVEPaKWppOXorIqPmrQ/dMq/j6HiQj5IRtLGVK+TwBtZ6VEkzYSRCqCvFjKt7JCOWpDN+2Tl74Pv@vger.kernel.org X-Gm-Message-State: AOJu0YxpqTwZ+9uIH9xOtW77czaUoQVjTMUSHdqk4i6db9etTNKuF5mK I6g0KLalZafFI2xdrw/BN7P8mmEZ7dB9dWrWWoT4o/bpgnkFfPpw X-Gm-Gg: ASbGncuXVU73nL4hYQno+NENe1nYevUtb7GK4KlYt81H3iP11gbgtzSyjZqLDpt6z3T u8ZMDyNiTc7u71JjLlS9Ob6HuLlvVlXqAE9eUkizsPgREnz32O4RIuHMt6bspijlfDkA19+yx/m oVXldYKhFWeLCvOpfwPciZtCpp/g7BjjaJvvVVwXdRRbYFpurwAihyFYphrzuX6oJvQBc6WECxc KrKUxm1E8ApY3QMZ6Cr30kpgbDO1xfhb6Q/ebcPLOnFYfPIripfLcvwitT8dz35XYDDSo9W3ove meawJmjVLeJnMYJHh4WqxdTQU3q/eLaJfzY= X-Google-Smtp-Source: AGHT+IFouYnQAwtexoi6dP+OVGJx4v7bt2UWzUG67N9X0whECk67EvHRtaJOAjme7NVSrlm3zmSO3A== X-Received: by 2002:a05:620a:2b99:b0:7bf:ff64:3378 with SMTP id af79cd13be357-7c047cad8a8mr540553285a.53.1738936735160; Fri, 07 Feb 2025 05:58:55 -0800 (PST) Received: from [192.168.1.159] ([2600:4041:5be7:7c00:fb:aded:686f:8a03]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7c041e11d19sm191919685a.52.2025.02.07.05.58.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 05:58:54 -0800 (PST) From: Tamir Duberstein Date: Fri, 07 Feb 2025 08:58:26 -0500 Subject: [PATCH v16 3/4] rust: xarray: Add an abstraction for XArray Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250207-rust-xarray-bindings-v16-3-256b0cf936bd@gmail.com> References: <20250207-rust-xarray-bindings-v16-0-256b0cf936bd@gmail.com> In-Reply-To: <20250207-rust-xarray-bindings-v16-0-256b0cf936bd@gmail.com> To: Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Matthew Wilcox , Bjorn Helgaas , Greg Kroah-Hartman , "Rafael J. Wysocki" , Tamir Duberstein , FUJITA Tomonori , "Rob Herring (Arm)" Cc: =?utf-8?q?Ma=C3=ADra_Canal?= , Asahi Lina , rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org X-Mailer: b4 0.15-dev `XArray` is an efficient sparse array of pointers. Add a Rust abstraction for this type. This implementation bounds the element type on `ForeignOwnable` and requires explicit locking for all operations. Future work may leverage RCU to enable lockless operation. Inspired-by: MaĆ­ra Canal Inspired-by: Asahi Lina Reviewed-by: Andreas Hindborg Reviewed-by: Alice Ryhl Signed-off-by: Tamir Duberstein --- rust/bindings/bindings_helper.h | 6 + rust/helpers/helpers.c | 1 + rust/helpers/xarray.c | 28 ++++ rust/kernel/alloc.rs | 5 + rust/kernel/lib.rs | 1 + rust/kernel/xarray.rs | 276 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 317 insertions(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 55354e4dec14..249070b5abf9 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -34,6 +34,7 @@ #include #include #include +#include #include /* `bindgen` gets confused at certain things. */ @@ -47,3 +48,8 @@ const gfp_t RUST_CONST_HELPER___GFP_ZERO = __GFP_ZERO; const gfp_t RUST_CONST_HELPER___GFP_HIGHMEM = ___GFP_HIGHMEM; const gfp_t RUST_CONST_HELPER___GFP_NOWARN = ___GFP_NOWARN; const blk_features_t RUST_CONST_HELPER_BLK_FEAT_ROTATIONAL = BLK_FEAT_ROTATIONAL; + +const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT; + +const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC = XA_FLAGS_ALLOC; +const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC1 = XA_FLAGS_ALLOC1; diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 0640b7e115be..6811f71f2cbb 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -35,3 +35,4 @@ #include "vmalloc.c" #include "wait.c" #include "workqueue.c" +#include "xarray.c" diff --git a/rust/helpers/xarray.c b/rust/helpers/xarray.c new file mode 100644 index 000000000000..60b299f11451 --- /dev/null +++ b/rust/helpers/xarray.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +int rust_helper_xa_err(void *entry) +{ + return xa_err(entry); +} + +void rust_helper_xa_init_flags(struct xarray *xa, gfp_t flags) +{ + return xa_init_flags(xa, flags); +} + +int rust_helper_xa_trylock(struct xarray *xa) +{ + return xa_trylock(xa); +} + +void rust_helper_xa_lock(struct xarray *xa) +{ + return xa_lock(xa); +} + +void rust_helper_xa_unlock(struct xarray *xa) +{ + return xa_unlock(xa); +} diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index fc9c9c41cd79..77840413598d 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -39,6 +39,11 @@ pub struct Flags(u32); impl Flags { + /// Get a flags value with all bits unset. + pub fn empty() -> Self { + Self(0) + } + /// Get the raw representation of this flag. pub(crate) fn as_raw(self) -> u32 { self.0 diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 496ed32b0911..abe419362c73 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -84,6 +84,7 @@ pub mod types; pub mod uaccess; pub mod workqueue; +pub mod xarray; #[doc(hidden)] pub use bindings; diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs new file mode 100644 index 000000000000..8115dd7b4dd0 --- /dev/null +++ b/rust/kernel/xarray.rs @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! XArray abstraction. +//! +//! C header: [`include/linux/xarray.h`](srctree/include/linux/xarray.h) + +use crate::{ + alloc, bindings, build_assert, + error::{Error, Result}, + init::PinInit, + pin_init, + types::{ForeignOwnable, NotThreadSafe, Opaque}, +}; +use core::{iter, marker::PhantomData, mem, pin::Pin, ptr::NonNull}; +use macros::{pin_data, pinned_drop}; + +/// An array which efficiently maps sparse integer indices to owned objects. +/// +/// This is similar to a [`crate::alloc::kvec::Vec>`], but more efficient when there are +/// holes in the index space, and can be efficiently grown. +/// +/// # Invariants +/// +/// `self.xa` is always an initialized and valid [`bindings::xarray`] whose entries are either +/// `XA_ZERO_ENTRY` or came from `T::into_foreign`. +/// +/// # Examples +/// +/// ```rust +/// use kernel::alloc::KBox; +/// use kernel::xarray::{AllocKind, XArray}; +/// +/// let xa = KBox::pin_init(XArray::new(AllocKind::Alloc1), GFP_KERNEL)?; +/// +/// let dead = KBox::new(0xdead, GFP_KERNEL)?; +/// let beef = KBox::new(0xbeef, GFP_KERNEL)?; +/// +/// let mut guard = xa.lock(); +/// +/// assert_eq!(guard.get(0), None); +/// +/// assert_eq!(guard.store(0, dead, GFP_KERNEL)?.as_deref(), None); +/// assert_eq!(guard.get(0).copied(), Some(0xdead)); +/// +/// *guard.get_mut(0).unwrap() = 0xffff; +/// assert_eq!(guard.get(0).copied(), Some(0xffff)); +/// +/// assert_eq!(guard.store(0, beef, GFP_KERNEL)?.as_deref().copied(), Some(0xffff)); +/// assert_eq!(guard.get(0).copied(), Some(0xbeef)); +/// +/// guard.remove(0); +/// assert_eq!(guard.get(0), None); +/// +/// # Ok::<(), Error>(()) +/// ``` +#[pin_data(PinnedDrop)] +pub struct XArray { + #[pin] + xa: Opaque, + _p: PhantomData, +} + +#[pinned_drop] +impl PinnedDrop for XArray { + fn drop(self: Pin<&mut Self>) { + self.iter().for_each(|ptr| { + let ptr = ptr.as_ptr(); + // SAFETY: `ptr` came from `T::into_foreign`. + // + // INVARIANT: we own the only reference to the array which is being dropped so the + // broken invariant is not observable on function exit. + drop(unsafe { T::from_foreign(ptr) }) + }); + + // SAFETY: `self.xa` is always valid by the type invariant. + unsafe { bindings::xa_destroy(self.xa.get()) }; + } +} + +/// Flags passed to [`XArray::new`] to configure the array's allocation tracking behavior. +pub enum AllocKind { + /// Consider the first element to be at index 0. + Alloc, + /// Consider the first element to be at index 1. + Alloc1, +} + +impl XArray { + /// Creates a new [`XArray`]. + pub fn new(kind: AllocKind) -> impl PinInit { + let flags = match kind { + AllocKind::Alloc => bindings::XA_FLAGS_ALLOC, + AllocKind::Alloc1 => bindings::XA_FLAGS_ALLOC1, + }; + pin_init!(Self { + // SAFETY: `xa` is valid while the closure is called. + xa <- Opaque::ffi_init(|xa| unsafe { + bindings::xa_init_flags(xa, flags) + }), + _p: PhantomData, + }) + } + + fn iter(&self) -> impl Iterator> + '_ { + let mut index = 0; + + // SAFETY: `self.xa` is always valid by the type invariant. + iter::once(unsafe { + bindings::xa_find(self.xa.get(), &mut index, usize::MAX, bindings::XA_PRESENT) + }) + .chain(iter::from_fn(move || { + // SAFETY: `self.xa` is always valid by the type invariant. + Some(unsafe { + bindings::xa_find_after(self.xa.get(), &mut index, usize::MAX, bindings::XA_PRESENT) + }) + })) + .map_while(|ptr| NonNull::new(ptr.cast())) + } + + /// Attempts to lock the [`XArray`] for exclusive access. + pub fn try_lock(&self) -> Option> { + // SAFETY: `self.xa` is always valid by the type invariant. + if (unsafe { bindings::xa_trylock(self.xa.get()) } != 0) { + Some(Guard { + xa: self, + _not_send: NotThreadSafe, + }) + } else { + None + } + } + + /// Locks the [`XArray`] for exclusive access. + pub fn lock(&self) -> Guard<'_, T> { + // SAFETY: `self.xa` is always valid by the type invariant. + unsafe { bindings::xa_lock(self.xa.get()) }; + + Guard { + xa: self, + _not_send: NotThreadSafe, + } + } +} + +/// A lock guard. +/// +/// The lock is unlocked when the guard goes out of scope. +#[must_use = "the lock unlocks immediately when the guard is unused"] +pub struct Guard<'a, T: ForeignOwnable> { + xa: &'a XArray, + _not_send: NotThreadSafe, +} + +impl Drop for Guard<'_, T> { + fn drop(&mut self) { + // SAFETY: + // - `self.xa.xa` is always valid by the type invariant. + // - The caller holds the lock, so it is safe to unlock it. + unsafe { bindings::xa_unlock(self.xa.xa.get()) }; + } +} + +/// The error returned by [`store`](Guard::store). +/// +/// Contains the underlying error and the value that was not stored. +pub struct StoreError { + /// The error that occurred. + pub error: Error, + /// The value that was not stored. + pub value: T, +} + +impl From> for Error { + fn from(value: StoreError) -> Self { + let StoreError { error, value: _ } = value; + error + } +} + +impl<'a, T: ForeignOwnable> Guard<'a, T> { + fn load(&self, index: usize, f: F) -> Option + where + F: FnOnce(NonNull) -> U, + { + // SAFETY: `self.xa.xa` is always valid by the type invariant. + let ptr = unsafe { bindings::xa_load(self.xa.xa.get(), index) }; + let ptr = NonNull::new(ptr.cast())?; + Some(f(ptr)) + } + + /// Provides a reference to the element at the given index. + pub fn get(&self, index: usize) -> Option> { + self.load(index, |ptr| { + // SAFETY: `ptr` came from `T::into_foreign`. + unsafe { T::borrow(ptr.as_ptr()) } + }) + } + + /// Provides a mutable reference to the element at the given index. + pub fn get_mut(&mut self, index: usize) -> Option> { + self.load(index, |ptr| { + // SAFETY: `ptr` came from `T::into_foreign`. + unsafe { T::borrow_mut(ptr.as_ptr()) } + }) + } + + /// Removes and returns the element at the given index. + pub fn remove(&mut self, index: usize) -> Option { + // SAFETY: `self.xa.xa` is always valid by the type invariant. + // + // SAFETY: The caller holds the lock. + let ptr = unsafe { bindings::__xa_erase(self.xa.xa.get(), index) }.cast(); + // SAFETY: `ptr` is either NULL or came from `T::into_foreign`. + // + // SAFETY: `&mut self` guarantees that the lifetimes of [`T::Borrowed`] and + // [`T::BorrowedMut`] borrowed from `self` have ended. + unsafe { T::try_from_foreign(ptr) } + } + + /// Stores an element at the given index. + /// + /// May drop the lock if needed to allocate memory, and then reacquire it afterwards. + /// + /// On success, returns the element which was previously at the given index. + /// + /// On failure, returns the element which was attempted to be stored. + pub fn store( + &mut self, + index: usize, + value: T, + gfp: alloc::Flags, + ) -> Result, StoreError> { + build_assert!( + mem::align_of::() >= 4, + "pointers stored in XArray must be 4-byte aligned" + ); + let new = value.into_foreign(); + + let old = { + let new = new.cast(); + // SAFETY: `self.xa.xa` is always valid by the type invariant. + // + // SAFETY: The caller holds the lock. + // + // INVARIANT: `new` came from `T::into_foreign`. + unsafe { bindings::__xa_store(self.xa.xa.get(), index, new, gfp.as_raw()) } + }; + + // SAFETY: `__xa_store` returns the old entry at this index on success or `xa_err` if an + // error happened. + let errno = unsafe { bindings::xa_err(old) }; + if errno != 0 { + // SAFETY: `new` came from `T::into_foreign` and `__xa_store` does not take + // ownership of the value on error. + let value = unsafe { T::from_foreign(new) }; + Err(StoreError { + value, + error: Error::from_errno(errno), + }) + } else { + let old = old.cast(); + // SAFETY: `ptr` is either NULL or came from `T::into_foreign`. + // + // NB: `XA_ZERO_ENTRY` is never returned by functions belonging to the Normal XArray + // API; such entries present as `NULL`. + Ok(unsafe { T::try_from_foreign(old) }) + } + } +} + +// SAFETY: `XArray` has no shared mutable state so it is `Send` iff `T` is `Send`. +unsafe impl Send for XArray {} + +// SAFETY: `XArray` serialises the interior mutability it provides so it is `Sync` iff `T` is +// `Send`. +unsafe impl Sync for XArray {} From patchwork Fri Feb 7 13:58:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamir Duberstein X-Patchwork-Id: 13965033 X-Patchwork-Delegate: bhelgaas@google.com Received: from mail-qk1-f175.google.com (mail-qk1-f175.google.com [209.85.222.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5A3BA2206BF; Fri, 7 Feb 2025 13:58:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738936740; cv=none; b=iZFYWV1Y+obM8tcgFQTUqrRMXxaY3sHxLpEfhDHRV50J1OJOz+LJApJJCy3QhEtL2/dtgbopibcjyn05Hx+Oke35BCAF2nmFqBYlF4ergqPkcKtNlTNS1HRNqLVYL8kAWD3lyZ4cexII5A8pyPQkTGoioszyrKvuUuW4W2rrHnw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738936740; c=relaxed/simple; bh=e0wLf1qpU3M4sIm0BwevK2p1vbX/X3wSyPu95F+7SS8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UijgFp8jTRNIIRYgDaNC4AT1L4ADvx6hu/Oydqzkqjn0b6VXLpppWfsidSklpPnU4tO/+EKjlhSbzVZXWtl3fm7ypIu3Cb9IUDLBtgNJfK0sGVe5WluHx/EB9TrcRJtPNDzF8ZldLdtnCviBOrsiopQXgIbl69Gp9QqWNOHECn8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=HckszuxN; arc=none smtp.client-ip=209.85.222.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="HckszuxN" Received: by mail-qk1-f175.google.com with SMTP id af79cd13be357-7b6f0afda3fso245221085a.2; Fri, 07 Feb 2025 05:58:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1738936738; x=1739541538; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=Wpn3/XdlKwUhqavi+cPgIf8RKcnm9C0yzO7icUqL2zg=; b=HckszuxNx5+e9F0U99sDOm+AtbbtaCeCD3XujC2dGEosqYZ83/qVBoNZ66+9yE6UqZ bRoXF1wyMPFb4i8mu0Kn56NrQNRjuKYb7OoWCHPihecBFovNZcoHYb2hn5inuaFuYW2H 2kE8KfJ4/BqJYgaLR0u8Y738rTlVQEXN+SmnFIb7c/LDCBQ0sJ21Q3ZzV88jvrAnZu5H 1riBTinCwZRERO4k4Wk4rOpQ6le1MWXWL+0KS91V23Ijycr1hUBWIzvez0NSQBYnuOPl gJRmk8ql5AGa5xFw6ClTKD/3BIPixZl7iE9QM+A6dKCSx3bkgv3U17LSuqFtQqylJhRE sg2A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738936738; x=1739541538; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Wpn3/XdlKwUhqavi+cPgIf8RKcnm9C0yzO7icUqL2zg=; b=n2UISO1xbCBPY/8jNuzVyUfBgd4gTdaeYcQcXyurePVNAMw19z2qKGrM6n8Drmr4Nv p8iBrolhmaXEZb2sKoXSrfW9CMNKRD+RLqrxfmFFbaqHYkdqWlZfEdDppWEKG0c2pz9p Bcyhm0n77+ymhcm95QrEPSN/0LOU3gb36bhAKGrNNxfks6Pi+oyecxJux2yAydK/gSEv yE+uXN2G/SsnbS/nMYqBud4gT1l0LYMFqP4szkSySFQEIaD1+ubYm2pYSk5IzlnS/QNI YMbP0oW8xdMbc2U1HnzZXGa8Wg48lv1Wv19JiZsOFueUeKDSXF7zypGOuHJg7zkgDKCm I5dQ== X-Forwarded-Encrypted: i=1; AJvYcCVeqxOtjk+Yig9Q+lh/mZz9PAaYlQyCTNVefD1u52vIz/3WimfITjrxSXWWQroPOwd7Yq6wn0GvoOvIjbzsKNg=@vger.kernel.org, AJvYcCVtHZHiEzFeHl1NDUBS9EIuSZ8INgAOrxlQ/SjIsagpff8dD88gwjynqMKpeyIV9Vh5qex6XOGRKsgJ@vger.kernel.org, AJvYcCWF9NYsf1JD0lwniRGHLVvj8aYM3YQ9oWE9p0o2S90x+SuXHNPCmlZCObT8a4xwu6EKna53VG4Qc6/GPvTp@vger.kernel.org, AJvYcCXGfQGZO3pjyMYcFLH7wUrsvAlfzPpH0QB0QX38n4sQ5ZSkH82/oD1loRqBiI7oKI5YmemySTiAd1Qb0XP2@vger.kernel.org X-Gm-Message-State: AOJu0YwAQS0sLF7XIKI3vu1bH3fboUp1iwvY5PwmlHJXaUX/YYmuX2S/ Jq+c6YTPZtd2Mah66kLquJHRjpxNLkrK4a/tW8XKekTCshZk/TJr X-Gm-Gg: ASbGncutHrp1NhICXGj7MXwNYWAPBEhw4t2uHYhsTkRDSl97LNIMHE42+SN7LgyNPP2 qySICyVYSppv8S8jdTr5ANtRVFadVUDU5UbX/TO79V8eZ7THaCffRdXZuij7rHFQM4Y7kSWypPD QP+Dr19qPGUkQjbFma7emthr62njWVaiKDlXsO2islwoABiku6CXykYPvZEpIEfQI/sBds7+NLT DUEXBPYdtD4PI28i27QewZ88ojUTh2xisp8bEpnFCAxYbNiWsP5F/45o/dknsGMTRZRFqPumIhs T08A5ULeUEDWcev+aokI43ZpEEMg97azTkc= X-Google-Smtp-Source: AGHT+IHJwjaC/82Oy+hjq0+mAZvGgxUq5cE3OAHB2Kmlq6SS61f+ujr3KqeeL6FpscTZDohbCf9ruA== X-Received: by 2002:a05:620a:2994:b0:7b6:d5cb:43b0 with SMTP id af79cd13be357-7c047c9a788mr462795385a.39.1738936738181; Fri, 07 Feb 2025 05:58:58 -0800 (PST) Received: from [192.168.1.159] ([2600:4041:5be7:7c00:fb:aded:686f:8a03]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7c041e11d19sm191919685a.52.2025.02.07.05.58.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 05:58:56 -0800 (PST) From: Tamir Duberstein Date: Fri, 07 Feb 2025 08:58:27 -0500 Subject: [PATCH v16 4/4] MAINTAINERS: add entry for Rust XArray API Precedence: bulk X-Mailing-List: linux-pci@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250207-rust-xarray-bindings-v16-4-256b0cf936bd@gmail.com> References: <20250207-rust-xarray-bindings-v16-0-256b0cf936bd@gmail.com> In-Reply-To: <20250207-rust-xarray-bindings-v16-0-256b0cf936bd@gmail.com> To: Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Matthew Wilcox , Bjorn Helgaas , Greg Kroah-Hartman , "Rafael J. Wysocki" , Tamir Duberstein , FUJITA Tomonori , "Rob Herring (Arm)" Cc: =?utf-8?q?Ma=C3=ADra_Canal?= , Asahi Lina , rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org X-Mailer: b4 0.15-dev Add an entry for the Rust xarray abstractions. Acked-by: Andreas Hindborg Signed-off-by: Tamir Duberstein --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 896a307fa065..88282b6e689b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25749,6 +25749,17 @@ F: lib/test_xarray.c F: lib/xarray.c F: tools/testing/radix-tree +XARRAY API [RUST] +M: Tamir Duberstein +M: Andreas Hindborg +L: rust-for-linux@vger.kernel.org +S: Supported +W: https://rust-for-linux.com +B: https://github.com/Rust-for-Linux/linux/issues +C: https://rust-for-linux.zulipchat.com +T: git https://github.com/Rust-for-Linux/linux.git rust-next +F: rust/kernel/xarray.rs + XBOX DVD IR REMOTE M: Benjamin Valentin S: Maintained