mirror of
https://github.com/torvalds/linux.git
synced 2026-01-25 15:03:52 +08:00
rust_binder: report freeze notification only when fully frozen
Binder only sends out freeze notifications when ioctl_freeze() completes and the process has become fully frozen. However, if a freeze notification is registered during the freeze operation, then it registers an initial state of 'frozen'. This is a problem because if the freeze operation fails, then the listener is not told about that state change, leading to lost updates. Signed-off-by: Alice Ryhl <aliceryhl@google.com> Acked-by: Carlos Llamas <cmllamas@google.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
99559e5bb4
commit
b5ce7a5cc5
@@ -121,7 +121,7 @@ impl DeliverToRead for FreezeMessage {
|
||||
writer.write_payload(&self.cookie.0)?;
|
||||
Ok(true)
|
||||
} else {
|
||||
let is_frozen = freeze.node.owner.inner.lock().is_frozen;
|
||||
let is_frozen = freeze.node.owner.inner.lock().is_frozen.is_fully_frozen();
|
||||
if freeze.last_is_frozen == Some(is_frozen) {
|
||||
return Ok(true);
|
||||
}
|
||||
@@ -254,7 +254,7 @@ impl Process {
|
||||
);
|
||||
return Err(EINVAL);
|
||||
}
|
||||
let is_frozen = freeze.node.owner.inner.lock().is_frozen;
|
||||
let is_frozen = freeze.node.owner.inner.lock().is_frozen.is_fully_frozen();
|
||||
if freeze.is_clearing || freeze.last_is_frozen != Some(is_frozen) {
|
||||
// Immediately send another FreezeMessage.
|
||||
clear_msg = Some(FreezeMessage::init(alloc, cookie));
|
||||
|
||||
@@ -72,6 +72,33 @@ impl Mapping {
|
||||
const PROC_DEFER_FLUSH: u8 = 1;
|
||||
const PROC_DEFER_RELEASE: u8 = 2;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) enum IsFrozen {
|
||||
Yes,
|
||||
No,
|
||||
InProgress,
|
||||
}
|
||||
|
||||
impl IsFrozen {
|
||||
/// Whether incoming transactions should be rejected due to freeze.
|
||||
pub(crate) fn is_frozen(self) -> bool {
|
||||
match self {
|
||||
IsFrozen::Yes => true,
|
||||
IsFrozen::No => false,
|
||||
IsFrozen::InProgress => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether freeze notifications consider this process frozen.
|
||||
pub(crate) fn is_fully_frozen(self) -> bool {
|
||||
match self {
|
||||
IsFrozen::Yes => true,
|
||||
IsFrozen::No => false,
|
||||
IsFrozen::InProgress => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The fields of `Process` protected by the spinlock.
|
||||
pub(crate) struct ProcessInner {
|
||||
is_manager: bool,
|
||||
@@ -98,7 +125,7 @@ pub(crate) struct ProcessInner {
|
||||
/// are woken up.
|
||||
outstanding_txns: u32,
|
||||
/// Process is frozen and unable to service binder transactions.
|
||||
pub(crate) is_frozen: bool,
|
||||
pub(crate) is_frozen: IsFrozen,
|
||||
/// Process received sync transactions since last frozen.
|
||||
pub(crate) sync_recv: bool,
|
||||
/// Process received async transactions since last frozen.
|
||||
@@ -124,7 +151,7 @@ impl ProcessInner {
|
||||
started_thread_count: 0,
|
||||
defer_work: 0,
|
||||
outstanding_txns: 0,
|
||||
is_frozen: false,
|
||||
is_frozen: IsFrozen::No,
|
||||
sync_recv: false,
|
||||
async_recv: false,
|
||||
binderfs_file: None,
|
||||
@@ -1260,7 +1287,7 @@ impl Process {
|
||||
let is_manager = {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.is_dead = true;
|
||||
inner.is_frozen = false;
|
||||
inner.is_frozen = IsFrozen::No;
|
||||
inner.sync_recv = false;
|
||||
inner.async_recv = false;
|
||||
inner.is_manager
|
||||
@@ -1367,7 +1394,7 @@ impl Process {
|
||||
return;
|
||||
}
|
||||
inner.outstanding_txns -= 1;
|
||||
inner.is_frozen && inner.outstanding_txns == 0
|
||||
inner.is_frozen.is_frozen() && inner.outstanding_txns == 0
|
||||
};
|
||||
|
||||
if wake {
|
||||
@@ -1381,7 +1408,7 @@ impl Process {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.sync_recv = false;
|
||||
inner.async_recv = false;
|
||||
inner.is_frozen = false;
|
||||
inner.is_frozen = IsFrozen::No;
|
||||
drop(inner);
|
||||
msgs.send_messages();
|
||||
return Ok(());
|
||||
@@ -1390,7 +1417,7 @@ impl Process {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.sync_recv = false;
|
||||
inner.async_recv = false;
|
||||
inner.is_frozen = true;
|
||||
inner.is_frozen = IsFrozen::InProgress;
|
||||
|
||||
if info.timeout_ms > 0 {
|
||||
let mut jiffies = kernel::time::msecs_to_jiffies(info.timeout_ms);
|
||||
@@ -1404,7 +1431,7 @@ impl Process {
|
||||
.wait_interruptible_timeout(&mut inner, jiffies)
|
||||
{
|
||||
CondVarTimeoutResult::Signal { .. } => {
|
||||
inner.is_frozen = false;
|
||||
inner.is_frozen = IsFrozen::No;
|
||||
return Err(ERESTARTSYS);
|
||||
}
|
||||
CondVarTimeoutResult::Woken { jiffies: remaining } => {
|
||||
@@ -1418,17 +1445,18 @@ impl Process {
|
||||
}
|
||||
|
||||
if inner.txns_pending_locked() {
|
||||
inner.is_frozen = false;
|
||||
inner.is_frozen = IsFrozen::No;
|
||||
Err(EAGAIN)
|
||||
} else {
|
||||
drop(inner);
|
||||
match self.prepare_freeze_messages() {
|
||||
Ok(batch) => {
|
||||
self.inner.lock().is_frozen = IsFrozen::Yes;
|
||||
batch.send_messages();
|
||||
Ok(())
|
||||
}
|
||||
Err(kernel::alloc::AllocError) => {
|
||||
self.inner.lock().is_frozen = false;
|
||||
self.inner.lock().is_frozen = IsFrozen::No;
|
||||
Err(ENOMEM)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ impl Transaction {
|
||||
|
||||
if oneway {
|
||||
if let Some(target_node) = self.target_node.clone() {
|
||||
if process_inner.is_frozen {
|
||||
if process_inner.is_frozen.is_frozen() {
|
||||
process_inner.async_recv = true;
|
||||
if self.flags & TF_UPDATE_TXN != 0 {
|
||||
if let Some(t_outdated) =
|
||||
@@ -270,7 +270,7 @@ impl Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
if process_inner.is_frozen {
|
||||
if process_inner.is_frozen.is_frozen() {
|
||||
return Err(BinderError::new_frozen_oneway());
|
||||
} else {
|
||||
return Ok(());
|
||||
@@ -280,7 +280,7 @@ impl Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
if process_inner.is_frozen {
|
||||
if process_inner.is_frozen.is_frozen() {
|
||||
process_inner.sync_recv = true;
|
||||
return Err(BinderError::new_frozen());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user