From patchwork Tue Jul 23 18:10:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 13740267 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 CE371C3DA63 for ; Tue, 23 Jul 2024 18:12:30 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 555DA6B00AC; Tue, 23 Jul 2024 14:12:30 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 505D26B00AB; Tue, 23 Jul 2024 14:12:30 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 358526B00AC; Tue, 23 Jul 2024 14:12:30 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id E3F066B00A9 for ; Tue, 23 Jul 2024 14:12:29 -0400 (EDT) Received: from smtpin26.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id 9FC341C0A1F for ; Tue, 23 Jul 2024 18:12:29 +0000 (UTC) X-FDA: 82371812418.26.A2D60A4 Received: from sin.source.kernel.org (sin.source.kernel.org [145.40.73.55]) by imf29.hostedemail.com (Postfix) with ESMTP id 4FEF7120005 for ; Tue, 23 Jul 2024 18:12:26 +0000 (UTC) Authentication-Results: imf29.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=b6wl7t6V; spf=pass (imf29.hostedemail.com: domain of dakr@kernel.org designates 145.40.73.55 as permitted sender) smtp.mailfrom=dakr@kernel.org; dmarc=pass (policy=none) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1721758300; 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=lE/7nuqyVKQjk+p/Al1d7AqOwfZe5RxQ1Di6Mhjy0EY=; b=DP1RBS1tAfzcICZFOwJ9l+QSsaW21HUZvsM6fPw8poutqN/wSS0QigEHsny5SR8KDdqpHW MTbiT2fp7p+zmxIBFCHhjcE7i+ppkFvYAaU/HL2LUmNY0/xz7Rd+9Ovg7kKY29LxTv7ANZ c89kjS9J+Z054eWaIIJ1GDVr6sCRwRk= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1721758300; a=rsa-sha256; cv=none; b=qcPGkU6NwdGh5UGSteAojlHyawdjWGrswqr4vM+yaEcrXs2vwzisO/w0tD2C5tbWDrpXdz SBsnrJFfh73yy1S5IohndBqHNh8QqfjkLBK89xex6XIcjDzPnxyXTLIrEUSut4iyA41lis +PgeoaHx612Zu351iwgnc/ihcLU5Bqo= ARC-Authentication-Results: i=1; imf29.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=b6wl7t6V; spf=pass (imf29.hostedemail.com: domain of dakr@kernel.org designates 145.40.73.55 as permitted sender) smtp.mailfrom=dakr@kernel.org; dmarc=pass (policy=none) header.from=kernel.org Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sin.source.kernel.org (Postfix) with ESMTP id 5BDE4CE0E92; Tue, 23 Jul 2024 18:12:24 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 65FCAC4AF0E; Tue, 23 Jul 2024 18:12:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1721758343; bh=ycTccZRzwhnWmuZYl2yN5kvt/i9Cmr0VW9EfC/7UA54=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=b6wl7t6Vnx/yEyZvnuZI8xejX+EMDqYiC6oixtqi/wC6OK3zAe8IYO6hbfIV8Ma17 RLaPGrXo7rmTxgNQsHHTld9g3PEBCvQv37hOE6l4eGRycKf3zDA6Ds91DfzKciIRJa xrJISI+8CpDkcJvGGqsiv2f8NIOZoQaebEQGdV8TPKFui73DeJNhn/C0DdSKZD+W1N EWZuuocRtFqpv8tzGfD4nbDUCqzsDaPU0a8cpGlp1G6UQn08G1EvnJDiAkj/QNDeRa 4r+Y1p3whwd4s+LMBVGqd0ARazU1VyOY7jVc6P2Sel5BoUB+gK/Nn+ud9PeO7QF458 d5aCwheSsNJqw== From: Danilo Krummrich To: 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, akpm@linux-foundation.org Cc: daniel.almeida@collabora.com, faith.ekstrand@collabora.com, boris.brezillon@collabora.com, lina@asahilina.net, mcanal@igalia.com, zhiw@nvidia.com, acurrid@nvidia.com, cjia@nvidia.com, jhubbard@nvidia.com, airlied@redhat.com, ajanulgu@redhat.com, lyude@redhat.com, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-mm@kvack.org, Danilo Krummrich Subject: [PATCH v2 16/23] rust: alloc: implement `collect` for `IntoIter` Date: Tue, 23 Jul 2024 20:10:05 +0200 Message-ID: <20240723181024.21168-17-dakr@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240723181024.21168-1-dakr@kernel.org> References: <20240723181024.21168-1-dakr@kernel.org> MIME-Version: 1.0 X-Stat-Signature: f8sq3zr8aoci4z1ubxhow1r4awiy3ri3 X-Rspamd-Queue-Id: 4FEF7120005 X-Rspam-User: X-Rspamd-Server: rspam08 X-HE-Tag: 1721758346-788220 X-HE-Meta: U2FsdGVkX1/NAAI0nJNC4Y5DEmwZfQZeF/j4ZQxBdbn37lYC2wLTm5Wv48q80G25Vh0pOqd9nnk/Mjy0sCCx5A96RD/+sCa+K0Bvkev1oKhpPiGvX5ir3aH7CxS8M+OatX/PCql1KsZTSZ6XWZ9ErBtqwSoMINjVqUfaRqQlf0v6bqeoyZdm0XybjCcfX76VoccO4X2dqO0zBYweFus+h4HHxLS1GOGyn48bpAeiadArdW1mqkalCSPMLThOgZCIrmGhEF5cVicAUkE9gLJs0GOAjPGpMsBjg1HNhVD8JL9BqgjDE4ub3huHUdG3L+00qpc3UaoKt2P0gm4Hn4yOAFUO7bAg4m2n/BRAy9tpwSa6YonYhCctaZlqxLtXbV4zgqMMa+s+yJLy5Jz2DkQjJJaSgzXgWEHRKU/uRkturIlIeb4AMoEgOjN4+WSjTnfhpxJEijhkwVh0vjrHcvjMdLKXMTeEUEC5ot3OErY+G4XHN7T6zcxcEUrFFvZ+VerqBRMEcGtdbgD4OplYIzGHvFsRmnwqgmEjz884dmOqBh2dz2dbVcP9HaYjt7NC7OfpgYwIjKTx3c2qhevGSVxS3odzl2wqAIKPLh/AcSKbGOQ/dd2uTXBzp/NZofd8CFwQZdIzGG3O3AUv/u39DWosy1CxVCdQdrjLVchO948szPIWATye5p2vVgC6qmCBp7mf/pXSxQNOP8Dc6QtkMPY7H50os4JLJyrXjPG1rP719XExl5wmo8z5i3z+EhSwhD8qQVRlqdMHySmUDH7mYUkTdQ/pFOGsNKuvBl2Ik1hmyQvlmlFlA9dVaK7QmmNi0+SbjESf88s1NPqDDxBtkuPNuUk//olNwZhqgTbB/bEe22tiklyvunTTvrIn9vtudcH0XOvnh0Gl6KAjpNMQE9+OX4r9Nld6D0Dkl9y3f0yOXNhv7K81i9VtUdh5afogOTvE8CeUj6OYwyu6v/RsjHj GmSKALgy C80AxTXMj/31Jq8ZSrBjQudXL/x3aavohglE7xl57jufVm1geR8L7kapTYPALPcbjbOnDw1cwILv4qTUmsk+yQ2KIhOK2AG8ILi7O++EoDyqMkUgbtAB48HczYA8NgPrWF5LafYvmh6I1vnicSRxQHnnxXhRCZsCmjYtSWDCaAt8k8y6OSQ3SFMnh+4cfJ7BEDhpA6l79G1jNpuJIImR3NXVfaPqSTiAS3FccWjsGjHnDj8DL8Iz5ifq0cxbZUXkiAgsBjANmHvmdUylFtIa5k1lFZgbDgqJxbtTmQ5lzL01gb3Q4HEfD8v4AWoKhmXrcF+bJKgvPUh5lrkM4wbb0l0TQbw== 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: Currently, we can't implement `FromIterator`. There are a couple of issues with this trait in the kernel, namely: - Rust's specialization feature is unstable. This prevents us to optimze for the special case where `I::IntoIter` equals `Vec`'s `IntoIter` type. - We also can't use `I::IntoIter`'s type ID either to work around this, since `FromIterator` doesn't require this type to be `'static`. - `FromIterator::from_iter` does return `Self` instead of `Result`, hence we can't properly handle allocation failures. - Neither `Iterator::collect` nor `FromIterator::from_iter` can handle additional allocation flags. Instead, provide `IntoIter::collect`, such that we can at least convert `IntoIter` into a `Vec` again. Signed-off-by: Danilo Krummrich --- rust/kernel/alloc/kvec.rs | 80 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs index fbfb755b252d..5c317931e14c 100644 --- a/rust/kernel/alloc/kvec.rs +++ b/rust/kernel/alloc/kvec.rs @@ -2,7 +2,7 @@ //! Implementation of [`Vec`]. -use super::{AllocError, Allocator, Flags}; +use super::{flags::*, AllocError, Allocator, Flags}; use crate::types::Unique; use core::{ fmt, @@ -633,6 +633,84 @@ impl IntoIter fn as_raw_mut_slice(&mut self) -> *mut [T] { ptr::slice_from_raw_parts_mut(self.ptr, self.len) } + + fn into_raw_parts(self) -> (*mut T, NonNull, usize, usize) { + let me = ManuallyDrop::new(self); + let ptr = me.ptr; + let buf = me.buf; + let len = me.len; + let cap = me.cap; + (ptr, buf, len, cap) + } + + /// Same as `Iterator::collect` but specialized for `Vec`'s `IntoIter`. + /// + /// Currently, we can't implement `FromIterator`. There are a couple of issues with this trait + /// in the kernel, namely: + /// + /// - Rust's specialization feature is unstable. This prevents us to optimze for the special + /// case where `I::IntoIter` equals `Vec`'s `IntoIter` type. + /// - We also can't use `I::IntoIter`'s type ID either to work around this, since `FromIterator` + /// doesn't require this type to be `'static`. + /// - `FromIterator::from_iter` does return `Self` instead of `Result`, hence + /// we can't properly handle allocation failures. + /// - Neither `Iterator::collect` nor `FromIterator::from_iter` can handle additional allocation + /// flags. + /// + /// Instead, provide `IntoIter::collect`, such that we can at least convert a `IntoIter` into a + /// `Vec` again. + /// + /// Note that `IntoIter::collect` doesn't require `Flags`, since it re-uses the existing backing + /// buffer. However, this backing buffer may be shrunk to the actual count of elements. + /// + /// # Examples + /// + /// ``` + /// let v = kernel::kvec![1, 2, 3]?; + /// let mut it = v.into_iter(); + /// + /// assert_eq!(it.next(), Some(1)); + /// + /// let v = it.collect(); + /// assert_eq!(v, [2, 3]); + /// + /// # Ok::<(), Error>(()) + /// ``` + pub fn collect(self) -> Vec { + let (mut ptr, buf, len, mut cap) = self.into_raw_parts(); + let has_advanced = ptr != buf.as_ptr(); + + if has_advanced { + // SAFETY: Copy the contents we have advanced to at the beginning of the buffer. + // `ptr` is guaranteed to be between `buf` and `buf.add(cap)` and `ptr.add(len)` is + // guaranteed to be smaller than `buf.add(cap)`. + unsafe { ptr::copy(ptr, buf.as_ptr(), len) }; + ptr = buf.as_ptr(); + } + + // This can never fail, `len` is guaranteed to be smaller than `cap`. + let layout = core::alloc::Layout::array::(len).unwrap(); + + // SAFETY: `buf` points to the start of the backing buffer and `len` is guaranteed to be + // smaller than `cap`. Depending on `alloc` this operation may shrink the buffer or leaves + // it as it is. + ptr = match unsafe { A::realloc(Some(buf.cast()), layout, GFP_KERNEL) } { + // If we fail to shrink, which likely can't even happen, continue with the existing + // buffer. + Err(_) => ptr, + Ok(ptr) => { + cap = len; + ptr.as_ptr().cast() + } + }; + + // SAFETY: If the iterator has been advanced, the advanced elements have been copied to + // the beginning of the buffer and `len` has been adjusted accordingly. `ptr` is guaranteed + // to point to the start of the backing buffer. `cap` is either the original capacity or, + // after shrinking the buffer, equal to `len`. `alloc` is guaranteed to be unchanged since + // `into_iter` has been called on the original `Vec`. + unsafe { Vec::from_raw_parts(ptr, len, cap) } + } } impl Iterator for IntoIter