| @@ -2626,6 +2626,56 @@ static int binder_fixup_parent(struct list_head *pf_head, · 2625 unmodified lines |
| 2626 | return binder_add_fixup(pf_head, buffer_offset, bp->buffer, 0); | 2626 | return binder_add_fixup(pf_head, buffer_offset, bp->buffer, 0); |
| 2627 | } | 2627 | } |
| 2628 | | 2628 | |
| | 2629 | /** |
| | 2630 | * binder_can_update_transaction() - Can a txn be superseded by an updated one? |
| | 2631 | * @t1: the pending async txn in the frozen process |
| | 2632 | * @t2: the new async txn to supersede the outdated pending one |
| | 2633 | * |
| | 2634 | * Return: true if t2 can supersede t1 |
| | 2635 | * false if t2 can not supersede t1 |
| | 2636 | */ |
| | 2637 | static bool binder_can_update_transaction(struct binder_transaction *t1, |
| | 2638 | struct binder_transaction *t2) |
| | 2639 | { |
| | 2640 | if ((t1->flags & t2->flags & (TF_ONE_WAY | TF_UPDATE_TXN)) != |
| | 2641 | (TF_ONE_WAY | TF_UPDATE_TXN) || !t1->to_proc || !t2->to_proc) |
| | 2642 | return false; |
| | 2643 | if (t1->to_proc->tsk == t2->to_proc->tsk && t1->code == t2->code && |
| | 2644 | t1->flags == t2->flags && t1->buffer->pid == t2->buffer->pid && |
| | 2645 | t1->buffer->target_node->ptr == t2->buffer->target_node->ptr && |
| | 2646 | t1->buffer->target_node->cookie == t2->buffer->target_node->cookie) |
| | 2647 | return true; |
| | 2648 | return false; |
| | 2649 | } |
| | 2650 | |
| | 2651 | /** |
| | 2652 | * binder_find_outdated_transaction_ilocked() - Find the outdated transaction |
| | 2653 | * @t: new async transaction |
| | 2654 | * @target_list: list to find outdated transaction |
| | 2655 | * |
| | 2656 | * Return: the outdated transaction if found |
| | 2657 | * NULL if no outdated transacton can be found |
| | 2658 | * |
| | 2659 | * Requires the proc->inner_lock to be held. |
| | 2660 | */ |
| | 2661 | static struct binder_transaction * |
| | 2662 | binder_find_outdated_transaction_ilocked(struct binder_transaction *t, |
| | 2663 | struct list_head *target_list) |
| | 2664 | { |
| | 2665 | struct binder_work *w; |
| | 2666 | |
| | 2667 | list_for_each_entry(w, target_list, entry) { |
| | 2668 | struct binder_transaction *t_queued; |
| | 2669 | |
| | 2670 | if (w->type != BINDER_WORK_TRANSACTION) |
| | 2671 | continue; |
| | 2672 | t_queued = container_of(w, struct binder_transaction, work); |
| | 2673 | if (binder_can_update_transaction(t_queued, t)) |
| | 2674 | return t_queued; |
| | 2675 | } |
| | 2676 | return NULL; |
| | 2677 | } |
| | 2678 | |
| 2629 | /** | 2679 | /** |
| 2630 | * binder_proc_transaction() - sends a transaction to a process and wakes it up | 2680 | * binder_proc_transaction() - sends a transaction to a process and wakes it up |
| 2631 | * @t: transaction to send | 2681 | * @t: transaction to send |
| @@ -2651,6 +2701,7 @@ static int binder_proc_transaction(struct binder_transaction *t, · 19 unmodified lines |
| 2651 | struct binder_node *node = t->buffer->target_node; | 2701 | struct binder_node *node = t->buffer->target_node; |
| 2652 | bool oneway = !!(t->flags & TF_ONE_WAY); | 2702 | bool oneway = !!(t->flags & TF_ONE_WAY); |
| 2653 | bool pending_async = false; | 2703 | bool pending_async = false; |
| | 2704 | struct binder_transaction *t_outdated = NULL; |
| 2654 | | 2705 | |
| 2655 | BUG_ON(!node); | 2706 | BUG_ON(!node); |
| 2656 | binder_node_lock(node); | 2707 | binder_node_lock(node); |
| @@ -2678,12 +2729,24 @@ static int binder_proc_transaction(struct binder_transaction *t, · 21 unmodified lines |
| 2678 | if (!thread && !pending_async) | 2729 | if (!thread && !pending_async) |
| 2679 | thread = binder_select_thread_ilocked(proc); | 2730 | thread = binder_select_thread_ilocked(proc); |
| 2680 | | 2731 | |
| 2681 | if (thread) | 2732 | if (thread) { |
| 2682 | binder_enqueue_thread_work_ilocked(thread, &t->work); | 2733 | binder_enqueue_thread_work_ilocked(thread, &t->work); |
| 2683 | else if (!pending_async) | 2734 | } else if (!pending_async) { |
| 2684 | binder_enqueue_work_ilocked(&t->work, &proc->todo); | 2735 | binder_enqueue_work_ilocked(&t->work, &proc->todo); |
| 2685 | else | 2736 | } else { |
| | 2737 | if ((t->flags & TF_UPDATE_TXN) && proc->is_frozen) { |
| | 2738 | t_outdated = binder_find_outdated_transaction_ilocked(t, |
| | 2739 | &node->async_todo); |
| | 2740 | if (t_outdated) { |
| | 2741 | binder_debug(BINDER_DEBUG_TRANSACTION, |
| | 2742 | "txn %d supersedes %d\n", |
| | 2743 | t->debug_id, t_outdated->debug_id); |
| | 2744 | list_del_init(&t_outdated->work.entry); |
| | 2745 | proc->outstanding_txns--; |
| | 2746 | } |
| | 2747 | } |
| 2686 | binder_enqueue_work_ilocked(&t->work, &node->async_todo); | 2748 | binder_enqueue_work_ilocked(&t->work, &node->async_todo); |
| | 2749 | } |
| 2687 | | 2750 | |
| 2688 | if (!pending_async) | 2751 | if (!pending_async) |
| 2689 | binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); | 2752 | binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); |
| @@ -2692,6 +2755,22 @@ static int binder_proc_transaction(struct binder_transaction *t, · 2 unmodified lines |
| 2692 | binder_inner_proc_unlock(proc); | 2755 | binder_inner_proc_unlock(proc); |
| 2693 | binder_node_unlock(node); | 2756 | binder_node_unlock(node); |
| 2694 | | 2757 | |
| | 2758 | /* |
| | 2759 | * To reduce potential contention, free the outdated transaction and |
| | 2760 | * buffer after releasing the locks. |
| | 2761 | */ |
| | 2762 | if (t_outdated) { |
| | 2763 | struct binder_buffer *buffer = t_outdated->buffer; |
| | 2764 | |
| | 2765 | t_outdated->buffer = NULL; |
| | 2766 | buffer->transaction = NULL; |
| | 2767 | trace_binder_transaction_update_buffer_release(buffer); |
| | 2768 | binder_transaction_buffer_release(proc, NULL, buffer, 0, 0); |
| | 2769 | binder_alloc_free_buf(&proc->alloc, buffer); |
| | 2770 | kfree(t_outdated); |
| | 2771 | binder_stats_deleted(BINDER_STAT_TRANSACTION); |
| | 2772 | } |
| | 2773 | |
| 2695 | return 0; | 2774 | return 0; |
| 2696 | } | 2775 | } |
| 2697 | | 2776 | |