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>

authored by Alice Ryhl and committed by Greg Kroah-Hartman b5ce7a5c 99559e5b

+42 -14
+2 -2
drivers/android/binder/freeze.rs
··· 121 writer.write_payload(&self.cookie.0)?; 122 Ok(true) 123 } else { 124 - let is_frozen = freeze.node.owner.inner.lock().is_frozen; 125 if freeze.last_is_frozen == Some(is_frozen) { 126 return Ok(true); 127 } ··· 254 ); 255 return Err(EINVAL); 256 } 257 - let is_frozen = freeze.node.owner.inner.lock().is_frozen; 258 if freeze.is_clearing || freeze.last_is_frozen != Some(is_frozen) { 259 // Immediately send another FreezeMessage. 260 clear_msg = Some(FreezeMessage::init(alloc, cookie));
··· 121 writer.write_payload(&self.cookie.0)?; 122 Ok(true) 123 } else { 124 + let is_frozen = freeze.node.owner.inner.lock().is_frozen.is_fully_frozen(); 125 if freeze.last_is_frozen == Some(is_frozen) { 126 return Ok(true); 127 } ··· 254 ); 255 return Err(EINVAL); 256 } 257 + let is_frozen = freeze.node.owner.inner.lock().is_frozen.is_fully_frozen(); 258 if freeze.is_clearing || freeze.last_is_frozen != Some(is_frozen) { 259 // Immediately send another FreezeMessage. 260 clear_msg = Some(FreezeMessage::init(alloc, cookie));
+37 -9
drivers/android/binder/process.rs
··· 72 const PROC_DEFER_FLUSH: u8 = 1; 73 const PROC_DEFER_RELEASE: u8 = 2; 74 75 /// The fields of `Process` protected by the spinlock. 76 pub(crate) struct ProcessInner { 77 is_manager: bool, ··· 125 /// are woken up. 126 outstanding_txns: u32, 127 /// Process is frozen and unable to service binder transactions. 128 - pub(crate) is_frozen: bool, 129 /// Process received sync transactions since last frozen. 130 pub(crate) sync_recv: bool, 131 /// Process received async transactions since last frozen. ··· 151 started_thread_count: 0, 152 defer_work: 0, 153 outstanding_txns: 0, 154 - is_frozen: false, 155 sync_recv: false, 156 async_recv: false, 157 binderfs_file: None, ··· 1287 let is_manager = { 1288 let mut inner = self.inner.lock(); 1289 inner.is_dead = true; 1290 - inner.is_frozen = false; 1291 inner.sync_recv = false; 1292 inner.async_recv = false; 1293 inner.is_manager ··· 1394 return; 1395 } 1396 inner.outstanding_txns -= 1; 1397 - inner.is_frozen && inner.outstanding_txns == 0 1398 }; 1399 1400 if wake { ··· 1408 let mut inner = self.inner.lock(); 1409 inner.sync_recv = false; 1410 inner.async_recv = false; 1411 - inner.is_frozen = false; 1412 drop(inner); 1413 msgs.send_messages(); 1414 return Ok(()); ··· 1417 let mut inner = self.inner.lock(); 1418 inner.sync_recv = false; 1419 inner.async_recv = false; 1420 - inner.is_frozen = true; 1421 1422 if info.timeout_ms > 0 { 1423 let mut jiffies = kernel::time::msecs_to_jiffies(info.timeout_ms); ··· 1431 .wait_interruptible_timeout(&mut inner, jiffies) 1432 { 1433 CondVarTimeoutResult::Signal { .. } => { 1434 - inner.is_frozen = false; 1435 return Err(ERESTARTSYS); 1436 } 1437 CondVarTimeoutResult::Woken { jiffies: remaining } => { ··· 1445 } 1446 1447 if inner.txns_pending_locked() { 1448 - inner.is_frozen = false; 1449 Err(EAGAIN) 1450 } else { 1451 drop(inner); 1452 match self.prepare_freeze_messages() { 1453 Ok(batch) => { 1454 batch.send_messages(); 1455 Ok(()) 1456 } 1457 Err(kernel::alloc::AllocError) => { 1458 - self.inner.lock().is_frozen = false; 1459 Err(ENOMEM) 1460 } 1461 }
··· 72 const PROC_DEFER_FLUSH: u8 = 1; 73 const PROC_DEFER_RELEASE: u8 = 2; 74 75 + #[derive(Copy, Clone)] 76 + pub(crate) enum IsFrozen { 77 + Yes, 78 + No, 79 + InProgress, 80 + } 81 + 82 + impl IsFrozen { 83 + /// Whether incoming transactions should be rejected due to freeze. 84 + pub(crate) fn is_frozen(self) -> bool { 85 + match self { 86 + IsFrozen::Yes => true, 87 + IsFrozen::No => false, 88 + IsFrozen::InProgress => true, 89 + } 90 + } 91 + 92 + /// Whether freeze notifications consider this process frozen. 93 + pub(crate) fn is_fully_frozen(self) -> bool { 94 + match self { 95 + IsFrozen::Yes => true, 96 + IsFrozen::No => false, 97 + IsFrozen::InProgress => false, 98 + } 99 + } 100 + } 101 + 102 /// The fields of `Process` protected by the spinlock. 103 pub(crate) struct ProcessInner { 104 is_manager: bool, ··· 98 /// are woken up. 99 outstanding_txns: u32, 100 /// Process is frozen and unable to service binder transactions. 101 + pub(crate) is_frozen: IsFrozen, 102 /// Process received sync transactions since last frozen. 103 pub(crate) sync_recv: bool, 104 /// Process received async transactions since last frozen. ··· 124 started_thread_count: 0, 125 defer_work: 0, 126 outstanding_txns: 0, 127 + is_frozen: IsFrozen::No, 128 sync_recv: false, 129 async_recv: false, 130 binderfs_file: None, ··· 1260 let is_manager = { 1261 let mut inner = self.inner.lock(); 1262 inner.is_dead = true; 1263 + inner.is_frozen = IsFrozen::No; 1264 inner.sync_recv = false; 1265 inner.async_recv = false; 1266 inner.is_manager ··· 1367 return; 1368 } 1369 inner.outstanding_txns -= 1; 1370 + inner.is_frozen.is_frozen() && inner.outstanding_txns == 0 1371 }; 1372 1373 if wake { ··· 1381 let mut inner = self.inner.lock(); 1382 inner.sync_recv = false; 1383 inner.async_recv = false; 1384 + inner.is_frozen = IsFrozen::No; 1385 drop(inner); 1386 msgs.send_messages(); 1387 return Ok(()); ··· 1390 let mut inner = self.inner.lock(); 1391 inner.sync_recv = false; 1392 inner.async_recv = false; 1393 + inner.is_frozen = IsFrozen::InProgress; 1394 1395 if info.timeout_ms > 0 { 1396 let mut jiffies = kernel::time::msecs_to_jiffies(info.timeout_ms); ··· 1404 .wait_interruptible_timeout(&mut inner, jiffies) 1405 { 1406 CondVarTimeoutResult::Signal { .. } => { 1407 + inner.is_frozen = IsFrozen::No; 1408 return Err(ERESTARTSYS); 1409 } 1410 CondVarTimeoutResult::Woken { jiffies: remaining } => { ··· 1418 } 1419 1420 if inner.txns_pending_locked() { 1421 + inner.is_frozen = IsFrozen::No; 1422 Err(EAGAIN) 1423 } else { 1424 drop(inner); 1425 match self.prepare_freeze_messages() { 1426 Ok(batch) => { 1427 + self.inner.lock().is_frozen = IsFrozen::Yes; 1428 batch.send_messages(); 1429 Ok(()) 1430 } 1431 Err(kernel::alloc::AllocError) => { 1432 + self.inner.lock().is_frozen = IsFrozen::No; 1433 Err(ENOMEM) 1434 } 1435 }
+3 -3
drivers/android/binder/transaction.rs
··· 249 250 if oneway { 251 if let Some(target_node) = self.target_node.clone() { 252 - if process_inner.is_frozen { 253 process_inner.async_recv = true; 254 if self.flags & TF_UPDATE_TXN != 0 { 255 if let Some(t_outdated) = ··· 270 } 271 } 272 273 - if process_inner.is_frozen { 274 return Err(BinderError::new_frozen_oneway()); 275 } else { 276 return Ok(()); ··· 280 } 281 } 282 283 - if process_inner.is_frozen { 284 process_inner.sync_recv = true; 285 return Err(BinderError::new_frozen()); 286 }
··· 249 250 if oneway { 251 if let Some(target_node) = self.target_node.clone() { 252 + if process_inner.is_frozen.is_frozen() { 253 process_inner.async_recv = true; 254 if self.flags & TF_UPDATE_TXN != 0 { 255 if let Some(t_outdated) = ··· 270 } 271 } 272 273 + if process_inner.is_frozen.is_frozen() { 274 return Err(BinderError::new_frozen_oneway()); 275 } else { 276 return Ok(()); ··· 280 } 281 } 282 283 + if process_inner.is_frozen.is_frozen() { 284 process_inner.sync_recv = true; 285 return Err(BinderError::new_frozen()); 286 }