FROMLIST: binder: refactor binder ref inc/dec for thread safety
authorTodd Kjos <tkjos@google.com>
Mon, 8 May 2017 16:16:27 +0000 (09:16 -0700)
committerDanny Wood <danwood76@gmail.com>
Tue, 26 Feb 2019 11:36:33 +0000 (11:36 +0000)
(from https://patchwork.kernel.org/patch/9817781/)

Once locks are added, binder_ref's will only be accessed
safely with the proc lock held. Refactor the inc/dec paths
to make them atomic with the binder_get_ref* paths and
node inc/dec. For example, instead of:

  ref = binder_get_ref(proc, handle, strong);
  ...
  binder_dec_ref(ref, strong);

we now have:

  ret = binder_dec_ref_for_handle(proc, handle, strong, &rdata);

Since the actual ref is no longer exposed to callers, a
new struct binder_ref_data is introduced which can be used
to return a copy of ref state.

Change-Id: I7de22107f8ebc967cee63251d584fceb4ea56250
Signed-off-by: Todd Kjos <tkjos@google.com>
drivers/android/binder.c
drivers/android/binder_trace.h

index 5928076d840b9bf96b1ddb6aeb568bb4c11ea636..e4dcf51803938f2c37124193cc03099731adad4a 100644 (file)
@@ -291,20 +291,51 @@ struct binder_ref_death {
        binder_uintptr_t cookie;
 };
 
+/**
+ * struct binder_ref_data - binder_ref counts and id
+ * @debug_id:        unique ID for the ref
+ * @desc:            unique userspace handle for ref
+ * @strong:          strong ref count (debugging only if not locked)
+ * @weak:            weak ref count (debugging only if not locked)
+ *
+ * Structure to hold ref count and ref id information. Since
+ * the actual ref can only be accessed with a lock, this structure
+ * is used to return information about the ref to callers of
+ * ref inc/dec functions.
+ */
+struct binder_ref_data {
+       int debug_id;
+       uint32_t desc;
+       int strong;
+       int weak;
+};
+
+/**
+ * struct binder_ref - struct to track references on nodes
+ * @data:        binder_ref_data containing id, handle, and current refcounts
+ * @rb_node_desc: node for lookup by @data.desc in proc's rb_tree
+ * @rb_node_node: node for lookup by @node in proc's rb_tree
+ * @node_entry:  list entry for node->refs list in target node
+ * @proc:        binder_proc containing ref
+ * @node:        binder_node of target node. When cleaning up a
+ *               ref for deletion in binder_cleanup_ref, a non-NULL
+ *               @node indicates the node must be freed
+ * @death:       pointer to death notification (ref_death) if requested
+ *
+ * Structure to track references from procA to target node (on procB). This
+ * structure is unsafe to access without holding @proc->outer_lock.
+ */
 struct binder_ref {
        /* Lookups needed: */
        /*   node + proc => ref (transaction) */
        /*   desc + proc => ref (transaction, inc/dec ref) */
        /*   node => refs + procs (proc exit) */
-       int debug_id;
+       struct binder_ref_data data;
        struct rb_node rb_node_desc;
        struct rb_node rb_node_node;
        struct hlist_node node_entry;
        struct binder_proc *proc;
        struct binder_node *node;
-       uint32_t desc;
-       int strong;
-       int weak;
        struct binder_ref_death *death;
 };
 
@@ -628,11 +659,11 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc,
        while (n) {
                ref = rb_entry(n, struct binder_ref, rb_node_desc);
 
-               if (desc < ref->desc) {
+               if (desc < ref->data.desc) {
                        n = n->rb_left;
-               } else if (desc > ref->desc) {
+               } else if (desc > ref->data.desc) {
                        n = n->rb_right;
-               } else if (need_strong_ref && !ref->strong) {
+               } else if (need_strong_ref && !ref->data.strong) {
                        binder_user_error("tried to use weak ref as strong ref\n");
                        return NULL;
                } else {
@@ -642,14 +673,33 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc,
        return NULL;
 }
 
+/**
+ * binder_get_ref_for_node() - get the ref associated with given node
+ * @proc:      binder_proc that owns the ref
+ * @node:      binder_node of target
+ * @new_ref:   newly allocated binder_ref to be initialized or %NULL
+ *
+ * Look up the ref for the given node and return it if it exists
+ *
+ * If it doesn't exist and the caller provides a newly allocated
+ * ref, initialize the fields of the newly allocated ref and insert
+ * into the given proc rb_trees and node refs list.
+ *
+ * Return:     the ref for node. It is possible that another thread
+ *             allocated/initialized the ref first in which case the
+ *             returned ref would be different than the passed-in
+ *             new_ref. new_ref must be kfree'd by the caller in
+ *             this case.
+ */
 static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
-                                                 struct binder_node *node)
+                                                 struct binder_node *node,
+                                                 struct binder_ref *new_ref)
 {
-       struct rb_node *n;
+       struct binder_context *context = proc->context;
        struct rb_node **p = &proc->refs_by_node.rb_node;
        struct rb_node *parent = NULL;
-       struct binder_ref *ref, *new_ref;
-       struct binder_context *context = proc->context;
+       struct binder_ref *ref;
+       struct rb_node *n;
 
        while (*p) {
                parent = *p;
@@ -662,22 +712,22 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
                else
                        return ref;
        }
-       new_ref = kzalloc(sizeof(*ref), GFP_KERNEL);
-       if (new_ref == NULL)
+       if (!new_ref)
                return NULL;
+
        binder_stats_created(BINDER_STAT_REF);
-       new_ref->debug_id = atomic_inc_return(&binder_last_id);
+       new_ref->data.debug_id = atomic_inc_return(&binder_last_id);
        new_ref->proc = proc;
        new_ref->node = node;
        rb_link_node(&new_ref->rb_node_node, parent, p);
        rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node);
 
-       new_ref->desc = (node == context->binder_context_mgr_node) ? 0 : 1;
+       new_ref->data.desc = (node == context->binder_context_mgr_node) ? 0 : 1;
        for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) {
                ref = rb_entry(n, struct binder_ref, rb_node_desc);
-               if (ref->desc > new_ref->desc)
+               if (ref->data.desc > new_ref->data.desc)
                        break;
-               new_ref->desc = ref->desc + 1;
+               new_ref->data.desc = ref->data.desc + 1;
        }
 
        p = &proc->refs_by_desc.rb_node;
