Skip to content

Commit f7679bb

Browse files
committed
Introduce a new io_buffer module.
It abstracts buffers involved in IO. This is in preparation for allowing drivers to implement `write_iter` and `read_iter`. No behaviour change is intended, this is a pure refactor. Signed-off-by: Wedson Almeida Filho <[email protected]>
1 parent 74e7d7e commit f7679bb

File tree

14 files changed

+191
-143
lines changed

14 files changed

+191
-143
lines changed

drivers/android/defs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use core::ops::{Deref, DerefMut};
44
use kernel::{
55
bindings,
66
bindings::*,
7-
user_ptr::{ReadableFromBytes, WritableToBytes},
7+
io_buffer::{ReadableFromBytes, WritableToBytes},
88
};
99

1010
macro_rules! pub_no_prefix {

drivers/android/node.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use core::{
66
sync::atomic::{AtomicU64, Ordering},
77
};
88
use kernel::{
9+
io_buffer::IoBufferWriter,
910
linked_list::{GetLinks, Links, List},
1011
prelude::*,
1112
sync::{Guard, LockedBy, Mutex, Ref, SpinLock},

drivers/android/process.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use core::{
99
use kernel::{
1010
bindings, c_types,
1111
file_operations::{File, FileOpener, FileOperations, IoctlCommand, IoctlHandler, PollTable},
12+
io_buffer::{IoBufferReader, IoBufferWriter},
1213
linked_list::List,
1314
pages::Pages,
1415
prelude::*,

drivers/android/rust_binder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use alloc::{boxed::Box, sync::Arc};
1111
use core::pin::Pin;
1212
use kernel::{
1313
cstr,
14+
io_buffer::IoBufferWriter,
1415
linked_list::{GetLinks, GetLinksWrapped, Links},
1516
miscdev::Registration,
1617
prelude::*,

drivers/android/thread.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use core::{alloc::AllocError, mem::size_of, pin::Pin};
55
use kernel::{
66
bindings,
77
file_operations::{File, PollTable},
8+
io_buffer::{IoBufferReader, IoBufferWriter},
89
linked_list::{GetLinks, Links, List},
910
prelude::*,
1011
sync::{CondVar, Ref, SpinLock},

drivers/android/transaction.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
use alloc::sync::Arc;
44
use core::sync::atomic::{AtomicBool, Ordering};
5-
use kernel::{bindings, linked_list::Links, prelude::*, sync::Ref, user_ptr::UserSlicePtrWriter};
5+
use kernel::{
6+
bindings, io_buffer::IoBufferWriter, linked_list::Links, prelude::*, sync::Ref,
7+
user_ptr::UserSlicePtrWriter,
8+
};
69

710
use crate::{
811
defs::*,

rust/kernel/io_buffer.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Buffers used in IO.
4+
5+
use crate::KernelResult;
6+
use alloc::vec::Vec;
7+
use core::mem::{size_of, MaybeUninit};
8+
9+
/// Represents a buffer to be read from during IO.
10+
pub trait IoBufferReader {
11+
/// Returns the number of bytes left to be read from the io buffer.
12+
///
13+
/// Note that even reading less than this number of bytes may fail.
14+
fn len(&self) -> usize;
15+
16+
/// Returns `true` if no data is available in the io buffer.
17+
fn is_empty(&self) -> bool {
18+
self.len() == 0
19+
}
20+
21+
/// Reads raw data from the io buffer into a raw kernel buffer.
22+
///
23+
/// # Safety
24+
///
25+
/// The output buffer must be valid.
26+
unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> KernelResult;
27+
28+
/// Reads all data remaining in the io buffer.
29+
///
30+
/// Returns `EFAULT` if the address does not currently point to mapped, readable memory.
31+
fn read_all(&mut self) -> KernelResult<Vec<u8>> {
32+
let mut data = Vec::<u8>::new();
33+
data.try_reserve_exact(self.len())?;
34+
data.resize(self.len(), 0);
35+
36+
// SAFETY: The output buffer is valid as we just allocated it.
37+
unsafe { self.read_raw(data.as_mut_ptr(), data.len())? };
38+
Ok(data)
39+
}
40+
41+
/// Reads a byte slice from the io buffer.
42+
///
43+
/// Returns `EFAULT` if the byte slice is bigger than the remaining size of the user slice or
44+
/// if the address does not currently point to mapped, readable memory.
45+
fn read_slice(&mut self, data: &mut [u8]) -> KernelResult {
46+
// SAFETY: The output buffer is valid as it's coming from a live reference.
47+
unsafe { self.read_raw(data.as_mut_ptr(), data.len()) }
48+
}
49+
50+
/// Reads the contents of a plain old data (POD) type from the io buffer.
51+
fn read<T: ReadableFromBytes>(&mut self) -> KernelResult<T> {
52+
let mut out = MaybeUninit::<T>::uninit();
53+
// SAFETY: The buffer is valid as it was just allocated.
54+
unsafe { self.read_raw(out.as_mut_ptr() as _, size_of::<T>()) }?;
55+
// SAFETY: We just initialised the data.
56+
Ok(unsafe { out.assume_init() })
57+
}
58+
}
59+
60+
/// Represents a buffer to be written to during IO.
61+
pub trait IoBufferWriter {
62+
/// Returns the number of bytes left to be written into the io buffer.
63+
///
64+
/// Note that even writing less than this number of bytes may fail.
65+
fn len(&self) -> usize;
66+
67+
/// Returns `true` if the io buffer cannot hold any additional data.
68+
fn is_empty(&self) -> bool {
69+
self.len() == 0
70+
}
71+
72+
/// Writes zeroes to the io buffer.
73+
///
74+
/// Differently from the other write functions, `clear` will zero as much as it can and update
75+
/// the writer internal state to reflect this. It will, however, return an error if it cannot
76+
/// clear `len` bytes.
77+
///
78+
/// For example, if a caller requests that 100 bytes be cleared but a segfault happens after
79+
/// 20 bytes, then EFAULT is returned and the writer is advanced by 20 bytes.
80+
fn clear(&mut self, len: usize) -> KernelResult;
81+
82+
/// Writes a byte slice into the io buffer.
83+
///
84+
/// Returns `EFAULT` if the byte slice is bigger than the remaining size of the io buffer or if
85+
/// the address does not currently point to mapped, writable memory.
86+
fn write_slice(&mut self, data: &[u8]) -> KernelResult {
87+
// SAFETY: The input buffer is valid as it's coming from a live reference.
88+
unsafe { self.write_raw(data.as_ptr(), data.len()) }
89+
}
90+
91+
/// Writes raw data to the io buffer from a raw kernel buffer.
92+
///
93+
/// # Safety
94+
///
95+
/// The input buffer must be valid.
96+
unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> KernelResult;
97+
98+
/// Writes the contents of the given data into the io buffer.
99+
fn write<T: WritableToBytes>(&mut self, data: &T) -> KernelResult<()> {
100+
// SAFETY: The input buffer is valid as it's coming from a live
101+
// reference to a type that implements `WritableToBytes`.
102+
unsafe { self.write_raw(data as *const T as _, size_of::<T>()) }
103+
}
104+
}
105+
106+
/// Specifies that a type is safely readable from byte slices.
107+
///
108+
/// Not all types can be safely read from byte slices; examples from
109+
/// <https://doc.rust-lang.org/reference/behavior-considered-undefined.html> include `bool`
110+
/// that must be either `0` or `1`, and `char` that cannot be a surrogate or above `char::MAX`.
111+
///
112+
/// # Safety
113+
///
114+
/// Implementers must ensure that the type is made up only of types that can be safely read from
115+
/// arbitrary byte sequences (e.g., `u32`, `u64`, etc.).
116+
pub unsafe trait ReadableFromBytes {}
117+
118+
// SAFETY: All bit patterns are acceptable values of the types below.
119+
unsafe impl ReadableFromBytes for u8 {}
120+
unsafe impl ReadableFromBytes for u16 {}
121+
unsafe impl ReadableFromBytes for u32 {}
122+
unsafe impl ReadableFromBytes for u64 {}
123+
unsafe impl ReadableFromBytes for usize {}
124+
unsafe impl ReadableFromBytes for i8 {}
125+
unsafe impl ReadableFromBytes for i16 {}
126+
unsafe impl ReadableFromBytes for i32 {}
127+
unsafe impl ReadableFromBytes for i64 {}
128+
unsafe impl ReadableFromBytes for isize {}
129+
130+
/// Specifies that a type is safely writable to byte slices.
131+
///
132+
/// This means that we don't read undefined values (which leads to UB) in preparation for writing
133+
/// to the byte slice. It also ensures that no potentially sensitive information is leaked into the
134+
/// byte slices.
135+
///
136+
/// # Safety
137+
///
138+
/// A type must not include padding bytes and must be fully initialised to safely implement
139+
/// [`WritableToBytes`] (i.e., it doesn't contain [`MaybeUninit`] fields). A composition of
140+
/// writable types in a structure is not necessarily writable because it may result in padding
141+
/// bytes.
142+
pub unsafe trait WritableToBytes {}
143+
144+
// SAFETY: Initialised instances of the following types have no uninitialised portions.
145+
unsafe impl WritableToBytes for u8 {}
146+
unsafe impl WritableToBytes for u16 {}
147+
unsafe impl WritableToBytes for u32 {}
148+
unsafe impl WritableToBytes for u64 {}
149+
unsafe impl WritableToBytes for usize {}
150+
unsafe impl WritableToBytes for i8 {}
151+
unsafe impl WritableToBytes for i16 {}
152+
unsafe impl WritableToBytes for i32 {}
153+
unsafe impl WritableToBytes for i64 {}
154+
unsafe impl WritableToBytes for isize {}

rust/kernel/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ pub mod sync;
5959
#[cfg(CONFIG_SYSCTL)]
6060
pub mod sysctl;
6161

62+
pub mod io_buffer;
6263
mod types;
6364
pub mod user_ptr;
6465

rust/kernel/pages.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
//!
55
//! TODO: This module is a work in progress.
66
7-
use crate::{bindings, c_types, user_ptr::UserSlicePtrReader, Error, KernelResult, PAGE_SIZE};
7+
use crate::{
8+
bindings, c_types, io_buffer::IoBufferReader, user_ptr::UserSlicePtrReader, Error,
9+
KernelResult, PAGE_SIZE,
10+
};
811
use core::{marker::PhantomData, ptr};
912

1013
extern "C" {
@@ -95,7 +98,7 @@ impl<const ORDER: u32> Pages<ORDER> {
9598
///
9699
/// Callers must ensure that the destination buffer is valid for the given length.
97100
/// Additionally, if the raw buffer is intended to be recast, they must ensure that the data
98-
/// can be safely cast; [`crate::user_ptr::ReadableFromBytes`] has more details about it.
101+
/// can be safely cast; [`crate::io_buffer::ReadableFromBytes`] has more details about it.
99102
pub unsafe fn read(&self, dest: *mut u8, offset: usize, len: usize) -> KernelResult {
100103
// TODO: For now this only works on the first page.
101104
let end = offset.checked_add(len).ok_or(Error::EINVAL)?;
@@ -114,7 +117,7 @@ impl<const ORDER: u32> Pages<ORDER> {
114117
///
115118
/// Callers must ensure that the buffer is valid for the given length. Additionally, if the
116119
/// page is (or will be) mapped by userspace, they must ensure that no kernel data is leaked
117-
/// through padding if it was cast from another type; [`crate::user_ptr::WritableToBytes`] has
120+
/// through padding if it was cast from another type; [`crate::io_buffer::WritableToBytes`] has
118121
/// more details about it.
119122
pub unsafe fn write(&self, src: *const u8, offset: usize, len: usize) -> KernelResult {
120123
// TODO: For now this only works on the first page.

rust/kernel/sysctl.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ use core::mem;
1212
use core::ptr;
1313
use core::sync::atomic;
1414

15-
use crate::bindings;
16-
use crate::c_types;
17-
use crate::error;
18-
use crate::types;
19-
use crate::user_ptr::{UserSlicePtr, UserSlicePtrWriter};
15+
use crate::{
16+
bindings, c_types, error,
17+
io_buffer::IoBufferWriter,
18+
types,
19+
user_ptr::{UserSlicePtr, UserSlicePtrWriter},
20+
};
2021

2122
/// Sysctl storage.
2223
pub trait SysctlStorage: Sync {

0 commit comments

Comments
 (0)