From patchwork Tue Nov 19 11:24:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abdiel Janulgue X-Patchwork-Id: 13879745 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 69DB7D44146 for ; Tue, 19 Nov 2024 11:24:44 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id ED6DA6B009C; Tue, 19 Nov 2024 06:24:43 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id E38AA6B009D; Tue, 19 Nov 2024 06:24:43 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id CD8DF6B009E; Tue, 19 Nov 2024 06:24:43 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id B036D6B009C for ; Tue, 19 Nov 2024 06:24:43 -0500 (EST) Received: from smtpin08.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id 702BDAD681 for ; Tue, 19 Nov 2024 11:24:43 +0000 (UTC) X-FDA: 82802609778.08.C32B27D Received: from mail-lf1-f51.google.com (mail-lf1-f51.google.com [209.85.167.51]) by imf29.hostedemail.com (Postfix) with ESMTP id 9108F120004 for ; Tue, 19 Nov 2024 11:23:33 +0000 (UTC) Authentication-Results: imf29.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=VNjDKu2v; spf=pass (imf29.hostedemail.com: domain of abdiel.janulgue@gmail.com designates 209.85.167.51 as permitted sender) smtp.mailfrom=abdiel.janulgue@gmail.com; dmarc=pass (policy=none) header.from=gmail.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1732015390; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=O5in6My0kdNSS1puRd/yLqubLQBCE2d2SsFq7ndctiY=; b=SqMfEROvpD7SQeNHV2T0GAkWhutMkfj+8mAv4wxLSptaxduMAMacYUS9erxJ1yrKUSwCVO u5lW0bJPwsJaf1/4osIqQZb3lq959rZRx4Z4gRMAbgQuRo58YUJ7wy6VZm+up2NxlTX6yF ocejpsr9V76U5bhmM+MS/G0dbOmbTd0= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1732015390; a=rsa-sha256; cv=none; b=gWIcRNYMfjbpBOUuuL1BxbZ8ZQbUeA62xaqSnMXjGKF2khF/MmsbXm0H5+sVsI0lYgesVl 8CFhJCZtbRCMXCfpIxLrgeZUtb6/U/fluhTZI18QdDlTs4w3jqtIu6pelhJgCW1ENOy44e p2qWS4B/XrG/SdMEbn5vRhiUu2i/99k= ARC-Authentication-Results: i=1; imf29.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=VNjDKu2v; spf=pass (imf29.hostedemail.com: domain of abdiel.janulgue@gmail.com designates 209.85.167.51 as permitted sender) smtp.mailfrom=abdiel.janulgue@gmail.com; dmarc=pass (policy=none) header.from=gmail.com Received: by mail-lf1-f51.google.com with SMTP id 2adb3069b0e04-53da4fd084dso5385865e87.0 for ; Tue, 19 Nov 2024 03:24:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1732015480; x=1732620280; darn=kvack.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=O5in6My0kdNSS1puRd/yLqubLQBCE2d2SsFq7ndctiY=; b=VNjDKu2vLbk+ddHPlcUO0qRP8H3Xt+l5urt9bPPkuirnuahXgdH9+jVUksoKi/LDR+ H4iJv4GIrZXw+y2nHzVYk6uoa4CyPTAZi+pAJPZYznlBnbzrDEkzPdSvZIB66vtgGisD UiKO+y3zsvaxQ/FLkkfiAMNp4PLNlx7cfd+gGJJIxGTlBpz4ppZz4Y5RVT+6Q162ZN/H mvfqEf5P7PO9mh67Z/hFjDQAkhU92jROQ+VRmrzmx5NQF9r9XlxPCgTPF1JERcmU6BLR 1DTGu1xlANFpASthiw6L5mAOcD18KtKvLSNI4XukOIt/anL5f0CPu6lCRErZCKcJuqYD h4eg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732015480; x=1732620280; 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=O5in6My0kdNSS1puRd/yLqubLQBCE2d2SsFq7ndctiY=; b=B7fULtwT4uxoNrqJcdRBA1zWEcQ7nZKzRLwdzyYF6Rv7/o2J9ePZXxNcqa+39JJpPk y2lwcmraiyOO2Y3BLF1O7GuQ8yNQYdw0u9w4nCPENLSU70yS3oVY4zYwl+8Uv3mAWCVH UfuYBQVgweSlRe1w3J4nystv4EiO9UePgIOtxOwShaFl8SBloEosq9K5YJLFIrcDyPR3 znoFaYRJ5I0JIyLVl80x0OwPad5K5ywIb45glfAsgBmwYG5yKe3xVyB7q4NVdoWZoujL fpaTT7oUS/MFRYbJy/+JbmgaMPhWpg3HgKPj88gWO2sjfLVvGgKPD2Fh5Lxv6Gb89Q2P 5izw== X-Forwarded-Encrypted: i=1; AJvYcCXzWMkFuH7j8iSHRG355z6RleaB+MHDvVqPDnVP3fdE32+z8G/JIkhymw917kDhm++KGV9qFy+mdw==@kvack.org X-Gm-Message-State: AOJu0YzSGU7orupOGfi0N6F6R/AQd1RgUP4xGUeAUdlWomBSRvrzCmv5 NDEVMub9mLmi6Xr07RVu4Er5YI62a/8dE0RN0gxsACHBAYHZba// X-Google-Smtp-Source: AGHT+IEKjqLZdyXdfGQjRw6AYYj6v+Q15TvM5GNLUQ+CaJiPip4JE/yx1g/kjPZdw+FLybza4MV/MQ== X-Received: by 2002:a19:8c05:0:b0:53d:abc4:820f with SMTP id 2adb3069b0e04-53dbd47128bmr779557e87.6.1732015479658; Tue, 19 Nov 2024 03:24:39 -0800 (PST) Received: from abj-NUC9VXQNX.. (87-94-132-183.rev.dnainternet.fi. [87.94.132.183]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-53dbd478279sm271899e87.232.2024.11.19.03.24.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 19 Nov 2024 03:24:38 -0800 (PST) From: Abdiel Janulgue To: rust-for-linux@vger.kernel.org Cc: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?B?= =?utf-8?q?j=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Wedson Almeida Filho , Valentin Obst , linux-kernel@vger.kernel.org (open list), Andrew Morton , linux-mm@kvack.org (open list:MEMORY MANAGEMENT), airlied@redhat.com, Abdiel Janulgue Subject: [PATCH v3 1/2] rust: page: use the page's reference count to decide when to free the allocation Date: Tue, 19 Nov 2024 13:24:02 +0200 Message-ID: <20241119112408.779243-2-abdiel.janulgue@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241119112408.779243-1-abdiel.janulgue@gmail.com> References: <20241119112408.779243-1-abdiel.janulgue@gmail.com> MIME-Version: 1.0 X-Rspamd-Server: rspam10 X-Stat-Signature: ng9bkw1w4k9zes65fmxetruq4kis7u91 X-Rspamd-Queue-Id: 9108F120004 X-Rspam-User: X-HE-Tag: 1732015413-4463 X-HE-Meta: U2FsdGVkX19cwZZ1iY+rbFtOpCfguHj9AEEfKPaVGCgelfrvjAnhYkJnBrmqjX0FP7P8MlGliupOijW5WJjm/OkwtI68U7qOxsg7Ol9w/6XPbv6AbGSB8hhWHFcrTB19syf3/yZhphwKOA/MfaKFf9S5jlQ+f4DN0IzCh3/HX6ig7K9VplYN2OIuK4nRSqHITcXKqgCWIEF/dpSa7dzumU7iQp18gmiC/5TTlq+mj8XcPyMxuPR9bkRamCmR8QuVml5+4ZG0JEPxVU2kxfTV7hQczS9yOkPi30ERvsalyaBupp48MDl+QNQxLwJ8j0P/eO3BX2rLrOlyFN12dbkQnJG10glx0ZSPGBBfOnfrpkuunvZglLAHw+tGjD4lXS9ObrUfMIt60cstwQG2OPUlPG/GHdeft67YKnR0o9Le5DFj0Zx6FvGSDF0laHtqWA+Uk2vv0O2QKy2KLo89FCbaxpgAtVMaVTxXoMgfBVfSqOTn+jP4fpbUoAVJLB2rIBM4fsXv4H4XG7VSfgIYt7FBXsGNxe72jgOp6hyjfXTKIepimconCY0YvBm4fWf42rpFepHqo+xRFy6x7mt3ADo4pYriUVxUVcCVNsbIhTJXiKzNVsKCLVBCqb2PO5fA6a/TuylumRWjgK3QHobBe3t57t2wuE5ImUbS4qYAu1a+3q5j5ExluwF9PUm+q4t5Cn2I8KYuObnz59UQ8Qp8pShUC2v+N3NPNrM+wnoSgwI9SCvnSVpYA4xEuuF/HVZYjBzxxD6q5J4fPIE+KjW5ulTc22mczA6NapT6xxUJMWxqDTM3VM8bDVgx/kxiMkZmAza9aAQk+/CcXAIF310sr5Kvory0o2PmonKAOlLs0ACEa6DLZfDAhklDuVIEOuUj73MLXfCagB1ZKfrHfnMO1y9vcFu5AA/If664GCaqDVzw/MWefkcZ4g9inpU40nTv/1aF/cqncXQ5IfnXEaaIkO7 YLJQRQLR EDMKICBp3RSBQmbtVp1H0gwBXDioMLHqucAHvXTkcqnjSUlLaiySKVCrgD6DEQwZ2N3VyYlSuBCO2zYEtX7Gr60a7Rg5L4gkLs3A0fDNnb/ttEK6cxgezoLqlJNQge0pvK2zQ9HPhZ36sc7YKSvY01dQxakUbhZ99/eKUXksn2hDK67EZuhEIsyb2dMiFWMTX7FnyLMUke+mPw4kA6v/jdbhzqe2z5f6+9w3cyCsaJ/I1NO79rEVh+Z1vUiw6KEHsYlqdTIwPN6ZckpuOmIMO5IGNKQBhZP3O5/vAs9m4ooRuYPI2ev6EYEPrZCAmaIEMfNsty6KLzbi6BOOK3R5D31ytNLrzjTPsXxszCnnXo1VDFn8qJ9RvLZVTWpffaW5bcjRLRsdEeOGeRXKoD87gd2frD9yIDbKtQAqnOsJb72zrPeZeRkXoyoa3m9J1CEH8/UUFDpIhVVegTb5MP2loxqqWx6Lo1TS6kG02xpjs9Flw496pdXpG52oBKGuvIsrOIqzK X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Ensure pages returned by the constructor are always reference counted. This requires that we replace the page pointer wrapper with Opaque instead of NonNull to make it possible to cast to a Page pointer from a raw struct page pointer which is needed to create an ARef instance. Signed-off-by: Abdiel Janulgue --- rust/bindings/bindings_helper.h | 1 + rust/helpers/page.c | 10 +++++++++ rust/kernel/page.rs | 38 ++++++++++++++++++++++----------- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index a80783fcbe04..daa3225a185f 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers/page.c b/rust/helpers/page.c index b3f2b8fbf87f..48d4481c1e33 100644 --- a/rust/helpers/page.c +++ b/rust/helpers/page.c @@ -17,3 +17,13 @@ void rust_helper_kunmap_local(const void *addr) { kunmap_local(addr); } + +void rust_helper_put_page(struct page *page) +{ + put_page(page); +} + +void rust_helper_get_page(struct page *page) +{ + get_page(page); +} diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs index fdac6c375fe4..fdf7ee203597 100644 --- a/rust/kernel/page.rs +++ b/rust/kernel/page.rs @@ -8,6 +8,7 @@ error::code::*, error::Result, uaccess::UserSliceReader, + types::{Opaque, ARef}, }; use core::ptr::{self, NonNull}; @@ -30,13 +31,14 @@ pub const fn page_align(addr: usize) -> usize { (addr + (PAGE_SIZE - 1)) & PAGE_MASK } -/// A pointer to a page that owns the page allocation. +/// A pointer to a reference-counted page. /// /// # Invariants /// -/// The pointer is valid, and has ownership over the page. +/// The pointer is valid. +#[repr(transparent)] pub struct Page { - page: NonNull, + page: Opaque, } // SAFETY: Pages have no logic that relies on them staying on a given thread, so moving them across @@ -71,19 +73,23 @@ impl Page { /// let page = Page::alloc_page(GFP_KERNEL | __GFP_ZERO)?; /// # Ok(()) } /// ``` - pub fn alloc_page(flags: Flags) -> Result { + pub fn alloc_page(flags: Flags) -> Result, AllocError> { // SAFETY: Depending on the value of `gfp_flags`, this call may sleep. Other than that, it // is always safe to call this method. let page = unsafe { bindings::alloc_pages(flags.as_raw(), 0) }; - let page = NonNull::new(page).ok_or(AllocError)?; - // INVARIANT: We just successfully allocated a page, so we now have ownership of the newly - // allocated page. We transfer that ownership to the new `Page` object. - Ok(Self { page }) + if page.is_null() { + return Err(AllocError); + } + // CAST: Self` is a `repr(transparent)` wrapper around `bindings::page`. + let ptr = page.cast::(); + // INVARIANT: We just successfully allocated a page, ptr points to the new `Page` object. + // SAFETY: According to invariant above ptr is valid. + Ok(unsafe { ARef::from_raw(NonNull::new_unchecked(ptr)) }) } /// Returns a raw pointer to the page. pub fn as_ptr(&self) -> *mut bindings::page { - self.page.as_ptr() + self.page.get() } /// Runs a piece of code with this page mapped to an address. @@ -252,9 +258,15 @@ pub unsafe fn copy_from_user_slice_raw( } } -impl Drop for Page { - fn drop(&mut self) { - // SAFETY: By the type invariants, we have ownership of the page and can free it. - unsafe { bindings::__free_pages(self.page.as_ptr(), 0) }; +// SAFETY: Instances of `Page` are always reference-counted. +unsafe impl crate::types::AlwaysRefCounted for Page { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. + unsafe { bindings::get_page(self.as_ptr()) }; + } + + unsafe fn dec_ref(obj: ptr::NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is non-zero. + unsafe { bindings::put_page(obj.cast().as_ptr()) } } } From patchwork Tue Nov 19 11:24:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abdiel Janulgue X-Patchwork-Id: 13879746 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3C8C3D44147 for ; Tue, 19 Nov 2024 11:24:47 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id BEF586B009D; Tue, 19 Nov 2024 06:24:46 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id BA0A56B009F; Tue, 19 Nov 2024 06:24:46 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id A40F36B00A0; Tue, 19 Nov 2024 06:24:46 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id 829466B009D for ; Tue, 19 Nov 2024 06:24:46 -0500 (EST) Received: from smtpin13.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id 47792C038E for ; Tue, 19 Nov 2024 11:24:46 +0000 (UTC) X-FDA: 82802609610.13.DED0098 Received: from mail-lf1-f44.google.com (mail-lf1-f44.google.com [209.85.167.44]) by imf08.hostedemail.com (Postfix) with ESMTP id DDF46160003 for ; Tue, 19 Nov 2024 11:24:10 +0000 (UTC) Authentication-Results: imf08.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=Ld2tfN0X; spf=pass (imf08.hostedemail.com: domain of abdiel.janulgue@gmail.com designates 209.85.167.44 as permitted sender) smtp.mailfrom=abdiel.janulgue@gmail.com; dmarc=pass (policy=none) header.from=gmail.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1732015240; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=YSlE2AobDBjXj75h9dVNPb0c+CAMh4Q+j+w/qWySOZo=; b=AGQJgX7sWNNT1hrBru2oEramQck7IHSxIxf+TTr9c4+Lv8jtzoDoCdHGKfBvsa3UloClyv U40104w8fMMt4yI2eheKNmx28B/Am/LJv0M4AFyX7HaXt/4aDn8qsR26qtw0q6l3Xw0yzU kR3W8GGaPWXIene/5M4iOYpdze/tJgA= ARC-Authentication-Results: i=1; imf08.hostedemail.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=Ld2tfN0X; spf=pass (imf08.hostedemail.com: domain of abdiel.janulgue@gmail.com designates 209.85.167.44 as permitted sender) smtp.mailfrom=abdiel.janulgue@gmail.com; dmarc=pass (policy=none) header.from=gmail.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1732015240; a=rsa-sha256; cv=none; b=USQrIFLgLhjwFDJTzDJJiCFOE4GOwIj1ThG+qMHE4HBczJMDG4c6fwC/EOk/BOQFW52hQh LVEDO5W07GrW1P/bDKCH7+RZhmuOZebg06yaqz4lNYiOJ6EotIr9Bgpxk4ahaJVFSH6HdB bmWrmU1PzsqaiYrPg5NTK2ztv+q1nX8= Received: by mail-lf1-f44.google.com with SMTP id 2adb3069b0e04-53da6801c6dso3925045e87.0 for ; Tue, 19 Nov 2024 03:24:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1732015483; x=1732620283; darn=kvack.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=YSlE2AobDBjXj75h9dVNPb0c+CAMh4Q+j+w/qWySOZo=; b=Ld2tfN0XjQU8o7q/pHFD9ASC7W6VzsaxT9isgYMX4dzR4v6nGfX8R+2ukYebJuVVVs CnV1b4cT8ohSV7lslegiHe1MclUjS4D9ty4vgBuSlDxPAqaBY5NaukUv5bItJCS1l0HH HkreqK7UHhCBz+JPpCHQyfI7+mbew4E8u6U4p00EPkwrLQQAipEr4lDWeOgrXezOvsKb O7IAj1QoHPq0oTY+kyi3DVSa2smugbjX3eoQ6TZNc1DJHschUNv/LN1yE4cWYvC0wWJp LMPVcK9lHdEFhiJJw4mNGTSvfLHFeiA8dPVMLboObDXfmfLFa9bMgzoj27AU0A6Srfzd 4tTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732015483; x=1732620283; 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=YSlE2AobDBjXj75h9dVNPb0c+CAMh4Q+j+w/qWySOZo=; b=eA5pyxIjzcvJN/BfzBw+aJsCux61bhJ4HKizE9fnErLzOckdZOa1fgauomkqn1QvZ2 N2U/hFyb5K+NaDuaE/xWP1BbtPxXTfz6cRQmPpzEBTMsgCzpE4m5wlmQ2OaiEicmGhh7 HoTy/FnKAN+2w07Pw923o4CJfsFN3PEGNbVewQVfwEaAXDDkq5+hPx3ckJxSwpq8TGcm FKKnSiaguj13XVDZBQyg7DbmQOaf8OQgX7EDILY/zUnksXhHafu7PYy03aArJ03boRvR h2KdeGoTqJotvp8Kep5y7Tu8YN462Ebvy8VCdhqTRB8D+mzlOfUXkkS8wOsryXa0r6xe tuig== X-Forwarded-Encrypted: i=1; AJvYcCW0HzGTZhvmEBA7BamD19Y0uUnEs6YbwTCxM69mawwZhjQPnFgCCL2pKTZDzRafSIEGgT2kA30qKQ==@kvack.org X-Gm-Message-State: AOJu0Yxl5MmLe/YWbR5oGhR/mrBdGxF4wP/mjzWZpzAGjxVpiEtYueU8 hdnFt0dUDCho0w32QxwcOR+8ky/P87sDL7cDVqrjctckrme3pb2C X-Google-Smtp-Source: AGHT+IHClMNtG+d6fxlDY8MwP736UMKm9XCqQoUw9TgnQS0hL5N5cc0pjQHQFoHV43cUof90JEBn9w== X-Received: by 2002:a05:6512:3b86:b0:53d:a24b:db0f with SMTP id 2adb3069b0e04-53dab3c50b3mr6607291e87.57.1732015482420; Tue, 19 Nov 2024 03:24:42 -0800 (PST) Received: from abj-NUC9VXQNX.. (87-94-132-183.rev.dnainternet.fi. [87.94.132.183]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-53dbd478279sm271899e87.232.2024.11.19.03.24.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 19 Nov 2024 03:24:41 -0800 (PST) From: Abdiel Janulgue To: rust-for-linux@vger.kernel.org Cc: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?B?= =?utf-8?q?j=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Wedson Almeida Filho , Valentin Obst , linux-kernel@vger.kernel.org (open list), Andrew Morton , linux-mm@kvack.org (open list:MEMORY MANAGEMENT), airlied@redhat.com, Abdiel Janulgue Subject: [PATCH v3 2/2] rust: page: Extend support to existing struct page mappings Date: Tue, 19 Nov 2024 13:24:03 +0200 Message-ID: <20241119112408.779243-3-abdiel.janulgue@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241119112408.779243-1-abdiel.janulgue@gmail.com> References: <20241119112408.779243-1-abdiel.janulgue@gmail.com> MIME-Version: 1.0 X-Rspamd-Server: rspam06 X-Rspamd-Queue-Id: DDF46160003 X-Stat-Signature: 3fpie1uriiw5a4ya3hiapwzqwi8x9mks X-Rspam-User: X-HE-Tag: 1732015450-262127 X-HE-Meta: U2FsdGVkX19KG/1a/60lIFnIvpPxQVUnTWeu3BZiej9CkazSfYPr1kPD5kUrGN+LR383HaoVjaShfwOWQQ+AfglIIWtEzUcH9XFcAJQQR5SemJc9+RuReinFBhM8oMc0IMZEj2sbEddMqkS9y7i5dSj3Vp7Rf7/SFO0DwRDksAaIvkmHQLSWWtll9xgAgpkLAgGADkWxhhliNDYL8CGRgIOS5nVsQdU+JchY7iViOD1URU2ibOwXxLKzXt3e7Ud2f5RA8B8Xw0SNb/EJ48LcR0tSPfV5YUgIhMPYt3e4gEDBkrLDJ2dly+9auizsI+7VFqlQ9EeiU3f2/ZjUJ69R8C+eGHk6BA6mgX/7O4FB0CItp5gyuuw0KNJ3Jp3Z1u3+B5aa/U7e8yZ4tIUjPTkU/s8aXDATUf9aX8SXMDgDo9OoWw0WPLPAEE4Wr/1GYfiG62QLrnkmZFCCvfDvCQlyJi4pdduWr6lIdOQNbjzbTRAh3C+TQRs++mab73MX2uyhZpohiDv+wnA34NtYbpkPrjuB2w8aiLLCjEvXfn/ZJCBrxVcjewlB+vG3sZFE2ThKPpJpPlBS4ncLY0WBcXyhDNzs8m/Hehs3bfY2CxO4QLu7wU73Zwth7m13HCJa9QEQtQvDmDTNIMgazdkiZzzvJEeShxiw6ixhWbqhJe/CfZHV8wkvjlt1FgqDsEmXrjaAGvJ/jUY3RNx4TTWiF7IKSIFwgm3mv971d+38pI8K/uUie42A0JKUZN9gUbSsmaeRhv4pM/jO6bbw6te3Yohvz8f96Qkywjp0/CTaYMDQzkCoKy8dwyeqi19ff5ehpBUsFBkFfTfSFLChd3kXDBjzvt4bz0mupGIpntLjeX0iJOpnjkqIpoZi23OFEApOUw4m+kdijXlj0vtrb80iT3iuU82siloMBi7pvut6oBosabYgirOthCfnme0K9ZxDc+8OdOGWyTdXUgPSG5+LikU kX0/qUif S7PNiWJMe5oNTnfCTKKu1ma7nCCFsZ28+EnCi0szm8mtUY58LVPt7Sp59fjuRa80TVmr1+xHf3LP2MRyXD/H8UItLE6MOh3ZdvaunIpSpdYwBaKhWfVKBzrKRWJI9RflfRbiw6xcN0T9v+USpg4uQpxJc/xDPIPZpGC9eMCg9uwEu478rUfxh8yp2ZGzv/nrSISsCVWZkzfUa9BIZJMJf/zEJ7c+t+3pSZYct8cd1wMqOpxVr09CzQjMTwmrLUfDjDKSwnu0SnBaLHwQ3wiv0oIhgGkHC21djjg1LQmzIn1GeEHkqYgoY4yyT/Jv+Ys+RNZ/JMaNF/wMXeBG3oPrICkpN3MdWzu+hEWKhOnpnuw/MT9VjT+51U+M1N/MN0wzrSQmIbaeXvmBxNvj09LYGzg1bd9enLK/A4eld3y2YSkTh8ieTbkBu0ab7g01b06oMZQcbtjp4H5ai6vKPHRxFZvuY1vDfxeziyihd X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Extend Page to support pages that are not allocated by the constructor, for example, those returned by vmalloc_to_page() or virt_to_page(). Since we don't own those pages we shouldn't Drop them either. Hence we take advantage of the switch to Opaque so we can cast to a Page pointer from a struct page pointer and be able to retrieve the reference on an existing struct page mapping. In this case no destructor will be called since we are not instantiating a new Page instance. The new page_slice_to_page wrapper ensures that it explicity accepts only page-sized chunks. Signed-off-by: Abdiel Janulgue --- rust/helpers/page.c | 10 +++++ rust/kernel/page.rs | 97 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/rust/helpers/page.c b/rust/helpers/page.c index 48d4481c1e33..784563924b83 100644 --- a/rust/helpers/page.c +++ b/rust/helpers/page.c @@ -27,3 +27,13 @@ void rust_helper_get_page(struct page *page) { get_page(page); } + +struct page *rust_helper_virt_to_page(const void *kaddr) +{ + return virt_to_page(kaddr); +} + +bool rust_helper_virt_addr_valid(const void *kaddr) +{ + return virt_addr_valid(kaddr); +} diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs index fdf7ee203597..d0a896f53afb 100644 --- a/rust/kernel/page.rs +++ b/rust/kernel/page.rs @@ -3,7 +3,7 @@ //! Kernel page allocation and management. use crate::{ - alloc::{AllocError, Flags}, + alloc::{AllocError, Allocator, Flags, VVec, KVec, KVVec, Vec, flags::*}, bindings, error::code::*, error::Result, @@ -87,6 +87,49 @@ pub fn alloc_page(flags: Flags) -> Result, AllocError> { Ok(unsafe { ARef::from_raw(NonNull::new_unchecked(ptr)) }) } + /// Create a page object from a buffer which is associated with an existing C `struct page`. + /// + /// This function ensures it takes a page-sized buffer as represented by `PageSlice`. + /// + /// # Examples + /// + /// ``` + /// use kernel::page::*; + /// + /// let somedata: [u8; PAGE_SIZE * 2] = [0; PAGE_SIZE * 2]; + /// let buf: &[u8] = &somedata; + /// let pages: VVec = buf.try_into()?; + /// let page = Page::page_slice_to_page(&pages[0])?; + /// # Ok::<(), Error>(()) + /// ``` + pub fn page_slice_to_page<'a>(page: &PageSlice) -> Result<&'a Self> + { + let ptr: *const core::ffi::c_void = page.0.as_ptr() as _; + if ptr.is_null() { + return Err(EINVAL) + } + // SAFETY: We've checked that `ptr` is non-null, hence it's safe to call this method. + let page = if unsafe { bindings::is_vmalloc_addr(ptr) } { + // SAFETY: We've checked that `ptr` is non-null and within the vmalloc range, hence + // it's safe to call this method. + unsafe { bindings::vmalloc_to_page(ptr) } + // SAFETY: We've checked that `ptr` is non-null, hence it's safe to call this method. + } else if unsafe { bindings::virt_addr_valid(ptr) } { + // SAFETY: We've checked that `ptr` is non-null and a valid virtual address, hence + // it's safe to call this method. + unsafe { bindings::virt_to_page(ptr) } + } else { + ptr::null_mut() + }; + if page.is_null() { + return Err(EINVAL); + } + // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::page`. + // SAFETY: We just successfully retrieved an existing `bindings::page`, therefore + // dereferencing the page pointer is valid. + Ok(unsafe { &*page.cast() }) + } + /// Returns a raw pointer to the page. pub fn as_ptr(&self) -> *mut bindings::page { self.page.get() @@ -270,3 +313,55 @@ unsafe fn dec_ref(obj: ptr::NonNull) { unsafe { bindings::put_page(obj.cast().as_ptr()) } } } + +/// A page-aligned, page-sized object. +/// +/// This is used for convenience to convert a large buffer into an array of page-sized chunks +/// allocated with the kernel's allocators which can then be used in the +/// `Page::page_slice_to_page` wrapper. +/// +// FIXME: This should be `PAGE_SIZE`, but the compiler rejects everything except a literal +// integer argument for the `repr(align)` attribute. +#[repr(align(4096))] +pub struct PageSlice([u8; PAGE_SIZE]); + +fn to_vec_with_allocator(val: &[u8]) -> Result, AllocError> { + let mut k = Vec::::new(); + let pages = page_align(val.len()) >> PAGE_SHIFT; + match k.reserve(pages, GFP_KERNEL) { + Ok(()) => { + // SAFETY: from above, the length should be equal to the vector's capacity + unsafe { k.set_len(pages); } + // SAFETY: src buffer sized val.len() does not overlap with dst buffer since + // the dst buffer's size is val.len() padded up to a multiple of PAGE_SIZE. + unsafe { ptr::copy_nonoverlapping(val.as_ptr(), k.as_mut_ptr() as *mut u8, + val.len()) }; + Ok(k) + }, + Err(_) => Err(AllocError), + } +} + +impl TryFrom<&[u8]> for VVec { + type Error = AllocError; + + fn try_from(val: &[u8]) -> Result { + to_vec_with_allocator(val) + } +} + +impl TryFrom<&[u8]> for KVec { + type Error = AllocError; + + fn try_from(val: &[u8]) -> Result { + to_vec_with_allocator(val) + } +} + +impl TryFrom<&[u8]> for KVVec { + type Error = AllocError; + + fn try_from(val: &[u8]) -> Result { + to_vec_with_allocator(val) + } +}