Skip to content

Commit 671977d

Browse files
wedsonaffbq
authored andcommitted
rust: alloc: update VecExt to take allocation flags
We also rename the methods by removing the `try_` prefix since the names are available due to our usage of the `no_global_oom_handling` config when building the `alloc` crate. Reviewed-by: Boqun Feng <[email protected]> Signed-off-by: Wedson Almeida Filho <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 0fccd3a commit 671977d

File tree

6 files changed

+152
-34
lines changed

6 files changed

+152
-34
lines changed

rust/kernel/alloc/vec_ext.rs

+143-15
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,175 @@
22

33
//! Extensions to [`Vec`] for fallible allocations.
44
5-
use alloc::{collections::TryReserveError, vec::Vec};
5+
use super::Flags;
6+
use alloc::{alloc::AllocError, vec::Vec};
67
use core::result::Result;
78

89
/// Extensions to [`Vec`].
910
pub trait VecExt<T>: Sized {
1011
/// Creates a new [`Vec`] instance with at least the given capacity.
11-
fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError>;
12+
///
13+
/// # Examples
14+
///
15+
/// ```
16+
/// let v = Vec::<u32>::with_capacity(20, GFP_KERNEL)?;
17+
///
18+
/// assert!(v.capacity() >= 20);
19+
/// # Ok::<(), Error>(())
20+
/// ```
21+
fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError>;
1222

1323
/// Appends an element to the back of the [`Vec`] instance.
14-
fn try_push(&mut self, v: T) -> Result<(), TryReserveError>;
24+
///
25+
/// # Examples
26+
///
27+
/// ```
28+
/// let mut v = Vec::new();
29+
/// v.push(1, GFP_KERNEL)?;
30+
/// assert_eq!(&v, &[1]);
31+
///
32+
/// v.push(2, GFP_KERNEL)?;
33+
/// assert_eq!(&v, &[1, 2]);
34+
/// # Ok::<(), Error>(())
35+
/// ```
36+
fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError>;
1537

1638
/// Pushes clones of the elements of slice into the [`Vec`] instance.
17-
fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError>
39+
///
40+
/// # Examples
41+
///
42+
/// ```
43+
/// let mut v = Vec::new();
44+
/// v.push(1, GFP_KERNEL)?;
45+
///
46+
/// v.extend_from_slice(&[20, 30, 40], GFP_KERNEL)?;
47+
/// assert_eq!(&v, &[1, 20, 30, 40]);
48+
///
49+
/// v.extend_from_slice(&[50, 60], GFP_KERNEL)?;
50+
/// assert_eq!(&v, &[1, 20, 30, 40, 50, 60]);
51+
/// # Ok::<(), Error>(())
52+
/// ```
53+
fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError>
1854
where
1955
T: Clone;
56+
57+
/// Ensures that the capacity exceeds the length by at least `additional` elements.
58+
///
59+
/// # Examples
60+
///
61+
/// ```
62+
/// let mut v = Vec::new();
63+
/// v.push(1, GFP_KERNEL)?;
64+
///
65+
/// v.reserve(10, GFP_KERNEL)?;
66+
/// let cap = v.capacity();
67+
/// assert!(cap >= 10);
68+
///
69+
/// v.reserve(10, GFP_KERNEL)?;
70+
/// let new_cap = v.capacity();
71+
/// assert_eq!(new_cap, cap);
72+
///
73+
/// # Ok::<(), Error>(())
74+
/// ```
75+
fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError>;
2076
}
2177

