summaryrefslogtreecommitdiff
path: root/drivers/android
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/android')
-rw-r--r--drivers/android/binder.c12
-rw-r--r--drivers/android/binder_alloc.c74
-rw-r--r--drivers/android/binder_alloc.h12
-rw-r--r--drivers/android/binderfs.c31
4 files changed, 66 insertions, 63 deletions
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 50197ef4b787..880224ec6abb 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -1385,6 +1385,18 @@ static int binder_inc_ref_for_node(struct binder_proc *proc,
}
ret = binder_inc_ref_olocked(ref, strong, target_list);
*rdata = ref->data;
+ if (ret && ref == new_ref) {
+ /*
+ * Cleanup the failed reference here as the target
+ * could now be dead and have already released its
+ * references by now. Calling on the new reference
+ * with strong=0 and a tmp_refs will not decrement
+ * the node. The new_ref gets kfree'd below.
+ */
+ binder_cleanup_ref_olocked(new_ref);
+ ref = NULL;
+ }
+
binder_proc_unlock(proc);
if (new_ref && ref != new_ref)
/*
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index 1014beb12802..1c39cfce32fa 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -208,8 +208,8 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
}
}
- if (need_mm && mmget_not_zero(alloc->vma_vm_mm))
- mm = alloc->vma_vm_mm;
+ if (need_mm && mmget_not_zero(alloc->mm))
+ mm = alloc->mm;
if (mm) {
mmap_read_lock(mm);
@@ -309,35 +309,13 @@ err_no_vma:
return vma ? -ENOMEM : -ESRCH;
}
-
-static inline void binder_alloc_set_vma(struct binder_alloc *alloc,
- struct vm_area_struct *vma)
-{
- unsigned long vm_start = 0;
-
- /*
- * Allow clearing the vma with holding just the read lock to allow
- * munmapping downgrade of the write lock before freeing and closing the
- * file using binder_alloc_vma_close().
- */
- if (vma) {
- vm_start = vma->vm_start;
- alloc->vma_vm_mm = vma->vm_mm;
- mmap_assert_write_locked(alloc->vma_vm_mm);
- } else {
- mmap_assert_locked(alloc->vma_vm_mm);
- }
-
- alloc->vma_addr = vm_start;
-}
-
static inline struct vm_area_struct *binder_alloc_get_vma(
struct binder_alloc *alloc)
{
struct vm_area_struct *vma = NULL;
if (alloc->vma_addr)
- vma = vma_lookup(alloc->vma_vm_mm, alloc->vma_addr);
+ vma = vma_lookup(alloc->mm, alloc->vma_addr);
return vma;
}
@@ -402,12 +380,15 @@ static struct binder_buffer *binder_alloc_new_buf_locked(
size_t size, data_offsets_size;
int ret;
+ mmap_read_lock(alloc->mm);
if (!binder_alloc_get_vma(alloc)) {
+ mmap_read_unlock(alloc->mm);
binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
"%d: binder_alloc_buf, no vma\n",
alloc->pid);
return ERR_PTR(-ESRCH);
}
+ mmap_read_unlock(alloc->mm);
data_offsets_size = ALIGN(data_size, sizeof(void *)) +
ALIGN(offsets_size, sizeof(void *));
@@ -791,8 +772,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;
- binder_alloc_set_vma(alloc, vma);
- mmgrab(alloc->vma_vm_mm);
+ alloc->vma_addr = vma->vm_start;
return 0;
@@ -822,7 +802,7 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
buffers = 0;
mutex_lock(&alloc->mutex);
BUG_ON(alloc->vma_addr &&
- vma_lookup(alloc->vma_vm_mm, alloc->vma_addr));
+ vma_lookup(alloc->mm, alloc->vma_addr));
while ((n = rb_first(&alloc->allocated_buffers))) {
buffer = rb_entry(n, struct binder_buffer, rb_node);
@@ -872,8 +852,8 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
kfree(alloc->pages);
}
mutex_unlock(&alloc->mutex);
- if (alloc->vma_vm_mm)
- mmdrop(alloc->vma_vm_mm);
+ if (alloc->mm)
+ mmdrop(alloc->mm);
binder_alloc_debug(BINDER_DEBUG_OPEN_CLOSE,
"%s: %d buffers %d, pages %d\n",
@@ -929,17 +909,25 @@ void binder_alloc_print_pages(struct seq_file *m,
* Make sure the binder_alloc is fully initialized, otherwise we might
* read inconsistent state.
*/
- if (binder_alloc_get_vma(alloc) != NULL) {
- for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
- page = &alloc->pages[i];
- if (!page->page_ptr)
- free++;
- else if (list_empty(&page->lru))
- active++;
- else
- lru++;
- }
+
+ mmap_read_lock(alloc->mm);
+ if (binder_alloc_get_vma(alloc) == NULL) {
+ mmap_read_unlock(alloc->mm);
+ goto uninitialized;
}
+
+ mmap_read_unlock(alloc->mm);
+ for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
+ page = &alloc->pages[i];
+ if (!page->page_ptr)
+ free++;
+ else if (list_empty(&page->lru))
+ active++;
+ else
+ lru++;
+ }
+
+uninitialized:
mutex_unlock(&alloc->mutex);
seq_printf(m, " pages: %d:%d:%d\n", active, lru, free);
seq_printf(m, " pages high watermark: %zu\n", alloc->pages_high);
@@ -974,7 +962,7 @@ int binder_alloc_get_allocated_count(struct binder_alloc *alloc)
*/
void binder_alloc_vma_close(struct binder_alloc *alloc)
{
- binder_alloc_set_vma(alloc, NULL);
+ alloc->vma_addr = 0;
}
/**
@@ -1011,7 +999,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;
- mm = alloc->vma_vm_mm;
+ mm = alloc->mm;
if (!mmget_not_zero(mm))
goto err_mmget;
if (!mmap_read_trylock(mm))
@@ -1080,6 +1068,8 @@ static struct shrinker binder_shrinker = {
void binder_alloc_init(struct binder_alloc *alloc)
{
alloc->pid = current->group_leader->pid;
+ alloc->mm = current->mm;
+ mmgrab(alloc->mm);
mutex_init(&alloc->mutex);
INIT_LIST_HEAD(&alloc->buffers);
}
diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h
index 1e4fd37af5e0..0f811ac4bcff 100644
--- a/drivers/android/binder_alloc.h
+++ b/drivers/android/binder_alloc.h
@@ -74,11 +74,10 @@ struct binder_lru_page {
/**
* struct binder_alloc - per-binder proc state for binder allocator
- * @vma: vm_area_struct passed to mmap_handler
- * (invarient after mmap)
- * @tsk: tid for task that called init for this proc
- * (invariant after init)
- * @vma_vm_mm: copy of vma->vm_mm (invarient after mmap)
+ * @mutex: protects binder_alloc fields
+ * @vma_addr: vm_area_struct->vm_start passed to mmap_handler
+ * (invariant after mmap)
+ * @mm: copy of task->mm (invariant after open)
* @buffer: base of per-proc address space mapped via mmap
* @buffers: list of all buffers for this proc
* @free_buffers: rb tree of buffers available for allocation
@@ -101,7 +100,7 @@ struct binder_lru_page {
struct binder_alloc {
struct mutex mutex;
unsigned long vma_addr;
- struct mm_struct *vma_vm_mm;
+ struct mm_struct *mm;
void __user *buffer;
struct list_head buffers;
struct rb_root free_buffers;
@@ -109,7 +108,6 @@ struct binder_alloc {
size_t free_async_space;
struct binder_lru_page *pages;
size_t buffer_size;
- uint32_t buffer_free;
int pid;
size_t pages_high;
bool oneway_spam_detected;
diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c
index 588d753a7a19..09b2ce7e4c34 100644
--- a/drivers/android/binderfs.c
+++ b/drivers/android/binderfs.c
@@ -39,7 +39,6 @@
#define FIRST_INODE 1
#define SECOND_INODE 2
#define INODE_OFFSET 3
-#define INTSTRLEN 21
#define BINDERFS_MAX_MINOR (1U << MINORBITS)
/* Ensure that the initial ipc namespace always has devices available. */
#define BINDERFS_MAX_MINOR_CAPPED (BINDERFS_MAX_MINOR - 4)
@@ -340,22 +339,10 @@ static int binderfs_show_options(struct seq_file *seq, struct dentry *root)
return 0;
}
-static void binderfs_put_super(struct super_block *sb)
-{
- struct binderfs_info *info = sb->s_fs_info;
-
- if (info && info->ipc_ns)
- put_ipc_ns(info->ipc_ns);
-
- kfree(info);
- sb->s_fs_info = NULL;
-}
-
static const struct super_operations binderfs_super_ops = {
.evict_inode = binderfs_evict_inode,
.show_options = binderfs_show_options,
.statfs = simple_statfs,
- .put_super = binderfs_put_super,
};
static inline bool is_binderfs_control_device(const struct dentry *dentry)
@@ -785,11 +772,27 @@ static int binderfs_init_fs_context(struct fs_context *fc)
return 0;
}
+static void binderfs_kill_super(struct super_block *sb)
+{
+ struct binderfs_info *info = sb->s_fs_info;
+
+ /*
+ * During inode eviction struct binderfs_info is needed.
+ * So first wipe the super_block then free struct binderfs_info.
+ */
+ kill_litter_super(sb);
+
+ if (info && info->ipc_ns)
+ put_ipc_ns(info->ipc_ns);
+
+ kfree(info);
+}
+
static struct file_system_type binder_fs_type = {
.name = "binder",
.init_fs_context = binderfs_init_fs_context,
.parameters = binderfs_fs_parameters,
- .kill_sb = kill_litter_super,
+ .kill_sb = binderfs_kill_super,
.fs_flags = FS_USERNS_MOUNT,
};