From nobody Sun Dec 14 01:41:09 2025 Received: from mail-wr1-f74.google.com (mail-wr1-f74.google.com [209.85.221.74]) (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 A65412ED179 for ; Wed, 13 Aug 2025 08:27:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755073653; cv=none; b=fnMdn6Rj9k8qaNh4QN+O6wg11z/vUtuLGtfg62fQjvK8EW5pC7hsB1XRLJ+y0hPq3Bl5Lq/wmJyx89batc1nK3AiFERoRrh+pCRvkxxjVCOhEUjWTiOIlvTqJsKpek35MiQ7bN+MboCVK+Hp8gGaVrtTNlOG+KAdxPt+eP1gBfU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755073653; c=relaxed/simple; bh=Q7IeEd7aYRZgj1h25zT1BxWCdPplfVhmVNx+RhUQYt4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Fgt7LIBh2viBvBv48QPaHlXeIMhsiw/EgahhrDP4WqMvzO8CEgoThQ1QOJFA66qRGom4iBzCx0pLGRq8bMZx41ig1hhAUuslRtQFPGIf593eI7GT7wLuykysHSR2ICQT1gE629dba+qTJlpEPOsnjymXcNfTAT9kyX10Fbj4b7U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=lmpaeccs; arc=none smtp.client-ip=209.85.221.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="lmpaeccs" Received: by mail-wr1-f74.google.com with SMTP id ffacd0b85a97d-3b78c983014so4149594f8f.0 for ; Wed, 13 Aug 2025 01:27:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1755073649; x=1755678449; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=A+ShkJBKX50/8FM8O1XIBpOrp0flQDpGnL1nA8so21c=; b=lmpaeccsYo3LZMtHM5YW69K37hIFoTSWEpD8ADjvYVBxV1VeQKYSGqRKfheYcOKIFy /ReYN9KCVX07pICAP6Y4RSRX0aoubtwQJrT5NEOJwtG0o+RgW7JQCo6uI1lGtYeSBq7s 3MGwWVvgtn6/F9KVE4BktqtE5Lx11VJmOddQDiGRVMBrFyHit49VXq5a7tr5CngRcSvd iM1kMA5dMjh1Sv8iWP1FzA5ETSyjvrG7bZkeEazCmgt4Bkk62tOxtrK+K5Dc1ry0CRwS +b0rQ9Xw4GboUBNB8JoCUt0T1dgVWjKHuPJrls0r4yqzdcvPimFVi4leAVl3+V+P2uRK RbjQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1755073649; x=1755678449; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=A+ShkJBKX50/8FM8O1XIBpOrp0flQDpGnL1nA8so21c=; b=ngNrvrEP196iM74Q+WejwEYbxvsDkRbTYZNItUwezIzk6UzyrLd1I+gM36ADpRIAiH fUKFHQGJcYld42tBflF4ety5HqGWLDi3kU9hNnDbKnX+xbxnyUHJ5ffKNMuptqK/54WX ZCQ4YtfzOrv8rnXu4oHNyby1q+KzY2B1tZjxt3vkIjxV5xkNjcEC266+F0uKb9NP+I/4 PzXqOmSZaZxoshqImGvJpuTPnvta5m5ry4MOjP35+mgkuTu5kEM/waunNiCY8Hxd6zUg S0AlUK0iAMlGqpUt8pn9stXttpcHGobId6jTwjv7KyMJ72wFDK3mbqU385AKH9NgIkou XrqQ== X-Forwarded-Encrypted: i=1; AJvYcCVlyMekM4mGJlLa3tv/lN3NULG56YikTMSnUpcjjHOEz8BZZ+dEAffmfbJpm4alEpclbGBDUiIWJcL8kok=@vger.kernel.org X-Gm-Message-State: AOJu0YzLMmzkhtGmn4iuJj+IhlTL1wM8lXenMm02a4Alm4jMlLwjQKWz XYcftl4BLfFbKhKZ4Ee0GIT5Y/sZCZyc0k2BNGHMr47Sr5SPFeYhQBirWgJbNzTI4Z4pqZ2sTRN MsZJwrsnQuPmBYQEnQA== X-Google-Smtp-Source: AGHT+IFn7QYxeuJ613Cz2dqtl8L/2FlV8x/ACzhzxDRq3PXF58CxZD2zcEWKk294mLzBLOC1Hq1Ht1kJKQ5bO2k= X-Received: from wmqd20.prod.google.com ([2002:a05:600c:34d4:b0:459:de2a:4d58]) (user=aliceryhl job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:e04:b0:3b9:1c60:d795 with SMTP id ffacd0b85a97d-3b91c60d8f8mr79038f8f.22.1755073648714; Wed, 13 Aug 2025 01:27:28 -0700 (PDT) Date: Wed, 13 Aug 2025 08:27:17 +0000 In-Reply-To: <20250813-iov-iter-v4-0-c4f1932b05ef@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250813-iov-iter-v4-0-c4f1932b05ef@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=8439; i=aliceryhl@google.com; h=from:subject:message-id; bh=Q7IeEd7aYRZgj1h25zT1BxWCdPplfVhmVNx+RhUQYt4=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBonExtbNiFL5RYliQK3lHd3OD7ZWI4BrVxbx9LB RkMlpixphaJAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCaJxMbQAKCRAEWL7uWMY5 Rs1wD/4ytbR51FPP7CeqXgkPEvaQWs8da1BPgMlOc1A8qdSjt8RC9sE32/6a2ZKQWsqVSG5wK2W 151uZ5BWkKm6W4Uk73AbCWTb9WViZyvSNHgdqI00NmsQMozqStmJB1F7jGTS05aIs9Am9icomAV zwU+m1f70IjLn6rmQDCiVLbttan2jQnfcL+/0gtQ48gRi3hAaT8S9T8qFDkwXrjQbFqBbq5L+MI 5VYFRAbcg40dp1Ejyz2q2Uh7aa+hu5gl7LH1/3vCmMHakxG5EVIdoqFeUYhnU5KDstzWHTcoCDr pHBmhDqK8lCzzAFsMY+fBKYGDqPityNkFEDDIqNTnU8VxavXBMnT/vMirHJfEsDqR5fjHZJgDWw 4z024ly/kYIJyoUnQGw4rdlCR9raCCvMJMFBhxJHp431XKZAHypcePp0+a8jrJEqR8vC85Bi1Ge 3NZo2myOu8w0zXVKg8aNb0v3AJSS/qnhsB8n6os+ng13vziLzSald0lXEHMqS0ApKHayllqasRo 71OQVNWBfTsEuhth0vlKUJpMeuRbSM4AskqKWNYVqeDrWGclNrjzvMYazE1QHIKzOXwYbUQEcfB DQL9aFheoMNQX0Akd4hUSYt/0hJKZwD7BgnPMVeY5MrlfJ6h3iD4OG63kUt6AZ8msEPwPG4CPWI 0aAfRQt2M57MIwg== X-Mailer: b4 0.14.2 Message-ID: <20250813-iov-iter-v4-1-c4f1932b05ef@google.com> Subject: [PATCH v4 1/4] rust: iov: add iov_iter abstractions for ITER_SOURCE From: Alice Ryhl To: Greg Kroah-Hartman , Alexander Viro , Arnd Bergmann , Miguel Ojeda Cc: Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Andreas Hindborg , Trevor Gross , Danilo Krummrich , Matthew Maurer , Lee Jones , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Alice Ryhl , Benno Lossin Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable This adds abstractions for the iov_iter type in the case where data_source is ITER_SOURCE. This will make Rust implementations of fops->write_iter possible. This series only has support for using existing IO vectors created by C code. Additional abstractions will be needed to support the creation of IO vectors in Rust code. These abstractions make the assumption that `struct iov_iter` does not have internal self-references, which implies that it is valid to move it between different local variables. Reviewed-by: Andreas Hindborg Signed-off-by: Alice Ryhl Reviewed-by: Danilo Krummrich --- rust/kernel/iov.rs | 168 +++++++++++++++++++++++++++++++++++++++++++++++++= ++++ rust/kernel/lib.rs | 1 + 2 files changed, 169 insertions(+) diff --git a/rust/kernel/iov.rs b/rust/kernel/iov.rs new file mode 100644 index 0000000000000000000000000000000000000000..48510d9e8ef152ada337957771d= 7777fda24f351 --- /dev/null +++ b/rust/kernel/iov.rs @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +//! IO vectors. +//! +//! C headers: [`include/linux/iov_iter.h`](srctree/include/linux/iov_iter= .h), +//! [`include/linux/uio.h`](srctree/include/linux/uio.h) + +use crate::{ + alloc::{Allocator, Flags}, + bindings, + prelude::*, + types::Opaque, +}; +use core::{marker::PhantomData, mem::MaybeUninit, ptr, slice}; + +const ITER_SOURCE: bool =3D bindings::ITER_SOURCE !=3D 0; + +/// An IO vector that acts as a source of data. +/// +/// The data may come from many different sources. This includes both thin= gs in kernel-space and +/// reading from userspace. It's not necessarily the case that the data so= urce is immutable, so +/// rewinding the IO vector to read the same data twice is not guaranteed = to result in the same +/// bytes. It's also possible that the data source is mapped in a thread-l= ocal manner using e.g. +/// `kmap_local_page()`, so this type is not `Send` to ensure that the map= ping is read from the +/// right context in that scenario. +/// +/// # Invariants +/// +/// Must hold a valid `struct iov_iter` with `data_source` set to `ITER_SO= URCE`. For the duration +/// of `'data`, it must be safe to read from this IO vector using the stan= dard C methods for this +/// purpose. +#[repr(transparent)] +pub struct IovIterSource<'data> { + iov: Opaque, + /// Represent to the type system that this value contains a pointer to= readable data it does + /// not own. + _source: PhantomData<&'data [u8]>, +} + +impl<'data> IovIterSource<'data> { + /// Obtain an `IovIterSource` from a raw pointer. + /// + /// # Safety + /// + /// * The referenced `struct iov_iter` must be valid and must only be = accessed through the + /// returned reference for the duration of `'iov`. + /// * The referenced `struct iov_iter` must have `data_source` set to = `ITER_SOURCE`. + /// * For the duration of `'data`, it must be safe to read from this I= O vector using the + /// standard C methods for this purpose. + #[track_caller] + #[inline] + pub unsafe fn from_raw<'iov>(ptr: *mut bindings::iov_iter) -> &'iov mu= t IovIterSource<'data> { + // SAFETY: The caller ensures that `ptr` is valid. + let data_source =3D unsafe { (*ptr).data_source }; + assert_eq!(data_source, ITER_SOURCE); + + // SAFETY: The caller ensures the struct invariants for the right = durations, and + // `IovIterSource` is layout compatible with `struct iov_iter`. + unsafe { &mut *ptr.cast::>() } + } + + /// Access this as a raw `struct iov_iter`. + #[inline] + pub fn as_raw(&mut self) -> *mut bindings::iov_iter { + self.iov.get() + } + + /// Returns the number of bytes available in this IO vector. + /// + /// Note that this may overestimate the number of bytes. For example, = reading from userspace + /// memory could fail with `EFAULT`, which will be treated as the end = of the IO vector. + #[inline] + pub fn len(&self) -> usize { + // SAFETY: We have shared access to this IO vector, so we can read= its `count` field. + unsafe { + (*self.iov.get()) + .__bindgen_anon_1 + .__bindgen_anon_1 + .as_ref() + .count + } + } + + /// Returns whether there are any bytes left in this IO vector. + /// + /// This may return `true` even if there are no more bytes available. = For example, reading from + /// userspace memory could fail with `EFAULT`, which will be treated a= s the end of the IO vector. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() =3D=3D 0 + } + + /// Advance this IO vector by `bytes` bytes. + /// + /// If `bytes` is larger than the size of this IO vector, it is advanc= ed to the end. + #[inline] + pub fn advance(&mut self, bytes: usize) { + // SAFETY: By the struct invariants, `self.iov` is a valid IO vect= or. + unsafe { bindings::iov_iter_advance(self.as_raw(), bytes) }; + } + + /// Advance this IO vector backwards by `bytes` bytes. + /// + /// # Safety + /// + /// The IO vector must not be reverted to before its beginning. + #[inline] + pub unsafe fn revert(&mut self, bytes: usize) { + // SAFETY: By the struct invariants, `self.iov` is a valid IO vect= or, and the caller + // ensures that `bytes` is in bounds. + unsafe { bindings::iov_iter_revert(self.as_raw(), bytes) }; + } + + /// Read data from this IO vector. + /// + /// Returns the number of bytes that have been copied. + #[inline] + pub fn copy_from_iter(&mut self, out: &mut [u8]) -> usize { + // SAFETY: `Self::copy_from_iter_raw` guarantees that it will not = write any uninitialized + // bytes in the provided buffer, so `out` is still a valid `u8` sl= ice after this call. + let out =3D unsafe { &mut *(ptr::from_mut(out) as *mut [MaybeUnini= t]) }; + + self.copy_from_iter_raw(out).len() + } + + /// Read data from this IO vector and append it to a vector. + /// + /// Returns the number of bytes that have been copied. + #[inline] + pub fn copy_from_iter_vec( + &mut self, + out: &mut Vec, + flags: Flags, + ) -> Result { + out.reserve(self.len(), flags)?; + let len =3D self.copy_from_iter_raw(out.spare_capacity_mut()).len(= ); + // SAFETY: `Self::copy_from_iter_raw` guarantees that the first `l= en` bytes of the spare + // capacity have been initialized. + unsafe { out.inc_len(len) }; + Ok(len) + } + + /// Read data from this IO vector into potentially uninitialized memor= y. + /// + /// Returns the sub-slice of the output that has been initialized. If = the returned slice is + /// shorter than the input buffer, then the entire IO vector has been = read. + /// + /// This will never write uninitialized bytes to the provided buffer. + #[inline] + pub fn copy_from_iter_raw(&mut self, out: &mut [MaybeUninit]) -> &= mut [u8] { + let capacity =3D out.len(); + let out =3D out.as_mut_ptr().cast::(); + + // GUARANTEES: The C API guarantees that it does not write uniniti= alized bytes to the + // provided buffer. + // SAFETY: + // * By the struct invariants, it is still valid to read from this= IO vector. + // * `out` is valid for writing for `capacity` bytes because it co= mes from a slice of + // that length. + let len =3D unsafe { bindings::_copy_from_iter(out.cast(), capacit= y, self.as_raw()) }; + + // SAFETY: The underlying C api guarantees that initialized bytes = have been written to the + // first `len` bytes of the spare capacity. + unsafe { slice::from_raw_parts_mut(out, len) } + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index ed53169e795c0badf548025a57f946fa18bc73e3..99dbb7b2812e018ac4598948781= 6ce020f38aa61 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -92,6 +92,7 @@ pub mod init; pub mod io; pub mod ioctl; +pub mod iov; pub mod jump_label; #[cfg(CONFIG_KUNIT)] pub mod kunit; --=20 2.51.0.rc0.205.g4a044479a3-goog From nobody Sun Dec 14 01:41:09 2025 Received: from mail-wr1-f73.google.com (mail-wr1-f73.google.com [209.85.221.73]) (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 AA6112F0C45 for ; Wed, 13 Aug 2025 08:27:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755073656; cv=none; b=UC+l7PlT5fQNwcQzzDAz9pHuvIUZOWDhA0xXDXX0ZxGK0ltI69jgJ1O6hTegl7tIDlmH/TUfatGfIQ1Clx6C+sv/rBMVqqXysQfJcZRd3SvTDZfyBBRG8Py+qqPkTTze97PyNCVAuceCJpjwPZTWWxJT7F4DA/5DbwjiMYitt1I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755073656; c=relaxed/simple; bh=8GmvIZIGgqjz8wUeCB2jyp3T1L72lC0TvDtVBsbWwrY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=d710SXdyNdkWxPmueIQqu1bgCmMpoQYWL8+Q9tc/dcDdSA6k0QdMaSrPQFD43C35E1KuVsHptZM2pssLsdsmI3LDZEco/TuArcfaSFkuvFg3WVqsN+y/sk9/TK+P16zuW+9pYxyCB2d2T3WKpShao+9FXgvfq9hxlLpA5e5Ralw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Lm9GGPrA; arc=none smtp.client-ip=209.85.221.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Lm9GGPrA" Received: by mail-wr1-f73.google.com with SMTP id ffacd0b85a97d-3b91582e402so373628f8f.1 for ; Wed, 13 Aug 2025 01:27:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1755073652; x=1755678452; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=0v+hlZN0qOTV3FiOFS1cftKwP+d3Jf03nVeRsrqAlE0=; b=Lm9GGPrABoqY5gsk4xvwA/HWsdrC2Ms9IjeSh3Ph83a3WL7Tc3FFqAAeJbodxNWZp0 sLvrbdgIKxnJ7bP8Fta9UFJoTL9t+vmTr/XdYv36ONNP/x1JsbBItWiVXrJzI5bs3OyA 5V+oGML66O+UqCcX8eXIVIjdT20itaLMalnoJNLkNv2r4w2pJjG/yFw8gUkp6vBpHndh 8Q4hGhnGCRzlTJAobJN00pky/+OoKD1zHixw2vzn30hkiAHNTp09GMwTQFOR+dFcHH3u AfXeyP0lSXtGs26JEQdk4Q8Eo6bQqlCSILl09zYyiQnNq7CzESvZzYXDKLucz3eCCVPr xnQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1755073652; x=1755678452; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=0v+hlZN0qOTV3FiOFS1cftKwP+d3Jf03nVeRsrqAlE0=; b=EZOuKEctVdKp27nHEeOccXOrd0IZxDA67J6fULAA2877mjn3kRZvYRf4lcUVw6vIHr wcvfVwMSOVUNSXCLazhNp3jwYaH/V35Z35ZLCy+/xX2f5eWJPCb6pU5x+0TWr7EuI8PH W6dYotqsIS25Px5WXUK5DxHEPNpzRwY8Vi3kH/q4TwcJyijcqBtBmSWwxFHVzHFQmffx n0BhjVLqNyxqkQHA8ygzHdMubJ+m++PKSloYMqYOQvtdQpbYxBW7AkEc9zCmfocRF0UD UJXbN736Ezgl1x4whbbI6sS5sz5COZoTj2kZNUaQSh2uj9gYGGlYO34e1CI7YN1lUKRW h21A== X-Forwarded-Encrypted: i=1; AJvYcCUHNnXhNUAMcRldTMz1TC3W725QwSYura++DH1zmTDoT6XCcN3r0XjSzA4uCtYodWEEWCsiPuZA2w/iEP0=@vger.kernel.org X-Gm-Message-State: AOJu0Yyf1T8M9L7NKL6Qp5cq4qvYoE8gzrsUW9JsDreMRhyRgQ47rQLe 2Dv4JCjTMwzdM1pM4mH8xp+pgfEi/4jrCGLksJHvYkeDhsxEv3EywGC18CMYb4UsZXOxudiGH9j VT7XRVotD0vVKKkmVeA== X-Google-Smtp-Source: AGHT+IGsJwn0URuZJVJ1ARqHV9W1udtIKNGJ7JtwTo3h8EApwMiIPJsWupzab2j2spXttYUzHSFLED6y3qc0F74= X-Received: from wmqb7.prod.google.com ([2002:a05:600c:4e07:b0:459:dc99:51e4]) (user=aliceryhl job=prod-delivery.src-stubby-dispatcher) by 2002:a5d:5849:0:b0:3b7:9dc1:74a5 with SMTP id ffacd0b85a97d-3b917eb7c9emr1565139f8f.52.1755073651858; Wed, 13 Aug 2025 01:27:31 -0700 (PDT) Date: Wed, 13 Aug 2025 08:27:18 +0000 In-Reply-To: <20250813-iov-iter-v4-0-c4f1932b05ef@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250813-iov-iter-v4-0-c4f1932b05ef@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=7537; i=aliceryhl@google.com; h=from:subject:message-id; bh=8GmvIZIGgqjz8wUeCB2jyp3T1L72lC0TvDtVBsbWwrY=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBonExtQNbgrflr/bZRkchc/RYgoVj91A0aLaz95 O9nukaSoAOJAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCaJxMbQAKCRAEWL7uWMY5 RkGwD/wNZmw9xBkgoZPQvxPEi0LiAJUd040joIkFvr4kZE6rES8Z84SkULQ6hMXCl8EvGcd1YdB bzcXj2hn3gw9xhNbUZZ4TvXBCA/kPKHsshI3K+1MhRpvw3bv2D/bxq8J1SUDS5Q6ebQKyGkxjqR t4/BWbt9awOCmVs9kap7iBaVxZLRBS4EICs9PBPrtxB0vOJzLUZv27Jw0mF9AwJxEv052/lzzqM JUEo0d04y3wgvDOXWG9SXqV3SqKX+NxHW6g5U9bo04h/wpsxDMNt2tcMq4wbh62IKQYO68DTyIU CS7JSRbBiGJTgCYQFHu+z9Utl2ZL9Tc6RQyeD2gtgHvjfRImm3VfjsjKjmmvbRJxKas/M/uQxq1 jmRVkXeJRC/vg9PO5j2bP3VKjaUx6FB0sGZbbAvarHOTrTUcG6LNaRmLy2OsihN7qfN3JQ6CSH4 jpQj2ZI1Wz4t9PW5jjyWUOvhwkMH4Kd9JUfFanqM7ENSyaw8yLsrRGD3+DbpWe6c0bh8SK3gIHe 3UU/vmnRT0/l7RUcRa7H/Ehg+r9ZIZE8iO4PQVjH08PDq5ky0PSQ8bLkg1WaaY1uNHPRfGfpdmM Mmjdcrb1uyQiFltXGLsQa/hsMN8Mk7X+UKxgts6Nag64lJasKoHhLEa7y7rgBMKsm5hWwnrd0mD r8eSyirw/S5Ltyw== X-Mailer: b4 0.14.2 Message-ID: <20250813-iov-iter-v4-2-c4f1932b05ef@google.com> Subject: [PATCH v4 2/4] rust: iov: add iov_iter abstractions for ITER_DEST From: Alice Ryhl To: Greg Kroah-Hartman , Alexander Viro , Arnd Bergmann , Miguel Ojeda Cc: Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Andreas Hindborg , Trevor Gross , Danilo Krummrich , Matthew Maurer , Lee Jones , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Alice Ryhl , Benno Lossin Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable This adds abstractions for the iov_iter type in the case where data_source is ITER_DEST. This will make Rust implementations of fops->read_iter possible. This series only has support for using existing IO vectors created by C code. Additional abstractions will be needed to support the creation of IO vectors in Rust code. These abstractions make the assumption that `struct iov_iter` does not have internal self-references, which implies that it is valid to move it between different local variables. This patch adds an IovIterDest struct that is very similar to the IovIterSource from the previous patch. However, as the methods on the two structs have very little overlap (just getting the length and advance/revert), I do not think it is worth it to try and deduplicate this logic. Reviewed-by: Andreas Hindborg Signed-off-by: Alice Ryhl Reviewed-by: Danilo Krummrich --- rust/kernel/iov.rs | 143 +++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 143 insertions(+) diff --git a/rust/kernel/iov.rs b/rust/kernel/iov.rs index 48510d9e8ef152ada337957771d7777fda24f351..f55f8997ac2f79980b16ae60f1b= 46f6511510375 100644 --- a/rust/kernel/iov.rs +++ b/rust/kernel/iov.rs @@ -16,6 +16,15 @@ use core::{marker::PhantomData, mem::MaybeUninit, ptr, slice}; =20 const ITER_SOURCE: bool =3D bindings::ITER_SOURCE !=3D 0; +const ITER_DEST: bool =3D bindings::ITER_DEST !=3D 0; + +// Compile-time assertion for the above constants. +const _: () =3D { + build_assert!( + ITER_SOURCE !=3D ITER_DEST, + "ITER_DEST and ITER_SOURCE should be different." + ); +}; =20 /// An IO vector that acts as a source of data. /// @@ -166,3 +175,137 @@ pub fn copy_from_iter_raw(&mut self, out: &mut [Maybe= Uninit]) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(out, len) } } } + +/// An IO vector that acts as a destination for data. +/// +/// IO vectors support many different types of destinations. This includes= both buffers in +/// kernel-space and writing to userspace. It's possible that the destinat= ion buffer is mapped in a +/// thread-local manner using e.g. `kmap_local_page()`, so this type is no= t `Send` to ensure that +/// the mapping is written to the right context in that scenario. +/// +/// # Invariants +/// +/// Must hold a valid `struct iov_iter` with `data_source` set to `ITER_DE= ST`. For the duration of +/// `'data`, it must be safe to write to this IO vector using the standard= C methods for this +/// purpose. +#[repr(transparent)] +pub struct IovIterDest<'data> { + iov: Opaque, + /// Represent to the type system that this value contains a pointer to= writable data it does + /// not own. + _source: PhantomData<&'data mut [u8]>, +} + +impl<'data> IovIterDest<'data> { + /// Obtain an `IovIterDest` from a raw pointer. + /// + /// # Safety + /// + /// * The referenced `struct iov_iter` must be valid and must only be = accessed through the + /// returned reference for the duration of `'iov`. + /// * The referenced `struct iov_iter` must have `data_source` set to = `ITER_DEST`. + /// * For the duration of `'data`, it must be safe to write to this IO= vector using the + /// standard C methods for this purpose. + #[track_caller] + #[inline] + pub unsafe fn from_raw<'iov>(ptr: *mut bindings::iov_iter) -> &'iov mu= t IovIterDest<'data> { + // SAFETY: The caller ensures that `ptr` is valid. + let data_source =3D unsafe { (*ptr).data_source }; + assert_eq!(data_source, ITER_DEST); + + // SAFETY: The caller ensures the struct invariants for the right = durations, and + // `IovIterSource` is layout compatible with `struct iov_iter`. + unsafe { &mut *ptr.cast::>() } + } + + /// Access this as a raw `struct iov_iter`. + #[inline] + pub fn as_raw(&mut self) -> *mut bindings::iov_iter { + self.iov.get() + } + + /// Returns the number of bytes available in this IO vector. + /// + /// Note that this may overestimate the number of bytes. For example, = reading from userspace + /// memory could fail with EFAULT, which will be treated as the end of= the IO vector. + #[inline] + pub fn len(&self) -> usize { + // SAFETY: We have shared access to this IO vector, so we can read= its `count` field. + unsafe { + (*self.iov.get()) + .__bindgen_anon_1 + .__bindgen_anon_1 + .as_ref() + .count + } + } + + /// Returns whether there are any bytes left in this IO vector. + /// + /// This may return `true` even if there are no more bytes available. = For example, reading from + /// userspace memory could fail with EFAULT, which will be treated as = the end of the IO vector. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() =3D=3D 0 + } + + /// Advance this IO vector by `bytes` bytes. + /// + /// If `bytes` is larger than the size of this IO vector, it is advanc= ed to the end. + #[inline] + pub fn advance(&mut self, bytes: usize) { + // SAFETY: By the struct invariants, `self.iov` is a valid IO vect= or. + unsafe { bindings::iov_iter_advance(self.as_raw(), bytes) }; + } + + /// Advance this IO vector backwards by `bytes` bytes. + /// + /// # Safety + /// + /// The IO vector must not be reverted to before its beginning. + #[inline] + pub unsafe fn revert(&mut self, bytes: usize) { + // SAFETY: By the struct invariants, `self.iov` is a valid IO vect= or, and the caller + // ensures that `bytes` is in bounds. + unsafe { bindings::iov_iter_revert(self.as_raw(), bytes) }; + } + + /// Write data to this IO vector. + /// + /// Returns the number of bytes that were written. If this is shorter = than the provided slice, + /// then no more bytes can be written. + #[inline] + pub fn copy_to_iter(&mut self, input: &[u8]) -> usize { + // SAFETY: + // * By the struct invariants, it is still valid to write to this = IO vector. + // * `input` is valid for `input.len()` bytes. + unsafe { bindings::_copy_to_iter(input.as_ptr().cast(), input.len(= ), self.as_raw()) } + } + + /// Utility for implementing `read_iter` given the full contents of th= e file. + /// + /// The full contents of the file being read from is represented by `c= ontents`. This call will + /// write the appropriate sub-slice of `contents` and update the file = position in `ppos` so + /// that the file will appear to contain `contents` even if takes mult= iple reads to read the + /// entire file. + #[inline] + pub fn simple_read_from_buffer(&mut self, ppos: &mut i64, contents: &[= u8]) -> Result { + if *ppos < 0 { + return Err(EINVAL); + } + let Ok(pos) =3D usize::try_from(*ppos) else { + return Ok(0); + }; + if pos >=3D contents.len() { + return Ok(0); + } + + // BOUNDS: We just checked that `pos < contents.len()` above. + let num_written =3D self.copy_to_iter(&contents[pos..]); + + // OVERFLOW: `pos+num_written <=3D contents.len() <=3D isize::MAX = <=3D i64::MAX`. + *ppos =3D (pos + num_written) as i64; + + Ok(num_written) + } +} --=20 2.51.0.rc0.205.g4a044479a3-goog From nobody Sun Dec 14 01:41:09 2025 Received: from mail-wm1-f73.google.com (mail-wm1-f73.google.com [209.85.128.73]) (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 C714A2F0C49 for ; Wed, 13 Aug 2025 08:27:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755073656; cv=none; b=bOHBqcZysTDkHMIfjRJcNezAwkIHwzW3tL++cDXrLzGT07BZnM63ONfNuAzCBBqu4ikKe5WRANKEP5R/E2SwhBFlsm3fg4ffoHD0NIBsQHtp4Syk/IEdymFz3uH0+MYxjmWG1tSByOmDmDuA8rE2jD5/2Jqz4pn2ceVYS8SC7s4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755073656; c=relaxed/simple; bh=83CIG/yYVFV5oc5WpQxs7LvduOQS2arjCyxfm7bOmAQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=mhRSSyBYDo9tkOf9/XH3AXrluZ8SXwkRUZTRSOM7LNl7QcGxUdFlgLhub6N7f1VAdyB8/k3ItrQGGIzKQa5Cgv3vuLLrQa7Rta7B8CBoeQN24WmAbrJPmM3W/HbgqisRwF70fMhuGLOKO2gX6QlN3JEFdG/rvF7tGmWNCJ19BrY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=ceVBx8vj; arc=none smtp.client-ip=209.85.128.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ceVBx8vj" Received: by mail-wm1-f73.google.com with SMTP id 5b1f17b1804b1-458bf93f729so32829025e9.0 for ; Wed, 13 Aug 2025 01:27:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1755073653; x=1755678453; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Qv73A+++0TWQ7mgHKwS6GFRnfK2NLUU7501mITzCcHQ=; b=ceVBx8vjI7FjCAJaTtPzUca3LkTJEdKRDvpApYOgtyJvp9rn9yLY9yejjgF2XkPOAL YwuhJnP/7vdSWwb3e0DFNHr8e2dlEae4T8a1ChUGsL0Z3QKJ1UFHC1bdgnewjE6ayPUm FQ3YyKDhMMl1NlOB3yUMuc1NVow/UpWSveTIIUvDJh+LS/x17wyfTelgcax5z5H6jBvI 5nTHkjlKJigRnK6Rcya+571H6MMKbCcvnD2OypXweDqGQS/etkJJiu58UAe+QGJ33DdD uYi0V8Qqu5/mHmkcvMRvwk8Y5rPfhHFmm1+M3fk7b25pbuur9WWsusMC45MvPAIylXSH 07ww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1755073653; x=1755678453; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Qv73A+++0TWQ7mgHKwS6GFRnfK2NLUU7501mITzCcHQ=; b=k47Jrz2PAr1uXRElIyRH2DWdXErWG17OhWspgxMT7j53MF+ZYgl3k/C6Ktuh9oDemH AD1T169z6qn/V9yYb0aAvCmBrwz7WGs2iz21qZFuAw+0gIEigjJJU7LjNbZOqNVLam0q l5CbMZIyy+tEMHjbgrPmezQnS92gahlUMH2Ktv6uRmuh5wT///gJgTCcCJdBew6/9ob/ 5ro8Hi50V7gRcQ11aK7YG4v/NgV77QE1ODEGHX8I+5jI+b+P5+bVUKiwEJTcZcputiM/ EnFVNq7B1En/DBFs3YTDGvNMlM9+HnPM79OmRN0tFdmmMWNLBjmg3MJUiN6QVXUEWWoK vSxg== X-Forwarded-Encrypted: i=1; AJvYcCXZurXrDjgj2eEI0DLp8tOcigF7sl5Q4UmJ1llFiWI6htnoYBtNOtGTUCsGdZC9zSdd91wSVTkhg4aM1FU=@vger.kernel.org X-Gm-Message-State: AOJu0Yy0rMmhzepLojlB2rqyhrjgbQdHVxTHl2VaNmwKOGbMcO57ivDX CTl2G4gTv6Ck7sxyLBogU72O68elK+bYTU6NHJPmJcwVQWA9/NQHtsUag/pQm2QYIARgCOA+rWo t61RUzF3jeH6Nh6rWqQ== X-Google-Smtp-Source: AGHT+IHgWah8vaIyiZQvShZ+eP/Xc8juKyVKI8pMD5CVwQu1TaUbkPB2YIy8jD1J9uT8MJfn8rasAauKIeszqX8= X-Received: from wmti10.prod.google.com ([2002:a05:600c:8b8a:b0:459:dede:aaea]) (user=aliceryhl job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:19cb:b0:459:e3f8:92ec with SMTP id 5b1f17b1804b1-45a165a5acfmr21538855e9.10.1755073653092; Wed, 13 Aug 2025 01:27:33 -0700 (PDT) Date: Wed, 13 Aug 2025 08:27:19 +0000 In-Reply-To: <20250813-iov-iter-v4-0-c4f1932b05ef@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250813-iov-iter-v4-0-c4f1932b05ef@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=7253; i=aliceryhl@google.com; h=from:subject:message-id; bh=83CIG/yYVFV5oc5WpQxs7LvduOQS2arjCyxfm7bOmAQ=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBonExtDx2M5QU/HAIhxb7BlCGwVBsgpWSaCovO1 5VlhROSc4mJAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCaJxMbQAKCRAEWL7uWMY5 Rl7DEACuHjq3unzYiXXF1gBZmhUGn5ZpZujbc23zRbQzccdMtRXMp0E8Pr+UP/2B66gNSLrevnT OtYobEWd3ZKxTNZRikw0oNOiLHq4IApLoQfZtXu3C44HSlSpNY+kdcQKYw3/625IeMVRDMvNSb2 vVLuTICNlCy2y0TBjZnPpGs9y3F7Yy2bC23RUslHjifhizMBIZal0ivUqCxtkL+V6Dy4E+qBwgQ QPhXGtW9hrnP6R5v8l5K+789YKOXdcHNcRvd2PSsii3bxl1sTDRL99Y9x8Fh/oJJBhpDu6tjKda gcjYwHskokDXbHzBWhA1mJ9gIOUXRYz9Tf4EIy4Z+jtdvkyRCq0/DWp6ZhtLH++opF4pdnKccwM GUBeCKSGrJ/H/5YHRhd844addh6HilyspsL47h9c3qkXpnXa1d4ohutdBcjGxYyQvqWcXqwMX+E 5Yy4jwwnIk7JgsVdQ0xSRwKFLNWq1ROrKzvw2h5SH0pp0pLJBRAST40CXN2cC25ruBnVH8kV8FU CjG48vlV3LXATIuWSOMPoJJxXtZR8GGDKpieYm0lgSp+7ijVkKPZgYoH0EPRuMoU+F9M34xQHwG gBoe7Y4hbEbZbdQ7Z2U6HjbjMnHJ/1nOWfFSNxyXg3sPlmj0VgnFmzRBYRoLp8YJNGVv1YTgtKO oEJPrzLkep36aNw== X-Mailer: b4 0.14.2 Message-ID: <20250813-iov-iter-v4-3-c4f1932b05ef@google.com> Subject: [PATCH v4 3/4] rust: miscdevice: Provide additional abstractions for iov_iter and kiocb structures From: Alice Ryhl To: Greg Kroah-Hartman , Alexander Viro , Arnd Bergmann , Miguel Ojeda Cc: Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Andreas Hindborg , Trevor Gross , Danilo Krummrich , Matthew Maurer , Lee Jones , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Alice Ryhl , Benno Lossin , Christian Brauner Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable These will be used for the read_iter() and write_iter() callbacks, which are now the preferred back-ends for when a user operates on a char device with read() and write() respectively. Cc: Christian Brauner Co-developed-by: Lee Jones Signed-off-by: Lee Jones Signed-off-by: Alice Ryhl Reviewed-by: Andreas Hindborg --- rust/kernel/fs.rs | 3 +++ rust/kernel/fs/kiocb.rs | 68 +++++++++++++++++++++++++++++++++++++++++++= ++++ rust/kernel/miscdevice.rs | 63 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 133 insertions(+), 1 deletion(-) diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 0121b38c59e63d01a89f22c8ef6983ef5c3234de..6ba6bdf143cb991c6e78215178e= b585260215da0 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -6,3 +6,6 @@ =20 pub mod file; pub use self::file::{File, LocalFile}; + +mod kiocb; +pub use self::kiocb::Kiocb; diff --git a/rust/kernel/fs/kiocb.rs b/rust/kernel/fs/kiocb.rs new file mode 100644 index 0000000000000000000000000000000000000000..84c936cd69b0e9b490d54c87d8c= 7279b27d4476a --- /dev/null +++ b/rust/kernel/fs/kiocb.rs @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! Kernel IO callbacks. +//! +//! C headers: [`include/linux/fs.h`](srctree/include/linux/fs.h) + +use core::marker::PhantomData; +use core::ptr::NonNull; +use kernel::types::ForeignOwnable; + +/// Wrapper for the kernel's `struct kiocb`. +/// +/// Currently this abstractions is incomplete and is essentially just a tu= ple containing a +/// reference to a file and a file position. +/// +/// The type `T` represents the filesystem or driver specific data associa= ted with the file. +/// +/// # Invariants +/// +/// `inner` points at a valid `struct kiocb` whose file has the type `T` a= s its private data. +pub struct Kiocb<'a, T> { + inner: NonNull, + _phantom: PhantomData<&'a T>, +} + +impl<'a, T: ForeignOwnable> Kiocb<'a, T> { + /// Create a `Kiocb` from a raw pointer. + /// + /// # Safety + /// + /// The pointer must reference a valid `struct kiocb` for the duration= of `'a`. The private + /// data of the file must be `T`. + pub unsafe fn from_raw(kiocb: *mut bindings::kiocb) -> Self { + Self { + // SAFETY: If a pointer is valid it is not null. + inner: unsafe { NonNull::new_unchecked(kiocb) }, + _phantom: PhantomData, + } + } + + /// Access the underlying `struct kiocb` directly. + pub fn as_raw(&self) -> *mut bindings::kiocb { + self.inner.as_ptr() + } + + /// Get the filesystem or driver specific data associated with the fil= e. + pub fn file(&self) -> ::Borrowed<'a> { + // SAFETY: We have shared access to this kiocb and hence the under= lying file, so we can + // read the file's private data. + let private =3D unsafe { (*(*self.as_raw()).ki_filp).private_data = }; + // SAFETY: The kiocb has shared access to the private data. + unsafe { ::borrow(private) } + } + + /// Gets the current value of `ki_pos`. + pub fn ki_pos(&self) -> i64 { + // SAFETY: We have shared access to the kiocb, so we can read its = `ki_pos` field. + unsafe { (*self.as_raw()).ki_pos } + } + + /// Gets a mutable reference to the `ki_pos` field. + pub fn ki_pos_mut(&mut self) -> &mut i64 { + // SAFETY: We have exclusive access to the kiocb, so we can write = to `ki_pos`. + unsafe { &mut (*self.as_raw()).ki_pos } + } +} diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index 6373fe183b2748162988b45d7ed8f563045d3b4d..35630fc638751c416d009fcf0c0= ffdf0a4da1218 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -13,7 +13,8 @@ device::Device, error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR}, ffi::{c_int, c_long, c_uint, c_ulong}, - fs::File, + fs::{File, Kiocb}, + iov::{IovIterDest, IovIterSource}, mm::virt::VmaNew, prelude::*, seq_file::SeqFile, @@ -141,6 +142,16 @@ fn mmap( build_error!(VTABLE_DEFAULT_ERROR) } =20 + /// Read from this miscdevice. + fn read_iter(_kiocb: Kiocb<'_, Self::Ptr>, _iov: &mut IovIterDest<'_>)= -> Result { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Write to this miscdevice. + fn write_iter(_kiocb: Kiocb<'_, Self::Ptr>, _iov: &mut IovIterSource<'= _>) -> Result { + build_error!(VTABLE_DEFAULT_ERROR) + } + /// Handler for ioctls. /// /// The `cmd` argument is usually manipulated using the utilities in [= `kernel::ioctl`]. @@ -245,6 +256,46 @@ impl MiscdeviceVTable { 0 } =20 + /// # Safety + /// + /// `kiocb` must be correspond to a valid file that is associated with= a + /// `MiscDeviceRegistration`. `iter` must be a valid `struct iov_it= er` for writing. + unsafe extern "C" fn read_iter( + kiocb: *mut bindings::kiocb, + iter: *mut bindings::iov_iter, + ) -> isize { + // SAFETY: The caller provides a valid `struct kiocb` associated w= ith a + // `MiscDeviceRegistration` file. + let kiocb =3D unsafe { Kiocb::from_raw(kiocb) }; + // SAFETY: This is a valid `struct iov_iter` for writing. + let iov =3D unsafe { IovIterDest::from_raw(iter) }; + + match T::read_iter(kiocb, iov) { + Ok(res) =3D> res as isize, + Err(err) =3D> err.to_errno() as isize, + } + } + + /// # Safety + /// + /// `kiocb` must be correspond to a valid file that is associated with= a + /// `MiscDeviceRegistration`. `iter` must be a valid `struct iov_it= er` for writing. + unsafe extern "C" fn write_iter( + kiocb: *mut bindings::kiocb, + iter: *mut bindings::iov_iter, + ) -> isize { + // SAFETY: The caller provides a valid `struct kiocb` associated w= ith a + // `MiscDeviceRegistration` file. + let kiocb =3D unsafe { Kiocb::from_raw(kiocb) }; + // SAFETY: This is a valid `struct iov_iter` for reading. + let iov =3D unsafe { IovIterSource::from_raw(iter) }; + + match T::write_iter(kiocb, iov) { + Ok(res) =3D> res as isize, + Err(err) =3D> err.to_errno() as isize, + } + } + /// # Safety /// /// `file` must be a valid file that is associated with a `MiscDeviceR= egistration`. @@ -341,6 +392,16 @@ impl MiscdeviceVTable { open: Some(Self::open), release: Some(Self::release), mmap: if T::HAS_MMAP { Some(Self::mmap) } else { None }, + read_iter: if T::HAS_READ_ITER { + Some(Self::read_iter) + } else { + None + }, + write_iter: if T::HAS_WRITE_ITER { + Some(Self::write_iter) + } else { + None + }, unlocked_ioctl: if T::HAS_IOCTL { Some(Self::ioctl) } else { --=20 2.51.0.rc0.205.g4a044479a3-goog From nobody Sun Dec 14 01:41:09 2025 Received: from mail-ed1-f73.google.com (mail-ed1-f73.google.com [209.85.208.73]) (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 5DC112F0C59 for ; Wed, 13 Aug 2025 08:27:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755073658; cv=none; b=cBniTbfGH9mQigk8+wqXG9k0UCJjhULKO+1ijYSqpxWtZJKmYYSUMu2O0O41l0cNmnpgITGvXL1FZt686qpyTIRphFBxjJixnQIN8EAGemc3ud8XlE3bm+bj4+Ik4R/GL3LBGx2jv7EqvtyGasC90DLGN8U91kBwaX3Zm7T8/oA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755073658; c=relaxed/simple; bh=NvRCQIGdGJIWo6z/G2tCNyjPRInHwov/dUCUXA2+eg4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=LzxtXxhy4A1dS+nCOsTgG8rdVYxDhiZXZ8M2lUcQRsdYc2wp6PBYIhAQwOkXa9kiSr4QYyzVuADfWMwHKYYPc1qxLLEA3CbVZqZMbihReaJ8yqPo/cdaikbdjNXe3k3nve+Ob3m8XuB1YZ07FqjxXkY8szRyf2AdnDRANx+GLX0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Hyd8uJxD; arc=none smtp.client-ip=209.85.208.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Hyd8uJxD" Received: by mail-ed1-f73.google.com with SMTP id 4fb4d7f45d1cf-61530559847so4695928a12.0 for ; Wed, 13 Aug 2025 01:27:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1755073654; x=1755678454; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=dIJ+x4zOPX38S26xHW3ogZFnx98GYdUErZ7Lc5KD+uk=; b=Hyd8uJxD4wJXtBpX3Y6w8nX1ZqHtObQrXPPOwzUdI3ZxQx+oXQddFhfQnye574YRTT +rnGipbDAtalXeNbqrRmplkb1UDrPLhz9u3N+lVtU1hE1zGLOcc6lkTU1Hv5W179etdn o4rvL46NQGYImi9IlplxCHuiRoCyD90QwGDaIeAOpR82UpI8BjYBqqR9iVe9vpjA0/MG u4uyzd8I3bN3a6wxfmafo6auCR/VA0q905jo+cYuTIZTmWldRzNfyj5a1wYxnNkifsyz mbS7BXvObLZPReApsmp8x9A18WLxpqzJnufCHA7DeTEuVvznI9vW3rGptd4vy7gcBQYO fK3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1755073655; x=1755678455; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=dIJ+x4zOPX38S26xHW3ogZFnx98GYdUErZ7Lc5KD+uk=; b=XzNOp0h5v5DnIzFct+opIifJ43t9XjB4RzBEZZRufQSPlzTQDODA3q+1IA57VE7Wwz d0XalMm5gyFzI1RCm8/yEAGczA2nxntkbBuAb4BqM2ZpkiBHIR2Tjt0YzUQnTJBhDnRF xoORFUXeJW8j7kVC4pCkQOqk43jAm55EyoDByTwtn8av/3bSAIGrM/P+K7hCFKzD3yzB sUdD5mYxVSPXpFnZS6kyniTBdzR/ypCXoRRZb1svU0nQ9OoMtwhycWHrY7vjJ0Wt6jQ8 1+4SNBJ3Rt3IJ0Hzd8eOSLxtCs1Osh7g8vHq7vTHobmMNRvNHtAtE6S/ZlmLF9rnFcIn cfMQ== X-Forwarded-Encrypted: i=1; AJvYcCVWwpfB6wxqpQz+99QI4M4C4GCKW8wbcvvZCJ5MaeqCr7CyWujdgxJTFYc1Pby+rmNASD4EyLt2qxbu2SM=@vger.kernel.org X-Gm-Message-State: AOJu0YyCv4dcCN+27x2lnhm4XhmAVFv6ZjBSS9tykhTy/x1P57qr0qRJ PUmEsyLdMO3MXI4OPOG6ZydRPGDkMwrVr6ZajA0zHUBOjJxVktGabgVO9fNS+hdWlqBPHApSRwg 2SHzKJqbq/cUST3CWqw== X-Google-Smtp-Source: AGHT+IE8ydanFwGG7KesQpAN8skGF2NnY35RVGG+5pSg3DQ1udrmQq4PkLWonfAcxDhio26JiagvnS+7olbq9ac= X-Received: from edn14.prod.google.com ([2002:a05:6402:a0ce:b0:615:49c7:ddf6]) (user=aliceryhl job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:44c9:b0:618:273b:4f51 with SMTP id 4fb4d7f45d1cf-6186bfd5757mr1340836a12.23.1755073654306; Wed, 13 Aug 2025 01:27:34 -0700 (PDT) Date: Wed, 13 Aug 2025 08:27:20 +0000 In-Reply-To: <20250813-iov-iter-v4-0-c4f1932b05ef@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250813-iov-iter-v4-0-c4f1932b05ef@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=3154; i=aliceryhl@google.com; h=from:subject:message-id; bh=eF5bCKQbWoDK+4GDnO0XjfTUd6tLFH3Wpg7SaPmi7HE=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBonExt5tmxz5dadRkEbyP/qbVmEqwLito1TQxGa v2Wm02OrvCJAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCaJxMbQAKCRAEWL7uWMY5 RpmfD/0SM46L161T6o/+tvWN8XkkrrDFh1/r3CbeOCqgv8y6x9N1PLE1/g48HWviJyhJ/pOqUO9 LD8siSkS1DgF7oZJuvPfMZN+Zh5J4hhqLsoQgvuDAe6tZa4uQjTFF4N9hcF/6ikgxBpUwZq6wBa muQbThm+pD/m6TGglZIeVlIbia1tVO9LwbTMXPUlhdq3OWP9D7NQ2TaYlm1fryLb7vdC6CCb98S Czw1+YvaoVVEflEX7/mMvNBE4gM6mdmthjDsDW4OdggnMjCp8OHn6GOd4FACMYbY5mHBi6vSUL0 Y9FRNAxJapcHlJqbfFi/r9g5hz9gIvLfRiI30G3UtlUGJ4bHP9zxsFdVR0UGzHWnzLpHAMTlKsJ Z3Tis7T6h4UPTZ05WdcULNVAO/QumFEJF2xdnsjZ0fSmJ3N0HV0z5Fi1vitRQuRQ9pk3o3QdVL9 ALvHnfOJsLgyeaQAbClEHbXhbWxEMfzeReDhVmqTlG/pvS7MBCZMiKtzVtdqvTn0A8tbdrSQ8p1 kynBLZ1oNqksBSJRedldc0rDMuF2R3nqMd6ZJh0bHYAe/gegvTuiXIeoEie3M6e7jlPnjQwcQ2e HA4bPUiYawyvDt+jJUzv8GdE91FRXoT9QrP1qL64/eUD2zXFuP7u+j1VL0GLfr8M6JcyonHjbjM YAyPkNAoT385bCw== X-Mailer: b4 0.14.2 Message-ID: <20250813-iov-iter-v4-4-c4f1932b05ef@google.com> Subject: [PATCH v4 4/4] samples: rust_misc_device: Expand the sample to support read()ing from userspace From: Alice Ryhl To: Greg Kroah-Hartman , Alexander Viro , Arnd Bergmann , Miguel Ojeda Cc: Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Andreas Hindborg , Trevor Gross , Danilo Krummrich , Matthew Maurer , Lee Jones , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Alice Ryhl , Benno Lossin Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Lee Jones A userland application can now operate on the char device with read() in order to consume a locally held buffer. Memory for the buffer is to be provisioned and the buffer populated in its subsequently provided write() counterpart. Signed-off-by: Lee Jones Reviewed-by: Andreas Hindborg Co-developed-by: Alice Ryhl Signed-off-by: Alice Ryhl --- samples/rust/rust_misc_device.rs | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/samples/rust/rust_misc_device.rs b/samples/rust/rust_misc_devi= ce.rs index e7ab77448f754906615b6f89d72b51fa268f6c41..9e4005e337969af764e57a937ae= 5481d7710cfc9 100644 --- a/samples/rust/rust_misc_device.rs +++ b/samples/rust/rust_misc_device.rs @@ -100,8 +100,9 @@ use kernel::{ c_str, device::Device, - fs::File, + fs::{File, Kiocb}, ioctl::{_IO, _IOC_SIZE, _IOR, _IOW}, + iov::{IovIterDest, IovIterSource}, miscdevice::{MiscDevice, MiscDeviceOptions, MiscDeviceRegistration}, new_mutex, prelude::*, @@ -144,6 +145,7 @@ fn init(_module: &'static ThisModule) -> impl PinInit { =20 struct Inner { value: i32, + buffer: KVVec, } =20 #[pin_data(PinnedDrop)] @@ -165,7 +167,10 @@ fn open(_file: &File, misc: &MiscDeviceRegistration) -> Result) -> Result, iov: &mut IovIterDest<'_= >) -> Result { + let me =3D kiocb.file(); + dev_info!(me.dev, "Reading from Rust Misc Device Sample\n"); + + let inner =3D me.inner.lock(); + // Read the buffer contents, taking the file position into account. + let read =3D iov.simple_read_from_buffer(kiocb.ki_pos_mut(), &inne= r.buffer)?; + + Ok(read) + } + + fn write_iter(mut kiocb: Kiocb<'_, Self::Ptr>, iov: &mut IovIterSource= <'_>) -> Result { + let me =3D kiocb.file(); + dev_info!(me.dev, "Writing to Rust Misc Device Sample\n"); + + let mut inner =3D me.inner.lock(); + + // Replace buffer contents. + inner.buffer.clear(); + let len =3D iov.copy_from_iter_vec(&mut inner.buffer, GFP_KERNEL)?; + + // Set position to zero so that future `read` calls will see the n= ew contents. + *kiocb.ki_pos_mut() =3D 0; + + Ok(len) + } + fn ioctl(me: Pin<&RustMiscDevice>, _file: &File, cmd: u32, arg: usize)= -> Result { dev_info!(me.dev, "IOCTLing Rust Misc Device Sample\n"); =20 --=20 2.51.0.rc0.205.g4a044479a3-goog