diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2017-04-14 22:59:21 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-04-14 22:59:21 -0700 |
commit | 8c5d1ccf42ffbb609decac27ab1dbded9feba0ed (patch) | |
tree | 49607d281c331acdde4ed30026b7ee6c213d7dc4 /drivers | |
parent | d7ac7905d99dde0fd5c4e124d2d220f991074763 (diff) | |
parent | 0b5e71aa2e92b176163da09f6ef36efbff8354a2 (diff) |
Merge "android: binder: move global binder state into context struct."
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/android/binder.c | 392 |
1 files changed, 259 insertions, 133 deletions
diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 37b9eecf5c71..d1490be45c67 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -18,6 +18,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <asm/cacheflush.h> +#include <linux/atomic.h> #include <linux/fdtable.h> #include <linux/file.h> #include <linux/freezer.h> @@ -46,19 +47,11 @@ #include <uapi/linux/android/binder.h> #include "binder_trace.h" -static DEFINE_MUTEX(binder_main_lock); -static DEFINE_MUTEX(binder_deferred_lock); -static DEFINE_MUTEX(binder_mmap_lock); - static HLIST_HEAD(binder_devices); -static HLIST_HEAD(binder_procs); -static HLIST_HEAD(binder_deferred_list); -static HLIST_HEAD(binder_dead_nodes); static struct dentry *binder_debugfs_dir_entry_root; static struct dentry *binder_debugfs_dir_entry_proc; -static int binder_last_id; -static struct workqueue_struct *binder_deferred_workqueue; +atomic_t binder_last_id; #define BINDER_DEBUG_ENTRY(name) \ static int binder_##name##_open(struct inode *inode, struct file *file) \ @@ -173,20 +166,24 @@ enum binder_stat_types { struct binder_stats { int br[_IOC_NR(BR_FAILED_REPLY) + 1]; int bc[_IOC_NR(BC_REPLY_SG) + 1]; - int obj_created[BINDER_STAT_COUNT]; - int obj_deleted[BINDER_STAT_COUNT]; }; -static struct binder_stats binder_stats; +/* These are still global, since it's not always easy to get the context */ +struct binder_obj_stats { + atomic_t obj_created[BINDER_STAT_COUNT]; + atomic_t obj_deleted[BINDER_STAT_COUNT]; +}; + +static struct binder_obj_stats binder_obj_stats; static inline void binder_stats_deleted(enum binder_stat_types type) { - binder_stats.obj_deleted[type]++; + atomic_inc(&binder_obj_stats.obj_deleted[type]); } static inline void binder_stats_created(enum binder_stat_types type) { - binder_stats.obj_created[type]++; + atomic_inc(&binder_obj_stats.obj_created[type]); } struct binder_transaction_log_entry { @@ -207,8 +204,6 @@ struct binder_transaction_log { int full; struct binder_transaction_log_entry entry[32]; }; -static struct binder_transaction_log binder_transaction_log; -static struct binder_transaction_log binder_transaction_log_failed; static struct binder_transaction_log_entry *binder_transaction_log_add( struct binder_transaction_log *log) @@ -229,6 +224,21 @@ struct binder_context { struct binder_node *binder_context_mgr_node; kuid_t binder_context_mgr_uid; const char *name; + + struct mutex binder_main_lock; + struct mutex binder_deferred_lock; + struct mutex binder_mmap_lock; + + struct hlist_head binder_procs; + struct hlist_head binder_dead_nodes; + struct hlist_head binder_deferred_list; + + struct work_struct deferred_work; + struct workqueue_struct *binder_deferred_workqueue; + struct binder_transaction_log transaction_log; + struct binder_transaction_log transaction_log_failed; + + struct binder_stats binder_stats; }; struct binder_device { @@ -459,18 +469,19 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd) return retval; } -static inline void binder_lock(const char *tag) +static inline void binder_lock(struct binder_context *context, const char *tag) { trace_binder_lock(tag); - mutex_lock(&binder_main_lock); + mutex_lock(&context->binder_main_lock); preempt_disable(); trace_binder_locked(tag); } -static inline void binder_unlock(const char *tag) +static inline void binder_unlock(struct binder_context *context, + const char *tag) { trace_binder_unlock(tag); - mutex_unlock(&binder_main_lock); + mutex_unlock(&context->binder_main_lock); preempt_enable(); } @@ -1017,7 +1028,7 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, binder_stats_created(BINDER_STAT_NODE); rb_link_node(&node->rb_node, parent, p); rb_insert_color(&node->rb_node, &proc->nodes); - node->debug_id = ++binder_last_id; + node->debug_id = atomic_inc_return(&binder_last_id); node->proc = proc; node->ptr = ptr; node->cookie = cookie; @@ -1159,7 +1170,7 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, if (new_ref == NULL) return NULL; binder_stats_created(BINDER_STAT_REF); - new_ref->debug_id = ++binder_last_id; + new_ref->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); @@ -1920,7 +1931,7 @@ static void binder_transaction(struct binder_proc *proc, binder_size_t last_fixup_min_off = 0; struct binder_context *context = proc->context; - e = binder_transaction_log_add(&binder_transaction_log); + e = binder_transaction_log_add(&context->transaction_log); e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY); e->from_proc = proc->pid; e->from_thread = thread->pid; @@ -2042,7 +2053,7 @@ static void binder_transaction(struct binder_proc *proc, } binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE); - t->debug_id = ++binder_last_id; + t->debug_id = atomic_inc_return(&binder_last_id); e->debug_id = t->debug_id; if (reply) @@ -2315,7 +2326,8 @@ err_no_context_mgr_node: { struct binder_transaction_log_entry *fe; - fe = binder_transaction_log_add(&binder_transaction_log_failed); + fe = binder_transaction_log_add( + &context->transaction_log_failed); *fe = *e; } @@ -2343,8 +2355,8 @@ static int binder_thread_write(struct binder_proc *proc, return -EFAULT; ptr += sizeof(uint32_t); trace_binder_command(cmd); - if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) { - binder_stats.bc[_IOC_NR(cmd)]++; + if (_IOC_NR(cmd) < ARRAY_SIZE(context->binder_stats.bc)) { + context->binder_stats.bc[_IOC_NR(cmd)]++; proc->stats.bc[_IOC_NR(cmd)]++; thread->stats.bc[_IOC_NR(cmd)]++; } @@ -2710,8 +2722,8 @@ static void binder_stat_br(struct binder_proc *proc, struct binder_thread *thread, uint32_t cmd) { trace_binder_return(cmd); - if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) { - binder_stats.br[_IOC_NR(cmd)]++; + if (_IOC_NR(cmd) < ARRAY_SIZE(proc->stats.br)) { + proc->context->binder_stats.br[_IOC_NR(cmd)]++; proc->stats.br[_IOC_NR(cmd)]++; thread->stats.br[_IOC_NR(cmd)]++; } @@ -2775,7 +2787,7 @@ retry: if (wait_for_proc_work) proc->ready_threads++; - binder_unlock(__func__); + binder_unlock(proc->context, __func__); trace_binder_wait_for_work(wait_for_proc_work, !!thread->transaction_stack, @@ -2802,7 +2814,7 @@ retry: ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread)); } - binder_lock(__func__); + binder_lock(proc->context, __func__); if (wait_for_proc_work) proc->ready_threads--; @@ -3188,14 +3200,14 @@ static unsigned int binder_poll(struct file *filp, struct binder_thread *thread = NULL; int wait_for_proc_work; - binder_lock(__func__); + binder_lock(proc->context, __func__); thread = binder_get_thread(proc); wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo) && thread->return_error == BR_OK; - binder_unlock(__func__); + binder_unlock(proc->context, __func__); if (wait_for_proc_work) { if (binder_has_proc_work(proc, thread)) @@ -3322,6 +3334,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret; struct binder_proc *proc = filp->private_data; + struct binder_context *context = proc->context; struct binder_thread *thread; unsigned int size = _IOC_SIZE(cmd); void __user *ubuf = (void __user *)arg; @@ -3335,7 +3348,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (ret) goto err_unlocked; - binder_lock(__func__); + binder_lock(context, __func__); thread = binder_get_thread(proc); if (thread == NULL) { ret = -ENOMEM; @@ -3386,7 +3399,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) err: if (thread) thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN; - binder_unlock(__func__); + binder_unlock(context, __func__); wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret && ret != -ERESTARTSYS) pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); @@ -3459,7 +3472,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) } vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE; - mutex_lock(&binder_mmap_lock); + mutex_lock(&proc->context->binder_mmap_lock); if (proc->buffer) { ret = -EBUSY; failure_string = "already mapped"; @@ -3474,7 +3487,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) } proc->buffer = area->addr; proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer; - mutex_unlock(&binder_mmap_lock); + mutex_unlock(&proc->context->binder_mmap_lock); #ifdef CONFIG_CPU_CACHE_VIPT if (cache_is_vipt_aliasing()) { @@ -3523,12 +3536,12 @@ err_alloc_small_buf_failed: kfree(proc->pages); proc->pages = NULL; err_alloc_pages_failed: - mutex_lock(&binder_mmap_lock); + mutex_lock(&proc->context->binder_mmap_lock); vfree(proc->buffer); proc->buffer = NULL; err_get_vm_area_failed: err_already_mapped: - mutex_unlock(&binder_mmap_lock); + mutex_unlock(&proc->context->binder_mmap_lock); err_bad_arg: pr_err("binder_mmap: %d %lx-%lx %s failed %d\n", proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); @@ -3555,15 +3568,15 @@ static int binder_open(struct inode *nodp, struct file *filp) miscdev); proc->context = &binder_dev->context; - binder_lock(__func__); + binder_lock(proc->context, __func__); binder_stats_created(BINDER_STAT_PROC); - hlist_add_head(&proc->proc_node, &binder_procs); + hlist_add_head(&proc->proc_node, &proc->context->binder_procs); proc->pid = current->group_leader->pid; INIT_LIST_HEAD(&proc->delivered_death); filp->private_data = proc; - binder_unlock(__func__); + binder_unlock(proc->context, __func__); if (binder_debugfs_dir_entry_proc) { char strbuf[11]; @@ -3628,6 +3641,7 @@ static int binder_release(struct inode *nodp, struct file *filp) static int binder_node_release(struct binder_node *node, int refs) { struct binder_ref *ref; + struct binder_context *context = node->proc->context; int death = 0; list_del_init(&node->work.entry); @@ -3643,7 +3657,7 @@ static int binder_node_release(struct binder_node *node, int refs) node->proc = NULL; node->local_strong_refs = 0; node->local_weak_refs = 0; - hlist_add_head(&node->dead_node, &binder_dead_nodes); + hlist_add_head(&node->dead_node, &context->binder_dead_nodes); hlist_for_each_entry(ref, &node->refs, node_entry) { refs++; @@ -3708,7 +3722,8 @@ static void binder_deferred_release(struct binder_proc *proc) node = rb_entry(n, struct binder_node, rb_node); nodes++; rb_erase(&node->rb_node, &proc->nodes); - incoming_refs = binder_node_release(node, incoming_refs); + incoming_refs = binder_node_release(node, + incoming_refs); } outgoing_refs = 0; @@ -3780,18 +3795,20 @@ static void binder_deferred_func(struct work_struct *work) { struct binder_proc *proc; struct files_struct *files; + struct binder_context *context = + container_of(work, struct binder_context, deferred_work); int defer; do { trace_binder_lock(__func__); - mutex_lock(&binder_main_lock); + mutex_lock(&context->binder_main_lock); trace_binder_locked(__func__); - mutex_lock(&binder_deferred_lock); + mutex_lock(&context->binder_deferred_lock); preempt_disable(); - if (!hlist_empty(&binder_deferred_list)) { - proc = hlist_entry(binder_deferred_list.first, + if (!hlist_empty(&context->binder_deferred_list)) { + proc = hlist_entry(context->binder_deferred_list.first, struct binder_proc, deferred_work_node); hlist_del_init(&proc->deferred_work_node); defer = proc->deferred_work; @@ -3800,7 +3817,7 @@ static void binder_deferred_func(struct work_struct *work) proc = NULL; defer = 0; } - mutex_unlock(&binder_deferred_lock); + mutex_unlock(&context->binder_deferred_lock); files = NULL; if (defer & BINDER_DEFERRED_PUT_FILES) { @@ -3816,25 +3833,25 @@ static void binder_deferred_func(struct work_struct *work) binder_deferred_release(proc); /* frees proc */ trace_binder_unlock(__func__); - mutex_unlock(&binder_main_lock); + mutex_unlock(&context->binder_main_lock); preempt_enable_no_resched(); if (files) put_files_struct(files); } while (proc); } -static DECLARE_WORK(binder_deferred_work, binder_deferred_func); static void binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer) { - mutex_lock(&binder_deferred_lock); + mutex_lock(&proc->context->binder_deferred_lock); proc->deferred_work |= defer; if (hlist_unhashed(&proc->deferred_work_node)) { hlist_add_head(&proc->deferred_work_node, - &binder_deferred_list); - queue_work(binder_deferred_workqueue, &binder_deferred_work); + &proc->context->binder_deferred_list); + queue_work(proc->context->binder_deferred_workqueue, + &proc->context->deferred_work); } - mutex_unlock(&binder_deferred_lock); + mutex_unlock(&proc->context->binder_deferred_lock); } static void print_binder_transaction(struct seq_file *m, const char *prefix, @@ -4065,8 +4082,20 @@ static const char * const binder_objstat_strings[] = { "transaction_complete" }; +static void add_binder_stats(struct binder_stats *from, struct binder_stats *to) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(to->bc); i++) + to->bc[i] += from->bc[i]; + + for (i = 0; i < ARRAY_SIZE(to->br); i++) + to->br[i] += from->br[i]; +} + static void print_binder_stats(struct seq_file *m, const char *prefix, - struct binder_stats *stats) + struct binder_stats *stats, + struct binder_obj_stats *obj_stats) { int i; @@ -4086,16 +4115,21 @@ static void print_binder_stats(struct seq_file *m, const char *prefix, binder_return_strings[i], stats->br[i]); } - BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != + if (!obj_stats) + return; + + BUILD_BUG_ON(ARRAY_SIZE(obj_stats->obj_created) != ARRAY_SIZE(binder_objstat_strings)); - BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != - ARRAY_SIZE(stats->obj_deleted)); - for (i = 0; i < ARRAY_SIZE(stats->obj_created); i++) { - if (stats->obj_created[i] || stats->obj_deleted[i]) + BUILD_BUG_ON(ARRAY_SIZE(obj_stats->obj_created) != + ARRAY_SIZE(obj_stats->obj_deleted)); + for (i = 0; i < ARRAY_SIZE(obj_stats->obj_created); i++) { + int obj_created = atomic_read(&obj_stats->obj_created[i]); + int obj_deleted = atomic_read(&obj_stats->obj_deleted[i]); + + if (obj_created || obj_deleted) seq_printf(m, "%s%s: active %d total %d\n", prefix, - binder_objstat_strings[i], - stats->obj_created[i] - stats->obj_deleted[i], - stats->obj_created[i]); + binder_objstat_strings[i], + obj_created - obj_deleted, obj_created); } } @@ -4150,85 +4184,131 @@ static void print_binder_proc_stats(struct seq_file *m, } seq_printf(m, " pending transactions: %d\n", count); - print_binder_stats(m, " ", &proc->stats); + print_binder_stats(m, " ", &proc->stats, NULL); } static int binder_state_show(struct seq_file *m, void *unused) { + struct binder_device *device; + struct binder_context *context; struct binder_proc *proc; struct binder_node *node; int do_lock = !binder_debug_no_lock; - - if (do_lock) - binder_lock(__func__); + bool wrote_dead_nodes_header = false; seq_puts(m, "binder state:\n"); - if (!hlist_empty(&binder_dead_nodes)) - seq_puts(m, "dead nodes:\n"); - hlist_for_each_entry(node, &binder_dead_nodes, dead_node) - print_binder_node(m, node); + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + if (do_lock) + binder_lock(context, __func__); + if (!wrote_dead_nodes_header && + !hlist_empty(&context->binder_dead_nodes)) { + seq_puts(m, "dead nodes:\n"); + wrote_dead_nodes_header = true; + } + hlist_for_each_entry(node, &context->binder_dead_nodes, + dead_node) + print_binder_node(m, node); + + if (do_lock) + binder_unlock(context, __func__); + } - hlist_for_each_entry(proc, &binder_procs, proc_node) - print_binder_proc(m, proc, 1); - if (do_lock) - binder_unlock(__func__); + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + if (do_lock) + binder_lock(context, __func__); + + hlist_for_each_entry(proc, &context->binder_procs, proc_node) + print_binder_proc(m, proc, 1); + if (do_lock) + binder_unlock(context, __func__); + } return 0; } static int binder_stats_show(struct seq_file *m, void *unused) { + struct binder_device *device; + struct binder_context *context; struct binder_proc *proc; + struct binder_stats total_binder_stats; int do_lock = !binder_debug_no_lock; - if (do_lock) - binder_lock(__func__); + memset(&total_binder_stats, 0, sizeof(struct binder_stats)); + + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + if (do_lock) + binder_lock(context, __func__); + + add_binder_stats(&context->binder_stats, &total_binder_stats); + + if (do_lock) + binder_unlock(context, __func__); + } seq_puts(m, "binder stats:\n"); + print_binder_stats(m, "", &total_binder_stats, &binder_obj_stats); - print_binder_stats(m, "", &binder_stats); + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + if (do_lock) + binder_lock(context, __func__); - hlist_for_each_entry(proc, &binder_procs, proc_node) - print_binder_proc_stats(m, proc); - if (do_lock) - binder_unlock(__func__); + hlist_for_each_entry(proc, &context->binder_procs, proc_node) + print_binder_proc_stats(m, proc); + if (do_lock) + binder_unlock(context, __func__); + } return 0; } static int binder_transactions_show(struct seq_file *m, void *unused) { + struct binder_device *device; + struct binder_context *context; struct binder_proc *proc; int do_lock = !binder_debug_no_lock; - if (do_lock) - binder_lock(__func__); - seq_puts(m, "binder transactions:\n"); - hlist_for_each_entry(proc, &binder_procs, proc_node) - print_binder_proc(m, proc, 0); - if (do_lock) - binder_unlock(__func__); + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + if (do_lock) + binder_lock(context, __func__); + + hlist_for_each_entry(proc, &context->binder_procs, proc_node) + print_binder_proc(m, proc, 0); + if (do_lock) + binder_unlock(context, __func__); + } return 0; } static int binder_proc_show(struct seq_file *m, void *unused) { + struct binder_device *device; + struct binder_context *context; struct binder_proc *itr; int pid = (unsigned long)m->private; int do_lock = !binder_debug_no_lock; - if (do_lock) - binder_lock(__func__); + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + if (do_lock) + binder_lock(context, __func__); - hlist_for_each_entry(itr, &binder_procs, proc_node) { - if (itr->pid == pid) { - seq_puts(m, "binder proc state:\n"); - print_binder_proc(m, itr, 1); + hlist_for_each_entry(itr, &context->binder_procs, proc_node) { + if (itr->pid == pid) { + seq_puts(m, "binder proc state:\n"); + print_binder_proc(m, itr, 1); + } } + if (do_lock) + binder_unlock(context, __func__); } - if (do_lock) - binder_unlock(__func__); return 0; } @@ -4243,11 +4323,10 @@ static void print_binder_transaction_log_entry(struct seq_file *m, e->to_node, e->target_handle, e->data_size, e->offsets_size); } -static int binder_transaction_log_show(struct seq_file *m, void *unused) +static int print_binder_transaction_log(struct seq_file *m, + struct binder_transaction_log *log) { - struct binder_transaction_log *log = m->private; int i; - if (log->full) { for (i = log->next; i < ARRAY_SIZE(log->entry); i++) print_binder_transaction_log_entry(m, &log->entry[i]); @@ -4257,6 +4336,31 @@ static int binder_transaction_log_show(struct seq_file *m, void *unused) return 0; } +static int binder_transaction_log_show(struct seq_file *m, void *unused) +{ + struct binder_device *device; + struct binder_context *context; + + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + print_binder_transaction_log(m, &context->transaction_log); + } + return 0; +} + +static int binder_failed_transaction_log_show(struct seq_file *m, void *unused) +{ + struct binder_device *device; + struct binder_context *context; + + hlist_for_each_entry(device, &binder_devices, hlist) { + context = &device->context; + print_binder_transaction_log(m, + &context->transaction_log_failed); + } + return 0; +} + static const struct file_operations binder_fops = { .owner = THIS_MODULE, .poll = binder_poll, @@ -4272,11 +4376,20 @@ BINDER_DEBUG_ENTRY(state); BINDER_DEBUG_ENTRY(stats); BINDER_DEBUG_ENTRY(transactions); BINDER_DEBUG_ENTRY(transaction_log); +BINDER_DEBUG_ENTRY(failed_transaction_log); + +static void __init free_binder_device(struct binder_device *device) +{ + if (device->context.binder_deferred_workqueue) + destroy_workqueue(device->context.binder_deferred_workqueue); + kfree(device); +} static int __init init_binder_device(const char *name) { int ret; struct binder_device *binder_device; + struct binder_context *context; binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL); if (!binder_device) @@ -4286,31 +4399,65 @@ static int __init init_binder_device(const char *name) binder_device->miscdev.minor = MISC_DYNAMIC_MINOR; binder_device->miscdev.name = name; - binder_device->context.binder_context_mgr_uid = INVALID_UID; - binder_device->context.name = name; + context = &binder_device->context; + context->binder_context_mgr_uid = INVALID_UID; + context->name = name; + + mutex_init(&context->binder_main_lock); + mutex_init(&context->binder_deferred_lock); + mutex_init(&context->binder_mmap_lock); + + context->binder_deferred_workqueue = + create_singlethread_workqueue(name); + + if (!context->binder_deferred_workqueue) { + ret = -ENOMEM; + goto err_create_singlethread_workqueue_failed; + } + + INIT_HLIST_HEAD(&context->binder_procs); + INIT_HLIST_HEAD(&context->binder_dead_nodes); + INIT_HLIST_HEAD(&context->binder_deferred_list); + INIT_WORK(&context->deferred_work, binder_deferred_func); ret = misc_register(&binder_device->miscdev); if (ret < 0) { - kfree(binder_device); - return ret; + goto err_misc_register_failed; } hlist_add_head(&binder_device->hlist, &binder_devices); + return ret; + +err_create_singlethread_workqueue_failed: +err_misc_register_failed: + free_binder_device(binder_device); return ret; } static int __init binder_init(void) { - int ret; + int ret = 0; char *device_name, *device_names; struct binder_device *device; struct hlist_node *tmp; - binder_deferred_workqueue = create_singlethread_workqueue("binder"); - if (!binder_deferred_workqueue) + /* + * Copy the module_parameter string, because we don't want to + * tokenize it in-place. + */ + device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL); + if (!device_names) return -ENOMEM; + strcpy(device_names, binder_devices_param); + + while ((device_name = strsep(&device_names, ","))) { + ret = init_binder_device(device_name); + if (ret) + goto err_init_binder_device_failed; + } + binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL); if (binder_debugfs_dir_entry_root) binder_debugfs_dir_entry_proc = debugfs_create_dir("proc", @@ -4335,30 +4482,13 @@ static int __init binder_init(void) debugfs_create_file("transaction_log", S_IRUGO, binder_debugfs_dir_entry_root, - &binder_transaction_log, + NULL, &binder_transaction_log_fops); debugfs_create_file("failed_transaction_log", S_IRUGO, binder_debugfs_dir_entry_root, - &binder_transaction_log_failed, - &binder_transaction_log_fops); - } - - /* - * Copy the module_parameter string, because we don't want to - * tokenize it in-place. - */ - device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL); - if (!device_names) { - ret = -ENOMEM; - goto err_alloc_device_names_failed; - } - strcpy(device_names, binder_devices_param); - - while ((device_name = strsep(&device_names, ","))) { - ret = init_binder_device(device_name); - if (ret) - goto err_init_binder_device_failed; + NULL, + &binder_failed_transaction_log_fops); } return ret; @@ -4367,12 +4497,8 @@ err_init_binder_device_failed: hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) { misc_deregister(&device->miscdev); hlist_del(&device->hlist); - kfree(device); + free_binder_device(device); } -err_alloc_device_names_failed: - debugfs_remove_recursive(binder_debugfs_dir_entry_root); - - destroy_workqueue(binder_deferred_workqueue); return ret; } |