Skip to content

Commit 3c30819

Browse files
authored
Merge pull request #231 from wedsonaf/iter
Add support for `read_iter` and `write_iter`.
2 parents a6efc40 + ef558a5 commit 3c30819

File tree

6 files changed

+160
-3
lines changed

6 files changed

+160
-3
lines changed

rust/helpers.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <linux/sched/signal.h>
77
#include <linux/gfp.h>
88
#include <linux/highmem.h>
9+
#include <linux/uio.h>
910

1011
void rust_helper_BUG(void)
1112
{
@@ -92,6 +93,18 @@ int rust_helper_cond_resched(void)
9293
}
9394
EXPORT_SYMBOL_GPL(rust_helper_cond_resched);
9495

96+
size_t rust_helper_copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
97+
{
98+
return copy_from_iter(addr, bytes, i);
99+
}
100+
EXPORT_SYMBOL_GPL(rust_helper_copy_from_iter);
101+
102+
size_t rust_helper_copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
103+
{
104+
return copy_to_iter(addr, bytes, i);
105+
}
106+
EXPORT_SYMBOL_GPL(rust_helper_copy_to_iter);
107+
95108
#if !defined(CONFIG_ARM)
96109
// See https://github.com/rust-lang/rust-bindgen/issues/1671
97110
static_assert(__builtin_types_compatible_p(size_t, uintptr_t),

rust/kernel/bindings_helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/slab.h>
88
#include <linux/sysctl.h>
99
#include <linux/uaccess.h>
10+
#include <linux/uio.h>
1011
#include <linux/version.h>
1112
#include <linux/miscdevice.h>
1213
#include <linux/poll.h>

rust/kernel/file_operations.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::{
1414
bindings, c_types,
1515
error::{Error, KernelResult},
1616
io_buffer::{IoBufferReader, IoBufferWriter},
17+
iov_iter::IovIter,
1718
sync::{CondVar, Ref, RefCounted},
1819
user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter},
1920
};
@@ -157,6 +158,21 @@ unsafe extern "C" fn read_callback<T: FileOperations>(
157158
}
158159
}
159160

161+
unsafe extern "C" fn read_iter_callback<T: FileOperations>(
162+
iocb: *mut bindings::kiocb,
163+
raw_iter: *mut bindings::iov_iter,
164+
) -> isize {
165+
from_kernel_result! {
166+
let mut iter = IovIter::from_ptr(raw_iter);
167+
let file = (*iocb).ki_filp;
168+
let offset = (*iocb).ki_pos;
169+
let f = &*((*file).private_data as *const T);
170+
let read = f.read(&File::from_ptr(file), &mut iter, offset.try_into()?)?;
171+
(*iocb).ki_pos += bindings::loff_t::try_from(read).unwrap();
172+
Ok(read as _)
173+
}
174+
}
175+
160176
unsafe extern "C" fn write_callback<T: FileOperations>(
161177
file: *mut bindings::file,
162178
buf: *const c_types::c_char,
@@ -174,6 +190,21 @@ unsafe extern "C" fn write_callback<T: FileOperations>(
174190
}
175191
}
176192

193+
unsafe extern "C" fn write_iter_callback<T: FileOperations>(
194+
iocb: *mut bindings::kiocb,
195+
raw_iter: *mut bindings::iov_iter,
196+
) -> isize {
197+
from_kernel_result! {
198+
let mut iter = IovIter::from_ptr(raw_iter);
199+
let file = (*iocb).ki_filp;
200+
let offset = (*iocb).ki_pos;
201+
let f = &*((*file).private_data as *const T);
202+
let written = f.write(&File::from_ptr(file), &mut iter, offset.try_into()?)?;
203+
(*iocb).ki_pos += bindings::loff_t::try_from(written).unwrap();
204+
Ok(written as _)
205+
}
206+
}
207+
177208
unsafe extern "C" fn release_callback<T: FileOperations>(
178209
_inode: *mut bindings::inode,
179210
file: *mut bindings::file,
@@ -323,7 +354,11 @@ impl<A: FileOpenAdapter, T: FileOpener<A::Arg>> FileOperationsVtable<A, T> {
323354
} else {
324355
None
325356
},
326-
read_iter: None,
357+
read_iter: if T::TO_USE.read_iter {
358+
Some(read_iter_callback::<T>)
359+
} else {
360+
None
361+
},
327362
remap_file_range: None,
328363
sendpage: None,
329364
setlease: None,
@@ -335,7 +370,11 @@ impl<A: FileOpenAdapter, T: FileOpener<A::Arg>> FileOperationsVtable<A, T> {
335370
} else {
336371
None
337372
},
338-
write_iter: None,
373+
write_iter: if T::TO_USE.write_iter {
374+
Some(write_iter_callback::<T>)
375+
} else {
376+
None
377+
},
339378
};
340379

