[PATCH 5/5] samples: rust_misc_device: Expand the sample to support read()ing from userspace

Alice Ryhl
2025-03-11T14:26:10Z

From: Lee Jones <lee@kernel.org>

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 <lee@kernel.org>
Co-developed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
samples/rust/rust_misc_device.rs | 37 +++++++++++++++++++++++++++++++++++--
1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/samples/rust/rust_misc_device.rs b/samples/rust/rust_misc_device.rs
index 40ad7266c2252e5c0b4e91e501ef9ada2eda3b16..6405713fc8ff69659799f30710074487ea3bb14e 100644
--- a/samples/rust/rust_misc_device.rs
+++ b/samples/rust/rust_misc_device.rs
@@ -101,7 +101,9 @@
device::Device,
fs::File,
ioctl::{_IO, _IOC_SIZE, _IOR, _IOW},
- miscdevice::{MiscDevice, MiscDeviceOptions, MiscDeviceRegistration},
+ iov::{IovIterDest, IovIterSource},
+ kvec,
+ miscdevice::{Kiocb, MiscDevice, MiscDeviceOptions, MiscDeviceRegistration},
new_mutex,
prelude::*,
sync::Mutex,
@@ -143,6 +145,7 @@ fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {

struct Inner {
value: i32,
+ buffer: KVec<u8>,
}

#[pin_data(PinnedDrop)]
@@ -164,7 +167,10 @@ fn open(_file: &File, misc: &MiscDeviceRegistration<Self>) -> Result<Pin<KBox<Se
KBox::try_pin_init(
try_pin_init! {
RustMiscDevice {
- inner <- new_mutex!( Inner{ value: 0_i32 } ),
+ inner <- new_mutex!(Inner {
+ value: 0_i32,
+ buffer: kvec![],
+ }),
dev: dev,
}
},
@@ -172,6 +178,33 @@ fn open(_file: &File, misc: &MiscDeviceRegistration<Self>) -> Result<Pin<KBox<Se
)
}

+ fn read_iter(mut kiocb: Kiocb<'_, Self::Ptr>, iov: &mut IovIterDest<'_>) -> Result<usize> {
+ let me = kiocb.private_data();
+ dev_info!(me.dev, "Reading from Rust Misc Device Sample\n");
+
+ let inner = me.inner.lock();
+ // Read the buffer contents, taking the file position into account.
+ let read = iov.simple_read_from_buffer(kiocb.ki_pos_mut(), &inner.buffer)?;
+
+ Ok(read)
+ }
+
+ fn write_iter(mut kiocb: Kiocb<'_, Self::Ptr>, iov: &mut IovIterSource<'_>) -> Result<usize> {
+ let me = kiocb.private_data();
+ dev_info!(me.dev, "Writing to Rust Misc Device Sample\n");
+
+ let mut inner = me.inner.lock();
+
+ // Replace buffer contents.
+ inner.buffer.clear();
+ let len = iov.copy_from_iter_vec(&mut inner.buffer, GFP_KERNEL)?;
+
+ // Set position to zero so that future `read` calls will see the new contents.
+ *kiocb.ki_pos_mut() = 0;
+
+ Ok(len)
+ }
+
fn ioctl(me: Pin<&RustMiscDevice>, _file: &File, cmd: u32, arg: usize) -> Result<isize> {
dev_info!(me.dev, "IOCTLing Rust Misc Device Sample\n");

--
2.49.0.rc0.332.g42c0ae87b1-goog