Skip to content

Commit fbf8cb5

Browse files
committed
Merge branch 'Rust-for-Linux:rust' into 295-ERROR-invariant
2 parents 710bf7d + ac536cc commit fbf8cb5

File tree

3 files changed

+76
-9
lines changed

3 files changed

+76
-9
lines changed

drivers/android/transaction.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use alloc::sync::Arc;
44
use core::sync::atomic::{AtomicBool, Ordering};
55
use kernel::{
66
io_buffer::IoBufferWriter, linked_list::Links, prelude::*, sync::Ref,
7-
user_ptr::UserSlicePtrWriter,
7+
user_ptr::UserSlicePtrWriter, ScopeGuard,
88
};
99

1010
use crate::{
@@ -144,6 +144,10 @@ impl DeliverToRead for Transaction {
144144
pub sender_pid: pid_t,
145145
pub sender_euid: uid_t,
146146
*/
147+
let send_failed_reply = ScopeGuard::new(|| {
148+
let reply = Either::Right(BR_FAILED_REPLY);
149+
self.from.deliver_reply(reply, &self);
150+
});
147151
let mut tr = BinderTransactionData::default();
148152

149153
if let Some(nref) = &self.node_ref {
@@ -171,13 +175,13 @@ impl DeliverToRead for Transaction {
171175
BR_TRANSACTION
172176
};
173177

174-
// Write the transaction code and data to the user buffer. On failure we complete the
175-
// transaction with an error.
176-
if let Err(err) = writer.write(&code).and_then(|_| writer.write(&tr)) {
177-
let reply = Either::Right(BR_FAILED_REPLY);
178-
self.from.deliver_reply(reply, &self);
179-
return Err(err);
180-
}
178+
// Write the transaction code and data to the user buffer.
179+
writer.write(&code)?;
180+
writer.write(&tr)?;
181+
182+
// Dismiss the completion of transaction with a failure. No failure paths are allowed from
183+
// here on out.
184+
send_failed_reply.dismiss();
181185

182186
// When this is not a reply and not an async transaction, update `current_transaction`. If
183187
// it's a reply, `current_transaction` has already been updated appropriately.

rust/kernel/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ pub mod user_ptr;
7777
pub use build_error::build_error;
7878

7979
pub use crate::error::{Error, Result};
80-
pub use crate::types::Mode;
80+
pub use crate::types::{Mode, ScopeGuard};
8181

8282
/// Page size defined in terms of the `PAGE_SHIFT` macro from C.
8383
///

rust/kernel/types.rs

+63
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,66 @@ impl<T: PointerWrapper + Deref> PointerWrapper for Pin<T> {
9191
Pin::new_unchecked(T::from_pointer(p))
9292
}
9393
}
94+
95+
/// Runs a cleanup function/closure when dropped.
96+
///
97+
/// The [`ScopeGuard::dismiss`] function prevents the cleanup function from running.
98+
///
99+
/// # Examples
100+
///
101+
/// In the example below, we have multiple exit paths and we want to log regardless of which one is
102+
/// taken:
103+
/// ```
104+
/// fn example1(arg: bool) {
105+
/// let _log = ScopeGuard::new(|| pr_info!("example1 completed\n"));
106+
///
107+
/// if arg {
108+
/// return;
109+
/// }
110+
///
111+
/// // Do something...
112+
/// }
113+
/// ```
114+
///
115+
/// In the example below, we want to log the same message on all early exits but a different one on
116+
/// the main exit path:
117+
/// ```
118+
/// fn example2(arg: bool) {
119+
/// let log = ScopeGuard::new(|| pr_info!("example2 returned early\n"));
120+
///
121+
/// if arg {
122+
/// return;
123+
/// }
124+
///
125+
/// // (Other early returns...)
126+
///
127+
/// log.dismiss();
128+
/// pr_info!("example2 no early return\n");
129+
/// }
130+
/// ```
131+
pub struct ScopeGuard<T: FnOnce()> {
132+
cleanup_func: Option<T>,
133+
}
134+
135+
impl<T: FnOnce()> ScopeGuard<T> {
136+
/// Creates a new cleanup object with the given cleanup function.
137+
pub fn new(cleanup_func: T) -> Self {
138+
Self {
139+
cleanup_func: Some(cleanup_func),
140+
}
141+
}
142+
143+
/// Prevents the cleanup function from running.
144+
pub fn dismiss(mut self) {
145+
self.cleanup_func.take();
146+
}
147+
}
148+
149+
impl<T: FnOnce()> Drop for ScopeGuard<T> {
150+
fn drop(&mut self) {
151+
// Run the cleanup function if one is still present.
152+
if let Some(cleanup) = self.cleanup_func.take() {
153+
cleanup();
154+
}
155+
}
156+
}

0 commit comments

Comments
 (0)