@@ -685,9 +735,9 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
                parent = *p;
                ref = rb_entry(parent, struct binder_ref, rb_node_desc);
 
-               if (new_ref->desc < ref->desc)
+               if (new_ref->data.desc < ref->data.desc)
                        p = &(*p)->rb_left;
-               else if (new_ref->desc > ref->desc)
+               else if (new_ref->data.desc > ref->data.desc)
                        p = &(*p)->rb_right;
                else
                        BUG();
@@ -698,89 +748,267 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
 
        binder_debug(BINDER_DEBUG_INTERNAL_REFS,
                     "%d new ref %d desc %d for node %d\n",
-                     proc->pid, new_ref->debug_id, new_ref->desc,
+                     proc->pid, new_ref->data.debug_id, new_ref->data.desc,
                      node->debug_id);
        return new_ref;
 }
 
-static void binder_delete_ref(struct binder_ref *ref)
+static void binder_cleanup_ref(struct binder_ref *ref)
 {
        binder_debug(BINDER_DEBUG_INTERNAL_REFS,
                     "%d delete ref %d desc %d for node %d\n",
-                     ref->proc->pid, ref->debug_id, ref->desc,
+                     ref->proc->pid, ref->data.debug_id, ref->data.desc,
                      ref->node->debug_id);
 
        rb_erase(&ref->rb_node_desc, &ref->proc->refs_by_desc);
        rb_erase(&ref->rb_node_node, &ref->proc->refs_by_node);
-       if (ref->strong)
+
+       if (ref->data.strong)
                binder_dec_node(ref->node, 1, 1);
+
        hlist_del(&ref->node_entry);
        binder_dec_node(ref->node, 0, 1);
+
        if (ref->death) {
                binder_debug(BINDER_DEBUG_DEAD_BINDER,
                             "%d delete ref %d desc %d has death notification\n",
-                             ref->proc->pid, ref->debug_id, ref->desc);
+                             ref->proc->pid, ref->data.debug_id,
+                             ref->data.desc);
                list_del(&ref->death->work.entry);
-               kfree(ref->death);
                binder_stats_deleted(BINDER_STAT_DEATH);
        }