341380
/// Builds an instance of [`struct file_operations`].
@@ -353,9 +392,15 @@ pub struct ToUse {
353392
/// The `read` field of [`struct file_operations`].
354393
pub read: bool,
355394

395+
/// The `read_iter` field of [`struct file_operations`].
396+
pub read_iter: bool,
397+
356398
/// The `write` field of [`struct file_operations`].
357399
pub write: bool,
358400

401+
/// The `write_iter` field of [`struct file_operations`].
402+
pub write_iter: bool,
403+
359404
/// The `llseek` field of [`struct file_operations`].
360405
pub seek: bool,
361406

@@ -379,7 +424,9 @@ pub struct ToUse {
379424
/// be set to null pointers.
380425
pub const USE_NONE: ToUse = ToUse {
381426
read: false,
427+
read_iter: false,
382428
write: false,
429+
write_iter: false,
383430
seek: false,
384431
ioctl: false,
385432
compat_ioctl: false,

rust/kernel/iov_iter.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! IO vector iterators.
4+
//!
5+
//! C header: [`include/linux/uio.h`](../../../../include/linux/uio.h)
6+
7+
use crate::{
8+
bindings, c_types,
9+
error::Error,
10+
io_buffer::{IoBufferReader, IoBufferWriter},
11+
KernelResult,
12+
};
13+
14+
extern "C" {
15+
fn rust_helper_copy_to_iter(
16+
addr: *const c_types::c_void,
17+
bytes: usize,
18+
i: *mut bindings::iov_iter,
19+
) -> usize;
20+
21+
fn rust_helper_copy_from_iter(
22+
addr: *mut c_types::c_void,
23+
bytes: usize,
24+
i: *mut bindings::iov_iter,
25+
) -> usize;
26+
}
27+
28+
/// Wraps the kernel's `struct iov_iter`.
29+
///
30+
/// # Invariants
31+
///
32+
/// The pointer [`IovIter::ptr`] is non-null and valid.
33+
pub struct IovIter {
34+
ptr: *mut bindings::iov_iter,
35+
}
36+
37+
impl IovIter {
38+
fn common_len(&self) -> usize {
39+
// SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
40+
unsafe { (*self.ptr).count }
41+
}
42+
43+
/// Constructs a new [`struct iov_iter`] wrapper.
44+
///
45+
/// # Safety
46+
///
47+
/// The pointer `ptr` must be non-null and valid for the lifetime of the object.
48+
pub(crate) unsafe fn from_ptr(ptr: *mut bindings::iov_iter) -> Self {
49+
// INVARIANTS: the safety contract ensures the type invariant will hold.
50+
Self { ptr }
51+
}
52+
}
53+
54+
impl IoBufferWriter for IovIter {
55+
fn len(&self) -> usize {
56+
self.common_len()
57+
}
58+
59+
fn clear(&mut self, mut len: usize) -> KernelResult {
60+
while len > 0 {
61+
// SAFETY: `IovIter::ptr` is guaranteed to be valid by the type invariants.
62+
let written = unsafe { bindings::iov_iter_zero(len, self.ptr) };
63+
if written == 0 {
64+
return Err(Error::EFAULT);
65+
}
66+
67+
len -= written;
68+
}
69+
Ok(())
70+
}
71+
72+
unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> KernelResult {
73+
let res = rust_helper_copy_to_iter(data as _, len, self.ptr);
74+
if res != len {
75+
Err(Error::EFAULT)
76+
} else {
77+
Ok(())
78+
}
79+
}
80+
}
81+
82+
impl IoBufferReader for IovIter {
83+
fn len(&self) -> usize {
84+
self.common_len()
85+
}
86+
87+
unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> KernelResult {
88+
let res = rust_helper_copy_from_iter(out as _, len, self.ptr);
89+
if res != len {
90+
Err(Error::EFAULT)
91+
} else {
92+
Ok(())
93+
}
94+
}
95+
}

rust/kernel/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ pub mod sync;
6060
pub mod sysctl;
6161

6262
pub mod io_buffer;
63+
pub mod iov_iter;
6364
mod types;
6465
pub mod user_ptr;
6566

samples/rust/rust_random.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use kernel::{
1818
struct RandomFile;
1919

2020
impl FileOperations for RandomFile {
21-
kernel::declare_file_operations!(read, write);
21+
kernel::declare_file_operations!(read, write, read_iter, write_iter);
2222

2323
fn read<T: IoBufferWriter>(
2424
&self,

0 commit comments

Comments
 (0)