diff options
Diffstat (limited to 'drivers/staging/android/binder.c')
| -rw-r--r-- | drivers/staging/android/binder.c | 2093 |
1 files changed, 1000 insertions, 1093 deletions
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 17d89a8124a..a741da77828 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -15,9 +15,12 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <asm/cacheflush.h> #include <linux/fdtable.h> #include <linux/file.h> +#include <linux/freezer.h> #include <linux/fs.h> #include <linux/list.h> #include <linux/miscdevice.h> @@ -26,26 +29,49 @@ #include <linux/mutex.h> #include <linux/nsproxy.h> #include <linux/poll.h> -#include <linux/proc_fs.h> +#include <linux/debugfs.h> #include <linux/rbtree.h> #include <linux/sched.h> +#include <linux/seq_file.h> #include <linux/uaccess.h> #include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/pid_namespace.h> + #include "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 DEFINE_MUTEX(binder_lock); 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 struct binder_node *binder_context_mgr_node; -static uid_t binder_context_mgr_uid = -1; +static kuid_t binder_context_mgr_uid = INVALID_UID; static int binder_last_id; -static struct proc_dir_entry *binder_proc_dir_entry_root; -static struct proc_dir_entry *binder_proc_dir_entry_proc; -static struct hlist_head binder_dead_nodes; -static HLIST_HEAD(binder_deferred_list); -static DEFINE_MUTEX(binder_deferred_lock); +static struct workqueue_struct *binder_deferred_workqueue; -static int binder_read_proc_proc(char *page, char **start, off_t off, - int count, int *eof, void *data); +#define BINDER_DEBUG_ENTRY(name) \ +static int binder_##name##_open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, binder_##name##_show, inode->i_private); \ +} \ +\ +static const struct file_operations binder_##name##_fops = { \ + .owner = THIS_MODULE, \ + .open = binder_##name##_open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ +} + +static int binder_proc_show(struct seq_file *m, void *unused); +BINDER_DEBUG_ENTRY(proc); /* This is only defined in include/asm-arm/sizes.h */ #ifndef SZ_1K @@ -82,7 +108,7 @@ static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO); -static int binder_debug_no_lock; +static bool binder_debug_no_lock; module_param_named(proc_no_lock, binder_debug_no_lock, bool, S_IWUSR | S_IRUGO); static DECLARE_WAIT_QUEUE_HEAD(binder_user_error_wait); @@ -92,6 +118,7 @@ static int binder_set_stop_on_user_error(const char *val, struct kernel_param *kp) { int ret; + ret = param_set_int(val, kp); if (binder_stop_on_user_error < 2) wake_up(&binder_user_error_wait); @@ -100,15 +127,21 @@ static int binder_set_stop_on_user_error(const char *val, module_param_call(stop_on_user_error, binder_set_stop_on_user_error, param_get_int, &binder_stop_on_user_error, S_IWUSR | S_IRUGO); +#define binder_debug(mask, x...) \ + do { \ + if (binder_debug_mask & mask) \ + pr_info(x); \ + } while (0) + #define binder_user_error(x...) \ do { \ if (binder_debug_mask & BINDER_DEBUG_USER_ERROR) \ - printk(KERN_INFO x); \ + pr_info(x); \ if (binder_stop_on_user_error) \ binder_stop_on_user_error = 2; \ } while (0) -enum { +enum binder_stat_types { BINDER_STAT_PROC, BINDER_STAT_THREAD, BINDER_STAT_NODE, @@ -128,6 +161,16 @@ struct binder_stats { static struct binder_stats binder_stats; +static inline void binder_stats_deleted(enum binder_stat_types type) +{ + binder_stats.obj_deleted[type]++; +} + +static inline void binder_stats_created(enum binder_stat_types type) +{ + binder_stats.obj_created[type]++; +} + struct binder_transaction_log_entry { int debug_id; int call_type; @@ -145,13 +188,14 @@ struct binder_transaction_log { int full; struct binder_transaction_log_entry entry[32]; }; -struct binder_transaction_log binder_transaction_log; -struct binder_transaction_log binder_transaction_log_failed; +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) { struct binder_transaction_log_entry *e; + e = &log->entry[log->next]; memset(e, 0, sizeof(*e)); log->next++; @@ -186,8 +230,8 @@ struct binder_node { int internal_strong_refs; int local_weak_refs; int local_strong_refs; - void __user *ptr; - void __user *cookie; + binder_uintptr_t ptr; + binder_uintptr_t cookie; unsigned has_strong_ref:1; unsigned pending_strong_ref:1; unsigned has_weak_ref:1; @@ -200,7 +244,7 @@ struct binder_node { struct binder_ref_death { struct binder_work work; - void __user *cookie; + binder_uintptr_t cookie; }; struct binder_ref { @@ -221,7 +265,7 @@ struct binder_ref { }; struct binder_buffer { - struct list_head entry; /* free and allocated entries by addesss */ + struct list_head entry; /* free and allocated entries by address */ struct rb_node rb_node; /* free entry by size or allocated entry */ /* by address */ unsigned free:1; @@ -237,7 +281,7 @@ struct binder_buffer { uint8_t data[0]; }; -enum { +enum binder_deferred_state { BINDER_DEFERRED_PUT_FILES = 0x01, BINDER_DEFERRED_FLUSH = 0x02, BINDER_DEFERRED_RELEASE = 0x04, @@ -251,6 +295,7 @@ struct binder_proc { struct rb_root refs_by_node; int pid; struct vm_area_struct *vma; + struct mm_struct *vma_vm_mm; struct task_struct *tsk; struct files_struct *files; struct hlist_node deferred_work_node; @@ -275,6 +320,7 @@ struct binder_proc { int requested_threads_started; int ready_threads; long default_priority; + struct dentry *debugfs_entry; }; enum { @@ -317,77 +363,28 @@ struct binder_transaction { unsigned int flags; long priority; long saved_priority; - uid_t sender_euid; + kuid_t sender_euid; }; -static void binder_defer_work(struct binder_proc *proc, int defer); +static void +binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); -/* - * copied from get_unused_fd_flags - */ -int task_get_unused_fd_flags(struct binder_proc *proc, int flags) +static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) { struct files_struct *files = proc->files; - int fd, error; - struct fdtable *fdt; unsigned long rlim_cur; unsigned long irqs; if (files == NULL) return -ESRCH; - error = -EMFILE; - spin_lock(&files->file_lock); - -repeat: - fdt = files_fdtable(files); - fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds, - files->next_fd); - - /* - * N.B. For clone tasks sharing a files structure, this test - * will limit the total number of files that can be opened. - */ - rlim_cur = 0; - if (lock_task_sighand(proc->tsk, &irqs)) { - rlim_cur = proc->tsk->signal->rlim[RLIMIT_NOFILE].rlim_cur; - unlock_task_sighand(proc->tsk, &irqs); - } - if (fd >= rlim_cur) - goto out; - - /* Do we need to expand the fd array or fd set? */ - error = expand_files(files, fd); - if (error < 0) - goto out; - - if (error) { - /* - * If we needed to expand the fs array we - * might have blocked - try again. - */ - error = -EMFILE; - goto repeat; - } - - FD_SET(fd, fdt->open_fds); - if (flags & O_CLOEXEC) - FD_SET(fd, fdt->close_on_exec); - else - FD_CLR(fd, fdt->close_on_exec); - files->next_fd = fd + 1; -#if 1 - /* Sanity check */ - if (fdt->fd[fd] != NULL) { - printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); - fdt->fd[fd] = NULL; - } -#endif - error = fd; + if (!lock_task_sighand(proc->tsk, &irqs)) + return -EMFILE; -out: - spin_unlock(&files->file_lock); - return error; + rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE); + unlock_task_sighand(proc->tsk, &irqs); + + return __alloc_fd(files, 0, rlim_cur, flags); } /* @@ -396,28 +393,8 @@ out: static void task_fd_install( struct binder_proc *proc, unsigned int fd, struct file *file) { - struct files_struct *files = proc->files; - struct fdtable *fdt; - - if (files == NULL) - return; - - spin_lock(&files->file_lock); - fdt = files_fdtable(files); - BUG_ON(fdt->fd[fd] != NULL); - rcu_assign_pointer(fdt->fd[fd], file); - spin_unlock(&files->file_lock); -} - -/* - * copied from __put_unused_fd in open.c - */ -static void __put_unused_fd(struct files_struct *files, unsigned int fd) -{ - struct fdtable *fdt = files_fdtable(files); - __FD_CLR(fd, fdt->open_fds); - if (fd < files->next_fd) - files->next_fd = fd; + if (proc->files) + __fd_install(proc->files, fd, file); } /* @@ -425,27 +402,12 @@ static void __put_unused_fd(struct files_struct *files, unsigned int fd) */ static long task_close_fd(struct binder_proc *proc, unsigned int fd) { - struct file *filp; - struct files_struct *files = proc->files; - struct fdtable *fdt; int retval; - if (files == NULL) + if (proc->files == NULL) return -ESRCH; - spin_lock(&files->file_lock); - fdt = files_fdtable(files); - if (fd >= fdt->max_fds) - goto out_unlock; - filp = fdt->fd[fd]; - if (!filp) - goto out_unlock; - rcu_assign_pointer(fdt->fd[fd], NULL); - FD_CLR(fd, fdt->close_on_exec); - __put_unused_fd(files, fd); - spin_unlock(&files->file_lock); - retval = filp_close(filp, files); - + retval = __close_fd(proc->files, fd); /* can't restart close syscall because file table entry was cleared */ if (unlikely(retval == -ERESTARTSYS || retval == -ERESTARTNOINTR || @@ -454,27 +416,37 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd) retval = -EINTR; return retval; +} -out_unlock: - spin_unlock(&files->file_lock); - return -EBADF; +static inline void binder_lock(const char *tag) +{ + trace_binder_lock(tag); + mutex_lock(&binder_main_lock); + trace_binder_locked(tag); +} + +static inline void binder_unlock(const char *tag) +{ + trace_binder_unlock(tag); + mutex_unlock(&binder_main_lock); } static void binder_set_nice(long nice) { long min_nice; + if (can_nice(current, nice)) { set_user_nice(current, nice); return; } - min_nice = 20 - current->signal->rlim[RLIMIT_NICE].rlim_cur; - if (binder_debug_mask & BINDER_DEBUG_PRIORITY_CAP) - printk(KERN_INFO "binder: %d: nice value %ld not allowed use " - "%ld instead\n", current->pid, nice, min_nice); + min_nice = rlimit_to_nice(current->signal->rlim[RLIMIT_NICE].rlim_cur); + binder_debug(BINDER_DEBUG_PRIORITY_CAP, + "%d: nice value %ld not allowed use %ld instead\n", + current->pid, nice, min_nice); set_user_nice(current, min_nice); - if (min_nice < 20) + if (min_nice <= MAX_NICE) return; - binder_user_error("binder: %d RLIMIT_NICE not set\n", current->pid); + binder_user_error("%d RLIMIT_NICE not set\n", current->pid); } static size_t binder_buffer_size(struct binder_proc *proc, @@ -500,9 +472,9 @@ static void binder_insert_free_buffer(struct binder_proc *proc, new_buffer_size = binder_buffer_size(proc, new_buffer); - if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) - printk(KERN_INFO "binder: %d: add free buffer, size %zd, " - "at %p\n", proc->pid, new_buffer_size, new_buffer); + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: add free buffer, size %zd, at %p\n", + proc->pid, new_buffer_size, new_buffer); while (*p) { parent = *p; @@ -546,14 +518,14 @@ static void binder_insert_allocated_buffer(struct binder_proc *proc, } static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc, - void __user *user_ptr) + uintptr_t user_ptr) { struct rb_node *n = proc->allocated_buffers.rb_node; struct binder_buffer *buffer; struct binder_buffer *kern_ptr; - kern_ptr = user_ptr - proc->user_buffer_offset - - offsetof(struct binder_buffer, data); + kern_ptr = (struct binder_buffer *)(user_ptr - proc->user_buffer_offset + - offsetof(struct binder_buffer, data)); while (n) { buffer = rb_entry(n, struct binder_buffer, rb_node); @@ -579,13 +551,15 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, struct page **page; struct mm_struct *mm; - if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) - printk(KERN_INFO "binder: %d: %s pages %p-%p\n", - proc->pid, allocate ? "allocate" : "free", start, end); + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: %s pages %p-%p\n", proc->pid, + allocate ? "allocate" : "free", start, end); if (end <= start) return 0; + trace_binder_update_page_range(proc, allocate, start, end); + if (vma) mm = NULL; else @@ -594,27 +568,33 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, if (mm) { down_write(&mm->mmap_sem); vma = proc->vma; + if (vma && mm != proc->vma_vm_mm) { + pr_err("%d: vma mm and task mm mismatch\n", + proc->pid); + vma = NULL; + } } if (allocate == 0) goto free_range; if (vma == NULL) { - printk(KERN_ERR "binder: %d: binder_alloc_buf failed to " - "map pages in userspace, no vma\n", proc->pid); + pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n", + proc->pid); goto err_no_vma; } for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { int ret; struct page **page_array_ptr; + page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; BUG_ON(*page); - *page = alloc_page(GFP_KERNEL | __GFP_ZERO); + *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); if (*page == NULL) { - printk(KERN_ERR "binder: %d: binder_alloc_buf failed " - "for page at %p\n", proc->pid, page_addr); + pr_err("%d: binder_alloc_buf failed for page at %p\n", + proc->pid, page_addr); goto err_alloc_page_failed; } tmp_area.addr = page_addr; @@ -622,8 +602,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, page_array_ptr = page; ret = map_vm_area(&tmp_area, PAGE_KERNEL, &page_array_ptr); if (ret) { - printk(KERN_ERR "binder: %d: binder_alloc_buf failed " - "to map page at %p in kernel\n", + pr_err("%d: binder_alloc_buf failed to map page at %p in kernel\n", proc->pid, page_addr); goto err_map_kernel_failed; } @@ -631,8 +610,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, (uintptr_t)page_addr + proc->user_buffer_offset; ret = vm_insert_page(vma, user_page_addr, page[0]); if (ret) { - printk(KERN_ERR "binder: %d: binder_alloc_buf failed " - "to map page at %lx in userspace\n", + pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n", proc->pid, user_page_addr); goto err_vm_insert_page_failed; } @@ -680,7 +658,7 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, size_t size; if (proc->vma == NULL) { - printk(KERN_ERR "binder: %d: binder_alloc_buf, no vma\n", + pr_err("%d: binder_alloc_buf, no vma\n", proc->pid); return NULL; } @@ -689,17 +667,16 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, ALIGN(offsets_size, sizeof(void *)); if (size < data_size || size < offsets_size) { - binder_user_error("binder: %d: got transaction with invalid " - "size %zd-%zd\n", proc->pid, data_size, offsets_size); + binder_user_error("%d: got transaction with invalid size %zd-%zd\n", + proc->pid, data_size, offsets_size); return NULL; } if (is_async && proc->free_async_space < size + sizeof(struct binder_buffer)) { - if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) - printk(KERN_ERR - "binder: %d: binder_alloc_buf size %zd failed, " - "no async space left\n", proc->pid, size); + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd failed, no async space left\n", + proc->pid, size); return NULL; } @@ -719,17 +696,18 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, } } if (best_fit == NULL) { - printk(KERN_ERR "binder: %d: binder_alloc_buf size %zd failed, " - "no address space\n", proc->pid, size); + pr_err("%d: binder_alloc_buf size %zd failed, no address space\n", + proc->pid, size); return NULL; } if (n == NULL) { buffer = rb_entry(best_fit, struct binder_buffer, rb_node); buffer_size = binder_buffer_size(proc, buffer); } - if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) - printk(KERN_INFO "binder: %d: binder_alloc_buf size %zd got buff" - "er %p size %zd\n", proc->pid, size, buffer, buffer_size); + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd got buffer %p size %zd\n", + proc->pid, size, buffer, buffer_size); has_page_addr = (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK); @@ -752,22 +730,22 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, binder_insert_allocated_buffer(proc, buffer); if (buffer_size != size) { struct binder_buffer *new_buffer = (void *)buffer->data + size; + list_add(&new_buffer->entry, &buffer->entry); new_buffer->free = 1; binder_insert_free_buffer(proc, new_buffer); } - if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) - printk(KERN_INFO "binder: %d: binder_alloc_buf size %zd got " - "%p\n", proc->pid, size, buffer); + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_alloc_buf size %zd got %p\n", + proc->pid, size, buffer); buffer->data_size = data_size; buffer->offsets_size = offsets_size; buffer->async_transaction = is_async; if (is_async) { proc->free_async_space -= size + sizeof(struct binder_buffer); - if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC_ASYNC) - printk(KERN_INFO "binder: %d: binder_alloc_buf size %zd " - "async free %zd\n", proc->pid, size, - proc->free_async_space); + binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, + "%d: binder_alloc_buf size %zd async free %zd\n", + proc->pid, size, proc->free_async_space); } return buffer; @@ -797,9 +775,9 @@ static void binder_delete_free_buffer(struct binder_proc *proc, free_page_start = 0; if (buffer_end_page(prev) == buffer_end_page(buffer)) free_page_end = 0; - if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) - printk(KERN_INFO "binder: %d: merge free, buffer %p " - "share page with %p\n", proc->pid, buffer, prev); + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %p share page with %p\n", + proc->pid, buffer, prev); } if (!list_is_last(&buffer->entry, &proc->buffers)) { @@ -810,19 +788,17 @@ static void binder_delete_free_buffer(struct binder_proc *proc, if (buffer_start_page(next) == buffer_start_page(buffer)) free_page_start = 0; - if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) - printk(KERN_INFO "binder: %d: merge free, " - "buffer %p share page with %p\n", - proc->pid, buffer, prev); + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %p share page with %p\n", + proc->pid, buffer, prev); } } list_del(&buffer->entry); if (free_page_start || free_page_end) { - if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) - printk(KERN_INFO "binder: %d: merge free, buffer %p do " - "not share page%s%s with with %p or %p\n", - proc->pid, buffer, free_page_start ? "" : " end", - free_page_end ? "" : " start", prev, next); + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: merge free, buffer %p do not share page%s%s with %p or %p\n", + proc->pid, buffer, free_page_start ? "" : " end", + free_page_end ? "" : " start", prev, next); binder_update_page_range(proc, 0, free_page_start ? buffer_start_page(buffer) : buffer_end_page(buffer), (free_page_end ? buffer_end_page(buffer) : @@ -839,9 +815,10 @@ static void binder_free_buf(struct binder_proc *proc, size = ALIGN(buffer->data_size, sizeof(void *)) + ALIGN(buffer->offsets_size, sizeof(void *)); - if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) - printk(KERN_INFO "binder: %d: binder_free_buf %p size %zd buffer" - "_size %zd\n", proc->pid, buffer, size, buffer_size); + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: binder_free_buf %p size %zd buffer_size %zd\n", + proc->pid, buffer, size, buffer_size); BUG_ON(buffer->free); BUG_ON(size > buffer_size); @@ -851,10 +828,10 @@ static void binder_free_buf(struct binder_proc *proc, if (buffer->async_transaction) { proc->free_async_space += size + sizeof(struct binder_buffer); - if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC_ASYNC) - printk(KERN_INFO "binder: %d: binder_free_buf size %zd " - "async free %zd\n", proc->pid, size, - proc->free_async_space); + + binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, + "%d: binder_free_buf size %zd async free %zd\n", + proc->pid, size, proc->free_async_space); } binder_update_page_range(proc, 0, @@ -866,6 +843,7 @@ static void binder_free_buf(struct binder_proc *proc, if (!list_is_last(&buffer->entry, &proc->buffers)) { struct binder_buffer *next = list_entry(buffer->entry.next, struct binder_buffer, entry); + if (next->free) { rb_erase(&next->rb_node, &proc->free_buffers); binder_delete_free_buffer(proc, next); @@ -874,6 +852,7 @@ static void binder_free_buf(struct binder_proc *proc, if (proc->buffers.next != &buffer->entry) { struct binder_buffer *prev = list_entry(buffer->entry.prev, struct binder_buffer, entry); + if (prev->free) { binder_delete_free_buffer(proc, buffer); rb_erase(&prev->rb_node, &proc->free_buffers); @@ -884,7 +863,7 @@ static void binder_free_buf(struct binder_proc *proc, } static struct binder_node *binder_get_node(struct binder_proc *proc, - void __user *ptr) + binder_uintptr_t ptr) { struct rb_node *n = proc->nodes.rb_node; struct binder_node *node; @@ -903,8 +882,8 @@ static struct binder_node *binder_get_node(struct binder_proc *proc, } static struct binder_node *binder_new_node(struct binder_proc *proc, - void __user *ptr, - void __user *cookie) + binder_uintptr_t ptr, + binder_uintptr_t cookie) { struct rb_node **p = &proc->nodes.rb_node; struct rb_node *parent = NULL; @@ -925,7 +904,7 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, node = kzalloc(sizeof(*node), GFP_KERNEL); if (node == NULL) return NULL; - binder_stats.obj_created[BINDER_STAT_NODE]++; + 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; @@ -935,10 +914,10 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, node->work.type = BINDER_WORK_NODE; INIT_LIST_HEAD(&node->work.entry); INIT_LIST_HEAD(&node->async_todo); - if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS) - printk(KERN_INFO "binder: %d:%d node %d u%p c%p created\n", - proc->pid, current->pid, node->debug_id, - node->ptr, node->cookie); + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d:%d node %d u%016llx c%016llx created\n", + proc->pid, current->pid, node->debug_id, + (u64)node->ptr, (u64)node->cookie); return node; } @@ -951,8 +930,8 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal, node->internal_strong_refs == 0 && !(node == binder_context_mgr_node && node->has_strong_ref)) { - printk(KERN_ERR "binder: invalid inc strong " - "node for %d\n", node->debug_id); + pr_err("invalid inc strong node for %d\n", + node->debug_id); return -EINVAL; } node->internal_strong_refs++; @@ -967,8 +946,8 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal, node->local_weak_refs++; if (!node->has_weak_ref && list_empty(&node->work.entry)) { if (target_list == NULL) { - printk(KERN_ERR "binder: invalid inc weak node " - "for %d\n", node->debug_id); + pr_err("invalid inc weak node for %d\n", + node->debug_id); return -EINVAL; } list_add_tail(&node->work.entry, target_list); @@ -1003,15 +982,17 @@ static int binder_dec_node(struct binder_node *node, int strong, int internal) list_del_init(&node->work.entry); if (node->proc) { rb_erase(&node->rb_node, &node->proc->nodes); - if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS) - printk(KERN_INFO "binder: refless node %d deleted\n", node->debug_id); + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "refless node %d deleted\n", + node->debug_id); } else { hlist_del(&node->dead_node); - if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS) - printk(KERN_INFO "binder: dead node %d deleted\n", node->debug_id); + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "dead node %d deleted\n", + node->debug_id); } kfree(node); - binder_stats.obj_deleted[BINDER_STAT_NODE]++; + binder_stats_deleted(BINDER_STAT_NODE); } } @@ -1060,7 +1041,7 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, new_ref = kzalloc(sizeof(*ref), GFP_KERNEL); if (new_ref == NULL) return NULL; - binder_stats.obj_created[BINDER_STAT_REF]++; + binder_stats_created(BINDER_STAT_REF); new_ref->debug_id = ++binder_last_id; new_ref->proc = proc; new_ref->node = node; @@ -1091,25 +1072,26 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc); if (node) { hlist_add_head(&new_ref->node_entry, &node->refs); - if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS) - printk(KERN_INFO "binder: %d new ref %d desc %d for " - "node %d\n", proc->pid, new_ref->debug_id, - new_ref->desc, node->debug_id); + + 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, + node->debug_id); } else { - if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS) - printk(KERN_INFO "binder: %d new ref %d desc %d for " - "dead node\n", proc->pid, new_ref->debug_id, - new_ref->desc); + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d new ref %d desc %d for dead node\n", + proc->pid, new_ref->debug_id, new_ref->desc); } return new_ref; } static void binder_delete_ref(struct binder_ref *ref) { - if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS) - printk(KERN_INFO "binder: %d delete ref %d desc %d for " - "node %d\n", ref->proc->pid, ref->debug_id, - ref->desc, ref->node->debug_id); + 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->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) @@ -1117,22 +1099,22 @@ static void binder_delete_ref(struct binder_ref *ref) hlist_del(&ref->node_entry); binder_dec_node(ref->node, 0, 1); if (ref->death) { - if (binder_debug_mask & BINDER_DEBUG_DEAD_BINDER) - printk(KERN_INFO "binder: %d delete ref %d desc %d " - "has death notification\n", ref->proc->pid, - ref->debug_id, ref->desc); + binder_debug(BINDER_DEBUG_DEAD_BINDER, + "%d delete ref %d desc %d has death notification\n", + ref->proc->pid, ref->debug_id, ref->desc); list_del(&ref->death->work.entry); kfree(ref->death); - binder_stats.obj_deleted[BINDER_STAT_DEATH]++; + binder_stats_deleted(BINDER_STAT_DEATH); } kfree(ref); - binder_stats.obj_deleted[BINDER_STAT_REF]++; + binder_stats_deleted(BINDER_STAT_REF); } static int binder_inc_ref(struct binder_ref *ref, int strong, struct list_head *target_list) { int ret; + if (strong) { if (ref->strong == 0) { ret = binder_inc_node(ref->node, 1, 1, target_list); @@ -1156,8 +1138,7 @@ static int binder_dec_ref(struct binder_ref *ref, int strong) { if (strong) { if (ref->strong == 0) { - binder_user_error("binder: %d invalid dec strong, " - "ref %d desc %d s %d w %d\n", + 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; @@ -1165,14 +1146,14 @@ static int binder_dec_ref(struct binder_ref *ref, int strong) ref->strong--; if (ref->strong == 0) { int ret; + ret = binder_dec_node(ref->node, strong, 1); if (ret) return ret; } } else { if (ref->weak == 0) { - binder_user_error("binder: %d invalid dec weak, " - "ref %d desc %d s %d w %d\n", + 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; @@ -1198,13 +1179,14 @@ static void binder_pop_transaction(struct binder_thread *target_thread, if (t->buffer) t->buffer->transaction = NULL; kfree(t); - binder_stats.obj_deleted[BINDER_STAT_TRANSACTION]++; + binder_stats_deleted(BINDER_STAT_TRANSACTION); } static void binder_send_failed_reply(struct binder_transaction *t, uint32_t error_code) { struct binder_thread *target_thread; + BUG_ON(t->flags & TF_ONE_WAY); while (1) { target_thread = t->from; @@ -1216,17 +1198,17 @@ static void binder_send_failed_reply(struct binder_transaction *t, target_thread->return_error = BR_OK; } if (target_thread->return_error == BR_OK) { - if (binder_debug_mask & BINDER_DEBUG_FAILED_TRANSACTION) - printk(KERN_INFO "binder: send failed reply for transaction %d to %d:%d\n", - t->debug_id, target_thread->proc->pid, target_thread->pid); + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "send failed reply for transaction %d to %d:%d\n", + t->debug_id, target_thread->proc->pid, + target_thread->pid); binder_pop_transaction(target_thread, t); target_thread->return_error = error_code; wake_up_interruptible(&target_thread->wait); } else { - printk(KERN_ERR "binder: reply failed, target " - "thread, %d:%d, has error code %d " - "already\n", target_thread->proc->pid, + pr_err("reply failed, target thread, %d:%d, has error code %d already\n", + target_thread->proc->pid, target_thread->pid, target_thread->return_error); } @@ -1234,29 +1216,100 @@ static void binder_send_failed_reply(struct binder_transaction *t, } else { struct binder_transaction *next = t->from_parent; - if (binder_debug_mask & BINDER_DEBUG_FAILED_TRANSACTION) - printk(KERN_INFO "binder: send failed reply " - "for transaction %d, target dead\n", - t->debug_id); + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "send failed reply for transaction %d, target dead\n", + t->debug_id); binder_pop_transaction(target_thread, t); if (next == NULL) { - if (binder_debug_mask & BINDER_DEBUG_DEAD_BINDER) - printk(KERN_INFO "binder: reply failed," - " no target thread at root\n"); + binder_debug(BINDER_DEBUG_DEAD_BINDER, + "reply failed, no target thread at root\n"); return; } t = next; - if (binder_debug_mask & BINDER_DEBUG_DEAD_BINDER) - printk(KERN_INFO "binder: reply failed, no targ" - "et thread -- retry %d\n", t->debug_id); + binder_debug(BINDER_DEBUG_DEAD_BINDER, + "reply failed, no target thread -- retry %d\n", + t->debug_id); } } } static void binder_transaction_buffer_release(struct binder_proc *proc, struct binder_buffer *buffer, - size_t *failed_at); + binder_size_t *failed_at) +{ + binder_size_t *offp, *off_end; + int debug_id = buffer->debug_id; + + binder_debug(BINDER_DEBUG_TRANSACTION, + "%d buffer release %d, size %zd-%zd, failed at %p\n", + proc->pid, buffer->debug_id, + buffer->data_size, buffer->offsets_size, failed_at); + + if (buffer->target_node) + binder_dec_node(buffer->target_node, 1, 0); + + offp = (binder_size_t *)(buffer->data + + ALIGN(buffer->data_size, sizeof(void *))); + if (failed_at) + off_end = failed_at; + else + off_end = (void *)offp + buffer->offsets_size; + for (; offp < off_end; offp++) { + struct flat_binder_object *fp; + + if (*offp > buffer->data_size - sizeof(*fp) || + buffer->data_size < sizeof(*fp) || + !IS_ALIGNED(*offp, sizeof(u32))) { + pr_err("transaction release %d bad offset %lld, size %zd\n", + debug_id, (u64)*offp, buffer->data_size); + continue; + } + fp = (struct flat_binder_object *)(buffer->data + *offp); + switch (fp->type) { + case BINDER_TYPE_BINDER: + case BINDER_TYPE_WEAK_BINDER: { + struct binder_node *node = binder_get_node(proc, fp->binder); + + if (node == NULL) { + pr_err("transaction release %d bad node %016llx\n", + debug_id, (u64)fp->binder); + break; + } + binder_debug(BINDER_DEBUG_TRANSACTION, + " node %d u%016llx\n", + node->debug_id, (u64)node->ptr); + binder_dec_node(node, fp->type == BINDER_TYPE_BINDER, 0); + } break; + case BINDER_TYPE_HANDLE: + case BINDER_TYPE_WEAK_HANDLE: { + struct binder_ref *ref = binder_get_ref(proc, fp->handle); + + if (ref == NULL) { + pr_err("transaction release %d bad handle %d\n", + debug_id, fp->handle); + 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, fp->type == BINDER_TYPE_HANDLE); + } break; + + case BINDER_TYPE_FD: + binder_debug(BINDER_DEBUG_TRANSACTION, + " fd %d\n", fp->handle); + if (failed_at) + task_close_fd(proc, fp->handle); + break; + + default: + pr_err("transaction release %d bad object type %x\n", + debug_id, fp->type); + break; + } + } +} static void binder_transaction(struct binder_proc *proc, struct binder_thread *thread, @@ -1264,7 +1317,7 @@ static void binder_transaction(struct binder_proc *proc, { struct binder_transaction *t; struct binder_work *tcomplete; - size_t *offp, *off_end; + binder_size_t *offp, *off_end; struct binder_proc *target_proc; struct binder_thread *target_thread = NULL; struct binder_node *target_node = NULL; @@ -1285,17 +1338,14 @@ static void binder_transaction(struct binder_proc *proc, if (reply) { in_reply_to = thread->transaction_stack; if (in_reply_to == NULL) { - binder_user_error("binder: %d:%d got reply transaction " - "with no transaction stack\n", + binder_user_error("%d:%d got reply transaction with no transaction stack\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_empty_call_stack; } binder_set_nice(in_reply_to->saved_priority); if (in_reply_to->to_thread != thread) { - binder_user_error("binder: %d:%d got reply transaction " - "with bad transaction stack," - " transaction %d has target %d:%d\n", + binder_user_error("%d:%d got reply transaction with bad transaction stack, transaction %d has target %d:%d\n", proc->pid, thread->pid, in_reply_to->debug_id, in_reply_to->to_proc ? in_reply_to->to_proc->pid : 0, @@ -1312,9 +1362,7 @@ static void binder_transaction(struct binder_proc *proc, goto err_dead_binder; } if (target_thread->transaction_stack != in_reply_to) { - binder_user_error("binder: %d:%d got reply transaction " - "with bad target transaction stack %d, " - "expected %d\n", + binder_user_error("%d:%d got reply transaction with bad target transaction stack %d, expected %d\n", proc->pid, thread->pid, target_thread->transaction_stack ? target_thread->transaction_stack->debug_id : 0, @@ -1328,10 +1376,10 @@ static void binder_transaction(struct binder_proc *proc, } else { if (tr->target.handle) { struct binder_ref *ref; + ref = binder_get_ref(proc, tr->target.handle); if (ref == NULL) { - binder_user_error("binder: %d:%d got " - "transaction to invalid handle\n", + binder_user_error("%d:%d got transaction to invalid handle\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_invalid_target_handle; @@ -1352,11 +1400,10 @@ static void binder_transaction(struct binder_proc *proc, } if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { struct binder_transaction *tmp; + tmp = thread->transaction_stack; if (tmp->to_thread != thread) { - binder_user_error("binder: %d:%d got new " - "transaction with bad transaction stack" - ", transaction %d has target %d:%d\n", + binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n", proc->pid, thread->pid, tmp->debug_id, tmp->to_proc ? tmp->to_proc->pid : 0, tmp->to_thread ? @@ -1387,45 +1434,48 @@ static void binder_transaction(struct binder_proc *proc, return_error = BR_FAILED_REPLY; goto err_alloc_t_failed; } - binder_stats.obj_created[BINDER_STAT_TRANSACTION]++; + binder_stats_created(BINDER_STAT_TRANSACTION); tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); if (tcomplete == NULL) { return_error = BR_FAILED_REPLY; goto err_alloc_tcomplete_failed; } - binder_stats.obj_created[BINDER_STAT_TRANSACTION_COMPLETE]++; + binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE); t->debug_id = ++binder_last_id; e->debug_id = t->debug_id; - if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) { - if (reply) - printk(KERN_INFO "binder: %d:%d BC_REPLY %d -> %d:%d, " - "data %p-%p size %zd-%zd\n", - proc->pid, thread->pid, t->debug_id, - target_proc->pid, target_thread->pid, - tr->data.ptr.buffer, tr->data.ptr.offsets, - tr->data_size, tr->offsets_size); - else - printk(KERN_INFO "binder: %d:%d BC_TRANSACTION %d -> " - "%d - node %d, data %p-%p size %zd-%zd\n", - proc->pid, thread->pid, t->debug_id, - target_proc->pid, target_node->debug_id, - tr->data.ptr.buffer, tr->data.ptr.offsets, - tr->data_size, tr->offsets_size); - } + if (reply) + binder_debug(BINDER_DEBUG_TRANSACTION, + "%d:%d BC_REPLY %d -> %d:%d, data %016llx-%016llx size %lld-%lld\n", + proc->pid, thread->pid, t->debug_id, + target_proc->pid, target_thread->pid, + (u64)tr->data.ptr.buffer, + (u64)tr->data.ptr.offsets, + (u64)tr->data_size, (u64)tr->offsets_size); + else + binder_debug(BINDER_DEBUG_TRANSACTION, + "%d:%d BC_TRANSACTION %d -> %d - node %d, data %016llx-%016llx size %lld-%lld\n", + proc->pid, thread->pid, t->debug_id, + target_proc->pid, target_node->debug_id, + (u64)tr->data.ptr.buffer, + (u64)tr->data.ptr.offsets, + (u64)tr->data_size, (u64)tr->offsets_size); if (!reply && !(tr->flags & TF_ONE_WAY)) t->from = thread; else t->from = NULL; - t->sender_euid = proc->tsk->cred->euid; + t->sender_euid = task_euid(proc->tsk); t->to_proc = target_proc; t->to_thread = target_thread; t->code = tr->code; t->flags = tr->flags; t->priority = task_nice(current); + + trace_binder_transaction(reply, t, target_node); + t->buffer = binder_alloc_buf(target_proc, tr->data_size, tr->offsets_size, !reply && (t->flags & TF_ONE_WAY)); if (t->buffer == NULL) { @@ -1436,39 +1486,42 @@ static void binder_transaction(struct binder_proc *proc, t->buffer->debug_id = t->debug_id; t->buffer->transaction = t; t->buffer->target_node = target_node; + trace_binder_transaction_alloc_buf(t->buffer); if (target_node) binder_inc_node(target_node, 1, 0, NULL); - offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *))); + offp = (binder_size_t *)(t->buffer->data + + ALIGN(tr->data_size, sizeof(void *))); - if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) { - binder_user_error("binder: %d:%d got transaction with invalid " - "data ptr\n", proc->pid, thread->pid); + if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t) + tr->data.ptr.buffer, tr->data_size)) { + binder_user_error("%d:%d got transaction with invalid data ptr\n", + proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } - if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) { - binder_user_error("binder: %d:%d got transaction with invalid " - "offsets ptr\n", proc->pid, thread->pid); + if (copy_from_user(offp, (const void __user *)(uintptr_t) + tr->data.ptr.offsets, tr->offsets_size)) { + binder_user_error("%d:%d got transaction with invalid offsets ptr\n", + proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } - if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) { - binder_user_error("binder: %d:%d got transaction with " - "invalid offsets size, %zd\n", - proc->pid, thread->pid, tr->offsets_size); + if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) { + binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n", + proc->pid, thread->pid, (u64)tr->offsets_size); return_error = BR_FAILED_REPLY; goto err_bad_offset; } off_end = (void *)offp + tr->offsets_size; for (; offp < off_end; offp++) { struct flat_binder_object *fp; + if (*offp > t->buffer->data_size - sizeof(*fp) || t->buffer->data_size < sizeof(*fp) || - !IS_ALIGNED(*offp, sizeof(void *))) { - binder_user_error("binder: %d:%d got transaction with " - "invalid offset, %zd\n", - proc->pid, thread->pid, *offp); + !IS_ALIGNED(*offp, sizeof(u32))) { + binder_user_error("%d:%d got transaction with invalid offset, %lld\n", + proc->pid, thread->pid, (u64)*offp); return_error = BR_FAILED_REPLY; goto err_bad_offset; } @@ -1478,6 +1531,7 @@ static void binder_transaction(struct binder_proc *proc, case BINDER_TYPE_WEAK_BINDER: { struct binder_ref *ref; struct binder_node *node = binder_get_node(proc, fp->binder); + if (node == NULL) { node = binder_new_node(proc, fp->binder, fp->cookie); if (node == NULL) { @@ -1488,11 +1542,11 @@ static void binder_transaction(struct binder_proc *proc, node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); } if (fp->cookie != node->cookie) { - binder_user_error("binder: %d:%d sending u%p " - "node %d, cookie mismatch %p != %p\n", + binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, - fp->binder, node->debug_id, - fp->cookie, node->cookie); + (u64)fp->binder, node->debug_id, + (u64)fp->cookie, (u64)node->cookie); + return_error = BR_FAILED_REPLY; goto err_binder_get_ref_for_node_failed; } ref = binder_get_ref_for_node(target_proc, node); @@ -1505,19 +1559,23 @@ static void binder_transaction(struct binder_proc *proc, else fp->type = BINDER_TYPE_WEAK_HANDLE; fp->handle = ref->desc; - binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo); - if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) - printk(KERN_INFO " node %d u%p -> ref %d desc %d\n", - node->debug_id, node->ptr, ref->debug_id, ref->desc); + binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, + &thread->todo); + + trace_binder_transaction_node_to_ref(t, node, ref); + 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); } break; case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { struct binder_ref *ref = binder_get_ref(proc, fp->handle); + if (ref == NULL) { - binder_user_error("binder: %d:%d got " - "transaction with invalid " - "handle, %ld\n", proc->pid, - thread->pid, fp->handle); + binder_user_error("%d:%d got transaction with invalid handle, %d\n", + proc->pid, + thread->pid, fp->handle); return_error = BR_FAILED_REPLY; goto err_binder_get_ref_failed; } @@ -1529,11 +1587,14 @@ static void binder_transaction(struct binder_proc *proc, fp->binder = ref->node->ptr; fp->cookie = ref->node->cookie; binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL); - if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) - printk(KERN_INFO " ref %d desc %d -> node %d u%p\n", - ref->debug_id, ref->desc, ref->node->debug_id, ref->node->ptr); + trace_binder_transaction_ref_to_node(t, ref); + 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); } else { struct binder_ref *new_ref; + new_ref = binder_get_ref_for_node(target_proc, ref->node); if (new_ref == NULL) { return_error = BR_FAILED_REPLY; @@ -1541,9 +1602,12 @@ static void binder_transaction(struct binder_proc *proc, } fp->handle = new_ref->desc; binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL); - if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) - printk(KERN_INFO " 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); + trace_binder_transaction_ref_to_ref(t, ref, + new_ref); + 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); } } break; @@ -1553,13 +1617,13 @@ static void binder_transaction(struct binder_proc *proc, if (reply) { if (!(in_reply_to->flags & TF_ACCEPT_FDS)) { - binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n", + binder_user_error("%d:%d got reply with fd, %d, but target does not allow fds\n", proc->pid, thread->pid, fp->handle); return_error = BR_FAILED_REPLY; goto err_fd_not_allowed; } } else if (!target_node->accept_fds) { - binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n", + binder_user_error("%d:%d got transaction with fd, %d, but target does not allow fds\n", proc->pid, thread->pid, fp->handle); return_error = BR_FAILED_REPLY; goto err_fd_not_allowed; @@ -1567,7 +1631,7 @@ static void binder_transaction(struct binder_proc *proc, file = fget(fp->handle); if (file == NULL) { - binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n", + binder_user_error("%d:%d got transaction with invalid fd, %d\n", proc->pid, thread->pid, fp->handle); return_error = BR_FAILED_REPLY; goto err_fget_failed; @@ -1579,15 +1643,15 @@ static void binder_transaction(struct binder_proc *proc, goto err_get_unused_fd_failed; } task_fd_install(target_proc, target_fd, file); - if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) - printk(KERN_INFO " fd %ld -> %d\n", fp->handle, target_fd); + trace_binder_transaction_fd(t, fp->handle, target_fd); + binder_debug(BINDER_DEBUG_TRANSACTION, + " fd %d -> %d\n", fp->handle, target_fd); /* TODO: fput? */ fp->handle = target_fd; } break; default: - binder_user_error("binder: %d:%d got transactio" - "n with invalid object type, %lx\n", + binder_user_error("%d:%d got transaction with invalid object type, %x\n", proc->pid, thread->pid, fp->type); return_error = BR_FAILED_REPLY; goto err_bad_object_type; @@ -1627,29 +1691,30 @@ err_binder_new_node_failed: err_bad_object_type: err_bad_offset: err_copy_data_failed: + trace_binder_transaction_failed_buffer_release(t->buffer); binder_transaction_buffer_release(target_proc, t->buffer, offp); t->buffer->transaction = NULL; binder_free_buf(target_proc, t->buffer); err_binder_alloc_buf_failed: kfree(tcomplete); - binder_stats.obj_deleted[BINDER_STAT_TRANSACTION_COMPLETE]++; + binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); err_alloc_tcomplete_failed: kfree(t); - binder_stats.obj_deleted[BINDER_STAT_TRANSACTION]++; + binder_stats_deleted(BINDER_STAT_TRANSACTION); err_alloc_t_failed: err_bad_call_stack: err_empty_call_stack: err_dead_binder: err_invalid_target_handle: err_no_context_mgr_node: - if (binder_debug_mask & BINDER_DEBUG_FAILED_TRANSACTION) - printk(KERN_INFO "binder: %d:%d transaction failed %d, size" - "%zd-%zd\n", - proc->pid, thread->pid, return_error, - tr->data_size, tr->offsets_size); + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "%d:%d transaction failed %d, size %lld-%lld\n", + proc->pid, thread->pid, return_error, + (u64)tr->data_size, (u64)tr->offsets_size); { struct binder_transaction_log_entry *fe; + fe = binder_transaction_log_add(&binder_transaction_log_failed); *fe = *e; } @@ -1662,80 +1727,13 @@ err_no_context_mgr_node: thread->return_error = return_error; } -static void binder_transaction_buffer_release(struct binder_proc *proc, - struct binder_buffer *buffer, - size_t *failed_at) -{ - size_t *offp, *off_end; - int debug_id = buffer->debug_id; - - if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) - printk(KERN_INFO "binder: %d buffer release %d, size %zd-%zd, failed at %p\n", - proc->pid, buffer->debug_id, - buffer->data_size, buffer->offsets_size, failed_at); - - if (buffer->target_node) - binder_dec_node(buffer->target_node, 1, 0); - - offp = (size_t *)(buffer->data + ALIGN(buffer->data_size, sizeof(void *))); - if (failed_at) - off_end = failed_at; - else - off_end = (void *)offp + buffer->offsets_size; - for (; offp < off_end; offp++) { - struct flat_binder_object *fp; - if (*offp > buffer->data_size - sizeof(*fp) || - buffer->data_size < sizeof(*fp) || - !IS_ALIGNED(*offp, sizeof(void *))) { - printk(KERN_ERR "binder: transaction release %d bad" - "offset %zd, size %zd\n", debug_id, *offp, buffer->data_size); - continue; - } - fp = (struct flat_binder_object *)(buffer->data + *offp); - switch (fp->type) { - case BINDER_TYPE_BINDER: - case BINDER_TYPE_WEAK_BINDER: { - struct binder_node *node = binder_get_node(proc, fp->binder); - if (node == NULL) { - printk(KERN_ERR "binder: transaction release %d bad node %p\n", debug_id, fp->binder); - break; - } - if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) - printk(KERN_INFO " node %d u%p\n", - node->debug_id, node->ptr); - binder_dec_node(node, fp->type == BINDER_TYPE_BINDER, 0); - } break; - case BINDER_TYPE_HANDLE: - case BINDER_TYPE_WEAK_HANDLE: { - struct binder_ref *ref = binder_get_ref(proc, fp->handle); - if (ref == NULL) { - printk(KERN_ERR "binder: transaction release %d bad handle %ld\n", debug_id, fp->handle); - break; - } - if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) - printk(KERN_INFO " ref %d desc %d (node %d)\n", - ref->debug_id, ref->desc, ref->node->debug_id); - binder_dec_ref(ref, fp->type == BINDER_TYPE_HANDLE); - } break; - - case BINDER_TYPE_FD: - if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) - printk(KERN_INFO " fd %ld\n", fp->handle); - if (failed_at) - task_close_fd(proc, fp->handle); - break; - - default: - printk(KERN_ERR "binder: transaction release %d bad object type %lx\n", debug_id, fp->type); - break; - } - } -} - -int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, - void __user *buffer, int size, signed long *consumed) +static int binder_thread_write(struct binder_proc *proc, + struct binder_thread *thread, + binder_uintptr_t binder_buffer, size_t size, + binder_size_t *consumed) { uint32_t cmd; + void __user *buffer = (void __user *)(uintptr_t)binder_buffer; void __user *ptr = buffer + *consumed; void __user *end = buffer + size; @@ -1743,6 +1741,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, if (get_user(cmd, (uint32_t __user *)ptr)) 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)]++; proc->stats.bc[_IOC_NR(cmd)]++; @@ -1765,18 +1764,14 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, ref = binder_get_ref_for_node(proc, binder_context_mgr_node); if (ref->desc != target) { - binder_user_error("binder: %d:" - "%d tried to acquire " - "reference to desc 0, " - "got %d instead\n", + binder_user_error("%d:%d tried to acquire reference to desc 0, got %d instead\n", proc->pid, thread->pid, ref->desc); } } else ref = binder_get_ref(proc, target); if (ref == NULL) { - binder_user_error("binder: %d:%d refcou" - "nt change on invalid ref %d\n", + binder_user_error("%d:%d refcount change on invalid ref %d\n", proc->pid, thread->pid, target); break; } @@ -1799,49 +1794,46 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, binder_dec_ref(ref, 0); break; } - if (binder_debug_mask & BINDER_DEBUG_USER_REFS) - printk(KERN_INFO "binder: %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); + 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); break; } case BC_INCREFS_DONE: case BC_ACQUIRE_DONE: { - void __user *node_ptr; - void *cookie; + binder_uintptr_t node_ptr; + binder_uintptr_t cookie; struct binder_node *node; - if (get_user(node_ptr, (void * __user *)ptr)) + if (get_user(node_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); - if (get_user(cookie, (void * __user *)ptr)) + ptr += sizeof(binder_uintptr_t); + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); node = binder_get_node(proc, node_ptr); if (node == NULL) { - binder_user_error("binder: %d:%d " - "%s u%p no match\n", + binder_user_error("%d:%d %s u%016llx no match\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", - node_ptr); + (u64)node_ptr); break; } if (cookie != node->cookie) { - binder_user_error("binder: %d:%d %s u%p node %d" - " cookie mismatch %p != %p\n", + binder_user_error("%d:%d %s u%016llx node %d cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", - node_ptr, node->debug_id, - cookie, node->cookie); + (u64)node_ptr, node->debug_id, + (u64)cookie, (u64)node->cookie); break; } if (cmd == BC_ACQUIRE_DONE) { if (node->pending_strong_ref == 0) { - binder_user_error("binder: %d:%d " - "BC_ACQUIRE_DONE node %d has " - "no pending acquire request\n", + binder_user_error("%d:%d BC_ACQUIRE_DONE node %d has no pending acquire request\n", proc->pid, thread->pid, node->debug_id); break; @@ -1849,9 +1841,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, node->pending_strong_ref = 0; } else { if (node->pending_weak_ref == 0) { - binder_user_error("binder: %d:%d " - "BC_INCREFS_DONE node %d has " - "no pending increfs request\n", + binder_user_error("%d:%d BC_INCREFS_DONE node %d has no pending increfs request\n", proc->pid, thread->pid, node->debug_id); break; @@ -1859,44 +1849,44 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, node->pending_weak_ref = 0; } binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0); - if (binder_debug_mask & BINDER_DEBUG_USER_REFS) - printk(KERN_INFO "binder: %d:%d %s node %d ls %d lw %d\n", - proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", node->debug_id, node->local_strong_refs, node->local_weak_refs); + binder_debug(BINDER_DEBUG_USER_REFS, + "%d:%d %s node %d ls %d lw %d\n", + proc->pid, thread->pid, + cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", + node->debug_id, node->local_strong_refs, node->local_weak_refs); break; } case BC_ATTEMPT_ACQUIRE: - printk(KERN_ERR "binder: BC_ATTEMPT_ACQUIRE not supported\n"); + pr_err("BC_ATTEMPT_ACQUIRE not supported\n"); return -EINVAL; case BC_ACQUIRE_RESULT: - printk(KERN_ERR "binder: BC_ACQUIRE_RESULT not supported\n"); + pr_err("BC_ACQUIRE_RESULT not supported\n"); return -EINVAL; case BC_FREE_BUFFER: { - void __user *data_ptr; + binder_uintptr_t data_ptr; struct binder_buffer *buffer; - if (get_user(data_ptr, (void * __user *)ptr)) + if (get_user(data_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); buffer = binder_buffer_lookup(proc, data_ptr); if (buffer == NULL) { - binder_user_error("binder: %d:%d " - "BC_FREE_BUFFER u%p no match\n", - proc->pid, thread->pid, data_ptr); + binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", + proc->pid, thread->pid, (u64)data_ptr); break; } if (!buffer->allow_user_free) { - binder_user_error("binder: %d:%d " - "BC_FREE_BUFFER u%p matched " - "unreturned buffer\n", - proc->pid, thread->pid, data_ptr); + binder_user_error("%d:%d BC_FREE_BUFFER u%016llx matched unreturned buffer\n", + proc->pid, thread->pid, (u64)data_ptr); break; } - if (binder_debug_mask & BINDER_DEBUG_FREE_BUFFER) - printk(KERN_INFO "binder: %d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n", - proc->pid, thread->pid, data_ptr, buffer->debug_id, - buffer->transaction ? "active" : "finished"); + binder_debug(BINDER_DEBUG_FREE_BUFFER, + "%d:%d BC_FREE_BUFFER u%016llx found buffer %d for %s transaction\n", + proc->pid, thread->pid, (u64)data_ptr, + buffer->debug_id, + buffer->transaction ? "active" : "finished"); if (buffer->transaction) { buffer->transaction->buffer = NULL; @@ -1909,6 +1899,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, else list_move_tail(buffer->target_node->async_todo.next, &thread->todo); } + trace_binder_transaction_buffer_release(buffer); binder_transaction_buffer_release(proc, buffer, NULL); binder_free_buf(proc, buffer); break; @@ -1926,20 +1917,16 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, } case BC_REGISTER_LOOPER: - if (binder_debug_mask & BINDER_DEBUG_THREADS) - printk(KERN_INFO "binder: %d:%d BC_REGISTER_LOOPER\n", - proc->pid, thread->pid); + binder_debug(BINDER_DEBUG_THREADS, + "%d:%d BC_REGISTER_LOOPER\n", + proc->pid, thread->pid); if (thread->looper & BINDER_LOOPER_STATE_ENTERED) { thread->looper |= BINDER_LOOPER_STATE_INVALID; - binder_user_error("binder: %d:%d ERROR:" - " BC_REGISTER_LOOPER called " - "after BC_ENTER_LOOPER\n", + binder_user_error("%d:%d ERROR: BC_REGISTER_LOOPER called after BC_ENTER_LOOPER\n", proc->pid, thread->pid); } else if (proc->requested_threads == 0) { thread->looper |= BINDER_LOOPER_STATE_INVALID; - binder_user_error("binder: %d:%d ERROR:" - " BC_REGISTER_LOOPER called " - "without request\n", + binder_user_error("%d:%d ERROR: BC_REGISTER_LOOPER called without request\n", proc->pid, thread->pid); } else { proc->requested_threads--; @@ -1948,42 +1935,39 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, thread->looper |= BINDER_LOOPER_STATE_REGISTERED; break; case BC_ENTER_LOOPER: - if (binder_debug_mask & BINDER_DEBUG_THREADS) - printk(KERN_INFO "binder: %d:%d BC_ENTER_LOOPER\n", - proc->pid, thread->pid); + binder_debug(BINDER_DEBUG_THREADS, + "%d:%d BC_ENTER_LOOPER\n", + proc->pid, thread->pid); if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) { thread->looper |= BINDER_LOOPER_STATE_INVALID; - binder_user_error("binder: %d:%d ERROR:" - " BC_ENTER_LOOPER called after " - "BC_REGISTER_LOOPER\n", + binder_user_error("%d:%d ERROR: BC_ENTER_LOOPER called after BC_REGISTER_LOOPER\n", proc->pid, thread->pid); } thread->looper |= BINDER_LOOPER_STATE_ENTERED; break; case BC_EXIT_LOOPER: - if (binder_debug_mask & BINDER_DEBUG_THREADS) - printk(KERN_INFO "binder: %d:%d BC_EXIT_LOOPER\n", - proc->pid, thread->pid); + binder_debug(BINDER_DEBUG_THREADS, + "%d:%d BC_EXIT_LOOPER\n", + proc->pid, thread->pid); thread->looper |= BINDER_LOOPER_STATE_EXITED; break; case BC_REQUEST_DEATH_NOTIFICATION: case BC_CLEAR_DEATH_NOTIFICATION: { uint32_t target; - void __user *cookie; + binder_uintptr_t cookie; struct binder_ref *ref; struct binder_ref_death *death; if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (get_user(cookie, (void __user * __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); ref = binder_get_ref(proc, target); if (ref == NULL) { - binder_user_error("binder: %d:%d %s " - "invalid ref %d\n", + binder_user_error("%d:%d %s invalid ref %d\n", proc->pid, thread->pid, cmd == BC_REQUEST_DEATH_NOTIFICATION ? "BC_REQUEST_DEATH_NOTIFICATION" : @@ -1992,34 +1976,30 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, break; } - if (binder_debug_mask & BINDER_DEBUG_DEATH_NOTIFICATION) - printk(KERN_INFO "binder: %d:%d %s %p ref %d desc %d s %d w %d for node %d\n", - proc->pid, thread->pid, - cmd == BC_REQUEST_DEATH_NOTIFICATION ? - "BC_REQUEST_DEATH_NOTIFICATION" : - "BC_CLEAR_DEATH_NOTIFICATION", - cookie, ref->debug_id, ref->desc, - ref->strong, ref->weak, ref->node->debug_id); + binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, + "%d:%d %s %016llx ref %d desc %d s %d w %d for node %d\n", + proc->pid, thread->pid, + 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); if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { if (ref->death) { - binder_user_error("binder: %d:%" - "d BC_REQUEST_DEATH_NOTI" - "FICATION death notific" - "ation already set\n", + binder_user_error("%d:%d BC_REQUEST_DEATH_NOTIFICATION death notification already set\n", proc->pid, thread->pid); break; } death = kzalloc(sizeof(*death), GFP_KERNEL); if (death == NULL) { thread->return_error = BR_ERROR; - if (binder_debug_mask & BINDER_DEBUG_FAILED_TRANSACTION) - printk(KERN_INFO "binder: %d:%d " - "BC_REQUEST_DEATH_NOTIFICATION failed\n", - proc->pid, thread->pid); + binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, + "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", + proc->pid, thread->pid); break; } - binder_stats.obj_created[BINDER_STAT_DEATH]++; + binder_stats_created(BINDER_STAT_DEATH); INIT_LIST_HEAD(&death->work.entry); death->cookie = cookie; ref->death = death; @@ -2034,22 +2014,16 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, } } else { if (ref->death == NULL) { - binder_user_error("binder: %d:%" - "d BC_CLEAR_DEATH_NOTIFI" - "CATION death notificat" - "ion not active\n", + binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification not active\n", proc->pid, thread->pid); break; } death = ref->death; if (death->cookie != cookie) { - binder_user_error("binder: %d:%" - "d BC_CLEAR_DEATH_NOTIFI" - "CATION death notificat" - "ion cookie mismatch " - "%p != %p\n", + binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, - death->cookie, cookie); + (u64)death->cookie, + (u64)cookie); break; } ref->death = NULL; @@ -2069,26 +2043,28 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, } break; case BC_DEAD_BINDER_DONE: { struct binder_work *w; - void __user *cookie; + binder_uintptr_t cookie; struct binder_ref_death *death = NULL; - if (get_user(cookie, (void __user * __user *)ptr)) + + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(void *); list_for_each_entry(w, &proc->delivered_death, entry) { struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work); + if (tmp_death->cookie == cookie) { death = tmp_death; break; } } - if (binder_debug_mask & BINDER_DEBUG_DEAD_BINDER) - printk(KERN_INFO "binder: %d:%d BC_DEAD_BINDER_DONE %p found %p\n", - proc->pid, thread->pid, cookie, death); + binder_debug(BINDER_DEBUG_DEAD_BINDER, + "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n", + proc->pid, thread->pid, (u64)cookie, + death); if (death == NULL) { - binder_user_error("binder: %d:%d BC_DEAD" - "_BINDER_DONE %p not found\n", - proc->pid, thread->pid, cookie); + binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n", + proc->pid, thread->pid, (u64)cookie); break; } @@ -2105,7 +2081,7 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, } break; default: - printk(KERN_ERR "binder: %d:%d unknown command %d\n", + pr_err("%d:%d unknown command %d\n", proc->pid, thread->pid, cmd); return -EINVAL; } @@ -2114,9 +2090,10 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, return 0; } -void binder_stat_br(struct binder_proc *proc, struct binder_thread *thread, - uint32_t cmd) +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)]++; proc->stats.br[_IOC_NR(cmd)]++; @@ -2139,9 +2116,10 @@ static int binder_has_thread_work(struct binder_thread *thread) static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, - void __user *buffer, int size, - signed long *consumed, int non_block) + binder_uintptr_t binder_buffer, size_t size, + binder_size_t *consumed, int non_block) { + void __user *buffer = (void __user *)(uintptr_t)binder_buffer; void __user *ptr = buffer + *consumed; void __user *end = buffer + size; @@ -2163,6 +2141,7 @@ retry: if (put_user(thread->return_error2, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); + binder_stat_br(proc, thread, thread->return_error2); if (ptr == end) goto done; thread->return_error2 = BR_OK; @@ -2170,6 +2149,7 @@ retry: if (put_user(thread->return_error, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); + binder_stat_br(proc, thread, thread->return_error); thread->return_error = BR_OK; goto done; } @@ -2178,13 +2158,16 @@ retry: thread->looper |= BINDER_LOOPER_STATE_WAITING; if (wait_for_proc_work) proc->ready_threads++; - mutex_unlock(&binder_lock); + + binder_unlock(__func__); + + trace_binder_wait_for_work(wait_for_proc_work, + !!thread->transaction_stack, + !list_empty(&thread->todo)); if (wait_for_proc_work) { if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED))) { - binder_user_error("binder: %d:%d ERROR: Thread waiting " - "for process work before calling BC_REGISTER_" - "LOOPER or BC_ENTER_LOOPER (state %x)\n", + binder_user_error("%d:%d ERROR: Thread waiting for process work before calling BC_REGISTER_LOOPER or BC_ENTER_LOOPER (state %x)\n", proc->pid, thread->pid, thread->looper); wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); @@ -2194,15 +2177,17 @@ retry: if (!binder_has_proc_work(proc, thread)) ret = -EAGAIN; } else - ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread)); + ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread)); } else { if (non_block) { if (!binder_has_thread_work(thread)) ret = -EAGAIN; } else - ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread)); + ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread)); } - mutex_lock(&binder_lock); + + binder_lock(__func__); + if (wait_for_proc_work) proc->ready_threads--; thread->looper &= ~BINDER_LOOPER_STATE_WAITING; @@ -2240,13 +2225,13 @@ retry: ptr += sizeof(uint32_t); binder_stat_br(proc, thread, cmd); - if (binder_debug_mask & BINDER_DEBUG_TRANSACTION_COMPLETE) - printk(KERN_INFO "binder: %d:%d BR_TRANSACTION_COMPLETE\n", - proc->pid, thread->pid); + binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE, + "%d:%d BR_TRANSACTION_COMPLETE\n", + proc->pid, thread->pid); list_del(&w->entry); kfree(w); - binder_stats.obj_deleted[BINDER_STAT_TRANSACTION_COMPLETE]++; + binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); } break; case BINDER_WORK_NODE: { struct binder_node *node = container_of(w, struct binder_node, work); @@ -2254,6 +2239,7 @@ retry: const char *cmd_name; int strong = node->internal_strong_refs || node->local_strong_refs; int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong; + if (weak && !node->has_weak_ref) { cmd = BR_INCREFS; cmd_name = "BR_INCREFS"; @@ -2279,30 +2265,40 @@ retry: if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (put_user(node->ptr, (void * __user *)ptr)) + if (put_user(node->ptr, + (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); - if (put_user(node->cookie, (void * __user *)ptr)) + ptr += sizeof(binder_uintptr_t); + if (put_user(node->cookie, + (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); binder_stat_br(proc, thread, cmd); - if (binder_debug_mask & BINDER_DEBUG_USER_REFS) - printk(KERN_INFO "binder: %d:%d %s %d u%p c%p\n", - proc->pid, thread->pid, cmd_name, node->debug_id, node->ptr, node->cookie); + binder_debug(BINDER_DEBUG_USER_REFS, + "%d:%d %s %d u%016llx c%016llx\n", + proc->pid, thread->pid, cmd_name, + node->debug_id, + (u64)node->ptr, (u64)node->cookie); } else { list_del_init(&w->entry); if (!weak && !strong) { - if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS) - printk(KERN_INFO "binder: %d:%d node %d u%p c%p deleted\n", - proc->pid, thread->pid, node->debug_id, node->ptr, node->cookie); + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d:%d node %d u%016llx c%016llx deleted\n", + proc->pid, thread->pid, + node->debug_id, + (u64)node->ptr, + (u64)node->cookie); rb_erase(&node->rb_node, &proc->nodes); kfree(node); - binder_stats.obj_deleted[BINDER_STAT_NODE]++; + binder_stats_deleted(BINDER_STAT_NODE); } else { - if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS) - printk(KERN_INFO "binder: %d:%d node %d u%p c%p state unchanged\n", - proc->pid, thread->pid, node->debug_id, node->ptr, node->cookie); + binder_debug(BINDER_DEBUG_INTERNAL_REFS, + "%d:%d node %d u%016llx c%016llx state unchanged\n", + proc->pid, thread->pid, + node->debug_id, + (u64)node->ptr, + (u64)node->cookie); } } } break; @@ -2320,21 +2316,23 @@ retry: if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (put_user(death->cookie, (void * __user *)ptr)) + if (put_user(death->cookie, + (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); - if (binder_debug_mask & BINDER_DEBUG_DEATH_NOTIFICATION) - printk(KERN_INFO "binder: %d:%d %s %p\n", - proc->pid, thread->pid, - cmd == BR_DEAD_BINDER ? - "BR_DEAD_BINDER" : - "BR_CLEAR_DEATH_NOTIFICATION_DONE", - death->cookie); + ptr += sizeof(binder_uintptr_t); + binder_stat_br(proc, thread, cmd); + binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, + "%d:%d %s %016llx\n", + proc->pid, thread->pid, + cmd == BR_DEAD_BINDER ? + "BR_DEAD_BINDER" : + "BR_CLEAR_DEATH_NOTIFICATION_DONE", + (u64)death->cookie); if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { list_del(&w->entry); kfree(death); - binder_stats.obj_deleted[BINDER_STAT_DEATH]++; + binder_stats_deleted(BINDER_STAT_DEATH); } else list_move(&w->entry, &proc->delivered_death); if (cmd == BR_DEAD_BINDER) @@ -2348,6 +2346,7 @@ retry: BUG_ON(t->buffer == NULL); if (t->buffer->target_node) { struct binder_node *target_node = t->buffer->target_node; + tr.target.ptr = target_node->ptr; tr.cookie = target_node->cookie; t->saved_priority = task_nice(current); @@ -2359,26 +2358,28 @@ retry: binder_set_nice(target_node->min_priority); cmd = BR_TRANSACTION; } else { - tr.target.ptr = NULL; - tr.cookie = NULL; + tr.target.ptr = 0; + tr.cookie = 0; cmd = BR_REPLY; } tr.code = t->code; tr.flags = t->flags; - tr.sender_euid = t->sender_euid; + tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid); if (t->from) { struct task_struct *sender = t->from->proc->tsk; + tr.sender_pid = task_tgid_nr_ns(sender, - current->nsproxy->pid_ns); + task_active_pid_ns(current)); } else { tr.sender_pid = 0; } tr.data_size = t->buffer->data_size; tr.offsets_size = t->buffer->offsets_size; - tr.data.ptr.buffer = (void *)t->buffer->data + - proc->user_buffer_offset; + tr.data.ptr.buffer = (binder_uintptr_t)( + (uintptr_t)t->buffer->data + + proc->user_buffer_offset); tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); @@ -2390,17 +2391,17 @@ retry: return -EFAULT; ptr += sizeof(tr); + trace_binder_transaction_received(t); binder_stat_br(proc, thread, cmd); - if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) - printk(KERN_INFO "binder: %d:%d %s %d %d:%d, cmd %d" - "size %zd-%zd ptr %p-%p\n", - proc->pid, thread->pid, - (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : - "BR_REPLY", - t->debug_id, t->from ? t->from->proc->pid : 0, - t->from ? t->from->pid : 0, cmd, - t->buffer->data_size, t->buffer->offsets_size, - tr.data.ptr.buffer, tr.data.ptr.offsets); + binder_debug(BINDER_DEBUG_TRANSACTION, + "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n", + proc->pid, thread->pid, + (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : + "BR_REPLY", + t->debug_id, t->from ? t->from->proc->pid : 0, + t->from ? t->from->pid : 0, cmd, + t->buffer->data_size, t->buffer->offsets_size, + (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets); list_del(&t->work.entry); t->buffer->allow_user_free = 1; @@ -2411,7 +2412,7 @@ retry: } else { t->buffer->transaction = NULL; kfree(t); - binder_stats.obj_deleted[BINDER_STAT_TRANSACTION]++; + binder_stats_deleted(BINDER_STAT_TRANSACTION); } break; } @@ -2425,11 +2426,12 @@ done: BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */ /*spawn a new thread if we leave this out */) { proc->requested_threads++; - if (binder_debug_mask & BINDER_DEBUG_THREADS) - printk(KERN_INFO "binder: %d:%d BR_SPAWN_LOOPER\n", - proc->pid, thread->pid); + binder_debug(BINDER_DEBUG_THREADS, + "%d:%d BR_SPAWN_LOOPER\n", + proc->pid, thread->pid); if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer)) return -EFAULT; + binder_stat_br(proc, thread, BR_SPAWN_LOOPER); } return 0; } @@ -2437,6 +2439,7 @@ done: static void binder_release_work(struct list_head *list) { struct binder_work *w; + while (!list_empty(list)) { w = list_first_entry(list, struct binder_work, entry); list_del_init(&w->entry); @@ -2445,14 +2448,38 @@ static void binder_release_work(struct list_head *list) struct binder_transaction *t; t = container_of(w, struct binder_transaction, work); - if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) + if (t->buffer->target_node && + !(t->flags & TF_ONE_WAY)) { binder_send_failed_reply(t, BR_DEAD_REPLY); + } else { + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "undelivered transaction %d\n", + t->debug_id); + t->buffer->transaction = NULL; + kfree(t); + binder_stats_deleted(BINDER_STAT_TRANSACTION); + } } break; case BINDER_WORK_TRANSACTION_COMPLETE: { + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "undelivered TRANSACTION_COMPLETE\n"); kfree(w); - binder_stats.obj_deleted[BINDER_STAT_TRANSACTION_COMPLETE]++; + binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); + } break; + case BINDER_WORK_DEAD_BINDER_AND_CLEAR: + case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: { + struct binder_ref_death *death; + + death = container_of(w, struct binder_ref_death, work); + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "undelivered death notification, %016llx\n", + (u64)death->cookie); + kfree(death); + binder_stats_deleted(BINDER_STAT_DEATH); } break; default: + pr_err("unexpected work type, %d, not freed\n", + w->type); break; } } @@ -2480,7 +2507,7 @@ static struct binder_thread *binder_get_thread(struct binder_proc *proc) thread = kzalloc(sizeof(*thread), GFP_KERNEL); if (thread == NULL) return NULL; - binder_stats.obj_created[BINDER_STAT_THREAD]++; + binder_stats_created(BINDER_STAT_THREAD); thread->proc = proc; thread->pid = current->pid; init_waitqueue_head(&thread->wait); @@ -2507,11 +2534,12 @@ static int binder_free_thread(struct binder_proc *proc, send_reply = t; while (t) { active_transactions++; - if (binder_debug_mask & BINDER_DEBUG_DEAD_TRANSACTION) - printk(KERN_INFO "binder: release %d:%d transaction %d " - "%s, still active\n", proc->pid, thread->pid, - t->debug_id, - (t->to_thread == thread) ? "in" : "out"); + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "release %d:%d transaction %d %s, still active\n", + proc->pid, thread->pid, + t->debug_id, + (t->to_thread == thread) ? "in" : "out"); + if (t->to_thread == thread) { t->to_proc = NULL; t->to_thread = NULL; @@ -2530,7 +2558,7 @@ static int binder_free_thread(struct binder_proc *proc, binder_send_failed_reply(send_reply, BR_DEAD_REPLY); binder_release_work(&thread->todo); kfree(thread); - binder_stats.obj_deleted[BINDER_STAT_THREAD]++; + binder_stats_deleted(BINDER_STAT_THREAD); return active_transactions; } @@ -2541,12 +2569,14 @@ static unsigned int binder_poll(struct file *filp, struct binder_thread *thread = NULL; int wait_for_proc_work; - mutex_lock(&binder_lock); + binder_lock(__func__); + thread = binder_get_thread(proc); wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo) && thread->return_error == BR_OK; - mutex_unlock(&binder_lock); + + binder_unlock(__func__); if (wait_for_proc_work) { if (binder_has_proc_work(proc, thread)) @@ -2571,14 +2601,17 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct binder_thread *thread; unsigned int size = _IOC_SIZE(cmd); void __user *ubuf = (void __user *)arg; + kuid_t curr_euid = current_euid(); - /*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/ + /*pr_info("binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/ + + trace_binder_ioctl(cmd, arg); ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret) - return ret; + goto err_unlocked; - mutex_lock(&binder_lock); + binder_lock(__func__); thread = binder_get_thread(proc); if (thread == NULL) { ret = -ENOMEM; @@ -2588,6 +2621,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) switch (cmd) { case BINDER_WRITE_READ: { struct binder_write_read bwr; + if (size != sizeof(struct binder_write_read)) { ret = -EINVAL; goto err; @@ -2596,11 +2630,18 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = -EFAULT; goto err; } - if (binder_debug_mask & BINDER_DEBUG_READ_WRITE) - printk(KERN_INFO "binder: %d:%d write %ld at %08lx, read %ld at %08lx\n", - proc->pid, thread->pid, bwr.write_size, bwr.write_buffer, bwr.read_size, bwr.read_buffer); + binder_debug(BINDER_DEBUG_READ_WRITE, + "%d:%d write %lld at %016llx, read %lld at %016llx\n", + proc->pid, thread->pid, + (u64)bwr.write_size, (u64)bwr.write_buffer, + (u64)bwr.read_size, (u64)bwr.read_buffer); + if (bwr.write_size > 0) { - ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed); + ret = binder_thread_write(proc, thread, + bwr.write_buffer, + bwr.write_size, + &bwr.write_consumed); + trace_binder_write_done(ret); if (ret < 0) { bwr.read_consumed = 0; if (copy_to_user(ubuf, &bwr, sizeof(bwr))) @@ -2609,7 +2650,11 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } if (bwr.read_size > 0) { - ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); + ret = binder_thread_read(proc, thread, bwr.read_buffer, + bwr.read_size, + &bwr.read_consumed, + filp->f_flags & O_NONBLOCK); + trace_binder_read_done(ret); if (!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait); if (ret < 0) { @@ -2618,9 +2663,11 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) goto err; } } - if (binder_debug_mask & BINDER_DEBUG_READ_WRITE) - printk(KERN_INFO "binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n", - proc->pid, thread->pid, bwr.write_consumed, bwr.write_size, bwr.read_consumed, bwr.read_size); + binder_debug(BINDER_DEBUG_READ_WRITE, + "%d:%d wrote %lld of %lld, read return %lld of %lld\n", + proc->pid, thread->pid, + (u64)bwr.write_consumed, (u64)bwr.write_size, + (u64)bwr.read_consumed, (u64)bwr.read_size); if (copy_to_user(ubuf, &bwr, sizeof(bwr))) { ret = -EFAULT; goto err; @@ -2635,22 +2682,22 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; case BINDER_SET_CONTEXT_MGR: if (binder_context_mgr_node != NULL) { - printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n"); + pr_err("BINDER_SET_CONTEXT_MGR already set\n"); ret = -EBUSY; goto err; } - if (binder_context_mgr_uid != -1) { - if (binder_context_mgr_uid != current->cred->euid) { - printk(KERN_ERR "binder: BINDER_SET_" - "CONTEXT_MGR bad uid %d != %d\n", - current->cred->euid, - binder_context_mgr_uid); + if (uid_valid(binder_context_mgr_uid)) { + if (!uid_eq(binder_context_mgr_uid, curr_euid)) { + pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n", + from_kuid(&init_user_ns, curr_euid), + from_kuid(&init_user_ns, binder_context_mgr_uid)); ret = -EPERM; goto err; } - } else - binder_context_mgr_uid = current->cred->euid; - binder_context_mgr_node = binder_new_node(proc, NULL, NULL); + } else { + binder_context_mgr_uid = curr_euid; + } + binder_context_mgr_node = binder_new_node(proc, 0, 0); if (binder_context_mgr_node == NULL) { ret = -ENOMEM; goto err; @@ -2661,22 +2708,25 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) binder_context_mgr_node->has_weak_ref = 1; break; case BINDER_THREAD_EXIT: - if (binder_debug_mask & BINDER_DEBUG_THREADS) - printk(KERN_INFO "binder: %d:%d exit\n", - proc->pid, thread->pid); + binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n", + proc->pid, thread->pid); binder_free_thread(proc, thread); thread = NULL; break; - case BINDER_VERSION: + case BINDER_VERSION: { + struct binder_version __user *ver = ubuf; + if (size != sizeof(struct binder_version)) { ret = -EINVAL; goto err; } - if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, &((struct binder_version *)ubuf)->protocol_version)) { + if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, + &ver->protocol_version)) { ret = -EINVAL; goto err; } break; + } default: ret = -EINVAL; goto err; @@ -2685,35 +2735,37 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) err: if (thread) thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN; - mutex_unlock(&binder_lock); + binder_unlock(__func__); wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret && ret != -ERESTARTSYS) - printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); + pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); +err_unlocked: + trace_binder_ioctl_done(ret); return ret; } static void binder_vma_open(struct vm_area_struct *vma) { struct binder_proc *proc = vma->vm_private_data; - if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) - printk(KERN_INFO - "binder: %d open vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", - proc->pid, vma->vm_start, vma->vm_end, - (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, - (unsigned long)pgprot_val(vma->vm_page_prot)); - dump_stack(); + + binder_debug(BINDER_DEBUG_OPEN_CLOSE, + "%d open vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", + proc->pid, vma->vm_start, vma->vm_end, + (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, + (unsigned long)pgprot_val(vma->vm_page_prot)); } static void binder_vma_close(struct vm_area_struct *vma) { struct binder_proc *proc = vma->vm_private_data; - if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) - printk(KERN_INFO - "binder: %d close vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", - proc->pid, vma->vm_start, vma->vm_end, - (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, - (unsigned long)pgprot_val(vma->vm_page_prot)); + + binder_debug(BINDER_DEBUG_OPEN_CLOSE, + "%d close vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", + proc->pid, vma->vm_start, vma->vm_end, + (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, + (unsigned long)pgprot_val(vma->vm_page_prot)); proc->vma = NULL; + proc->vma_vm_mm = NULL; binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); } @@ -2730,15 +2782,17 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) const char *failure_string; struct binder_buffer *buffer; + if (proc->tsk != current) + return -EINVAL; + if ((vma->vm_end - vma->vm_start) > SZ_4M) vma->vm_end = vma->vm_start + SZ_4M; - if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) - printk(KERN_INFO - "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", - proc->pid, vma->vm_start, vma->vm_end, - (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, - (unsigned long)pgprot_val(vma->vm_page_prot)); + binder_debug(BINDER_DEBUG_OPEN_CLOSE, + "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", + proc->pid, vma->vm_start, vma->vm_end, + (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, + (unsigned long)pgprot_val(vma->vm_page_prot)); if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) { ret = -EPERM; @@ -2747,6 +2801,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); if (proc->buffer) { ret = -EBUSY; failure_string = "already mapped"; @@ -2761,11 +2816,12 @@ 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); #ifdef CONFIG_CPU_CACHE_VIPT if (cache_is_vipt_aliasing()) { while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) { - printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer); + pr_info("binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer); vma->vm_start += PAGE_SIZE; } } @@ -2795,8 +2851,9 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) barrier(); proc->files = get_files_struct(current); proc->vma = vma; + proc->vma_vm_mm = vma->vm_mm; - /*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n", + /*pr_info("binder_mmap: %d %lx-%lx maps %p\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ return 0; @@ -2804,12 +2861,14 @@ err_alloc_small_buf_failed: kfree(proc->pages); proc->pages = NULL; err_alloc_pages_failed: + mutex_lock(&binder_mmap_lock); vfree(proc->buffer); proc->buffer = NULL; err_get_vm_area_failed: err_already_mapped: + mutex_unlock(&binder_mmap_lock); err_bad_arg: - printk(KERN_ERR "binder_mmap: %d %lx-%lx %s failed %d\n", + pr_err("binder_mmap: %d %lx-%lx %s failed %d\n", proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); return ret; } @@ -2818,9 +2877,8 @@ static int binder_open(struct inode *nodp, struct file *filp) { struct binder_proc *proc; - if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) - printk(KERN_INFO "binder_open: %d:%d\n", - current->group_leader->pid, current->pid); + binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n", + current->group_leader->pid, current->pid); proc = kzalloc(sizeof(*proc), GFP_KERNEL); if (proc == NULL) @@ -2830,21 +2888,23 @@ static int binder_open(struct inode *nodp, struct file *filp) INIT_LIST_HEAD(&proc->todo); init_waitqueue_head(&proc->wait); proc->default_priority = task_nice(current); - mutex_lock(&binder_lock); - binder_stats.obj_created[BINDER_STAT_PROC]++; + + binder_lock(__func__); + + binder_stats_created(BINDER_STAT_PROC); hlist_add_head(&proc->proc_node, &binder_procs); proc->pid = current->group_leader->pid; INIT_LIST_HEAD(&proc->delivered_death); filp->private_data = proc; - mutex_unlock(&binder_lock); - if (binder_proc_dir_entry_proc) { + binder_unlock(__func__); + + if (binder_debugfs_dir_entry_proc) { char strbuf[11]; + snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); - remove_proc_entry(strbuf, binder_proc_dir_entry_proc); - create_proc_read_entry(strbuf, S_IRUGO, - binder_proc_dir_entry_proc, - binder_read_proc_proc, proc); + proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO, + binder_debugfs_dir_entry_proc, proc, &binder_proc_fops); } return 0; @@ -2863,8 +2923,10 @@ static void binder_deferred_flush(struct binder_proc *proc) { struct rb_node *n; int wake_count = 0; + for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); + thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; if (thread->looper & BINDER_LOOPER_STATE_WAITING) { wake_up_interruptible(&thread->wait); @@ -2873,129 +2935,155 @@ static void binder_deferred_flush(struct binder_proc *proc) } wake_up_interruptible_all(&proc->wait); - if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) - printk(KERN_INFO "binder_flush: %d woke %d threads\n", proc->pid, wake_count); + binder_debug(BINDER_DEBUG_OPEN_CLOSE, + "binder_flush: %d woke %d threads\n", proc->pid, + wake_count); } static int binder_release(struct inode *nodp, struct file *filp) { struct binder_proc *proc = filp->private_data; - if (binder_proc_dir_entry_proc) { - char strbuf[11]; - snprintf(strbuf, sizeof(strbuf), "%u", proc->pid); - remove_proc_entry(strbuf, binder_proc_dir_entry_proc); - } + debugfs_remove(proc->debugfs_entry); binder_defer_work(proc, BINDER_DEFERRED_RELEASE); return 0; } +static int binder_node_release(struct binder_node *node, int refs) +{ + struct binder_ref *ref; + int death = 0; + + list_del_init(&node->work.entry); + binder_release_work(&node->async_todo); + + if (hlist_empty(&node->refs)) { + kfree(node); + binder_stats_deleted(BINDER_STAT_NODE); + + return refs; + } + + node->proc = NULL; + node->local_strong_refs = 0; + node->local_weak_refs = 0; + hlist_add_head(&node->dead_node, &binder_dead_nodes); + + hlist_for_each_entry(ref, &node->refs, node_entry) { + refs++; + + if (!ref->death) + continue; + + death++; + + if (list_empty(&ref->death->work.entry)) { + ref->death->work.type = BINDER_WORK_DEAD_BINDER; + list_add_tail(&ref->death->work.entry, + &ref->proc->todo); + wake_up_interruptible(&ref->proc->wait); + } else + BUG(); + } + + binder_debug(BINDER_DEBUG_DEAD_BINDER, + "node %d now dead, refs %d, death %d\n", + node->debug_id, refs, death); + + return refs; +} + static void binder_deferred_release(struct binder_proc *proc) { - struct hlist_node *pos; struct binder_transaction *t; struct rb_node *n; - int threads, nodes, incoming_refs, outgoing_refs, buffers, active_transactions, page_count; + int threads, nodes, incoming_refs, outgoing_refs, buffers, + active_transactions, page_count; BUG_ON(proc->vma); BUG_ON(proc->files); hlist_del(&proc->proc_node); + if (binder_context_mgr_node && binder_context_mgr_node->proc == proc) { - if (binder_debug_mask & BINDER_DEBUG_DEAD_BINDER) - printk(KERN_INFO "binder_release: %d context_mgr_node gone\n", proc->pid); + binder_debug(BINDER_DEBUG_DEAD_BINDER, + "%s: %d context_mgr_node gone\n", + __func__, proc->pid); binder_context_mgr_node = NULL; } threads = 0; active_transactions = 0; while ((n = rb_first(&proc->threads))) { - struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); + struct binder_thread *thread; + + thread = rb_entry(n, struct binder_thread, rb_node); threads++; active_transactions += binder_free_thread(proc, thread); } + nodes = 0; incoming_refs = 0; while ((n = rb_first(&proc->nodes))) { - struct binder_node *node = rb_entry(n, struct binder_node, rb_node); + struct binder_node *node; + node = rb_entry(n, struct binder_node, rb_node); nodes++; rb_erase(&node->rb_node, &proc->nodes); - list_del_init(&node->work.entry); - if (hlist_empty(&node->refs)) { - kfree(node); - binder_stats.obj_deleted[BINDER_STAT_NODE]++; - } else { - struct binder_ref *ref; - int death = 0; - - node->proc = NULL; - node->local_strong_refs = 0; - node->local_weak_refs = 0; - hlist_add_head(&node->dead_node, &binder_dead_nodes); - - hlist_for_each_entry(ref, pos, &node->refs, node_entry) { - incoming_refs++; - if (ref->death) { - death++; - if (list_empty(&ref->death->work.entry)) { - ref->death->work.type = BINDER_WORK_DEAD_BINDER; - list_add_tail(&ref->death->work.entry, &ref->proc->todo); - wake_up_interruptible(&ref->proc->wait); - } else - BUG(); - } - } - if (binder_debug_mask & BINDER_DEBUG_DEAD_BINDER) - printk(KERN_INFO "binder: node %d now dead, " - "refs %d, death %d\n", node->debug_id, - incoming_refs, death); - } + incoming_refs = binder_node_release(node, incoming_refs); } + outgoing_refs = 0; while ((n = rb_first(&proc->refs_by_desc))) { - struct binder_ref *ref = rb_entry(n, struct binder_ref, - rb_node_desc); + struct binder_ref *ref; + + ref = rb_entry(n, struct binder_ref, rb_node_desc); outgoing_refs++; binder_delete_ref(ref); } + binder_release_work(&proc->todo); - buffers = 0; + binder_release_work(&proc->delivered_death); + buffers = 0; while ((n = rb_first(&proc->allocated_buffers))) { - struct binder_buffer *buffer = rb_entry(n, struct binder_buffer, - rb_node); + struct binder_buffer *buffer; + + buffer = rb_entry(n, struct binder_buffer, rb_node); + t = buffer->transaction; if (t) { t->buffer = NULL; buffer->transaction = NULL; - printk(KERN_ERR "binder: release proc %d, " - "transaction %d, not freed\n", + pr_err("release proc %d, transaction %d, not freed\n", proc->pid, t->debug_id); /*BUG();*/ } + binder_free_buf(proc, buffer); buffers++; } - binder_stats.obj_deleted[BINDER_STAT_PROC]++; + binder_stats_deleted(BINDER_STAT_PROC); page_count = 0; if (proc->pages) { int i; + for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) { - if (proc->pages[i]) { - if (binder_debug_mask & - BINDER_DEBUG_BUFFER_ALLOC) - printk(KERN_INFO - "binder_release: %d: " - "page %d at %p not freed\n", - proc->pid, i, - proc->buffer + i * PAGE_SIZE); - __free_page(proc->pages[i]); - page_count++; - } + void *page_addr; + + if (!proc->pages[i]) + continue; + + page_addr = proc->buffer + i * PAGE_SIZE; + binder_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%s: %d: page %d at %p not freed\n", + __func__, proc->pid, i, page_addr); + unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); + __free_page(proc->pages[i]); + page_count++; } kfree(proc->pages); vfree(proc->buffer); @@ -3003,13 +3091,10 @@ static void binder_deferred_release(struct binder_proc *proc) put_task_struct(proc->tsk); - if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) - printk(KERN_INFO - "binder_release: %d threads %d, nodes %d (ref %d), " - "refs %d, active transactions %d, buffers %d, " - "pages %d\n", - proc->pid, threads, nodes, incoming_refs, outgoing_refs, - active_transactions, buffers, page_count); + binder_debug(BINDER_DEBUG_OPEN_CLOSE, + "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d, buffers %d, pages %d\n", + __func__, proc->pid, threads, nodes, incoming_refs, + outgoing_refs, active_transactions, buffers, page_count); kfree(proc); } @@ -3020,8 +3105,9 @@ static void binder_deferred_func(struct work_struct *work) struct files_struct *files; int defer; + do { - mutex_lock(&binder_lock); + binder_lock(__func__); mutex_lock(&binder_deferred_lock); if (!hlist_empty(&binder_deferred_list)) { proc = hlist_entry(binder_deferred_list.first, @@ -3048,68 +3134,61 @@ static void binder_deferred_func(struct work_struct *work) if (defer & BINDER_DEFERRED_RELEASE) binder_deferred_release(proc); /* frees proc */ - mutex_unlock(&binder_lock); + binder_unlock(__func__); 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, int defer) +static void +binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer) { mutex_lock(&binder_deferred_lock); proc->deferred_work |= defer; if (hlist_unhashed(&proc->deferred_work_node)) { hlist_add_head(&proc->deferred_work_node, &binder_deferred_list); - schedule_work(&binder_deferred_work); + queue_work(binder_deferred_workqueue, &binder_deferred_work); } mutex_unlock(&binder_deferred_lock); } -static char *print_binder_transaction(char *buf, char *end, const char *prefix, - struct binder_transaction *t) -{ - buf += snprintf(buf, end - buf, - "%s %d: %p from %d:%d to %d:%d code %x " - "flags %x pri %ld r%d", - prefix, t->debug_id, t, - t->from ? t->from->proc->pid : 0, - t->from ? t->from->pid : 0, - t->to_proc ? t->to_proc->pid : 0, - t->to_thread ? t->to_thread->pid : 0, - t->code, t->flags, t->priority, t->need_reply); - if (buf >= end) - return buf; +static void print_binder_transaction(struct seq_file *m, const char *prefix, + struct binder_transaction *t) +{ + seq_printf(m, + "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d", + prefix, t->debug_id, t, + t->from ? t->from->proc->pid : 0, + t->from ? t->from->pid : 0, + t->to_proc ? t->to_proc->pid : 0, + t->to_thread ? t->to_thread->pid : 0, + t->code, t->flags, t->priority, t->need_reply); if (t->buffer == NULL) { - buf += snprintf(buf, end - buf, " buffer free\n"); - return buf; - } - if (t->buffer->target_node) { - buf += snprintf(buf, end - buf, " node %d", - t->buffer->target_node->debug_id); - if (buf >= end) - return buf; + seq_puts(m, " buffer free\n"); + return; } - buf += snprintf(buf, end - buf, " size %zd:%zd data %p\n", - t->buffer->data_size, t->buffer->offsets_size, - t->buffer->data); - return buf; + if (t->buffer->target_node) + seq_printf(m, " node %d", + t->buffer->target_node->debug_id); + seq_printf(m, " size %zd:%zd data %p\n", + t->buffer->data_size, t->buffer->offsets_size, + t->buffer->data); } -static char *print_binder_buffer(char *buf, char *end, const char *prefix, - struct binder_buffer *buffer) +static void print_binder_buffer(struct seq_file *m, const char *prefix, + struct binder_buffer *buffer) { - buf += snprintf(buf, end - buf, "%s %d: %p size %zd:%zd %s\n", - prefix, buffer->debug_id, buffer->data, - buffer->data_size, buffer->offsets_size, - buffer->transaction ? "active" : "delivered"); - return buf; + seq_printf(m, "%s %d: %p size %zd:%zd %s\n", + prefix, buffer->debug_id, buffer->data, + buffer->data_size, buffer->offsets_size, + buffer->transaction ? "active" : "delivered"); } -static char *print_binder_work(char *buf, char *end, const char *prefix, - const char *transaction_prefix, - struct binder_work *w) +static void print_binder_work(struct seq_file *m, const char *prefix, + const char *transaction_prefix, + struct binder_work *w) { struct binder_node *node; struct binder_transaction *t; @@ -3117,186 +3196,139 @@ static char *print_binder_work(char *buf, char *end, const char *prefix, switch (w->type) { case BINDER_WORK_TRANSACTION: t = container_of(w, struct binder_transaction, work); - buf = print_binder_transaction(buf, end, transaction_prefix, t); + print_binder_transaction(m, transaction_prefix, t); break; case BINDER_WORK_TRANSACTION_COMPLETE: - buf += snprintf(buf, end - buf, - "%stransaction complete\n", prefix); + seq_printf(m, "%stransaction complete\n", prefix); break; case BINDER_WORK_NODE: node = container_of(w, struct binder_node, work); - buf += snprintf(buf, end - buf, "%snode work %d: u%p c%p\n", - prefix, node->debug_id, node->ptr, - node->cookie); + seq_printf(m, "%snode work %d: u%016llx c%016llx\n", + prefix, node->debug_id, + (u64)node->ptr, (u64)node->cookie); break; case BINDER_WORK_DEAD_BINDER: - buf += snprintf(buf, end - buf, "%shas dead binder\n", prefix); + seq_printf(m, "%shas dead binder\n", prefix); break; case BINDER_WORK_DEAD_BINDER_AND_CLEAR: - buf += snprintf(buf, end - buf, - "%shas cleared dead binder\n", prefix); + seq_printf(m, "%shas cleared dead binder\n", prefix); break; case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: - buf += snprintf(buf, end - buf, - "%shas cleared death notification\n", prefix); + seq_printf(m, "%shas cleared death notification\n", prefix); break; default: - buf += snprintf(buf, end - buf, "%sunknown work: type %d\n", - prefix, w->type); + seq_printf(m, "%sunknown work: type %d\n", prefix, w->type); break; } - return buf; } -static char *print_binder_thread(char *buf, char *end, - struct binder_thread *thread, - int print_always) +static void print_binder_thread(struct seq_file *m, + struct binder_thread *thread, + int print_always) { struct binder_transaction *t; struct binder_work *w; - char *start_buf = buf; - char *header_buf; + size_t start_pos = m->count; + size_t header_pos; - buf += snprintf(buf, end - buf, " thread %d: l %02x\n", - thread->pid, thread->looper); - header_buf = buf; + seq_printf(m, " thread %d: l %02x\n", thread->pid, thread->looper); + header_pos = m->count; t = thread->transaction_stack; while (t) { - if (buf >= end) - break; if (t->from == thread) { - buf = print_binder_transaction(buf, end, - " outgoing transaction", t); + print_binder_transaction(m, + " outgoing transaction", t); t = t->from_parent; } else if (t->to_thread == thread) { - buf = print_binder_transaction(buf, end, - " incoming transaction", t); + print_binder_transaction(m, + " incoming transaction", t); t = t->to_parent; } else { - buf = print_binder_transaction(buf, end, - " bad transaction", t); + print_binder_transaction(m, " bad transaction", t); t = NULL; } } list_for_each_entry(w, &thread->todo, entry) { - if (buf >= end) - break; - buf = print_binder_work(buf, end, " ", - " pending transaction", w); + print_binder_work(m, " ", " pending transaction", w); } - if (!print_always && buf == header_buf) - buf = start_buf; - return buf; + if (!print_always && m->count == header_pos) + m->count = start_pos; } -static char *print_binder_node(char *buf, char *end, struct binder_node *node) +static void print_binder_node(struct seq_file *m, struct binder_node *node) { struct binder_ref *ref; - struct hlist_node *pos; struct binder_work *w; int count; count = 0; - hlist_for_each_entry(ref, pos, &node->refs, node_entry) + hlist_for_each_entry(ref, &node->refs, node_entry) count++; - buf += snprintf(buf, end - buf, - " node %d: u%p c%p hs %d hw %d ls %d lw %d " - "is %d iw %d", - node->debug_id, node->ptr, node->cookie, - node->has_strong_ref, node->has_weak_ref, - node->local_strong_refs, node->local_weak_refs, - node->internal_strong_refs, count); - if (buf >= end) - return buf; + seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d", + node->debug_id, (u64)node->ptr, (u64)node->cookie, + node->has_strong_ref, node->has_weak_ref, + node->local_strong_refs, node->local_weak_refs, + node->internal_strong_refs, count); if (count) { - buf += snprintf(buf, end - buf, " proc"); - if (buf >= end) - return buf; - hlist_for_each_entry(ref, pos, &node->refs, node_entry) { - buf += snprintf(buf, end - buf, " %d", ref->proc->pid); - if (buf >= end) - return buf; - } - } - buf += snprintf(buf, end - buf, "\n"); - list_for_each_entry(w, &node->async_todo, entry) { - if (buf >= end) - break; - buf = print_binder_work(buf, end, " ", - " pending async transaction", w); + seq_puts(m, " proc"); + hlist_for_each_entry(ref, &node->refs, node_entry) + seq_printf(m, " %d", ref->proc->pid); } - return buf; + seq_puts(m, "\n"); + list_for_each_entry(w, &node->async_todo, entry) + print_binder_work(m, " ", + " pending async transaction", w); } -static char *print_binder_ref(char *buf, char *end, struct binder_ref *ref) +static void print_binder_ref(struct seq_file *m, struct binder_ref *ref) { - buf += snprintf(buf, end - buf, - " 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); - return buf; + 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); } -static char *print_binder_proc(char *buf, char *end, - struct binder_proc *proc, int print_all) +static void print_binder_proc(struct seq_file *m, + struct binder_proc *proc, int print_all) { struct binder_work *w; struct rb_node *n; - char *start_buf = buf; - char *header_buf; - - buf += snprintf(buf, end - buf, "proc %d\n", proc->pid); - header_buf = buf; - - for (n = rb_first(&proc->threads); - n != NULL && buf < end; - n = rb_next(n)) - buf = print_binder_thread(buf, end, - rb_entry(n, struct binder_thread, - rb_node), print_all); - for (n = rb_first(&proc->nodes); - n != NULL && buf < end; - n = rb_next(n)) { + size_t start_pos = m->count; + size_t header_pos; + + seq_printf(m, "proc %d\n", proc->pid); + header_pos = m->count; + + for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) + print_binder_thread(m, rb_entry(n, struct binder_thread, + rb_node), print_all); + for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { struct binder_node *node = rb_entry(n, struct binder_node, rb_node); if (print_all || node->has_async_transaction) - buf = print_binder_node(buf, end, node); + print_binder_node(m, node); } if (print_all) { for (n = rb_first(&proc->refs_by_desc); - n != NULL && buf < end; + n != NULL; n = rb_next(n)) - buf = print_binder_ref(buf, end, - rb_entry(n, struct binder_ref, - rb_node_desc)); - } - for (n = rb_first(&proc->allocated_buffers); - n != NULL && buf < end; - n = rb_next(n)) - buf = print_binder_buffer(buf, end, " buffer", - rb_entry(n, struct binder_buffer, - rb_node)); - list_for_each_entry(w, &proc->todo, entry) { - if (buf >= end) - break; - buf = print_binder_work(buf, end, " ", - " pending transaction", w); + print_binder_ref(m, rb_entry(n, struct binder_ref, + rb_node_desc)); } + for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) + print_binder_buffer(m, " buffer", + rb_entry(n, struct binder_buffer, rb_node)); + list_for_each_entry(w, &proc->todo, entry) + print_binder_work(m, " ", " pending transaction", w); list_for_each_entry(w, &proc->delivered_death, entry) { - if (buf >= end) - break; - buf += snprintf(buf, end - buf, - " has delivered dead binder\n"); + seq_puts(m, " has delivered dead binder\n"); break; } - if (!print_all && buf == header_buf) - buf = start_buf; - return buf; + if (!print_all && m->count == header_pos) + m->count = start_pos; } -static const char *binder_return_strings[] = { +static const char * const binder_return_strings[] = { "BR_ERROR", "BR_OK", "BR_TRANSACTION", @@ -3317,7 +3349,7 @@ static const char *binder_return_strings[] = { "BR_FAILED_REPLY" }; -static const char *binder_command_strings[] = { +static const char * const binder_command_strings[] = { "BC_TRANSACTION", "BC_REPLY", "BC_ACQUIRE_RESULT", @@ -3337,7 +3369,7 @@ static const char *binder_command_strings[] = { "BC_DEAD_BINDER_DONE" }; -static const char *binder_objstat_strings[] = { +static const char * const binder_objstat_strings[] = { "proc", "thread", "node", @@ -3347,79 +3379,61 @@ static const char *binder_objstat_strings[] = { "transaction_complete" }; -static char *print_binder_stats(char *buf, char *end, const char *prefix, - struct binder_stats *stats) +static void print_binder_stats(struct seq_file *m, const char *prefix, + struct binder_stats *stats) { int i; BUILD_BUG_ON(ARRAY_SIZE(stats->bc) != - ARRAY_SIZE(binder_command_strings)); + ARRAY_SIZE(binder_command_strings)); for (i = 0; i < ARRAY_SIZE(stats->bc); i++) { if (stats->bc[i]) - buf += snprintf(buf, end - buf, "%s%s: %d\n", prefix, - binder_command_strings[i], - stats->bc[i]); - if (buf >= end) - return buf; + seq_printf(m, "%s%s: %d\n", prefix, + binder_command_strings[i], stats->bc[i]); } BUILD_BUG_ON(ARRAY_SIZE(stats->br) != - ARRAY_SIZE(binder_return_strings)); + ARRAY_SIZE(binder_return_strings)); for (i = 0; i < ARRAY_SIZE(stats->br); i++) { if (stats->br[i]) - buf += snprintf(buf, end - buf, "%s%s: %d\n", prefix, - binder_return_strings[i], stats->br[i]); - if (buf >= end) - return buf; + seq_printf(m, "%s%s: %d\n", prefix, + binder_return_strings[i], stats->br[i]); } BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != - ARRAY_SIZE(binder_objstat_strings)); + ARRAY_SIZE(binder_objstat_strings)); BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) != - ARRAY_SIZE(stats->obj_deleted)); + ARRAY_SIZE(stats->obj_deleted)); for (i = 0; i < ARRAY_SIZE(stats->obj_created); i++) { if (stats->obj_created[i] || stats->obj_deleted[i]) - buf += snprintf(buf, end - buf, - "%s%s: active %d total %d\n", prefix, - binder_objstat_strings[i], - stats->obj_created[i] - - stats->obj_deleted[i], - stats->obj_created[i]); - if (buf >= end) - return buf; + 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]); } - return buf; } -static char *print_binder_proc_stats(char *buf, char *end, - struct binder_proc *proc) +static void print_binder_proc_stats(struct seq_file *m, + struct binder_proc *proc) { struct binder_work *w; struct rb_node *n; int count, strong, weak; - buf += snprintf(buf, end - buf, "proc %d\n", proc->pid); - if (buf >= end) - return buf; + seq_printf(m, "proc %d\n", proc->pid); count = 0; for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) count++; - buf += snprintf(buf, end - buf, " threads: %d\n", count); - if (buf >= end) - return buf; - buf += snprintf(buf, end - buf, " requested threads: %d+%d/%d\n" + seq_printf(m, " threads: %d\n", count); + seq_printf(m, " requested threads: %d+%d/%d\n" " ready threads %d\n" " free async space %zd\n", proc->requested_threads, proc->requested_threads_started, proc->max_threads, proc->ready_threads, proc->free_async_space); - if (buf >= end) - return buf; count = 0; for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) count++; - buf += snprintf(buf, end - buf, " nodes: %d\n", count); - if (buf >= end) - return buf; + seq_printf(m, " nodes: %d\n", count); count = 0; strong = 0; weak = 0; @@ -3430,17 +3444,12 @@ static char *print_binder_proc_stats(char *buf, char *end, strong += ref->strong; weak += ref->weak; } - buf += snprintf(buf, end - buf, " refs: %d s %d w %d\n", - count, strong, weak); - if (buf >= end) - return buf; + seq_printf(m, " refs: %d s %d w %d\n", count, strong, weak); count = 0; for (n = rb_first(&proc->allocated_buffers); n != NULL; n = rb_next(n)) count++; - buf += snprintf(buf, end - buf, " buffers: %d\n", count); - if (buf >= end) - return buf; + seq_printf(m, " buffers: %d\n", count); count = 0; list_for_each_entry(w, &proc->todo, entry) { @@ -3452,228 +3461,114 @@ static char *print_binder_proc_stats(char *buf, char *end, break; } } - buf += snprintf(buf, end - buf, " pending transactions: %d\n", count); - if (buf >= end) - return buf; + seq_printf(m, " pending transactions: %d\n", count); - buf = print_binder_stats(buf, end, " ", &proc->stats); - - return buf; + print_binder_stats(m, " ", &proc->stats); } -static int binder_read_proc_state(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int binder_state_show(struct seq_file *m, void *unused) { struct binder_proc *proc; - struct hlist_node *pos; struct binder_node *node; - int len = 0; - char *buf = page; - char *end = page + PAGE_SIZE; int do_lock = !binder_debug_no_lock; - if (off) - return 0; - if (do_lock) - mutex_lock(&binder_lock); + binder_lock(__func__); - buf += snprintf(buf, end - buf, "binder state:\n"); + seq_puts(m, "binder state:\n"); if (!hlist_empty(&binder_dead_nodes)) - buf += snprintf(buf, end - buf, "dead nodes:\n"); - hlist_for_each_entry(node, pos, &binder_dead_nodes, dead_node) { - if (buf >= end) - break; - buf = print_binder_node(buf, end, node); - } + 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(proc, pos, &binder_procs, proc_node) { - if (buf >= end) - break; - buf = print_binder_proc(buf, end, proc, 1); - } + hlist_for_each_entry(proc, &binder_procs, proc_node) + print_binder_proc(m, proc, 1); if (do_lock) - mutex_unlock(&binder_lock); - if (buf > page + PAGE_SIZE) - buf = page + PAGE_SIZE; - - *start = page + off; - - len = buf - page; - if (len > off) - len -= off; - else - len = 0; - - return len < count ? len : count; + binder_unlock(__func__); + return 0; } -static int binder_read_proc_stats(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int binder_stats_show(struct seq_file *m, void *unused) { struct binder_proc *proc; - struct hlist_node *pos; - int len = 0; - char *p = page; int do_lock = !binder_debug_no_lock; - if (off) - return 0; - if (do_lock) - mutex_lock(&binder_lock); + binder_lock(__func__); - p += snprintf(p, PAGE_SIZE, "binder stats:\n"); + seq_puts(m, "binder stats:\n"); - p = print_binder_stats(p, page + PAGE_SIZE, "", &binder_stats); + print_binder_stats(m, "", &binder_stats); - hlist_for_each_entry(proc, pos, &binder_procs, proc_node) { - if (p >= page + PAGE_SIZE) - break; - p = print_binder_proc_stats(p, page + PAGE_SIZE, proc); - } + hlist_for_each_entry(proc, &binder_procs, proc_node) + print_binder_proc_stats(m, proc); if (do_lock) - mutex_unlock(&binder_lock); - if (p > page + PAGE_SIZE) - p = page + PAGE_SIZE; - - *start = page + off; - - len = p - page; - if (len > off) - len -= off; - else - len = 0; - - return len < count ? len : count; + binder_unlock(__func__); + return 0; } -static int binder_read_proc_transactions(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int binder_transactions_show(struct seq_file *m, void *unused) { struct binder_proc *proc; - struct hlist_node *pos; - int len = 0; - char *buf = page; - char *end = page + PAGE_SIZE; int do_lock = !binder_debug_no_lock; - if (off) - return 0; - if (do_lock) - mutex_lock(&binder_lock); + binder_lock(__func__); - buf += snprintf(buf, end - buf, "binder transactions:\n"); - hlist_for_each_entry(proc, pos, &binder_procs, proc_node) { - if (buf >= end) - break; - buf = print_binder_proc(buf, end, proc, 0); - } + seq_puts(m, "binder transactions:\n"); + hlist_for_each_entry(proc, &binder_procs, proc_node) + print_binder_proc(m, proc, 0); if (do_lock) - mutex_unlock(&binder_lock); - if (buf > page + PAGE_SIZE) - buf = page + PAGE_SIZE; - - *start = page + off; - - len = buf - page; - if (len > off) - len -= off; - else - len = 0; - - return len < count ? len : count; + binder_unlock(__func__); + return 0; } -static int binder_read_proc_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int binder_proc_show(struct seq_file *m, void *unused) { - struct binder_proc *proc = data; - int len = 0; - char *p = page; + struct binder_proc *proc = m->private; int do_lock = !binder_debug_no_lock; - if (off) - return 0; - if (do_lock) - mutex_lock(&binder_lock); - p += snprintf(p, PAGE_SIZE, "binder proc state:\n"); - p = print_binder_proc(p, page + PAGE_SIZE, proc, 1); + binder_lock(__func__); + seq_puts(m, "binder proc state:\n"); + print_binder_proc(m, proc, 1); if (do_lock) - mutex_unlock(&binder_lock); - - if (p > page + PAGE_SIZE) - p = page + PAGE_SIZE; - *start = page + off; - - len = p - page; - if (len > off) - len -= off; - else - len = 0; - - return len < count ? len : count; + binder_unlock(__func__); + return 0; } -static char *print_binder_transaction_log_entry(char *buf, char *end, +static void print_binder_transaction_log_entry(struct seq_file *m, struct binder_transaction_log_entry *e) { - buf += snprintf(buf, end - buf, - "%d: %s from %d:%d to %d:%d node %d handle %d " - "size %d:%d\n", - e->debug_id, (e->call_type == 2) ? "reply" : - ((e->call_type == 1) ? "async" : "call "), e->from_proc, - e->from_thread, e->to_proc, e->to_thread, e->to_node, - e->target_handle, e->data_size, e->offsets_size); - return buf; + seq_printf(m, + "%d: %s from %d:%d to %d:%d node %d handle %d size %d:%d\n", + e->debug_id, (e->call_type == 2) ? "reply" : + ((e->call_type == 1) ? "async" : "call "), e->from_proc, + e->from_thread, e->to_proc, e->to_thread, e->to_node, + e->target_handle, e->data_size, e->offsets_size); } -static int binder_read_proc_transaction_log( - char *page, char **start, off_t off, int count, int *eof, void *data) +static int binder_transaction_log_show(struct seq_file *m, void *unused) { - struct binder_transaction_log *log = data; - int len = 0; + struct binder_transaction_log *log = m->private; int i; - char *buf = page; - char *end = page + PAGE_SIZE; - - if (off) - return 0; if (log->full) { - for (i = log->next; i < ARRAY_SIZE(log->entry); i++) { - if (buf >= end) - break; - buf = print_binder_transaction_log_entry(buf, end, - &log->entry[i]); - } + for (i = log->next; i < ARRAY_SIZE(log->entry); i++) + print_binder_transaction_log_entry(m, &log->entry[i]); } - for (i = 0; i < log->next; i++) { - if (buf >= end) - break; - buf = print_binder_transaction_log_entry(buf, end, - &log->entry[i]); - } - - *start = page + off; - - len = buf - page; - if (len > off) - len -= off; - else - len = 0; - - return len < count ? len : count; + for (i = 0; i < log->next; i++) + print_binder_transaction_log_entry(m, &log->entry[i]); + return 0; } static const struct file_operations binder_fops = { .owner = THIS_MODULE, .poll = binder_poll, .unlocked_ioctl = binder_ioctl, + .compat_ioctl = binder_ioctl, .mmap = binder_mmap, .open = binder_open, .flush = binder_flush, @@ -3686,45 +3581,57 @@ static struct miscdevice binder_miscdev = { .fops = &binder_fops }; +BINDER_DEBUG_ENTRY(state); +BINDER_DEBUG_ENTRY(stats); +BINDER_DEBUG_ENTRY(transactions); +BINDER_DEBUG_ENTRY(transaction_log); + static int __init binder_init(void) { int ret; - binder_proc_dir_entry_root = proc_mkdir("binder", NULL); - if (binder_proc_dir_entry_root) - binder_proc_dir_entry_proc = proc_mkdir("proc", - binder_proc_dir_entry_root); + binder_deferred_workqueue = create_singlethread_workqueue("binder"); + if (!binder_deferred_workqueue) + return -ENOMEM; + + 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", + binder_debugfs_dir_entry_root); ret = misc_register(&binder_miscdev); - if (binder_proc_dir_entry_root) { - create_proc_read_entry("state", - S_IRUGO, - binder_proc_dir_entry_root, - binder_read_proc_state, - NULL); - create_proc_read_entry("stats", - S_IRUGO, - binder_proc_dir_entry_root, - binder_read_proc_stats, - NULL); - create_proc_read_entry("transactions", - S_IRUGO, - binder_proc_dir_entry_root, - binder_read_proc_transactions, - NULL); - create_proc_read_entry("transaction_log", - S_IRUGO, - binder_proc_dir_entry_root, - binder_read_proc_transaction_log, - &binder_transaction_log); - create_proc_read_entry("failed_transaction_log", - S_IRUGO, - binder_proc_dir_entry_root, - binder_read_proc_transaction_log, - &binder_transaction_log_failed); + if (binder_debugfs_dir_entry_root) { + debugfs_create_file("state", + S_IRUGO, + binder_debugfs_dir_entry_root, + NULL, + &binder_state_fops); + debugfs_create_file("stats", + S_IRUGO, + binder_debugfs_dir_entry_root, + NULL, + &binder_stats_fops); + debugfs_create_file("transactions", + S_IRUGO, + binder_debugfs_dir_entry_root, + NULL, + &binder_transactions_fops); + debugfs_create_file("transaction_log", + S_IRUGO, + binder_debugfs_dir_entry_root, + &binder_transaction_log, + &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); } return ret; } device_initcall(binder_init); +#define CREATE_TRACE_POINTS +#include "binder_trace.h" + MODULE_LICENSE("GPL v2"); |
