Commit 19c98724 authored by Todd Kjos's avatar Todd Kjos Committed by Greg Kroah-Hartman
Browse files

binder: separate out binder_alloc functions



Continuation of splitting the binder allocator from the binder
driver. Separate binder_alloc functions from normal binder
functions. Protect the allocator with a separate mutex.
Signed-off-by: default avatarTodd Kjos <tkjos@google.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7c03f0d6
......@@ -49,7 +49,7 @@
static DEFINE_MUTEX(binder_main_lock);
static DEFINE_MUTEX(binder_deferred_lock);
static DEFINE_MUTEX(binder_mmap_lock);
static DEFINE_MUTEX(binder_alloc_mmap_lock);
static HLIST_HEAD(binder_devices);
static HLIST_HEAD(binder_procs);
......@@ -104,9 +104,7 @@ enum {
BINDER_DEBUG_TRANSACTION_COMPLETE = 1U << 10,
BINDER_DEBUG_FREE_BUFFER = 1U << 11,
BINDER_DEBUG_INTERNAL_REFS = 1U << 12,
BINDER_DEBUG_BUFFER_ALLOC = 1U << 13,
BINDER_DEBUG_PRIORITY_CAP = 1U << 14,
BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 15,
BINDER_DEBUG_PRIORITY_CAP = 1U << 13,
};
static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR |
BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION;
......@@ -159,6 +157,27 @@ module_param_call(stop_on_user_error, binder_set_stop_on_user_error,
#define to_binder_fd_array_object(hdr) \
container_of(hdr, struct binder_fd_array_object, hdr)
/*
* debug declarations for binder_alloc. To be
* moved to binder_alloc.c
*/
enum {
BINDER_ALLOC_DEBUG_OPEN_CLOSE = 1U << 1,
BINDER_ALLOC_DEBUG_BUFFER_ALLOC = 1U << 2,
BINDER_ALLOC_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 3,
};
static uint32_t binder_alloc_debug_mask;
module_param_named(alloc_debug_mask, binder_alloc_debug_mask,
uint, 0644);
#define binder_alloc_debug(mask, x...) \
do { \
if (binder_alloc_debug_mask & mask) \
pr_info(x); \
} while (0)
/* end of binder_alloc debug declarations */
enum binder_stat_types {
BINDER_STAT_PROC,
BINDER_STAT_THREAD,
......@@ -342,6 +361,8 @@ enum binder_deferred_state {
* struct binder_buffer objects used to track the user buffers
*/
struct binder_alloc {
struct mutex mutex;
struct task_struct *tsk;
struct vm_area_struct *vma;
struct mm_struct *vma_vm_mm;
void *buffer;
......@@ -352,6 +373,7 @@ struct binder_alloc {
size_t free_async_space;
struct page **pages;
size_t buffer_size;
int pid;
};
struct binder_proc {
......@@ -423,6 +445,56 @@ struct binder_transaction {
kuid_t sender_euid;
};
/*
* Forward declarations of binder_alloc functions.
* These will be moved to binder_alloc.h when
* binder_alloc is moved to its own files.
*/
extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
size_t data_size,
size_t offsets_size,
size_t extra_buffers_size,
int is_async);
extern void binder_alloc_init(struct binder_alloc *alloc);
extern void binder_alloc_vma_close(struct binder_alloc *alloc);
extern struct binder_buffer *
binder_alloc_buffer_lookup(struct binder_alloc *alloc,
uintptr_t user_ptr);
extern void binder_alloc_free_buf(struct binder_alloc *alloc,
struct binder_buffer *buffer);
extern int binder_alloc_mmap_handler(struct binder_alloc *alloc,
struct vm_area_struct *vma);
extern void binder_alloc_deferred_release(struct binder_alloc *alloc);
extern int binder_alloc_get_allocated_count(struct binder_alloc *alloc);
extern void binder_alloc_print_allocated(struct seq_file *m,
struct binder_alloc *alloc);
static inline size_t
binder_alloc_get_free_async_space(struct binder_alloc *alloc)
{
size_t free_async_space;
mutex_lock(&alloc->mutex);
free_async_space = alloc->free_async_space;
mutex_unlock(&alloc->mutex);
return free_async_space;
}
static inline ptrdiff_t
binder_alloc_get_user_buffer_offset(struct binder_alloc *alloc)
{
/*
* user_buffer_offset is constant if vma is set and
* undefined if vma is not set. It is possible to
* get here with !alloc->vma if the target process
* is dying while a transaction is being initiated.
* Returning the old value is ok in this case and
* the transaction will fail.
*/
return alloc->user_buffer_offset;
}
/* end of binder_alloc declarations */
static void
binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer);
......@@ -506,21 +578,20 @@ static void binder_set_nice(long nice)
binder_user_error("%d RLIMIT_NICE not set\n", current->pid);
}
static size_t binder_buffer_size(struct binder_proc *proc,
struct binder_buffer *buffer)
static size_t binder_alloc_buffer_size(struct binder_alloc *alloc,
struct binder_buffer *buffer)
{
if (list_is_last(&buffer->entry, &proc->alloc.buffers))
return proc->alloc.buffer +
proc->alloc.buffer_size -
(void *)buffer->data;
if (list_is_last(&buffer->entry, &alloc->buffers))
return alloc->buffer +
alloc->buffer_size - (void *)buffer->data;
return (size_t)list_entry(buffer->entry.next,
struct binder_buffer, entry) - (size_t)buffer->data;
}
static void binder_insert_free_buffer(struct binder_proc *proc,
static void binder_insert_free_buffer(struct binder_alloc *alloc,
struct binder_buffer *new_buffer)
{
struct rb_node **p = &proc->alloc.free_buffers.rb_node;
struct rb_node **p = &alloc->free_buffers.rb_node;
struct rb_node *parent = NULL;
struct binder_buffer *buffer;
size_t buffer_size;
......@@ -528,18 +599,18 @@ static void binder_insert_free_buffer(struct binder_proc *proc,
BUG_ON(!new_buffer->free);
new_buffer_size = binder_buffer_size(proc, new_buffer);
new_buffer_size = binder_alloc_buffer_size(alloc, new_buffer);
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: add free buffer, size %zd, at %p\n",
proc->pid, new_buffer_size, new_buffer);
binder_alloc_debug(BINDER_ALLOC_DEBUG_BUFFER_ALLOC,
"%d: add free buffer, size %zd, at %pK\n",
alloc->pid, new_buffer_size, new_buffer);
while (*p) {
parent = *p;
buffer = rb_entry(parent, struct binder_buffer, rb_node);
BUG_ON(!buffer->free);
buffer_size = binder_buffer_size(proc, buffer);
buffer_size = binder_alloc_buffer_size(alloc, buffer);
if (new_buffer_size < buffer_size)
p = &parent->rb_left;
......@@ -547,13 +618,13 @@ static void binder_insert_free_buffer(struct binder_proc *proc,
p = &parent->rb_right;
}
rb_link_node(&new_buffer->rb_node, parent, p);
rb_insert_color(&new_buffer->rb_node, &proc->alloc.free_buffers);
rb_insert_color(&new_buffer->rb_node, &alloc->free_buffers);
}
static void binder_insert_allocated_buffer(struct binder_proc *proc,
static void binder_insert_allocated_buffer(struct binder_alloc *alloc,
struct binder_buffer *new_buffer)
{
struct rb_node **p = &proc->alloc.allocated_buffers.rb_node;
struct rb_node **p = &alloc->allocated_buffers.rb_node;
struct rb_node *parent = NULL;
struct binder_buffer *buffer;
......@@ -572,19 +643,19 @@ static void binder_insert_allocated_buffer(struct binder_proc *proc,
BUG();
}
rb_link_node(&new_buffer->rb_node, parent, p);
rb_insert_color(&new_buffer->rb_node, &proc->alloc.allocated_buffers);
rb_insert_color(&new_buffer->rb_node, &alloc->allocated_buffers);
}
static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc,
uintptr_t user_ptr)
static struct binder_buffer *binder_alloc_buffer_lookup_locked(
struct binder_alloc *alloc,
uintptr_t user_ptr)
{
struct rb_node *n = proc->alloc.allocated_buffers.rb_node;
struct rb_node *n = alloc->allocated_buffers.rb_node;
struct binder_buffer *buffer;
struct binder_buffer *kern_ptr;
kern_ptr = (struct binder_buffer *)
(user_ptr - proc->alloc.user_buffer_offset -
offsetof(struct binder_buffer, data));
kern_ptr = (struct binder_buffer *)(user_ptr - alloc->user_buffer_offset
- offsetof(struct binder_buffer, data));
while (n) {
buffer = rb_entry(n, struct binder_buffer, rb_node);
......@@ -600,7 +671,18 @@ static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc,
return NULL;
}
static int binder_update_page_range(struct binder_proc *proc, int allocate,
struct binder_buffer *binder_alloc_buffer_lookup(struct binder_alloc *alloc,
uintptr_t user_ptr)
{
struct binder_buffer *buffer;
mutex_lock(&alloc->mutex);
buffer = binder_alloc_buffer_lookup_locked(alloc, user_ptr);
mutex_unlock(&alloc->mutex);
return buffer;
}
static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
void *start, void *end,
struct vm_area_struct *vma)
{
......@@ -609,26 +691,26 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
struct page **page;
struct mm_struct *mm;
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: %s pages %p-%p\n", proc->pid,
binder_alloc_debug(BINDER_ALLOC_DEBUG_BUFFER_ALLOC,
"%d: %s pages %pK-%pK\n", alloc->pid,
allocate ? "allocate" : "free", start, end);
if (end <= start)
return 0;
trace_binder_update_page_range(proc, allocate, start, end);
trace_binder_update_page_range(alloc, allocate, start, end);
if (vma)
mm = NULL;
else
mm = get_task_mm(proc->tsk);
mm = get_task_mm(alloc->tsk);
if (mm) {
down_write(&mm->mmap_sem);
vma = proc->alloc.vma;
if (vma && mm != proc->alloc.vma_vm_mm) {
vma = alloc->vma;
if (vma && mm != alloc->vma_vm_mm) {
pr_err("%d: vma mm and task mm mismatch\n",
proc->pid);
alloc->pid);
vma = NULL;
}
}
......@@ -638,21 +720,20 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
if (vma == NULL) {
pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n",
proc->pid);
alloc->pid);
goto err_no_vma;
}
for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
int ret;
page = &proc->alloc.pages[
(page_addr - proc->alloc.buffer) / PAGE_SIZE];
page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
BUG_ON(*page);
*page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
if (*page == NULL) {
pr_err("%d: binder_alloc_buf failed for page at %p\n",
proc->pid, page_addr);
pr_err("%d: binder_alloc_buf failed for page at %pK\n",
alloc->pid, page_addr);
goto err_alloc_page_failed;
}
ret = map_kernel_range_noflush((unsigned long)page_addr,
......@@ -660,16 +741,16 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
flush_cache_vmap((unsigned long)page_addr,
(unsigned long)page_addr + PAGE_SIZE);
if (ret != 1) {
pr_err("%d: binder_alloc_buf failed to map page at %p in kernel\n",
proc->pid, page_addr);
pr_err("%d: binder_alloc_buf failed to map page at %pK in kernel\n",
alloc->pid, page_addr);
goto err_map_kernel_failed;
}
user_page_addr =
(uintptr_t)page_addr + proc->alloc.user_buffer_offset;
(uintptr_t)page_addr + alloc->user_buffer_offset;
ret = vm_insert_page(vma, user_page_addr, page[0]);
if (ret) {
pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n",
proc->pid, user_page_addr);
alloc->pid, user_page_addr);
goto err_vm_insert_page_failed;
}
/* vm_insert_page does not seem to increment the refcount */
......@@ -683,11 +764,10 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
free_range:
for (page_addr = end - PAGE_SIZE; page_addr >= start;
page_addr -= PAGE_SIZE) {
page = &proc->alloc.pages[
(page_addr - proc->alloc.buffer) / PAGE_SIZE];
page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
if (vma)
zap_page_range(vma, (uintptr_t)page_addr +
proc->alloc.user_buffer_offset, PAGE_SIZE);
alloc->user_buffer_offset, PAGE_SIZE);
err_vm_insert_page_failed:
unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
err_map_kernel_failed:
......@@ -704,13 +784,11 @@ err_no_vma:
return -ENOMEM;
}
static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
size_t data_size,
size_t offsets_size,
size_t extra_buffers_size,
int is_async)
static struct binder_buffer *binder_alloc_new_buf_locked(
struct binder_alloc *alloc, size_t data_size,
size_t offsets_size, size_t extra_buffers_size, int is_async)
{
struct rb_node *n = proc->alloc.free_buffers.rb_node;
struct rb_node *n = alloc->free_buffers.rb_node;
struct binder_buffer *buffer;
size_t buffer_size;
struct rb_node *best_fit = NULL;
......@@ -718,9 +796,9 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
void *end_page_addr;
size_t size, data_offsets_size;
if (proc->alloc.vma == NULL) {
if (alloc->vma == NULL) {
pr_err("%d: binder_alloc_buf, no vma\n",
proc->pid);
alloc->pid);
return NULL;
}
......@@ -728,29 +806,30 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
ALIGN(offsets_size, sizeof(void *));
if (data_offsets_size < data_size || data_offsets_size < offsets_size) {
binder_user_error("%d: got transaction with invalid size %zd-%zd\n",
proc->pid, data_size, offsets_size);
binder_alloc_debug(BINDER_ALLOC_DEBUG_BUFFER_ALLOC,
"%d: got transaction with invalid size %zd-%zd\n",
alloc->pid, data_size, offsets_size);
return NULL;
}
size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *));
if (size < data_offsets_size || size < extra_buffers_size) {
binder_user_error("%d: got transaction with invalid extra_buffers_size %zd\n",
proc->pid, extra_buffers_size);
binder_alloc_debug(BINDER_ALLOC_DEBUG_BUFFER_ALLOC,
"%d: got transaction with invalid extra_buffers_size %zd\n",
alloc->pid, extra_buffers_size);
return NULL;
}
if (is_async &&
proc->alloc.free_async_space <
size + sizeof(struct binder_buffer)) {
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
alloc->free_async_space < size + sizeof(struct binder_buffer)) {
binder_alloc_debug(BINDER_ALLOC_DEBUG_BUFFER_ALLOC,
"%d: binder_alloc_buf size %zd failed, no async space left\n",
proc->pid, size);
alloc->pid, size);
return NULL;
}
while (n) {
buffer = rb_entry(n, struct binder_buffer, rb_node);
BUG_ON(!buffer->free);
buffer_size = binder_buffer_size(proc, buffer);
buffer_size = binder_alloc_buffer_size(alloc, buffer);
if (size < buffer_size) {
best_fit = n;
......@@ -764,17 +843,17 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
}
if (best_fit == NULL) {
pr_err("%d: binder_alloc_buf size %zd failed, no address space\n",
proc->pid, size);
alloc->pid, size);
return NULL;
}
if (n == NULL) {
buffer = rb_entry(best_fit, struct binder_buffer, rb_node);
buffer_size = binder_buffer_size(proc, buffer);
buffer_size = binder_alloc_buffer_size(alloc, buffer);
}
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: binder_alloc_buf size %zd got buffer %p size %zd\n",
proc->pid, size, buffer, buffer_size);
binder_alloc_debug(BINDER_ALLOC_DEBUG_BUFFER_ALLOC,
"%d: %s size %zd got buffer %pK size %zd\n",
alloc->pid, __func__, size, buffer, buffer_size);
has_page_addr =
(void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK);
......@@ -788,38 +867,52 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
(void *)PAGE_ALIGN((uintptr_t)buffer->data + buffer_size);
if (end_page_addr > has_page_addr)
end_page_addr = has_page_addr;
if (binder_update_page_range(proc, 1,
if (binder_update_page_range(alloc, 1,
(void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL))
return NULL;
rb_erase(best_fit, &proc->alloc.free_buffers);
rb_erase(best_fit, &alloc->free_buffers);
buffer->free = 0;
binder_insert_allocated_buffer(proc, buffer);
binder_insert_allocated_buffer(alloc, 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);
binder_insert_free_buffer(alloc, new_buffer);
}
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: binder_alloc_buf size %zd got %p\n",
proc->pid, size, buffer);
binder_alloc_debug(BINDER_ALLOC_DEBUG_BUFFER_ALLOC,
"%d: %s size %zd got %pK\n",
alloc->pid, __func__, size, buffer);
buffer->data_size = data_size;
buffer->offsets_size = offsets_size;
buffer->extra_buffers_size = extra_buffers_size;
buffer->async_transaction = is_async;
buffer->extra_buffers_size = extra_buffers_size;
if (is_async) {
proc->alloc.free_async_space -=
size + sizeof(struct binder_buffer);
binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
alloc->free_async_space -= size + sizeof(struct binder_buffer);
binder_alloc_debug(BINDER_ALLOC_DEBUG_BUFFER_ALLOC_ASYNC,
"%d: binder_alloc_buf size %zd async free %zd\n",
proc->pid, size, proc->alloc.free_async_space);
alloc->pid, size, alloc->free_async_space);
}
return buffer;
}
struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
size_t data_size,
size_t offsets_size,
size_t extra_buffers_size,
int is_async)
{
struct binder_buffer *buffer;
mutex_lock(&alloc->mutex);
buffer = binder_alloc_new_buf_locked(alloc, data_size, offsets_size,
extra_buffers_size, is_async);
mutex_unlock(&alloc->mutex);
return buffer;
}
static void *buffer_start_page(struct binder_buffer *buffer)
{
return (void *)((uintptr_t)buffer & PAGE_MASK);
......@@ -830,26 +923,26 @@ static void *buffer_end_page(struct binder_buffer *buffer)
return (void *)(((uintptr_t)(buffer + 1) - 1) & PAGE_MASK);
}
static void binder_delete_free_buffer(struct binder_proc *proc,
static void binder_delete_free_buffer(struct binder_alloc *alloc,
struct binder_buffer *buffer)
{
struct binder_buffer *prev, *next = NULL;
int free_page_end = 1;
int free_page_start = 1;
BUG_ON(proc->alloc.buffers.next == &buffer->entry);
BUG_ON(alloc->buffers.next == &buffer->entry);
prev = list_entry(buffer->entry.prev, struct binder_buffer, entry);
BUG_ON(!prev->free);
if (buffer_end_page(prev) == buffer_start_page(buffer)) {
free_page_start = 0;
if (buffer_end_page(prev) == buffer_end_page(buffer))
free_page_end = 0;
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: merge free, buffer %p share page with %p\n",
proc->pid, buffer, prev);
binder_alloc_debug(BINDER_ALLOC_DEBUG_BUFFER_ALLOC,
"%d: merge free, buffer %pK share page with %pK\n",
alloc->pid, buffer, prev);
}
if (!list_is_last(&buffer->entry, &proc->alloc.buffers)) {
if (!list_is_last(&buffer->entry, &alloc->buffers)) {
next = list_entry(buffer->entry.next,
struct binder_buffer, entry);
if (buffer_start_page(next) == buffer_end_page(buffer)) {
......@@ -857,80 +950,88 @@ static void binder_delete_free_buffer(struct binder_proc *proc,
if (buffer_start_page(next) ==
buffer_start_page(buffer))
free_page_start = 0;
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: merge free, buffer %p share page with %p\n",
proc->pid, buffer, prev);
binder_alloc_debug(BINDER_ALLOC_DEBUG_BUFFER_ALLOC,
"%d: merge free, buffer %pK share page with %pK\n",
alloc->pid, buffer, prev);
}
}
list_del(&buffer->entry);
if (free_page_start || free_page_end) {
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",
binder_alloc_debug(BINDER_ALLOC_DEBUG_BUFFER_ALLOC,
"%d: merge free, buffer %pK do not share page%s%s with %pK or %pK\n",
alloc->pid, buffer, free_page_start ? "" : " end",
free_page_end ? "" : " start", prev, next);
binder_update_page_range(proc, 0, free_page_start ?
binder_update_page_range(alloc, 0, free_page_start ?
buffer_start_page(buffer) : buffer_end_page(buffer),
(free_page_end ? buffer_end_page(buffer) :
buffer_start_page(buffer)) + PAGE_SIZE, NULL);
}
}
static void binder_free_buf(struct binder_proc *proc,
struct binder_buffer *buffer)
static void binder_free_buf_locked(struct binder_alloc *alloc,
struct binder_buffer *buffer)
{
size_t size, buffer_size;
buffer_size = binder_buffer_size(proc, buffer);
buffer_size = binder_alloc_buffer_size(alloc, buffer);
size = ALIGN(buffer->data_size, sizeof(void *)) +
ALIGN(buffer->offsets_size, sizeof(void *)) +
ALIGN(buffer->extra_buffers_size, sizeof(void *));
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: binder_free_buf %p size %zd buffer_size %zd\n",
proc->pid, buffer, size, buffer_size);
binder_alloc_debug(BINDER_ALLOC_DEBUG_BUFFER_ALLOC,
"%d: binder_free_buf %pK size %zd buffer_size %zd\n",
alloc->pid, buffer, size, buffer_size);
BUG_ON(buffer->free);
BUG_ON(size > buffer_size);
BUG_ON(buffer->transaction != NULL);
BUG_ON((void *)buffer < proc->alloc.buffer);
BUG_ON((void *)buffer > proc->alloc.buffer + proc->alloc.buffer_size);
BUG_ON((void *)buffer < alloc->buffer);
BUG_ON((void *)buffer > alloc->buffer + alloc->buffer_size);
if (buffer->async_transaction) {
proc->alloc.free_async_space +=
size + sizeof(struct binder_buffer);
alloc->free_async_space += size + sizeof(struct binder_buffer);
binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
binder_alloc_debug(BINDER_ALLOC_DEBUG_BUFFER_ALLOC_ASYNC,
"%d: binder_free_buf size %zd async free %zd\n",
proc->pid, size, proc->alloc.free_async_space);
alloc->pid, size, alloc->free_async_space);
}
binder_update_page_range(proc, 0,
binder_update_page_range(alloc, 0,
(void *)PAGE_ALIGN((uintptr_t)buffer->data),
(void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK),
NULL);
rb_erase(&buffer->rb_node, &proc->alloc.allocated_buffers);
rb_erase(&buffer->rb_node, &alloc->allocated_buffers);
buffer->free = 1;
if (!list_is_last(&buffer->entry, &proc->alloc.buffers)) {
if (!list_is_last(&buffer->entry, &alloc->buffers)) {
struct binder_buffer *next = list_entry(buffer->entry.next,
struct binder_buffer, entry);
if (next->free) {
rb_erase(&next->rb_node, &proc->alloc.free_buffers);
binder_delete_free_buffer(proc, next);
rb_erase(&next->rb_node, &alloc->free_buffers);
binder_delete_free_buffer(alloc, next);
}
}
if (proc->alloc.buffers.next != &buffer->entry) {
if (alloc->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->alloc.free_buffers);
binder_delete_free_buffer(alloc, buffer);