-       kfree(ref);
        binder_stats_deleted(BINDER_STAT_REF);
 }
 
+/**
+ * binder_inc_ref() - increment the ref for given handle
+ * @ref:         ref to be incremented
+ * @strong:      if true, strong increment, else weak
+ * @target_list: list to queue node work on
+ *
+ * Increment the ref.
+ *
+ * Return: 0, if successful, else errno
+ */
 static int binder_inc_ref(struct binder_ref *ref, int strong,
                          struct list_head *target_list)
 {
        int ret;
 
        if (strong) {
-               if (ref->strong == 0) {
+               if (ref->data.strong == 0) {
                        ret = binder_inc_node(ref->node, 1, 1, target_list);
                        if (ret)
                                return ret;
                }
-               ref->strong++;
+               ref->data.strong++;
        } else {
-               if (ref->weak == 0) {
+               if (ref->data.weak == 0) {
                        ret = binder_inc_node(ref->node, 0, 1, target_list);
                        if (ret)
                                return ret;
                }
-               ref->weak++;
+               ref->data.weak++;
        }
        return 0;
 }
 
-
-static int binder_dec_ref(struct binder_ref *ref, int strong)
+/**
+ * binder_dec_ref() - dec the ref for given handle
+ * @ref:       ref to be decremented
+ * @strong:    if true, strong decrement, else weak
+ *
+ * Decrement the ref.
+ *
+ * TODO: kfree is avoided here since an upcoming patch
+ * will put this under a lock.
+ *
+ * Return: true if ref is cleaned up and ready to be freed
+ */
+static bool binder_dec_ref(struct binder_ref *ref, int strong)
 {
        if (strong) {
-               if (ref->strong == 0) {
+               if (ref->data.strong == 0) {
                        binder_user_error("%d invalid dec strong, ref %d desc %d s %d w %d\n",
-                                         ref->proc->pid, ref->debug_id,
-                                         ref->desc, ref->strong, ref->weak);
-                       return -EINVAL;
+                                         ref->proc->pid, ref->data.debug_id,
+                                         ref->data.desc, ref->data.strong,
+                                         ref->data.weak);
+                       return false;
                }
-               ref->strong--;
-               if (ref->strong == 0) {
+               ref->data.strong--;
+               if (ref->data.strong == 0) {
                        int ret;
 
                        ret = binder_dec_node(ref->node, strong, 1);
                        if (ret)
-                               return ret;
+                               return false;
                }
        } else {
-               if (ref->weak == 0) {
+               if (ref->data.weak == 0) {
                        binder_user_error("%d invalid dec weak, ref %d desc %d s %d w %d\n",
-                                         ref->proc->pid, ref->debug_id,
-                                         ref->desc, ref->strong, ref->weak);
-                       return -EINVAL;
+                                         ref->proc->pid, ref->data.debug_id,
+                                         ref->data.desc, ref->data.strong,
+                                         ref->data.weak);
+                       return false;
                }
-               ref->weak--;
+               ref->data.weak--;
        }
-       if (ref->strong == 0 && ref->weak == 0)
-               binder_delete_ref(ref);
-       return 0;
+       if (ref->data.strong == 0 && ref->data.weak == 0) {
+               binder_cleanup_ref(ref);
+               /*
+                * TODO: we could kfree(ref) here, but an upcoming
+                * patch will call this with a lock held, so we
+                * return an indication that the ref should be
+                * freed.
+                */
+               return true;
+       }
+       return false;
+}
+
+/**
+ * binder_get_node_from_ref() - get the node from the given proc/desc
+ * @proc:      proc containing the ref
+ * @desc:      the handle associated with the ref
+ * @need_strong_ref: if true, only return node if ref is strong
+ * @rdata:     the id/refcount data for the ref
+ *
+ * Given a proc and ref handle, return the associated binder_node
+ *
+ * Return: a binder_node or NULL if not found or not strong when strong required
+ */
+static struct binder_node *binder_get_node_from_ref(
+               struct binder_proc *proc,
+               u32 desc, bool need_strong_ref,
+               struct binder_ref_data *rdata)
+{
+       struct binder_node *node;
+       struct binder_ref *ref;
+
+       ref = binder_get_ref(proc, desc, need_strong_ref);
+       if (!ref)
+               goto err_no_ref;
+       node = ref->node;
+       if (rdata)
+               *rdata = ref->data;
+
+       return node;
+
+err_no_ref:
+       return NULL;
+}
+
+/**
+ * binder_free_ref() - free the binder_ref
+ * @ref:       ref to free
+ *
+ * Free the binder_ref and the binder_ref_death indicated by ref->death.
+ */
+static void binder_free_ref(struct binder_ref *ref)
+{
+       kfree(ref->death);
+       kfree(ref);
+}
+
+/**
+ * binder_update_ref_for_handle() - inc/dec the ref for given handle
+ * @proc:      proc containing the ref
+ * @desc:      the handle associated with the ref
+ * @increment: true=inc reference, false=dec reference
+ * @strong:    true=strong reference, false=weak reference
+ * @rdata:     the id/refcount data for the ref
+ *
+ * Given a proc and ref handle, increment or decrement the ref
+ * according to "increment" arg.
+ *
+ * Return: 0 if successful, else errno
+ */
+static int binder_update_ref_for_handle(struct binder_proc *proc,
+               uint32_t desc, bool increment, bool strong,
+               struct binder_ref_data *rdata)
+{
+       int ret = 0;
+       struct binder_ref *ref;
+       bool delete_ref = false;
+
+       ref = binder_get_ref(proc, desc, strong);
+       if (!ref) {
+               ret = -EINVAL;
+               goto err_no_ref;
+       }
+       if (increment)
+               ret = binder_inc_ref(ref, strong, NULL);
+       else
+               delete_ref = binder_dec_ref(ref, strong);
+
+       if (rdata)
+               *rdata = ref->data;
+
+       if (delete_ref)
+               binder_free_ref(ref);
+       return ret;
+
+err_no_ref:
+       return ret;
+}
+
+/**
+ * binder_dec_ref_for_handle() - dec the ref for given handle
+ * @proc:      proc containing the ref
+ * @desc:      the handle associated with the ref
+ * @strong:    true=strong reference, false=weak reference
+ * @rdata:     the id/refcount data for the ref
+ *
+ * Just calls binder_update_ref_for_handle() to decrement the ref.
+ *
+ * Return: 0 if successful, else errno
+ */
+static int binder_dec_ref_for_handle(struct binder_proc *proc,
+               uint32_t desc, bool strong, struct binder_ref_data *rdata)
+{
+       return binder_update_ref_for_handle(proc, desc, false, strong, rdata);
+}
+
+
+/**
+ * binder_inc_ref_for_node() - increment the ref for given proc/node
+ * @proc:       proc containing the ref
+ * @node:       target node
+ * @strong:     true=strong reference, false=weak reference
+ * @target_list: worklist to use if node is incremented
+ * @rdata:      the id/refcount data for the ref
+ *
+ * Given a proc and node, increment the ref. Create the ref if it
+ * doesn't already exist
+ *
+ * Return: 0 if successful, else errno
+ */
+static int binder_inc_ref_for_node(struct binder_proc *proc,
+                       struct binder_node *node,
+                       bool strong,
+                       struct list_head *target_list,
+                       struct binder_ref_data *rdata)
+{
+       struct binder_ref *ref;
+       struct binder_ref *new_ref = NULL;
+       int ret = 0;
+
+       ref = binder_get_ref_for_node(proc, node, NULL);
+       if (!ref) {
+               new_ref = kzalloc(sizeof(*ref), GFP_KERNEL);
+               if (!new_ref)
+                       return -ENOMEM;
+               ref = binder_get_ref_for_node(proc, node, new_ref);
+       }
+       ret = binder_inc_ref(ref, strong, target_list);
+       *rdata = ref->data;
+       if (new_ref && ref != new_ref)
+               /*
+                * Another thread created the ref first so
+                * free the one we allocated
+                */
+               kfree(new_ref);
+       return ret;
 }
 
 static void binder_pop_transaction(struct binder_thread *target_thread,
@@ -1125,20 +1353,21 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
                case BINDER_TYPE_HANDLE:
                case BINDER_TYPE_WEAK_HANDLE: {
                        struct flat_binder_object *fp;
-                       struct binder_ref *ref;
+                       struct binder_ref_data rdata;
+                       int ret;
 
                        fp = to_flat_binder_object(hdr);
-                       ref = binder_get_ref(proc, fp->handle,
-                                            hdr->type == BINDER_TYPE_HANDLE);
-                       if (ref == NULL) {
-                               pr_err("transaction release %d bad handle %d\n",
-                                debug_id, fp->handle);
+                       ret = binder_dec_ref_for_handle(proc, fp->handle,
+                               hdr->type == BINDER_TYPE_HANDLE, &rdata);
+
+                       if (ret) {
+                               pr_err("transaction release %d bad handle %d, ret = %d\n",
+                                debug_id, fp->handle, ret);
                                break;
                        }
                        binder_debug(BINDER_DEBUG_TRANSACTION,
-                                    "        ref %d desc %d (node %d)\n",
-                                    ref->debug_id, ref->desc, ref->node->debug_id);
-                       binder_dec_ref(ref, hdr->type == BINDER_TYPE_HANDLE);
+                                    "        ref %d desc %d\n",
+                                    rdata.debug_id, rdata.desc);
                } break;
 
                case BINDER_TYPE_FD: {
@@ -1210,9 +1439,10 @@ static int binder_translate_binder(struct flat_binder_object *fp,
                                   struct binder_thread *thread)
 {
        struct binder_node *node;
-       struct binder_ref *ref;
        struct binder_proc *proc = thread->proc;
        struct binder_proc *target_proc = t->to_proc;
+       struct binder_ref_data rdata;
+       int ret;
 
        node = binder_get_node(proc, fp->binder);
        if (!node) {
@@ -1233,25 +1463,25 @@ static int binder_translate_binder(struct flat_binder_object *fp,
        if (security_binder_transfer_binder(proc->tsk, target_proc->tsk))
                return -EPERM;
 
-       ref = binder_get_ref_for_node(target_proc, node);
-       if (!ref)
-               return -ENOMEM;
+       ret = binder_inc_ref_for_node(target_proc, node,
+                       fp->hdr.type == BINDER_TYPE_BINDER,
+                       &thread->todo, &rdata);
+       if (ret)
+               return ret;
 
        if (fp->hdr.type == BINDER_TYPE_BINDER)
                fp->hdr.type = BINDER_TYPE_HANDLE;
        else
                fp->hdr.type = BINDER_TYPE_WEAK_HANDLE;
        fp->binder = 0;
-       fp->handle = ref->desc;
+       fp->handle = rdata.desc;
        fp->cookie = 0;
-       binder_inc_ref(ref, fp->hdr.type == BINDER_TYPE_HANDLE, &thread->todo);
 
-       trace_binder_transaction_node_to_ref(t, node, ref);
+       trace_binder_transaction_node_to_ref(t, node, &rdata);
        binder_debug(BINDER_DEBUG_TRANSACTION,
                     "        node %d u%016llx -> ref %d desc %d\n",
                     node->debug_id, (u64)node->ptr,
-                    ref->debug_id, ref->desc);
-
+                    rdata.debug_id, rdata.desc);
        return 0;
 }
 
@@ -1259,13 +1489,14 @@ static int binder_translate_handle(struct flat_binder_object *fp,
                                   struct binder_transaction *t,
                                   struct binder_thread *thread)
 {
-       struct binder_ref *ref;
        struct binder_proc *proc = thread->proc;
        struct binder_proc *target_proc = t->to_proc;
+       struct binder_node *node;
+       struct binder_ref_data src_rdata;
 
-       ref = binder_get_ref(proc, fp->handle,
-                            fp->hdr.type == BINDER_TYPE_HANDLE);
-       if (!ref) {
+       node = binder_get_node_from_ref(proc, fp->handle,
+                       fp->hdr.type == BINDER_TYPE_HANDLE, &src_rdata);
+       if (!node) {
                binder_user_error("%d:%d got transaction with invalid handle, %d\n",
                                  proc->pid, thread->pid, fp->handle);
                return -EINVAL;
@@ -1273,37 +1504,41 @@ static int binder_translate_handle(struct flat_binder_object *fp,
        if (security_binder_transfer_binder(proc->tsk, target_proc->tsk))
                return -EPERM;
 
-       if (ref->node->proc == target_proc) {
+       if (node->proc == target_proc) {
                if (fp->hdr.type == BINDER_TYPE_HANDLE)
                        fp->hdr.type = BINDER_TYPE_BINDER;
                else
                        fp->hdr.type = BINDER_TYPE_WEAK_BINDER;
-               fp->binder = ref->node->ptr;
-               fp->cookie = ref->node->cookie;
-               binder_inc_node(ref->node, fp->hdr.type == BINDER_TYPE_BINDER,
+               fp->binder = node->ptr;
+               fp->cookie = node->cookie;
+               binder_inc_node(node,
+                               fp->hdr.type == BINDER_TYPE_BINDER,
                                0, NULL);
-               trace_binder_transaction_ref_to_node(t, ref);
+               trace_binder_transaction_ref_to_node(t, node, &src_rdata);
                binder_debug(BINDER_DEBUG_TRANSACTION,
                             "        ref %d desc %d -> node %d u%016llx\n",
-                            ref->debug_id, ref->desc, ref->node->debug_id,
-                            (u64)ref->node->ptr);
+                            src_rdata.debug_id, src_rdata.desc, node->debug_id,
+                            (u64)node->ptr);
        } else {
-               struct binder_ref *new_ref;
+               int ret;
+               struct binder_ref_data dest_rdata;
 
-               new_ref = binder_get_ref_for_node(target_proc, ref->node);
-               if (!new_ref)
-                       return -ENOMEM;
+               ret = binder_inc_ref_for_node(target_proc, node,
+                               fp->hdr.type == BINDER_TYPE_HANDLE,
+                               NULL, &dest_rdata);
+               if (ret)
+                       return ret;
 
                fp->binder = 0;
-               fp->handle = new_ref->desc;
+               fp->handle = dest_rdata.desc;
                fp->cookie = 0;
-               binder_inc_ref(new_ref, fp->hdr.type == BINDER_TYPE_HANDLE,
-                              NULL);
-               trace_binder_transaction_ref_to_ref(t, ref, new_ref);
+               trace_binder_transaction_ref_to_ref(t, node, &src_rdata,
+                                                   &dest_rdata);
                binder_debug(BINDER_DEBUG_TRANSACTION,
                             "        ref %d desc %d -> ref %d desc %d (node %d)\n",
-                            ref->debug_id, ref->desc, new_ref->debug_id,
-                            new_ref->desc, ref->node->debug_id);
+                            src_rdata.debug_id, src_rdata.desc,
+                            dest_rdata.debug_id, dest_rdata.desc,
+                            node->debug_id);
        }
        return 0;
 }
@@ -2045,6 +2280,8 @@ int binder_thread_write(struct binder_proc *proc,
        void __user *end = buffer + size;
 
        while (ptr < end && thread->return_error.cmd == BR_OK) {
+               int ret;
+
                if (get_user(cmd, (uint32_t __user *)ptr))
                        return -EFAULT;
                ptr += sizeof(uint32_t);
@@ -2060,62 +2297,61 @@ int binder_thread_write(struct binder_proc *proc,
                case BC_RELEASE:
                case BC_DECREFS: {
                        uint32_t target;
-                       struct binder_ref *ref = NULL;
                        const char *debug_string;
+                       bool strong = cmd == BC_ACQUIRE || cmd == BC_RELEASE;
+                       bool increment = cmd == BC_INCREFS || cmd == BC_ACQUIRE;
+                       struct binder_ref_data rdata;
 
                        if (get_user(target, (uint32_t __user *)ptr))
                                return -EFAULT;
 
                        ptr += sizeof(uint32_t);
-                       if (target == 0 &&
-                           (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) {
+                       ret = -1;
+                       if (increment && !target) {
                                struct binder_node *ctx_mgr_node;
-
                                mutex_lock(&context->context_mgr_node_lock);
                                ctx_mgr_node = context->binder_context_mgr_node;
-                               if (ctx_mgr_node) {
-                                       ref = binder_get_ref_for_node(proc,
-                                                       ctx_mgr_node);
-                                       if (ref && ref->desc != target) {
-                                               binder_user_error("%d:%d tried to acquire reference to desc 0, got %d instead\n",
-                                                       proc->pid, thread->pid,
-                                                       ref->desc);
-                                       }
-                               }
+                               if (ctx_mgr_node)
+                                       ret = binder_inc_ref_for_node(
+                                                       proc, ctx_mgr_node,
+                                                       strong, NULL, &rdata);
                                mutex_unlock(&context->context_mgr_node_lock);
                        }
-                       if (ref == NULL)
-                               ref = binder_get_ref(proc, target,
-                                                    cmd == BC_ACQUIRE ||
-                                                    cmd == BC_RELEASE);
-                       if (ref == NULL) {
-                               binder_user_error("%d:%d refcount change on invalid ref %d\n",
-                                       proc->pid, thread->pid, target);
-                               break;
+                       if (ret)
+                               ret = binder_update_ref_for_handle(
+                                               proc, target, increment, strong,
+                                               &rdata);
+                       if (!ret && rdata.desc != target) {
+                               binder_user_error("%d:%d tried to acquire reference to desc %d, got %d instead\n",
+                                       proc->pid, thread->pid,
+                                       target, rdata.desc);
                        }
                        switch (cmd) {
                        case BC_INCREFS:
                                debug_string = "IncRefs";
-                               binder_inc_ref(ref, 0, NULL);
                                break;
                        case BC_ACQUIRE:
                                debug_string = "Acquire";
-                               binder_inc_ref(ref, 1, NULL);
                                break;
                        case BC_RELEASE:
                                debug_string = "Release";
-                               binder_dec_ref(ref, 1);
                                break;
                        case BC_DECREFS:
                        default:
                                debug_string = "DecRefs";
-                               binder_dec_ref(ref, 0);
+                               break;
+                       }
+                       if (ret) {
+                               binder_user_error("%d:%d %s %d refcount change on invalid ref %d ret %d\n",
+                                       proc->pid, thread->pid, debug_string,
+                                       strong, target, ret);
                                break;
                        }
                        binder_debug(BINDER_DEBUG_USER_REFS,
-                                    "%d:%d %s ref %d desc %d s %d w %d for node %d\n",
-                                    proc->pid, thread->pid, debug_string, ref->debug_id,
-                                    ref->desc, ref->strong, ref->weak, ref->node->debug_id);
+                                    "%d:%d %s ref %d desc %d s %d w %d\n",
+                                    proc->pid, thread->pid, debug_string,
+                                    rdata.debug_id, rdata.desc, rdata.strong,
+                                    rdata.weak);
                        break;
                }
                case BC_INCREFS_DONE:
@@ -2313,8 +2549,9 @@ int binder_thread_write(struct binder_proc *proc,
                                     cmd == BC_REQUEST_DEATH_NOTIFICATION ?
                                     "BC_REQUEST_DEATH_NOTIFICATION" :
                                     "BC_CLEAR_DEATH_NOTIFICATION",
-                                    (u64)cookie, ref->debug_id, ref->desc,
-                                    ref->strong, ref->weak, ref->node->debug_id);
+                                    (u64)cookie, ref->data.debug_id,
+                                    ref->data.desc, ref->data.strong,
+                                    ref->data.weak, ref->node->debug_id);
 
                        if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
                                if (ref->death) {
@@ -3475,7 +3712,8 @@ static void binder_deferred_release(struct binder_proc *proc)
 
                ref = rb_entry(n, struct binder_ref, rb_node_desc);
                outgoing_refs++;
-               binder_delete_ref(ref);
+               binder_cleanup_ref(ref);
+               binder_free_ref(ref);
        }
 
        binder_release_work(&proc->todo);
@@ -3677,9 +3915,11 @@ static void print_binder_node(struct seq_file *m, struct binder_node *node)
 
 static void print_binder_ref(struct seq_file *m, struct binder_ref *ref)
 {
-       seq_printf(m, "  ref %d: desc %d %snode %d s %d w %d d %p\n",
-                  ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ",
-                  ref->node->debug_id, ref->strong, ref->weak, ref->death);
+       seq_printf(m, "  ref %d: desc %d %snode %d s %d w %d d %pK\n",
+                  ref->data.debug_id, ref->data.desc,
+                  ref->node->proc ? "" : "dead ",
+                  ref->node->debug_id, ref->data.strong,
+                  ref->data.weak, ref->death);
 }
 
 static void print_binder_proc(struct seq_file *m,
@@ -3846,8 +4086,8 @@ static void print_binder_proc_stats(struct seq_file *m,
                struct binder_ref *ref = rb_entry(n, struct binder_ref,
                                                  rb_node_desc);
                count++;
-               strong += ref->strong;
-               weak += ref->weak;
+               strong += ref->data.strong;
+               weak += ref->data.weak;
        }
        seq_printf(m, "  refs: %d s %d w %d\n", count, strong, weak);
 
index 50b0d21f42cf5d1cac62f53723fe77ba3457d7e7..7967db16ba5a653d898c097fd0323a23ec918bc0 100644 (file)
@@ -24,7 +24,7 @@ struct binder_buffer;
 struct binder_node;
 struct binder_proc;
 struct binder_alloc;
-struct binder_ref;
+struct binder_ref_data;
 struct binder_thread;
 struct binder_transaction;
 
@@ -147,8 +147,8 @@ TRACE_EVENT(binder_transaction_received,
 
 TRACE_EVENT(binder_transaction_node_to_ref,
        TP_PROTO(struct binder_transaction *t, struct binder_node *node,
-                struct binder_ref *ref),
-       TP_ARGS(t, node, ref),
+                struct binder_ref_data *rdata),
+       TP_ARGS(t, node, rdata),
 
        TP_STRUCT__entry(
                __field(int, debug_id)
@@ -161,8 +161,8 @@ TRACE_EVENT(binder_transaction_node_to_ref,
                __entry->debug_id = t->debug_id;
                __entry->node_debug_id = node->debug_id;
                __entry->node_ptr = node->ptr;
-               __entry->ref_debug_id = ref->debug_id;
-               __entry->ref_desc = ref->desc;
+               __entry->ref_debug_id = rdata->debug_id;
+               __entry->ref_desc = rdata->desc;
        ),
        TP_printk("transaction=%d node=%d src_ptr=0x%016llx ==> dest_ref=%d dest_desc=%d",
                  __entry->debug_id, __entry->node_debug_id,
@@ -171,8 +171,9 @@ TRACE_EVENT(binder_transaction_node_to_ref,
 );
 
 TRACE_EVENT(binder_transaction_ref_to_node,
-       TP_PROTO(struct binder_transaction *t, struct binder_ref *ref),
-       TP_ARGS(t, ref),
+       TP_PROTO(struct binder_transaction *t, struct binder_node *node,
+                struct binder_ref_data *rdata),
+       TP_ARGS(t, node, rdata),
 
        TP_STRUCT__entry(
                __field(int, debug_id)
@@ -183,10 +184,10 @@ TRACE_EVENT(binder_transaction_ref_to_node,
        ),
        TP_fast_assign(
                __entry->debug_id = t->debug_id;
-               __entry->ref_debug_id = ref->debug_id;
-               __entry->ref_desc = ref->desc;
-               __entry->node_debug_id = ref->node->debug_id;
-               __entry->node_ptr = ref->node->ptr;
+               __entry->ref_debug_id = rdata->debug_id;
+               __entry->ref_desc = rdata->desc;
+               __entry->node_debug_id = node->debug_id;
+               __entry->node_ptr = node->ptr;
        ),
        TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%016llx",
                  __entry->debug_id, __entry->node_debug_id,
@@ -195,9 +196,10 @@ TRACE_EVENT(binder_transaction_ref_to_node,
 );
 
 TRACE_EVENT(binder_transaction_ref_to_ref,
-       TP_PROTO(struct binder_transaction *t, struct binder_ref *src_ref,
-                struct binder_ref *dest_ref),
-       TP_ARGS(t, src_ref, dest_ref),
+       TP_PROTO(struct binder_transaction *t, struct binder_node *node,
+                struct binder_ref_data *src_ref,
+                struct binder_ref_data *dest_ref),
+       TP_ARGS(t, node, src_ref, dest_ref),
 
        TP_STRUCT__entry(
                __field(int, debug_id)
@@ -209,7 +211,7 @@ TRACE_EVENT(binder_transaction_ref_to_ref,
        ),
        TP_fast_assign(
                __entry->debug_id = t->debug_id;
-               __entry->node_debug_id = src_ref->node->debug_id;
+               __entry->node_debug_id = node->debug_id;
                __entry->src_ref_debug_id = src_ref->debug_id;
                __entry->src_ref_desc = src_ref->desc;
                __entry->dest_ref_debug_id = dest_ref->debug_id;