diff options
Diffstat (limited to 'drivers/android/binder_alloc.c')
| -rw-r--r-- | drivers/android/binder_alloc.c | 86 | 
1 files changed, 62 insertions, 24 deletions
| diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 2628806c64a2..64fd96eada31 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -17,7 +17,6 @@  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <asm/cacheflush.h>  #include <linux/list.h>  #include <linux/sched/mm.h>  #include <linux/module.h> @@ -28,6 +27,8 @@  #include <linux/slab.h>  #include <linux/sched.h>  #include <linux/list_lru.h> +#include <linux/ratelimit.h> +#include <asm/cacheflush.h>  #include "binder_alloc.h"  #include "binder_trace.h" @@ -36,11 +37,12 @@ struct list_lru binder_alloc_lru;  static DEFINE_MUTEX(binder_alloc_mmap_lock);  enum { +	BINDER_DEBUG_USER_ERROR             = 1U << 0,  	BINDER_DEBUG_OPEN_CLOSE             = 1U << 1,  	BINDER_DEBUG_BUFFER_ALLOC           = 1U << 2,  	BINDER_DEBUG_BUFFER_ALLOC_ASYNC     = 1U << 3,  }; -static uint32_t binder_alloc_debug_mask; +static uint32_t binder_alloc_debug_mask = BINDER_DEBUG_USER_ERROR;  module_param_named(debug_mask, binder_alloc_debug_mask,  		   uint, 0644); @@ -48,7 +50,7 @@ module_param_named(debug_mask, binder_alloc_debug_mask,  #define binder_alloc_debug(mask, x...) \  	do { \  		if (binder_alloc_debug_mask & mask) \ -			pr_info(x); \ +			pr_info_ratelimited(x); \  	} while (0)  static struct binder_buffer *binder_buffer_next(struct binder_buffer *buffer) @@ -152,8 +154,10 @@ static struct binder_buffer *binder_alloc_prepare_to_free_locked(  			 * free the buffer twice  			 */  			if (buffer->free_in_progress) { -				pr_err("%d:%d FREE_BUFFER u%016llx user freed buffer twice\n", -				       alloc->pid, current->pid, (u64)user_ptr); +				binder_alloc_debug(BINDER_DEBUG_USER_ERROR, +						   "%d:%d FREE_BUFFER u%016llx user freed buffer twice\n", +						   alloc->pid, current->pid, +						   (u64)user_ptr);  				return NULL;  			}  			buffer->free_in_progress = 1; @@ -224,8 +228,9 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate,  	}  	if (!vma && need_mm) { -		pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n", -			alloc->pid); +		binder_alloc_debug(BINDER_DEBUG_USER_ERROR, +				   "%d: binder_alloc_buf failed to map pages in userspace, no vma\n", +				   alloc->pid);  		goto err_no_vma;  	} @@ -327,6 +332,35 @@ err_no_vma:  	return vma ? -ENOMEM : -ESRCH;  } + +static inline void binder_alloc_set_vma(struct binder_alloc *alloc, +		struct vm_area_struct *vma) +{ +	if (vma) +		alloc->vma_vm_mm = vma->vm_mm; +	/* +	 * If we see alloc->vma is not NULL, buffer data structures set up +	 * completely. Look at smp_rmb side binder_alloc_get_vma. +	 * We also want to guarantee new alloc->vma_vm_mm is always visible +	 * if alloc->vma is set. +	 */ +	smp_wmb(); +	alloc->vma = vma; +} + +static inline struct vm_area_struct *binder_alloc_get_vma( +		struct binder_alloc *alloc) +{ +	struct vm_area_struct *vma = NULL; + +	if (alloc->vma) { +		/* Look at description in binder_alloc_set_vma */ +		smp_rmb(); +		vma = alloc->vma; +	} +	return vma; +} +  static struct binder_buffer *binder_alloc_new_buf_locked(  				struct binder_alloc *alloc,  				size_t data_size, @@ -343,9 +377,10 @@ static struct binder_buffer *binder_alloc_new_buf_locked(  	size_t size, data_offsets_size;  	int ret; -	if (alloc->vma == NULL) { -		pr_err("%d: binder_alloc_buf, no vma\n", -		       alloc->pid); +	if (!binder_alloc_get_vma(alloc)) { +		binder_alloc_debug(BINDER_DEBUG_USER_ERROR, +				   "%d: binder_alloc_buf, no vma\n", +				   alloc->pid);  		return ERR_PTR(-ESRCH);  	} @@ -417,11 +452,14 @@ static struct binder_buffer *binder_alloc_new_buf_locked(  			if (buffer_size > largest_free_size)  				largest_free_size = buffer_size;  		} -		pr_err("%d: binder_alloc_buf size %zd failed, no address space\n", -			alloc->pid, size); -		pr_err("allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)\n", -		       total_alloc_size, allocated_buffers, largest_alloc_size, -		       total_free_size, free_buffers, largest_free_size); +		binder_alloc_debug(BINDER_DEBUG_USER_ERROR, +				   "%d: binder_alloc_buf size %zd failed, no address space\n", +				   alloc->pid, size); +		binder_alloc_debug(BINDER_DEBUG_USER_ERROR, +				   "allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)\n", +				   total_alloc_size, allocated_buffers, +				   largest_alloc_size, total_free_size, +				   free_buffers, largest_free_size);  		return ERR_PTR(-ENOSPC);  	}  	if (n == NULL) { @@ -714,9 +752,7 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc,  	buffer->free = 1;  	binder_insert_free_buffer(alloc, buffer);  	alloc->free_async_space = alloc->buffer_size / 2; -	barrier(); -	alloc->vma = vma; -	alloc->vma_vm_mm = vma->vm_mm; +	binder_alloc_set_vma(alloc, vma);  	mmgrab(alloc->vma_vm_mm);  	return 0; @@ -731,8 +767,10 @@ err_alloc_pages_failed:  err_get_vm_area_failed:  err_already_mapped:  	mutex_unlock(&binder_alloc_mmap_lock); -	pr_err("%s: %d %lx-%lx %s failed %d\n", __func__, -	       alloc->pid, vma->vm_start, vma->vm_end, failure_string, ret); +	binder_alloc_debug(BINDER_DEBUG_USER_ERROR, +			   "%s: %d %lx-%lx %s failed %d\n", __func__, +			   alloc->pid, vma->vm_start, vma->vm_end, +			   failure_string, ret);  	return ret;  } @@ -743,10 +781,10 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)  	int buffers, page_count;  	struct binder_buffer *buffer; -	BUG_ON(alloc->vma); -  	buffers = 0;  	mutex_lock(&alloc->mutex); +	BUG_ON(alloc->vma); +  	while ((n = rb_first(&alloc->allocated_buffers))) {  		buffer = rb_entry(n, struct binder_buffer, rb_node); @@ -889,7 +927,7 @@ int binder_alloc_get_allocated_count(struct binder_alloc *alloc)   */  void binder_alloc_vma_close(struct binder_alloc *alloc)  { -	WRITE_ONCE(alloc->vma, NULL); +	binder_alloc_set_vma(alloc, NULL);  }  /** @@ -924,7 +962,7 @@ enum lru_status binder_alloc_free_page(struct list_head *item,  	index = page - alloc->pages;  	page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE; -	vma = alloc->vma; +	vma = binder_alloc_get_vma(alloc);  	if (vma) {  		if (!mmget_not_zero(alloc->vma_vm_mm))  			goto err_mmget; |