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) + } +}