2278
impl<T> VecExt<T> for Vec<T> {
23-
fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError> {
79+
fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError> {
2480
let mut v = Vec::new();
25-
v.try_reserve(capacity)?;
81+
<Self as VecExt<_>>::reserve(&mut v, capacity, flags)?;
2682
Ok(v)
2783
}
2884

29-
fn try_push(&mut self, v: T) -> Result<(), TryReserveError> {
30-
if let Err(retry) = self.push_within_capacity(v) {
31-
self.try_reserve(1)?;
32-
let _ = self.push_within_capacity(retry);
33-
}
85+
fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> {
86+
<Self as VecExt<_>>::reserve(self, 1, flags)?;
87+
let s = self.spare_capacity_mut();
88+
s[0].write(v);
89+
90+
// SAFETY: We just initialised the first spare entry, so it is safe to increase the length
91+
// by 1. We also know that the new length is <= capacity because of the previous call to
92+
// `reserve` above.
93+
unsafe { self.set_len(self.len() + 1) };
3494
Ok(())
3595
}
3696

37-
fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError>
97+
fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError>
3898
where
3999
T: Clone,
40100
{
41-
self.try_reserve(other.len())?;
42-
for item in other {
43-
self.try_push(item.clone())?;
101+
<Self as VecExt<_>>::reserve(self, other.len(), flags)?;
102+
for (slot, item) in core::iter::zip(self.spare_capacity_mut(), other) {
103+
slot.write(item.clone());
44104
}
45105

106+
// SAFETY: We just initialised the `other.len()` spare entries, so it is safe to increase
107+
// the length by the same amount. We also know that the new length is <= capacity because
108+
// of the previous call to `reserve` above.
109+
unsafe { self.set_len(self.len() + other.len()) };
110+
Ok(())
111+
}
112+
113+
#[cfg(any(test, testlib))]
114+
fn reserve(&mut self, additional: usize, _flags: Flags) -> Result<(), AllocError> {
115+
Vec::reserve(self, additional);
46116
Ok(())
47117
}
118+
119+
#[cfg(not(any(test, testlib)))]
120+
fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError> {
121+
let len = self.len();
122+
let cap = self.capacity();
123+
124+
if cap - len >= additional {
125+
return Ok(());
126+
}
127+
128+
if core::mem::size_of::<T>() == 0 {
129+
// The capacity is already `usize::MAX` for SZTs, we can't go higher.
130+
return Err(AllocError);
131+
}
132+
133+
// We know cap is <= `isize::MAX` because `Layout::array` fails if the resulting byte size
134+
// is greater than `isize::MAX`. So the multiplication by two won't overflow.
135+
let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?);
136+
let layout = core::alloc::Layout::array::<T>(new_cap).map_err(|_| AllocError)?;
137+
138+
let (ptr, len, cap) = destructure(self);
139+
140+
// SAFETY: `ptr` is valid because it's either NULL or comes from a previous call to
141+
// `krealloc_aligned`. We also verified that the type is not a ZST.
142+
let new_ptr = unsafe { super::allocator::krealloc_aligned(ptr.cast(), layout, flags) };
143+
if new_ptr.is_null() {
144+
// SAFETY: We are just rebuilding the existing `Vec` with no changes.
145+
unsafe { rebuild(self, ptr, len, cap) };
146+
Err(AllocError)
147+
} else {
148+
// SAFETY: `ptr` has been reallocated with the layout for `new_cap` elements. New cap
149+
// is greater than `cap`, so it continues to be >= `len`.
150+
unsafe { rebuild(self, new_ptr.cast::<T>(), len, new_cap) };
151+
Ok(())
152+
}
153+
}
154+
}
155+
156+
#[cfg(not(any(test, testlib)))]
157+
fn destructure<T>(v: &mut Vec<T>) -> (*mut T, usize, usize) {
158+
let mut tmp = Vec::new();
159+
core::mem::swap(&mut tmp, v);
160+
let mut tmp = core::mem::ManuallyDrop::new(tmp);
161+
let len = tmp.len();
162+
let cap = tmp.capacity();
163+
(tmp.as_mut_ptr(), len, cap)
164+
}
165+
166+
/// Rebuilds a `Vec` from a pointer, length, and capacity.
167+
///
168+
/// # Safety
169+
///
170+
/// The same as [`Vec::from_raw_parts`].
171+
#[cfg(not(any(test, testlib)))]
172+
unsafe fn rebuild<T>(v: &mut Vec<T>, ptr: *mut T, len: usize, cap: usize) {
173+
// SAFETY: The safety requirements from this function satisfy those of `from_raw_parts`.
174+
let mut tmp = unsafe { Vec::from_raw_parts(ptr, len, cap) };
175+
core::mem::swap(&mut tmp, v);
48176
}

rust/kernel/error.rs

+1-10
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@
66
77
use crate::str::CStr;
88

9-
use alloc::{
10-
alloc::{AllocError, LayoutError},
11-
collections::TryReserveError,
12-
};
9+
use alloc::alloc::{AllocError, LayoutError};
1310

1411
use core::convert::From;
1512
use core::fmt;
@@ -192,12 +189,6 @@ impl From<Utf8Error> for Error {
192189
}
193190
}
194191

195-
impl From<TryReserveError> for Error {
196-
fn from(_: TryReserveError) -> Error {
197-
code::ENOMEM
198-
}
199-
}
200-
201192
impl From<LayoutError> for Error {
202193
fn from(_: LayoutError) -> Error {
203194
code::ENOMEM

rust/kernel/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#![feature(offset_of)]
2020
#![feature(receiver_trait)]
2121
#![feature(unsize)]
22-
#![feature(vec_push_within_capacity)]
2322

2423
// Ensure conditional compilation based on the kernel configuration works;
2524
// otherwise we may silently break things like initcall handling.

rust/kernel/str.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
//! String representations.
44
5-
use crate::alloc::vec_ext::VecExt;
5+
use crate::alloc::{flags::*, vec_ext::VecExt};
66
use alloc::alloc::AllocError;
77
use alloc::vec::Vec;
88
use core::fmt::{self, Write};
@@ -730,7 +730,7 @@ impl CString {
730730
let size = f.bytes_written();
731731

732732
// Allocate a vector with the required number of bytes, and write to it.
733-
let mut buf = Vec::try_with_capacity(size)?;
733+
let mut buf = <Vec<_> as VecExt<_>>::with_capacity(size, GFP_KERNEL)?;
734734
// SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes.
735735
let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) };
736736
f.write_fmt(args)?;
@@ -771,7 +771,7 @@ impl<'a> TryFrom<&'a CStr> for CString {
771771
fn try_from(cstr: &'a CStr) -> Result<CString, AllocError> {
772772
let mut buf = Vec::new();
773773

774-
buf.try_extend_from_slice(cstr.as_bytes_with_nul())
774+
<Vec<_> as VecExt<_>>::extend_from_slice(&mut buf, cstr.as_bytes_with_nul(), GFP_KERNEL)
775775
.map_err(|_| AllocError)?;
776776

777777
// INVARIANT: The `CStr` and `CString` types have the same invariants for

rust/kernel/types.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,11 @@ impl ForeignOwnable for () {
157157
/// let mut vec =
158158
/// ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len()));
159159
///
160-
/// vec.try_push(10u8)?;
160+
/// vec.push(10u8, GFP_KERNEL)?;
161161
/// if arg {
162162
/// return Ok(());
163163
/// }
164-
/// vec.try_push(20u8)?;
164+
/// vec.push(20u8, GFP_KERNEL)?;
165165
/// Ok(())
166166
/// }
167167
///

samples/rust/rust_minimal.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ impl kernel::Module for RustMinimal {
2222
pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
2323

2424
let mut numbers = Vec::new();
25-
numbers.try_push(72)?;
26-
numbers.try_push(108)?;
27-
numbers.try_push(200)?;
25+
numbers.push(72, GFP_KERNEL)?;
26+
numbers.push(108, GFP_KERNEL)?;
27+
numbers.push(200, GFP_KERNEL)?;
2828

2929
Ok(RustMinimal { numbers })
3030
}

0 commit comments

Comments
 (0)