diff options
Diffstat (limited to 'drivers/android')
| -rw-r--r-- | drivers/android/binder.c | 38 | ||||
| -rw-r--r-- | drivers/android/binder/freeze.rs | 18 | ||||
| -rw-r--r-- | drivers/android/binder/node.rs | 2 | ||||
| -rw-r--r-- | drivers/android/binder/process.rs | 50 | ||||
| -rw-r--r-- | drivers/android/binder/transaction.rs | 6 | 
5 files changed, 70 insertions, 44 deletions
diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 8c99ceaa303b..a3a1b5c33ba3 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -851,17 +851,8 @@ static int binder_inc_node_nilocked(struct binder_node *node, int strong,  	} else {  		if (!internal)  			node->local_weak_refs++; -		if (!node->has_weak_ref && list_empty(&node->work.entry)) { -			if (target_list == NULL) { -				pr_err("invalid inc weak node for %d\n", -					node->debug_id); -				return -EINVAL; -			} -			/* -			 * See comment above -			 */ +		if (!node->has_weak_ref && target_list && list_empty(&node->work.entry))  			binder_enqueue_work_ilocked(&node->work, target_list); -		}  	}  	return 0;  } @@ -2418,10 +2409,10 @@ err_fd_not_accepted:  /**   * struct binder_ptr_fixup - data to be fixed-up in target buffer - * @offset	offset in target buffer to fixup - * @skip_size	bytes to skip in copy (fixup will be written later) - * @fixup_data	data to write at fixup offset - * @node	list node + * @offset:      offset in target buffer to fixup + * @skip_size:   bytes to skip in copy (fixup will be written later) + * @fixup_data:  data to write at fixup offset + * @node:        list node   *   * This is used for the pointer fixup list (pf) which is created and consumed   * during binder_transaction() and is only accessed locally. No @@ -2438,10 +2429,10 @@ struct binder_ptr_fixup {  /**   * struct binder_sg_copy - scatter-gather data to be copied - * @offset		offset in target buffer - * @sender_uaddr	user address in source buffer - * @length		bytes to copy - * @node		list node + * @offset:        offset in target buffer + * @sender_uaddr:  user address in source buffer + * @length:        bytes to copy + * @node:          list node   *   * This is used for the sg copy list (sgc) which is created and consumed   * during binder_transaction() and is only accessed locally. No @@ -4063,14 +4054,15 @@ binder_freeze_notification_done(struct binder_proc *proc,  /**   * binder_free_buf() - free the specified buffer - * @proc:	binder proc that owns buffer - * @buffer:	buffer to be freed - * @is_failure:	failed to send transaction + * @proc:       binder proc that owns buffer + * @thread:     binder thread performing the buffer release + * @buffer:     buffer to be freed + * @is_failure: failed to send transaction   * - * If buffer for an async transaction, enqueue the next async + * If the buffer is for an async transaction, enqueue the next async   * transaction from the node.   * - * Cleanup buffer and free it. + * Cleanup the buffer and free it.   */  static void  binder_free_buf(struct binder_proc *proc, diff --git a/drivers/android/binder/freeze.rs b/drivers/android/binder/freeze.rs index e68c3c8bc55a..220de35ae85a 100644 --- a/drivers/android/binder/freeze.rs +++ b/drivers/android/binder/freeze.rs @@ -106,13 +106,22 @@ impl DeliverToRead for FreezeMessage {              return Ok(true);          }          if freeze.is_clearing { -            _removed_listener = freeze_entry.remove_node(); +            kernel::warn_on!(freeze.num_cleared_duplicates != 0); +            if freeze.num_pending_duplicates > 0 { +                // The primary freeze listener was deleted, so convert a pending duplicate back +                // into the primary one. +                freeze.num_pending_duplicates -= 1; +                freeze.is_pending = true; +                freeze.is_clearing = true; +            } else { +                _removed_listener = freeze_entry.remove_node(); +            }              drop(node_refs);              writer.write_code(BR_CLEAR_FREEZE_NOTIFICATION_DONE)?;              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);              } @@ -245,8 +254,9 @@ impl Process {                  );                  return Err(EINVAL);              } -            if freeze.is_clearing { -                // Immediately send another FreezeMessage for BR_CLEAR_FREEZE_NOTIFICATION_DONE. +            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));              }              freeze.is_pending = false; diff --git a/drivers/android/binder/node.rs b/drivers/android/binder/node.rs index ade895ef791e..08d362deaf61 100644 --- a/drivers/android/binder/node.rs +++ b/drivers/android/binder/node.rs @@ -687,7 +687,7 @@ impl Node {              );          }          if inner.freeze_list.is_empty() { -            _unused_capacity = mem::replace(&mut inner.freeze_list, KVVec::new()); +            _unused_capacity = mem::take(&mut inner.freeze_list);          }      } diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs index f13a747e784c..7607353a5e92 100644 --- a/drivers/android/binder/process.rs +++ b/drivers/android/binder/process.rs @@ -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 @@ -1346,10 +1373,6 @@ impl Process {                  .alloc                  .take_for_each(|offset, size, debug_id, odata| {                      let ptr = offset + address; -                    pr_warn!( -                        "{}: removing orphan mapping {offset}:{size}\n", -                        self.pid_in_current_ns() -                    );                      let mut alloc =                          Allocation::new(self.clone(), debug_id, offset, size, ptr, false);                      if let Some(data) = odata { @@ -1371,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 { @@ -1385,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(()); @@ -1394,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); @@ -1408,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 } => { @@ -1422,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)                  }              } diff --git a/drivers/android/binder/transaction.rs b/drivers/android/binder/transaction.rs index 02512175d622..4bd3c0e417eb 100644 --- a/drivers/android/binder/transaction.rs +++ b/drivers/android/binder/transaction.rs @@ -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());          }  | 
