summaryrefslogtreecommitdiff
path: root/drivers/android
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/android')
-rw-r--r--drivers/android/Kconfig41
-rw-r--r--drivers/android/Makefile3
-rw-r--r--drivers/android/binder.c3
-rw-r--r--drivers/android/binder/Makefile4
-rw-r--r--drivers/android/binder/allocation.rs10
-rw-r--r--drivers/android/binder/defs.rs3
-rw-r--r--drivers/android/binder/freeze.rs11
-rw-r--r--drivers/android/binder/node.rs30
-rw-r--r--drivers/android/binder/node/wrapper.rs36
-rw-r--r--drivers/android/binder/page_range.rs6
-rw-r--r--drivers/android/binder/process.rs21
-rw-r--r--drivers/android/binder/range_alloc/array.rs2
-rw-r--r--drivers/android/binder/range_alloc/mod.rs2
-rw-r--r--drivers/android/binder/range_alloc/tree.rs2
-rw-r--r--drivers/android/binder/rust_binder_main.rs14
-rw-r--r--drivers/android/binder/rust_binderfs.c10
-rw-r--r--drivers/android/binder/thread.rs66
-rw-r--r--drivers/android/binder/transaction.rs3
-rw-r--r--drivers/android/binder_alloc.h189
-rw-r--r--drivers/android/binder_internal.h597
-rw-r--r--drivers/android/binder_netlink.c32
-rw-r--r--drivers/android/binder_netlink.h21
-rw-r--r--drivers/android/binder_trace.h448
-rw-r--r--drivers/android/binderfs.c786
-rw-r--r--drivers/android/dbitmap.h169
-rw-r--r--drivers/android/tests/.kunitconfig7
-rw-r--r--drivers/android/tests/Makefile6
-rw-r--r--drivers/android/tests/binder_alloc_kunit.c572
28 files changed, 162 insertions, 2932 deletions
diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig
index 606a9d07f774..c920d52c0221 100644
--- a/drivers/android/Kconfig
+++ b/drivers/android/Kconfig
@@ -1,10 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
menu "Android"
-config ANDROID_BINDER_IPC
+config ANDROID_BINDER_IPC_RUST
bool "Android Binder IPC Driver"
depends on MMU
depends on NET
+ depends on RUST
default n
help
Binder is used in Android for both communication between processes,
@@ -14,34 +15,9 @@ config ANDROID_BINDER_IPC
Android process, using Binder to identify, invoke and pass arguments
between said processes.
-config ANDROID_BINDER_IPC_RUST
- bool "Rust version of Android Binder IPC Driver"
- depends on RUST && MMU && NET && !ANDROID_BINDER_IPC
- help
- This enables the Rust implementation of the Binder driver.
-
- Binder is used in Android for both communication between processes,
- and remote method invocation.
-
- This means one Android process can call a method/routine in another
- Android process, using Binder to identify, invoke and pass arguments
- between said processes.
-
-config ANDROID_BINDERFS
- bool "Android Binderfs filesystem"
- depends on ANDROID_BINDER_IPC
- default n
- help
- Binderfs is a pseudo-filesystem for the Android Binder IPC driver
- which can be mounted per-ipc namespace allowing to run multiple
- instances of Android.
- Each binderfs mount initially only contains a binder-control device.
- It can be used to dynamically allocate new binder IPC devices via
- ioctls.
-
config ANDROID_BINDER_DEVICES
string "Android Binder devices"
- depends on ANDROID_BINDER_IPC || ANDROID_BINDER_IPC_RUST
+ depends on ANDROID_BINDER_IPC_RUST
default "binder,hwbinder,vndbinder"
help
Default value for the binder.devices parameter.
@@ -51,15 +27,4 @@ config ANDROID_BINDER_DEVICES
created. Each binder device has its own context manager, and is
therefore logically separated from the other devices.
-config ANDROID_BINDER_ALLOC_KUNIT_TEST
- tristate "KUnit Tests for Android Binder Alloc" if !KUNIT_ALL_TESTS
- depends on ANDROID_BINDER_IPC && KUNIT
- default KUNIT_ALL_TESTS
- help
- This feature builds the binder alloc KUnit tests.
-
- Each test case runs using a pared-down binder_alloc struct and
- test-specific freelist, which allows this KUnit module to be loaded
- for testing without interfering with a running system.
-
endmenu
diff --git a/drivers/android/Makefile b/drivers/android/Makefile
index e0c650d3898e..f83d39d16f6e 100644
--- a/drivers/android/Makefile
+++ b/drivers/android/Makefile
@@ -1,7 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
ccflags-y += -I$(src) # needed for trace events
-obj-$(CONFIG_ANDROID_BINDERFS) += binderfs.o
-obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o binder_netlink.o
-obj-$(CONFIG_ANDROID_BINDER_ALLOC_KUNIT_TEST) += tests/
obj-$(CONFIG_ANDROID_BINDER_IPC_RUST) += binder/
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 8f2ef1bd539f..bc8bc9ee43a5 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -2930,8 +2930,9 @@ static int binder_proc_transaction(struct binder_transaction *t,
t_outdated->buffer = NULL;
buffer->transaction = NULL;
trace_binder_transaction_update_buffer_release(buffer);
- binder_release_entire_buffer(proc, NULL, buffer, false);
+ binder_release_entire_buffer(proc, NULL, buffer, true);
binder_alloc_free_buf(&proc->alloc, buffer);
+ binder_free_txn_fixups(t_outdated);
kfree(t_outdated);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
diff --git a/drivers/android/binder/Makefile b/drivers/android/binder/Makefile
index 7e0cd9782a8b..fe474628a94e 100644
--- a/drivers/android/binder/Makefile
+++ b/drivers/android/binder/Makefile
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
ccflags-y += -I$(src) # needed for trace events
-obj-$(CONFIG_ANDROID_BINDER_IPC_RUST) += rust_binder.o
-rust_binder-y := \
+obj-$(CONFIG_ANDROID_BINDER_IPC_RUST) += binder.o
+binder-y := \
rust_binder_main.o \
rust_binderfs.o \
rust_binder_events.o
diff --git a/drivers/android/binder/allocation.rs b/drivers/android/binder/allocation.rs
index 165cb797eb1e..2f0763e6868d 100644
--- a/drivers/android/binder/allocation.rs
+++ b/drivers/android/binder/allocation.rs
@@ -208,7 +208,7 @@ impl Allocation {
let num_close_on_free = files.iter().filter(|entry| entry.close_on_free).count();
let mut close_on_free = KVec::with_capacity(num_close_on_free, GFP_KERNEL)?;
- let mut reservations = KVec::with_capacity(files.len(), GFP_KERNEL)?;
+ let mut reservations = KVVec::with_capacity(files.len(), GFP_KERNEL)?;
for file_info in files {
let res = FileDescriptorReservation::get_unused_fd_flags(bindings::O_CLOEXEC)?;
let fd = res.reserved_fd();
@@ -503,7 +503,7 @@ impl BinderObject {
/// The closure should write the bytes for the object into the provided slice.
pub(crate) fn read_from_inner<R>(reader: R) -> Result<BinderObject>
where
- R: FnOnce(&mut [u8; size_of::<BinderObject>()]) -> Result<()>,
+ R: FnOnce(&mut [u8; size_of::<BinderObject>()]) -> Result,
{
let mut obj = MaybeUninit::<BinderObject>::zeroed();
@@ -567,7 +567,7 @@ impl BinderObject {
#[derive(Default)]
struct FileList {
- files_to_translate: KVec<FileEntry>,
+ files_to_translate: KVVec<FileEntry>,
close_on_free: KVec<u32>,
}
@@ -581,7 +581,7 @@ struct FileEntry {
}
pub(crate) struct TranslatedFds {
- reservations: KVec<Reservation>,
+ reservations: KVVec<Reservation>,
/// If commit is called, then these fds should be closed. (If commit is not called, then they
/// shouldn't be closed.)
close_on_free: FdsCloseOnFree,
@@ -595,7 +595,7 @@ struct Reservation {
impl TranslatedFds {
pub(crate) fn new() -> Self {
Self {
- reservations: KVec::new(),
+ reservations: KVVec::new(),
close_on_free: FdsCloseOnFree(KVec::new()),
}
}
diff --git a/drivers/android/binder/defs.rs b/drivers/android/binder/defs.rs
index 8ac9bdd7a499..cc4becd6e168 100644
--- a/drivers/android/binder/defs.rs
+++ b/drivers/android/binder/defs.rs
@@ -77,7 +77,8 @@ pub_no_prefix!(
TF_ONE_WAY,
TF_ACCEPT_FDS,
TF_CLEAR_BUF,
- TF_UPDATE_TXN
+ TF_UPDATE_TXN,
+ TF_DEFER_COMPLETE,
);
pub(crate) use uapi::{
diff --git a/drivers/android/binder/freeze.rs b/drivers/android/binder/freeze.rs
index 66912b4cb527..ea2450f3f16f 100644
--- a/drivers/android/binder/freeze.rs
+++ b/drivers/android/binder/freeze.rs
@@ -155,7 +155,7 @@ impl DeliverToRead for FreezeMessage {
}
#[inline(never)]
- fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> {
+ fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result {
seq_print!(m, "{}has frozen binder\n", prefix);
Ok(())
}
@@ -177,10 +177,7 @@ impl FreezeListener {
}
impl Process {
- pub(crate) fn request_freeze_notif(
- self: &Arc<Self>,
- reader: &mut UserSliceReader,
- ) -> Result<()> {
+ pub(crate) fn request_freeze_notif(self: &Arc<Self>, reader: &mut UserSliceReader) -> Result {
let hc = reader.read::<BinderHandleCookie>()?;
let handle = hc.handle;
let cookie = FreezeCookie(hc.cookie);
@@ -272,7 +269,7 @@ impl Process {
Ok(())
}
- pub(crate) fn freeze_notif_done(self: &Arc<Self>, reader: &mut UserSliceReader) -> Result<()> {
+ pub(crate) fn freeze_notif_done(self: &Arc<Self>, reader: &mut UserSliceReader) -> Result {
let cookie = FreezeCookie(reader.read()?);
let alloc = FreezeMessage::new(GFP_KERNEL)?;
let mut node_refs_guard = self.node_refs.lock();
@@ -313,7 +310,7 @@ impl Process {
Ok(())
}
- pub(crate) fn clear_freeze_notif(self: &Arc<Self>, reader: &mut UserSliceReader) -> Result<()> {
+ pub(crate) fn clear_freeze_notif(self: &Arc<Self>, reader: &mut UserSliceReader) -> Result {
let hc = reader.read::<BinderHandleCookie>()?;
let handle = hc.handle;
let cookie = FreezeCookie(hc.cookie);
diff --git a/drivers/android/binder/node.rs b/drivers/android/binder/node.rs
index 0a82af14cda3..b16ea0ff9ed9 100644
--- a/drivers/android/binder/node.rs
+++ b/drivers/android/binder/node.rs
@@ -51,9 +51,9 @@ pub(crate) struct CouldNotDeliverCriticalIncrement;
/// about to drop the weak reference, then the strong increment could be processed after the
/// other thread has already exited, which would be too late.
///
-/// Note that trying to create a `ListArc` to the node can succeed even if `has_normal_push` is
+/// Note that trying to create a `ListArc` to the node can succeed even if `has_pushed_node` is
/// set. This is because another thread might just have popped the node from a todo list, but not
-/// yet called `do_work`. However, if `has_normal_push` is false, then creating a `ListArc` should
+/// yet called `do_work`. However, if `has_pushed_node` is false, then creating a `ListArc` should
/// always succeed.
///
/// Like the other fields in `NodeInner`, the delivery state is protected by the process lock.
@@ -255,11 +255,7 @@ impl Node {
}
#[inline(never)]
- pub(crate) fn full_debug_print(
- &self,
- m: &SeqFile,
- owner_inner: &mut ProcessInner,
- ) -> Result<()> {
+ pub(crate) fn full_debug_print(&self, m: &SeqFile, owner_inner: &mut ProcessInner) -> Result {
let inner = self.inner.access_mut(owner_inner);
seq_print!(
m,
@@ -738,14 +734,28 @@ impl DeliverToRead for Node {
self.do_work_locked(writer, owner_inner)
}
- fn cancel(self: DArc<Self>) {}
+ fn cancel(self: DArc<Self>) {
+ let _drop_outside_lock;
+ let mut owner_inner = self.owner.inner.lock();
+
+ // We only do something on BINDER_THREAD_EXIT, not process exit.
+ if owner_inner.is_dead {
+ return;
+ }
+
+ // If BINDER_THREAD_EXIT is invoked on a thread with a pending node refcount update, we
+ // should move ourselves to ensure the refcount update is still delivered.
+ if let Some(node) = ListArc::try_from_arc_borrow(self.as_arc_borrow()) {
+ _drop_outside_lock = owner_inner.push_work(&self.owner, node);
+ }
+ }
fn should_sync_wakeup(&self) -> bool {
false
}
#[inline(never)]
- fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> {
+ fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result {
seq_print!(
m,
"{}node work {}: u{:016x} c{:016x}\n",
@@ -1140,7 +1150,7 @@ impl DeliverToRead for NodeDeath {
}
#[inline(never)]
- fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> {
+ fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result {
let inner = self.inner.lock();
let dead_binder = inner.dead && !inner.notification_done;
diff --git a/drivers/android/binder/node/wrapper.rs b/drivers/android/binder/node/wrapper.rs
index 6e4ca01c941a..5a5e5e9883a4 100644
--- a/drivers/android/binder/node/wrapper.rs
+++ b/drivers/android/binder/node/wrapper.rs
@@ -57,14 +57,46 @@ impl DeliverToRead for NodeWrapper {
node.do_work_locked(writer, owner_inner)
}
- fn cancel(self: DArc<Self>) {}
+ fn cancel(self: DArc<Self>) {
+ let _drop_outside_lock;
+ let node = &self.node;
+ let mut owner_inner = node.owner.inner.lock();
+
+ // We only do something on BINDER_THREAD_EXIT, not process exit.
+ if owner_inner.is_dead {
+ return;
+ }
+
+ // We transfer the responsibility of the node refcount update to the scheduled Node because
+ // NodeWrapper has no way to re-create the ListArc.
+ let inner = node.inner.access_mut(&mut owner_inner);
+
+ let ds = &mut inner.delivery_state;
+ assert!(ds.has_pushed_wrapper);
+ assert!(ds.has_strong_zero2one);
+ ds.has_pushed_wrapper = false;
+
+ // We are changing the state to one where the Node is the strong zero2one update instead of
+ // the wrapper.
+ ds.has_weak_zero2one = false;
+
+ if !ds.has_pushed_node {
+ if let Some(node2) = ListArc::try_from_arc_borrow(node.as_arc_borrow()) {
+ ds.has_pushed_node = true;
+ _drop_outside_lock = owner_inner.push_work(&node.owner, node2);
+ } else {
+ // This can't actually happen.
+ ds.has_strong_zero2one = false;
+ }
+ }
+ }
fn should_sync_wakeup(&self) -> bool {
false
}
#[inline(never)]
- fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> {
+ fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result {
seq_print!(
m,
"{}node work {}: u{:016x} c{:016x}\n",
diff --git a/drivers/android/binder/page_range.rs b/drivers/android/binder/page_range.rs
index 71febd3d5b07..74c99432f867 100644
--- a/drivers/android/binder/page_range.rs
+++ b/drivers/android/binder/page_range.rs
@@ -66,7 +66,7 @@ impl Shrinker {
}
/// Register this shrinker with the kernel.
- pub(crate) fn register(&'static self, name: &CStr) -> Result<()> {
+ pub(crate) fn register(&'static self, name: &CStr) -> Result {
// SAFETY: These fields are not yet used, so it's okay to zero them.
unsafe {
self.inner.get().write(ptr::null_mut());
@@ -352,7 +352,7 @@ impl ShrinkablePageRange {
/// Make sure that the given pages are allocated and mapped.
///
/// Must not be called from an atomic context.
- pub(crate) fn use_range(&self, start: usize, end: usize) -> Result<()> {
+ pub(crate) fn use_range(&self, start: usize, end: usize) -> Result {
if start >= end {
return Ok(());
}
@@ -398,7 +398,7 @@ impl ShrinkablePageRange {
///
/// Assumes that `i` is in bounds.
#[cold]
- unsafe fn use_page_slow(&self, i: usize) -> Result<()> {
+ unsafe fn use_page_slow(&self, i: usize) -> Result {
let new_page = Page::alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO)?;
let mm_mutex = self.mm_lock.lock();
diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs
index 5372bfbd93b3..58c84be8ab77 100644
--- a/drivers/android/binder/process.rs
+++ b/drivers/android/binder/process.rs
@@ -548,7 +548,7 @@ impl Process {
}
#[inline(never)]
- pub(crate) fn debug_print_stats(&self, m: &SeqFile, ctx: &Context) -> Result<()> {
+ pub(crate) fn debug_print_stats(&self, m: &SeqFile, ctx: &Context) -> Result {
seq_print!(m, "proc {}\n", self.pid_in_current_ns());
seq_print!(m, "context {}\n", &*ctx.name);
@@ -596,7 +596,7 @@ impl Process {
}
#[inline(never)]
- pub(crate) fn debug_print(&self, m: &SeqFile, ctx: &Context, print_all: bool) -> Result<()> {
+ pub(crate) fn debug_print(&self, m: &SeqFile, ctx: &Context, print_all: bool) -> Result {
seq_print!(m, "proc {}\n", self.pid_in_current_ns());
seq_print!(m, "context {}\n", &*ctx.name);
@@ -686,8 +686,16 @@ impl Process {
pub(crate) fn get_work_or_register<'a>(
&'a self,
thread: &'a Arc<Thread>,
+ thread_has_deferred_work: bool,
) -> GetWorkOrRegister<'a> {
let mut inner = self.inner.lock();
+
+ if thread_has_deferred_work && !inner.work.is_empty() {
+ if let Some(work) = thread.pop_work_even_if_deferred() {
+ return GetWorkOrRegister::Work(work);
+ }
+ }
+
// Try to get work from the process queue.
if let Some(work) = inner.work.pop_front() {
return GetWorkOrRegister::Work(work);
@@ -1208,11 +1216,10 @@ impl Process {
{
let inner = self.inner.lock();
- for (node_ptr, node) in &inner.nodes {
- if *node_ptr > ptr {
- node.populate_debug_info(&mut out, &inner);
- break;
- }
+ // cursor_lower_bound retrieves the "key" passed or the next existing larger key
+ if let Some(cursor) = inner.nodes.cursor_lower_bound(&(ptr + 1)) {
+ let (_, node) = cursor.current();
+ node.populate_debug_info(&mut out, &inner);
}
}
diff --git a/drivers/android/binder/range_alloc/array.rs b/drivers/android/binder/range_alloc/array.rs
index 081d19b09d4b..71bf49f9db0d 100644
--- a/drivers/android/binder/range_alloc/array.rs
+++ b/drivers/android/binder/range_alloc/array.rs
@@ -61,7 +61,7 @@ impl<T> ArrayRangeAllocator<T> {
self.ranges.len() == self.ranges.capacity()
}
- pub(crate) fn debug_print(&self, m: &SeqFile) -> Result<()> {
+ pub(crate) fn debug_print(&self, m: &SeqFile) -> Result {
for range in &self.ranges {
seq_print!(
m,
diff --git a/drivers/android/binder/range_alloc/mod.rs b/drivers/android/binder/range_alloc/mod.rs
index 1f4734468ff1..bb6e0ec9650e 100644
--- a/drivers/android/binder/range_alloc/mod.rs
+++ b/drivers/android/binder/range_alloc/mod.rs
@@ -141,7 +141,7 @@ impl<T> RangeAllocator<T> {
}
}
- pub(crate) fn debug_print(&self, m: &SeqFile) -> Result<()> {
+ pub(crate) fn debug_print(&self, m: &SeqFile) -> Result {
match &self.inner {
Impl::Empty(_size) => Ok(()),
Impl::Array(array) => array.debug_print(m),
diff --git a/drivers/android/binder/range_alloc/tree.rs b/drivers/android/binder/range_alloc/tree.rs
index 48796fcdb362..058ff7498fa5 100644
--- a/drivers/android/binder/range_alloc/tree.rs
+++ b/drivers/android/binder/range_alloc/tree.rs
@@ -111,7 +111,7 @@ impl<T> TreeRangeAllocator<T> {
.count()
}
- pub(crate) fn debug_print(&self, m: &SeqFile) -> Result<()> {
+ pub(crate) fn debug_print(&self, m: &SeqFile) -> Result {
for desc in self.tree.values() {
let state = match &desc.state {
Some(state) => &state.0,
diff --git a/drivers/android/binder/rust_binder_main.rs b/drivers/android/binder/rust_binder_main.rs
index 955c4c348f73..92bf33f9ff1c 100644
--- a/drivers/android/binder/rust_binder_main.rs
+++ b/drivers/android/binder/rust_binder_main.rs
@@ -81,7 +81,7 @@ mod binderfs {
module! {
type: BinderModule,
- name: "rust_binder",
+ name: "binder",
authors: ["Wedson Almeida Filho", "Alice Ryhl"],
description: "Android Binder",
license: "GPL",
@@ -158,7 +158,7 @@ trait DeliverToRead: ListArcSafe + Send + Sync {
/// Generally only set to true for non-oneway transactions.
fn should_sync_wakeup(&self) -> bool;
- fn debug_print(&self, m: &SeqFile, prefix: &str, transaction_prefix: &str) -> Result<()>;
+ fn debug_print(&self, m: &SeqFile, prefix: &str, transaction_prefix: &str) -> Result;
}
// Wrapper around a `DeliverToRead` with linked list links.
@@ -274,7 +274,7 @@ impl DeliverToRead for DeliverCode {
false
}
- fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> {
+ fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result {
seq_print!(m, "{}", prefix);
if self.skip.load(Relaxed) {
seq_print!(m, "(skipped) ");
@@ -545,7 +545,7 @@ unsafe extern "C" fn rust_binder_transactions_show(
0
}
-fn rust_binder_transactions_show_impl(m: &SeqFile) -> Result<()> {
+fn rust_binder_transactions_show_impl(m: &SeqFile) -> Result {
seq_print!(m, "binder transactions:\n");
let contexts = context::get_all_contexts()?;
for ctx in contexts {
@@ -558,7 +558,7 @@ fn rust_binder_transactions_show_impl(m: &SeqFile) -> Result<()> {
Ok(())
}
-fn rust_binder_stats_show_impl(m: &SeqFile) -> Result<()> {
+fn rust_binder_stats_show_impl(m: &SeqFile) -> Result {
seq_print!(m, "binder stats:\n");
stats::GLOBAL_STATS.debug_print("", m);
let contexts = context::get_all_contexts()?;
@@ -572,7 +572,7 @@ fn rust_binder_stats_show_impl(m: &SeqFile) -> Result<()> {
Ok(())
}
-fn rust_binder_state_show_impl(m: &SeqFile) -> Result<()> {
+fn rust_binder_state_show_impl(m: &SeqFile) -> Result {
seq_print!(m, "binder state:\n");
let contexts = context::get_all_contexts()?;
for ctx in contexts {
@@ -585,7 +585,7 @@ fn rust_binder_state_show_impl(m: &SeqFile) -> Result<()> {
Ok(())
}
-fn rust_binder_proc_show_impl(m: &SeqFile, pid: Pid) -> Result<()> {
+fn rust_binder_proc_show_impl(m: &SeqFile, pid: Pid) -> Result {
seq_print!(m, "binder proc state:\n");
let contexts = context::get_all_contexts()?;
for ctx in contexts {
diff --git a/drivers/android/binder/rust_binderfs.c b/drivers/android/binder/rust_binderfs.c
index 300cc65562d1..acc83a179f38 100644
--- a/drivers/android/binder/rust_binderfs.c
+++ b/drivers/android/binder/rust_binderfs.c
@@ -49,7 +49,7 @@ DEFINE_SHOW_ATTRIBUTE(rust_binder_transactions);
DEFINE_SHOW_ATTRIBUTE(rust_binder_proc);
char *rust_binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES;
-module_param_named(rust_devices, rust_binder_devices_param, charp, 0444);
+module_param_named(devices, rust_binder_devices_param, charp, 0444);
extern u32 rust_binder_debug_mask;
module_param_named(debug_mask, rust_binder_debug_mask, uint, 0644);
@@ -72,6 +72,7 @@ struct binder_features {
bool oneway_spam_detection;
bool extended_error;
bool freeze_notification;
+ bool transaction_report;
};
static const struct constant_table binderfs_param_stats[] = {
@@ -89,6 +90,7 @@ static struct binder_features binder_features = {
.oneway_spam_detection = true,
.extended_error = true,
.freeze_notification = true,
+ .transaction_report = true,
};
static inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb)
@@ -566,6 +568,12 @@ static int init_binder_features(struct super_block *sb)
if (IS_ERR(dentry))
return PTR_ERR(dentry);
+ dentry = rust_binderfs_create_file(dir, "transaction_report",
+ &binder_features_fops,
+ &binder_features.transaction_report);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+
return 0;
}
diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs
index 18a14aa8a835..edafce806d27 100644
--- a/drivers/android/binder/thread.rs
+++ b/drivers/android/binder/thread.rs
@@ -481,7 +481,7 @@ impl Thread {
}
#[inline(never)]
- pub(crate) fn debug_print(self: &Arc<Self>, m: &SeqFile, print_all: bool) -> Result<()> {
+ pub(crate) fn debug_print(self: &Arc<Self>, m: &SeqFile, print_all: bool) -> Result {
let inner = self.inner.lock();
if print_all || inner.current_transaction.is_some() || !inner.work_list.is_empty() {
@@ -584,9 +584,21 @@ impl Thread {
// mangled symbol names.
#[export_name = "rust_binder_wait"]
fn get_work(self: &Arc<Self>, wait: bool) -> Result<Option<DLArc<dyn DeliverToRead>>> {
+ let thread_has_deferred_work;
+
// Try to get work from the thread's work queue, using only a local lock.
{
let mut inner = self.inner.lock();
+
+ // The process_work_list boolean is used to make us go to sleep even if there is work
+ // in the thread todo-list, but it doesn't apply to the process todo-list. Furthermore,
+ // work in the thread todo-list must still be delivered before the process list.
+ //
+ // Thus, in some scenarios we must return the thread work now even if we were requested
+ // to wait. Adjust `process_work_list` to `true` accordingly.
+ inner.process_work_list |= inner.looper_need_return;
+ inner.process_work_list |= !wait;
+
if let Some(work) = inner.pop_work() {
return Ok(Some(work));
}
@@ -594,18 +606,26 @@ impl Thread {
drop(inner);
return Ok(self.process.get_work());
}
+
+ // Note that if the thread list is empty, then the call to `pop_work()` has changed
+ // `process_work_list` back to `false` even if we set it to `true` above.
+ thread_has_deferred_work = !inner.work_list.is_empty();
}
// If the caller doesn't want to wait, try to grab work from the process queue.
//
// We know nothing will have been queued directly to the thread queue because it is not in
- // a transaction and it is not in the process' ready list.
+ // a transaction and it is not in the process' ready list. We also know the thread list has
+ // no deferred work due to the `inner.process_work_list |= !wait` call above.
if !wait {
return self.process.get_work().ok_or(EAGAIN).map(Some);
}
// Get work from the process queue. If none is available, atomically register as ready.
- let reg = match self.process.get_work_or_register(self) {
+ let reg = match self
+ .process
+ .get_work_or_register(self, thread_has_deferred_work)
+ {
GetWorkOrRegister::Work(work) => return Ok(Some(work)),
GetWorkOrRegister::Register(reg) => reg,
};
@@ -621,14 +641,18 @@ impl Thread {
inner.looper_flags &= !(LooperFlag::Waiting | LooperFlag::WaitingProc);
if signal_pending || inner.looper_need_return {
- // We need to return now. We need to pull the thread off the list of ready threads
- // (by dropping `reg`), then check the state again after it's off the list to
- // ensure that something was not queued in the meantime. If something has been
- // queued, we just return it (instead of the error).
+ // We need to return now.
+ //
+ // We need to pull the thread off the list of ready threads (by dropping `reg`),
+ // then check the state again after it's off the list to ensure that something was
+ // not queued in the meantime. If something has been queued (or if there is
+ // deferred work), we just return it (instead of the error).
drop(inner);
drop(reg);
- let res = match self.inner.lock().pop_work() {
+ inner = self.inner.lock();
+ inner.process_work_list = true;
+ let res = match inner.pop_work() {
Some(work) => Ok(Some(work)),
None if signal_pending => Err(EINTR),
None => Ok(None),
@@ -686,6 +710,12 @@ impl Thread {
self.inner.lock().push_return_work(reply);
}
+ pub(crate) fn pop_work_even_if_deferred(&self) -> Option<DLArc<dyn DeliverToRead>> {
+ let mut thread_inner = self.inner.lock();
+ thread_inner.process_work_list = true;
+ thread_inner.pop_work()
+ }
+
fn translate_object(
&self,
obj_index: usize,
@@ -1250,7 +1280,7 @@ impl Thread {
cmd: u32,
reader: &mut UserSliceReader,
info: &mut TransactionInfo,
- ) -> Result<()> {
+ ) -> Result {
let td = match cmd {
BC_TRANSACTION | BC_REPLY => {
reader.read::<BinderTransactionData>()?.with_buffers_size(0)
@@ -1281,7 +1311,7 @@ impl Thread {
}
#[inline(never)]
- fn transaction(self: &Arc<Self>, cmd: u32, reader: &mut UserSliceReader) -> Result<()> {
+ fn transaction(self: &Arc<Self>, cmd: u32, reader: &mut UserSliceReader) -> Result {
let mut info = TransactionInfo::zeroed();
self.read_transaction_info(cmd, reader, &mut info)?;
@@ -1410,8 +1440,16 @@ impl Thread {
let process = orig.from.process.clone();
let allow_fds = orig.flags.contains(TransactionFlag::AcceptFds);
let reply = Transaction::new_reply(self, process, info, allow_fds)?;
- // Not notifying: Reply to current thread.
- let _ = self.inner.lock().push_work(completion);
+ {
+ let mut inner = self.inner.lock();
+ if info.flags.contains(TransactionFlag::DeferComplete) {
+ // The flag is set. Perform a deferred push so that `read` can wait for the
+ // next incoming transaction without a userspace roundtrip.
+ inner.push_work_deferred(completion);
+ } else {
+ let _ = inner.push_work(completion);
+ }
+ }
orig.from.deliver_reply(Ok(reply), &orig, None);
Ok(())
})()
@@ -1678,7 +1716,7 @@ impl Thread {
self.unwind_transaction_stack();
// Cancel all pending work items.
- while let Ok(Some(work)) = self.get_work_local(false) {
+ while let Some(work) = self.pop_work_even_if_deferred() {
work.into_arc().cancel();
}
}
@@ -1738,7 +1776,7 @@ impl DeliverToRead for ThreadError {
false
}
- fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> {
+ fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result {
seq_print!(
m,
"{}transaction error: {}\n",
diff --git a/drivers/android/binder/transaction.rs b/drivers/android/binder/transaction.rs
index 245f1556b5db..888a9e0eba8f 100644
--- a/drivers/android/binder/transaction.rs
+++ b/drivers/android/binder/transaction.rs
@@ -39,6 +39,7 @@ kernel::impl_flags!(
AcceptFds = TF_ACCEPT_FDS,
ClearBuf = TF_CLEAR_BUF,
UpdateTxn = TF_UPDATE_TXN,
+ DeferComplete = TF_DEFER_COMPLETE,
}
);
@@ -576,7 +577,7 @@ impl DeliverToRead for Transaction {
!self.flags.is_oneway()
}
- fn debug_print(&self, m: &SeqFile, _prefix: &str, tprefix: &str) -> Result<()> {
+ fn debug_print(&self, m: &SeqFile, _prefix: &str, tprefix: &str) -> Result {
self.debug_print_inner(m, tprefix);
Ok(())
}
diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h
deleted file mode 100644
index d6f1f6f2d00e..000000000000
--- a/drivers/android/binder_alloc.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2017 Google, Inc.
- */
-
-#ifndef _LINUX_BINDER_ALLOC_H
-#define _LINUX_BINDER_ALLOC_H
-
-#include <linux/rbtree.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/rtmutex.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/list_lru.h>
-#include <uapi/linux/android/binder.h>
-
-struct binder_transaction;
-
-/**
- * struct binder_buffer - buffer used for binder transactions
- * @entry: entry alloc->buffers
- * @rb_node: node for allocated_buffers/free_buffers rb trees
- * @free: %true if buffer is free
- * @clear_on_free: %true if buffer must be zeroed after use
- * @allow_user_free: %true if user is allowed to free buffer
- * @async_transaction: %true if buffer is in use for an async txn
- * @oneway_spam_suspect: %true if total async allocate size just exceed
- * spamming detect threshold
- * @debug_id: unique ID for debugging
- * @transaction: pointer to associated struct binder_transaction
- * @target_node: struct binder_node associated with this buffer
- * @data_size: size of @transaction data
- * @offsets_size: size of array of offsets
- * @extra_buffers_size: size of space for other objects (like sg lists)
- * @user_data: user pointer to base of buffer space
- * @pid: pid to attribute the buffer to (caller)
- *
- * Bookkeeping structure for binder transaction buffers
- */
-struct binder_buffer {
- 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;
- unsigned clear_on_free:1;
- unsigned allow_user_free:1;
- unsigned async_transaction:1;
- unsigned oneway_spam_suspect:1;
- unsigned debug_id:27;
- struct binder_transaction *transaction;
- struct binder_node *target_node;
- size_t data_size;
- size_t offsets_size;
- size_t extra_buffers_size;
- unsigned long user_data;
- int pid;
-};
-
-/**
- * struct binder_shrinker_mdata - binder metadata used to reclaim pages
- * @lru: LRU entry in binder_freelist
- * @alloc: binder_alloc owning the page to reclaim
- * @page_index: offset in @alloc->pages[] into the page to reclaim
- */
-struct binder_shrinker_mdata {
- struct list_head lru;
- struct binder_alloc *alloc;
- unsigned long page_index;
-};
-
-static inline struct list_head *page_to_lru(struct page *p)
-{
- struct binder_shrinker_mdata *mdata;
-
- mdata = (struct binder_shrinker_mdata *)page_private(p);
-
- return &mdata->lru;
-}
-
-/**
- * struct binder_alloc - per-binder proc state for binder allocator
- * @mutex: protects binder_alloc fields
- * @mm: copy of task->mm (invariant after open)
- * @vm_start: 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
- * sorted by size
- * @allocated_buffers: rb tree of allocated buffers sorted by address
- * @free_async_space: VA space available for async buffers. This is
- * initialized at mmap time to 1/2 the full VA space
- * @pages: array of struct page *
- * @freelist: lru list to use for free pages (invariant after init)
- * @buffer_size: size of address space specified via mmap
- * @pid: pid for associated binder_proc (invariant after init)
- * @pages_high: high watermark of offset in @pages
- * @mapped: whether the vm area is mapped, each binder instance is
- * allowed a single mapping throughout its lifetime
- * @oneway_spam_detected: %true if oneway spam detection fired, clear that
- * flag once the async buffer has returned to a healthy state
- *
- * Bookkeeping structure for per-proc address space management for binder
- * buffers. It is normally initialized during binder_init() and binder_mmap()
- * calls. The address space is used for both user-visible buffers and for
- * struct binder_buffer objects used to track the user buffers
- */
-struct binder_alloc {
- struct mutex mutex;
- struct mm_struct *mm;
- unsigned long vm_start;
- struct list_head buffers;
- struct rb_root free_buffers;
- struct rb_root allocated_buffers;
- size_t free_async_space;
- struct page **pages;
- struct list_lru *freelist;
- size_t buffer_size;
- int pid;
- size_t pages_high;
- bool mapped;
- bool oneway_spam_detected;
-};
-
-enum lru_status binder_alloc_free_page(struct list_head *item,
- struct list_lru_one *lru,
- void *cb_arg);
-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);
-void binder_alloc_init(struct binder_alloc *alloc);
-int binder_alloc_shrinker_init(void);
-void binder_alloc_shrinker_exit(void);
-void binder_alloc_vma_close(struct binder_alloc *alloc);
-struct binder_buffer *
-binder_alloc_prepare_to_free(struct binder_alloc *alloc,
- unsigned long user_ptr);
-void binder_alloc_free_buf(struct binder_alloc *alloc,
- struct binder_buffer *buffer);
-int binder_alloc_mmap_handler(struct binder_alloc *alloc,
- struct vm_area_struct *vma);
-void binder_alloc_deferred_release(struct binder_alloc *alloc);
-int binder_alloc_get_allocated_count(struct binder_alloc *alloc);
-void binder_alloc_print_allocated(struct seq_file *m,
- struct binder_alloc *alloc);
-void binder_alloc_print_pages(struct seq_file *m,
- struct binder_alloc *alloc);
-
-/**
- * binder_alloc_get_free_async_space() - get free space available for async
- * @alloc: binder_alloc for this proc
- *
- * Return: the bytes remaining in the address-space for async transactions
- */
-static inline size_t
-binder_alloc_get_free_async_space(struct binder_alloc *alloc)
-{
- guard(mutex)(&alloc->mutex);
- return alloc->free_async_space;
-}
-
-unsigned long
-binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc,
- struct binder_buffer *buffer,
- binder_size_t buffer_offset,
- const void __user *from,
- size_t bytes);
-
-int binder_alloc_copy_to_buffer(struct binder_alloc *alloc,
- struct binder_buffer *buffer,
- binder_size_t buffer_offset,
- void *src,
- size_t bytes);
-
-int binder_alloc_copy_from_buffer(struct binder_alloc *alloc,
- void *dest,
- struct binder_buffer *buffer,
- binder_size_t buffer_offset,
- size_t bytes);
-
-#if IS_ENABLED(CONFIG_KUNIT)
-void __binder_alloc_init(struct binder_alloc *alloc, struct list_lru *freelist);
-size_t binder_alloc_buffer_size(struct binder_alloc *alloc,
- struct binder_buffer *buffer);
-#endif
-
-#endif /* _LINUX_BINDER_ALLOC_H */
-
diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h
deleted file mode 100644
index 342574bfd28a..000000000000
--- a/drivers/android/binder_internal.h
+++ /dev/null
@@ -1,597 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-#ifndef _LINUX_BINDER_INTERNAL_H
-#define _LINUX_BINDER_INTERNAL_H
-
-#include <linux/fs.h>
-#include <linux/list.h>
-#include <linux/miscdevice.h>
-#include <linux/mutex.h>
-#include <linux/refcount.h>
-#include <linux/stddef.h>
-#include <linux/types.h>
-#include <linux/uidgid.h>
-#include <uapi/linux/android/binderfs.h>
-#include "binder_alloc.h"
-#include "dbitmap.h"
-
-struct binder_context {
- struct binder_node *binder_context_mgr_node;
- struct mutex context_mgr_node_lock;
- kuid_t binder_context_mgr_uid;
- const char *name;
-};
-
-/**
- * struct binder_device - information about a binder device node
- * @hlist: list of binder devices
- * @miscdev: information about a binder character device node
- * @context: binder context information
- * @binderfs_inode: This is the inode of the root dentry of the super block
- * belonging to a binderfs mount.
- */
-struct binder_device {
- struct hlist_node hlist;
- struct miscdevice miscdev;
- struct binder_context context;
- struct inode *binderfs_inode;
- refcount_t ref;
-};
-
-/**
- * binderfs_mount_opts - mount options for binderfs
- * @max: maximum number of allocatable binderfs binder devices
- * @stats_mode: enable binder stats in binderfs.
- */
-struct binderfs_mount_opts {
- int max;
- int stats_mode;
-};
-
-/**
- * binderfs_info - information about a binderfs mount
- * @ipc_ns: The ipc namespace the binderfs mount belongs to.
- * @control_dentry: This records the dentry of this binderfs mount
- * binder-control device.
- * @root_uid: uid that needs to be used when a new binder device is
- * created.
- * @root_gid: gid that needs to be used when a new binder device is
- * created.
- * @mount_opts: The mount options in use.
- * @device_count: The current number of allocated binder devices.
- * @proc_log_dir: Pointer to the directory dentry containing process-specific
- * logs.
- */
-struct binderfs_info {
- struct ipc_namespace *ipc_ns;
- struct dentry *control_dentry;
- kuid_t root_uid;
- kgid_t root_gid;
- struct binderfs_mount_opts mount_opts;
- int device_count;
- struct dentry *proc_log_dir;
-};
-
-extern const struct file_operations binder_fops;
-
-extern char *binder_devices_param;
-
-#ifdef CONFIG_ANDROID_BINDERFS
-extern bool is_binderfs_device(const struct inode *inode);
-extern struct dentry *binderfs_create_file(struct dentry *dir, const char *name,
- const struct file_operations *fops,
- void *data);
-#else
-static inline bool is_binderfs_device(const struct inode *inode)
-{
- return false;
-}
-static inline struct dentry *binderfs_create_file(struct dentry *dir,
- const char *name,
- const struct file_operations *fops,
- void *data)
-{
- return NULL;
-}
-#endif
-
-#ifdef CONFIG_ANDROID_BINDERFS
-extern int __init init_binderfs(void);
-#else
-static inline int __init init_binderfs(void)
-{
- return 0;
-}
-#endif
-
-struct binder_debugfs_entry {
- const char *name;
- umode_t mode;
- const struct file_operations *fops;
- void *data;
-};
-
-extern const struct binder_debugfs_entry binder_debugfs_entries[];
-
-#define binder_for_each_debugfs_entry(entry) \
- for ((entry) = binder_debugfs_entries; \
- (entry)->name; \
- (entry)++)
-
-enum binder_stat_types {
- BINDER_STAT_PROC,
- BINDER_STAT_THREAD,
- BINDER_STAT_NODE,
- BINDER_STAT_REF,
- BINDER_STAT_DEATH,
- BINDER_STAT_TRANSACTION,
- BINDER_STAT_TRANSACTION_COMPLETE,
- BINDER_STAT_FREEZE,
- BINDER_STAT_COUNT
-};
-
-struct binder_stats {
- atomic_t br[_IOC_NR(BR_CLEAR_FREEZE_NOTIFICATION_DONE) + 1];
- atomic_t bc[_IOC_NR(BC_FREEZE_NOTIFICATION_DONE) + 1];
- atomic_t obj_created[BINDER_STAT_COUNT];
- atomic_t obj_deleted[BINDER_STAT_COUNT];
-};
-
-/**
- * struct binder_work - work enqueued on a worklist
- * @entry: node enqueued on list
- * @type: type of work to be performed
- *
- * There are separate work lists for proc, thread, and node (async).
- */
-struct binder_work {
- struct list_head entry;
-
- enum binder_work_type {
- BINDER_WORK_TRANSACTION = 1,
- BINDER_WORK_TRANSACTION_COMPLETE,
- BINDER_WORK_TRANSACTION_PENDING,
- BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT,
- BINDER_WORK_RETURN_ERROR,
- BINDER_WORK_NODE,
- BINDER_WORK_DEAD_BINDER,
- BINDER_WORK_DEAD_BINDER_AND_CLEAR,
- BINDER_WORK_CLEAR_DEATH_NOTIFICATION,
- BINDER_WORK_FROZEN_BINDER,
- BINDER_WORK_CLEAR_FREEZE_NOTIFICATION,
- } type;
-};
-
-struct binder_error {
- struct binder_work work;
- uint32_t cmd;
-};
-
-/**
- * struct binder_node - binder node bookkeeping
- * @debug_id: unique ID for debugging
- * (invariant after initialized)
- * @lock: lock for node fields
- * @work: worklist element for node work
- * (protected by @proc->inner_lock)
- * @rb_node: element for proc->nodes tree
- * (protected by @proc->inner_lock)
- * @dead_node: element for binder_dead_nodes list
- * (protected by binder_dead_nodes_lock)
- * @proc: binder_proc that owns this node
- * (invariant after initialized)
- * @refs: list of references on this node
- * (protected by @lock)
- * @internal_strong_refs: used to take strong references when
- * initiating a transaction
- * (protected by @proc->inner_lock if @proc
- * and by @lock)
- * @local_weak_refs: weak user refs from local process
- * (protected by @proc->inner_lock if @proc
- * and by @lock)
- * @local_strong_refs: strong user refs from local process
- * (protected by @proc->inner_lock if @proc
- * and by @lock)
- * @tmp_refs: temporary kernel refs
- * (protected by @proc->inner_lock while @proc
- * is valid, and by binder_dead_nodes_lock
- * if @proc is NULL. During inc/dec and node release
- * it is also protected by @lock to provide safety
- * as the node dies and @proc becomes NULL)
- * @ptr: userspace pointer for node
- * (invariant, no lock needed)
- * @cookie: userspace cookie for node
- * (invariant, no lock needed)
- * @has_strong_ref: userspace notified of strong ref
- * (protected by @proc->inner_lock if @proc
- * and by @lock)
- * @pending_strong_ref: userspace has acked notification of strong ref
- * (protected by @proc->inner_lock if @proc
- * and by @lock)
- * @has_weak_ref: userspace notified of weak ref
- * (protected by @proc->inner_lock if @proc
- * and by @lock)
- * @pending_weak_ref: userspace has acked notification of weak ref
- * (protected by @proc->inner_lock if @proc
- * and by @lock)
- * @has_async_transaction: async transaction to node in progress
- * (protected by @lock)
- * @accept_fds: file descriptor operations supported for node
- * (invariant after initialized)
- * @min_priority: minimum scheduling priority
- * (invariant after initialized)
- * @txn_security_ctx: require sender's security context
- * (invariant after initialized)
- * @async_todo: list of async work items
- * (protected by @proc->inner_lock)
- *
- * Bookkeeping structure for binder nodes.
- */
-struct binder_node {
- int debug_id;
- spinlock_t lock;
- struct binder_work work;
- union {
- struct rb_node rb_node;
- struct hlist_node dead_node;
- };
- struct binder_proc *proc;
- struct hlist_head refs;
- int internal_strong_refs;
- int local_weak_refs;
- int local_strong_refs;
- int tmp_refs;
- binder_uintptr_t ptr;
- binder_uintptr_t cookie;
- struct {
- /*
- * bitfield elements protected by
- * proc inner_lock
- */
- u8 has_strong_ref:1;
- u8 pending_strong_ref:1;
- u8 has_weak_ref:1;
- u8 pending_weak_ref:1;
- };
- struct {
- /*
- * invariant after initialization
- */
- u8 accept_fds:1;
- u8 txn_security_ctx:1;
- u8 min_priority;
- };
- bool has_async_transaction;
- struct list_head async_todo;
-};
-
-struct binder_ref_death {
- /**
- * @work: worklist element for death notifications
- * (protected by inner_lock of the proc that
- * this ref belongs to)
- */
- struct binder_work work;
- binder_uintptr_t cookie;
-};
-
-struct binder_ref_freeze {
- struct binder_work work;
- binder_uintptr_t cookie;
- bool is_frozen:1;
- bool sent:1;
- bool resend:1;
-};
-
-/**
- * struct binder_ref_data - binder_ref counts and id
- * @debug_id: unique ID for the ref
- * @desc: unique userspace handle for ref
- * @strong: strong ref count (debugging only if not locked)
- * @weak: weak ref count (debugging only if not locked)
- *
- * Structure to hold ref count and ref id information. Since
- * the actual ref can only be accessed with a lock, this structure
- * is used to return information about the ref to callers of
- * ref inc/dec functions.
- */
-struct binder_ref_data {
- int debug_id;
- uint32_t desc;
- int strong;
- int weak;
-};
-
-/**
- * struct binder_ref - struct to track references on nodes
- * @data: binder_ref_data containing id, handle, and current refcounts
- * @rb_node_desc: node for lookup by @data.desc in proc's rb_tree
- * @rb_node_node: node for lookup by @node in proc's rb_tree
- * @node_entry: list entry for node->refs list in target node
- * (protected by @node->lock)
- * @proc: binder_proc containing ref
- * @node: binder_node of target node. When cleaning up a
- * ref for deletion in binder_cleanup_ref, a non-NULL
- * @node indicates the node must be freed
- * @death: pointer to death notification (ref_death) if requested
- * (protected by @node->lock)
- * @freeze: pointer to freeze notification (ref_freeze) if requested
- * (protected by @node->lock)
- *
- * Structure to track references from procA to target node (on procB). This
- * structure is unsafe to access without holding @proc->outer_lock.
- */
-struct binder_ref {
- /* Lookups needed: */
- /* node + proc => ref (transaction) */
- /* desc + proc => ref (transaction, inc/dec ref) */
- /* node => refs + procs (proc exit) */
- struct binder_ref_data data;
- struct rb_node rb_node_desc;
- struct rb_node rb_node_node;
- struct hlist_node node_entry;
- struct binder_proc *proc;
- struct binder_node *node;
- struct binder_ref_death *death;
- struct binder_ref_freeze *freeze;
-};
-
-/**
- * struct binder_proc - binder process bookkeeping
- * @proc_node: element for binder_procs list
- * @threads: rbtree of binder_threads in this proc
- * (protected by @inner_lock)
- * @nodes: rbtree of binder nodes associated with
- * this proc ordered by node->ptr
- * (protected by @inner_lock)
- * @refs_by_desc: rbtree of refs ordered by ref->desc
- * (protected by @outer_lock)
- * @refs_by_node: rbtree of refs ordered by ref->node
- * (protected by @outer_lock)
- * @waiting_threads: threads currently waiting for proc work
- * (protected by @inner_lock)
- * @pid PID of group_leader of process
- * (invariant after initialized)
- * @tsk task_struct for group_leader of process
- * (invariant after initialized)
- * @cred struct cred associated with the `struct file`
- * in binder_open()
- * (invariant after initialized)
- * @deferred_work_node: element for binder_deferred_list
- * (protected by binder_deferred_lock)
- * @deferred_work: bitmap of deferred work to perform
- * (protected by binder_deferred_lock)
- * @outstanding_txns: number of transactions to be transmitted before
- * processes in freeze_wait are woken up
- * (protected by @inner_lock)
- * @is_dead: process is dead and awaiting free
- * when outstanding transactions are cleaned up
- * (protected by @inner_lock)
- * @is_frozen: process is frozen and unable to service
- * binder transactions
- * (protected by @inner_lock)
- * @sync_recv: process received sync transactions since last frozen
- * bit 0: received sync transaction after being frozen
- * bit 1: new pending sync transaction during freezing
- * (protected by @inner_lock)
- * @async_recv: process received async transactions since last frozen
- * (protected by @inner_lock)
- * @freeze_wait: waitqueue of processes waiting for all outstanding
- * transactions to be processed
- * (protected by @inner_lock)
- * @dmap dbitmap to manage available reference descriptors
- * (protected by @outer_lock)
- * @todo: list of work for this process
- * (protected by @inner_lock)
- * @stats: per-process binder statistics
- * (atomics, no lock needed)
- * @delivered_death: list of delivered death notification
- * (protected by @inner_lock)
- * @delivered_freeze: list of delivered freeze notification
- * (protected by @inner_lock)
- * @max_threads: cap on number of binder threads
- * (protected by @inner_lock)
- * @requested_threads: number of binder threads requested but not
- * yet started. In current implementation, can
- * only be 0 or 1.
- * (protected by @inner_lock)
- * @requested_threads_started: number binder threads started
- * (protected by @inner_lock)
- * @tmp_ref: temporary reference to indicate proc is in use
- * (protected by @inner_lock)
- * @default_priority: default scheduler priority
- * (invariant after initialized)
- * @debugfs_entry: debugfs node
- * @alloc: binder allocator bookkeeping
- * @context: binder_context for this proc
- * (invariant after initialized)
- * @inner_lock: can nest under outer_lock and/or node lock
- * @outer_lock: no nesting under innor or node lock
- * Lock order: 1) outer, 2) node, 3) inner
- * @binderfs_entry: process-specific binderfs log file
- * @oneway_spam_detection_enabled: process enabled oneway spam detection
- * or not
- *
- * Bookkeeping structure for binder processes
- */
-struct binder_proc {
- struct hlist_node proc_node;
- struct rb_root threads;
- struct rb_root nodes;
- struct rb_root refs_by_desc;
- struct rb_root refs_by_node;
- struct list_head waiting_threads;
- int pid;
- struct task_struct *tsk;
- const struct cred *cred;
- struct hlist_node deferred_work_node;
- int deferred_work;
- int outstanding_txns;
- bool is_dead;
- bool is_frozen;
- bool sync_recv;
- bool async_recv;
- wait_queue_head_t freeze_wait;
- struct dbitmap dmap;
- struct list_head todo;
- struct binder_stats stats;
- struct list_head delivered_death;
- struct list_head delivered_freeze;
- u32 max_threads;
- int requested_threads;
- int requested_threads_started;
- int tmp_ref;
- long default_priority;
- struct dentry *debugfs_entry;
- struct binder_alloc alloc;
- struct binder_context *context;
- spinlock_t inner_lock;
- spinlock_t outer_lock;
- struct dentry *binderfs_entry;
- bool oneway_spam_detection_enabled;
-};
-
-/**
- * struct binder_thread - binder thread bookkeeping
- * @proc: binder process for this thread
- * (invariant after initialization)
- * @rb_node: element for proc->threads rbtree
- * (protected by @proc->inner_lock)
- * @waiting_thread_node: element for @proc->waiting_threads list
- * (protected by @proc->inner_lock)
- * @pid: PID for this thread
- * (invariant after initialization)
- * @looper: bitmap of looping state
- * (only accessed by this thread)
- * @looper_needs_return: looping thread needs to exit driver
- * (no lock needed)
- * @transaction_stack: stack of in-progress transactions for this thread
- * (protected by @proc->inner_lock)
- * @todo: list of work to do for this thread
- * (protected by @proc->inner_lock)
- * @process_todo: whether work in @todo should be processed
- * (protected by @proc->inner_lock)
- * @return_error: transaction errors reported by this thread
- * (only accessed by this thread)
- * @reply_error: transaction errors reported by target thread
- * (protected by @proc->inner_lock)
- * @ee: extended error information from this thread
- * (protected by @proc->inner_lock)
- * @wait: wait queue for thread work
- * @stats: per-thread statistics
- * (atomics, no lock needed)
- * @tmp_ref: temporary reference to indicate thread is in use
- * (atomic since @proc->inner_lock cannot
- * always be acquired)
- * @is_dead: thread is dead and awaiting free
- * when outstanding transactions are cleaned up
- * (protected by @proc->inner_lock)
- *
- * Bookkeeping structure for binder threads.
- */
-struct binder_thread {
- struct binder_proc *proc;
- struct rb_node rb_node;
- struct list_head waiting_thread_node;
- int pid;
- int looper; /* only modified by this thread */
- bool looper_need_return; /* can be written by other thread */
- struct binder_transaction *transaction_stack;
- struct list_head todo;
- bool process_todo;
- struct binder_error return_error;
- struct binder_error reply_error;
- struct binder_extended_error ee;
- wait_queue_head_t wait;
- struct binder_stats stats;
- atomic_t tmp_ref;
- bool is_dead;
-};
-
-/**
- * struct binder_txn_fd_fixup - transaction fd fixup list element
- * @fixup_entry: list entry
- * @file: struct file to be associated with new fd
- * @offset: offset in buffer data to this fixup
- * @target_fd: fd to use by the target to install @file
- *
- * List element for fd fixups in a transaction. Since file
- * descriptors need to be allocated in the context of the
- * target process, we pass each fd to be processed in this
- * struct.
- */
-struct binder_txn_fd_fixup {
- struct list_head fixup_entry;
- struct file *file;
- size_t offset;
- int target_fd;
-};
-
-struct binder_transaction {
- int debug_id;
- struct binder_work work;
- struct binder_thread *from;
- pid_t from_pid;
- pid_t from_tid;
- struct binder_transaction *from_parent;
- struct binder_proc *to_proc;
- struct binder_thread *to_thread;
- struct binder_transaction *to_parent;
- unsigned is_async:1;
- unsigned is_reply:1;
-
- struct binder_buffer *buffer;
- unsigned int code;
- unsigned int flags;
- long priority;
- long saved_priority;
- kuid_t sender_euid;
- ktime_t start_time;
- struct list_head fd_fixups;
- binder_uintptr_t security_ctx;
- /**
- * @lock: protects @from, @to_proc, and @to_thread
- *
- * @from, @to_proc, and @to_thread can be set to NULL
- * during thread teardown
- */
- spinlock_t lock;
-};
-
-/**
- * struct binder_object - union of flat binder object types
- * @hdr: generic object header
- * @fbo: binder object (nodes and refs)
- * @fdo: file descriptor object
- * @bbo: binder buffer pointer
- * @fdao: file descriptor array
- *
- * Used for type-independent object copies
- */
-struct binder_object {
- union {
- struct binder_object_header hdr;
- struct flat_binder_object fbo;
- struct binder_fd_object fdo;
- struct binder_buffer_object bbo;
- struct binder_fd_array_object fdao;
- };
-};
-
-/**
- * Add a binder device to binder_devices
- * @device: the new binder device to add to the global list
- */
-void binder_add_device(struct binder_device *device);
-
-/**
- * Remove a binder device to binder_devices
- * @device: the binder device to remove from the global list
- */
-void binder_remove_device(struct binder_device *device);
-
-#if IS_ENABLED(CONFIG_KUNIT)
-vm_fault_t binder_vm_fault(struct vm_fault *vmf);
-#endif
-
-#endif /* _LINUX_BINDER_INTERNAL_H */
diff --git a/drivers/android/binder_netlink.c b/drivers/android/binder_netlink.c
deleted file mode 100644
index 81e8432b5904..000000000000
--- a/drivers/android/binder_netlink.c
+++ /dev/null
@@ -1,32 +0,0 @@
-// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
-/* Do not edit directly, auto-generated from: */
-/* Documentation/netlink/specs/binder.yaml */
-/* YNL-GEN kernel source */
-/* To regenerate run: tools/net/ynl/ynl-regen.sh */
-
-#include <net/netlink.h>
-#include <net/genetlink.h>
-
-#include "binder_netlink.h"
-
-#include <uapi/linux/android/binder_netlink.h>
-
-/* Ops table for binder */
-static const struct genl_split_ops binder_nl_ops[] = {
-};
-
-static const struct genl_multicast_group binder_nl_mcgrps[] = {
- [BINDER_NLGRP_REPORT] = { "report", },
-};
-
-struct genl_family binder_nl_family __ro_after_init = {
- .name = BINDER_FAMILY_NAME,
- .version = BINDER_FAMILY_VERSION,
- .netnsok = true,
- .parallel_ops = true,
- .module = THIS_MODULE,
- .split_ops = binder_nl_ops,
- .n_split_ops = ARRAY_SIZE(binder_nl_ops),
- .mcgrps = binder_nl_mcgrps,
- .n_mcgrps = ARRAY_SIZE(binder_nl_mcgrps),
-};
diff --git a/drivers/android/binder_netlink.h b/drivers/android/binder_netlink.h
deleted file mode 100644
index 57399942a5e3..000000000000
--- a/drivers/android/binder_netlink.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
-/* Do not edit directly, auto-generated from: */
-/* Documentation/netlink/specs/binder.yaml */
-/* YNL-GEN kernel header */
-/* To regenerate run: tools/net/ynl/ynl-regen.sh */
-
-#ifndef _LINUX_BINDER_GEN_H
-#define _LINUX_BINDER_GEN_H
-
-#include <net/netlink.h>
-#include <net/genetlink.h>
-
-#include <uapi/linux/android/binder_netlink.h>
-
-enum {
- BINDER_NLGRP_REPORT,
-};
-
-extern struct genl_family binder_nl_family;
-
-#endif /* _LINUX_BINDER_GEN_H */
diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h
deleted file mode 100644
index fa5eb61cf580..000000000000
--- a/drivers/android/binder_trace.h
+++ /dev/null
@@ -1,448 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2012 Google, Inc.
- */
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM binder
-
-#if !defined(_BINDER_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _BINDER_TRACE_H
-
-#include <linux/tracepoint.h>
-
-struct binder_buffer;
-struct binder_node;
-struct binder_proc;
-struct binder_alloc;
-struct binder_ref_data;
-struct binder_thread;
-struct binder_transaction;
-
-TRACE_EVENT(binder_ioctl,
- TP_PROTO(unsigned int cmd, unsigned long arg),
- TP_ARGS(cmd, arg),
-
- TP_STRUCT__entry(
- __field(unsigned int, cmd)
- __field(unsigned long, arg)
- ),
- TP_fast_assign(
- __entry->cmd = cmd;
- __entry->arg = arg;
- ),
- TP_printk("cmd=0x%x arg=0x%lx", __entry->cmd, __entry->arg)
-);
-
-DECLARE_EVENT_CLASS(binder_function_return_class,
- TP_PROTO(int ret),
- TP_ARGS(ret),
- TP_STRUCT__entry(
- __field(int, ret)
- ),
- TP_fast_assign(
- __entry->ret = ret;
- ),
- TP_printk("ret=%d", __entry->ret)
-);
-
-#define DEFINE_BINDER_FUNCTION_RETURN_EVENT(name) \
-DEFINE_EVENT(binder_function_return_class, name, \
- TP_PROTO(int ret), \
- TP_ARGS(ret))
-
-DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_ioctl_done);
-DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_write_done);
-DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_read_done);
-
-TRACE_EVENT(binder_wait_for_work,
- TP_PROTO(bool proc_work, bool transaction_stack, bool thread_todo),
- TP_ARGS(proc_work, transaction_stack, thread_todo),
-
- TP_STRUCT__entry(
- __field(bool, proc_work)
- __field(bool, transaction_stack)
- __field(bool, thread_todo)
- ),
- TP_fast_assign(
- __entry->proc_work = proc_work;
- __entry->transaction_stack = transaction_stack;
- __entry->thread_todo = thread_todo;
- ),
- TP_printk("proc_work=%d transaction_stack=%d thread_todo=%d",
- __entry->proc_work, __entry->transaction_stack,
- __entry->thread_todo)
-);
-
-TRACE_EVENT(binder_txn_latency_free,
- TP_PROTO(struct binder_transaction *t,
- int from_proc, int from_thread,
- int to_proc, int to_thread),
- TP_ARGS(t, from_proc, from_thread, to_proc, to_thread),
- TP_STRUCT__entry(
- __field(int, debug_id)
- __field(int, from_proc)
- __field(int, from_thread)
- __field(int, to_proc)
- __field(int, to_thread)
- __field(unsigned int, code)
- __field(unsigned int, flags)
- ),
- TP_fast_assign(
- __entry->debug_id = t->debug_id;
- __entry->from_proc = from_proc;
- __entry->from_thread = from_thread;
- __entry->to_proc = to_proc;
- __entry->to_thread = to_thread;
- __entry->code = t->code;
- __entry->flags = t->flags;
- ),
- TP_printk("transaction=%d from %d:%d to %d:%d flags=0x%x code=0x%x",
- __entry->debug_id, __entry->from_proc, __entry->from_thread,
- __entry->to_proc, __entry->to_thread, __entry->code,
- __entry->flags)
-);
-
-TRACE_EVENT(binder_transaction,
- TP_PROTO(bool reply, struct binder_transaction *t,
- struct binder_node *target_node),
- TP_ARGS(reply, t, target_node),
- TP_STRUCT__entry(
- __field(int, debug_id)
- __field(int, target_node)
- __field(int, to_proc)
- __field(int, to_thread)
- __field(int, reply)
- __field(unsigned int, code)
- __field(unsigned int, flags)
- ),
- TP_fast_assign(
- __entry->debug_id = t->debug_id;
- __entry->target_node = target_node ? target_node->debug_id : 0;
- __entry->to_proc = t->to_proc->pid;
- __entry->to_thread = t->to_thread ? t->to_thread->pid : 0;
- __entry->reply = reply;
- __entry->code = t->code;
- __entry->flags = t->flags;
- ),
- TP_printk("transaction=%d dest_node=%d dest_proc=%d dest_thread=%d reply=%d flags=0x%x code=0x%x",
- __entry->debug_id, __entry->target_node,
- __entry->to_proc, __entry->to_thread,
- __entry->reply, __entry->flags, __entry->code)
-);
-
-TRACE_EVENT(binder_transaction_received,
- TP_PROTO(struct binder_transaction *t),
- TP_ARGS(t),
-
- TP_STRUCT__entry(
- __field(int, debug_id)
- ),
- TP_fast_assign(
- __entry->debug_id = t->debug_id;
- ),
- TP_printk("transaction=%d", __entry->debug_id)
-);
-
-TRACE_EVENT(binder_transaction_node_to_ref,
- TP_PROTO(struct binder_transaction *t, struct binder_node *node,
- struct binder_ref_data *rdata),
- TP_ARGS(t, node, rdata),
-
- TP_STRUCT__entry(
- __field(int, debug_id)
- __field(int, node_debug_id)
- __field(binder_uintptr_t, node_ptr)
- __field(int, ref_debug_id)
- __field(uint32_t, ref_desc)
- ),
- TP_fast_assign(
- __entry->debug_id = t->debug_id;
- __entry->node_debug_id = node->debug_id;
- __entry->node_ptr = node->ptr;
- __entry->ref_debug_id = rdata->debug_id;
- __entry->ref_desc = rdata->desc;
- ),
- TP_printk("transaction=%d node=%d src_ptr=0x%016llx ==> dest_ref=%d dest_desc=%d",
- __entry->debug_id, __entry->node_debug_id,
- (u64)__entry->node_ptr,
- __entry->ref_debug_id, __entry->ref_desc)
-);
-
-TRACE_EVENT(binder_transaction_ref_to_node,
- TP_PROTO(struct binder_transaction *t, struct binder_node *node,
- struct binder_ref_data *rdata),
- TP_ARGS(t, node, rdata),
-
- TP_STRUCT__entry(
- __field(int, debug_id)
- __field(int, ref_debug_id)
- __field(uint32_t, ref_desc)
- __field(int, node_debug_id)
- __field(binder_uintptr_t, node_ptr)
- ),
- TP_fast_assign(
- __entry->debug_id = t->debug_id;
- __entry->ref_debug_id = rdata->debug_id;
- __entry->ref_desc = rdata->desc;
- __entry->node_debug_id = node->debug_id;
- __entry->node_ptr = node->ptr;
- ),
- TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%016llx",
- __entry->debug_id, __entry->node_debug_id,
- __entry->ref_debug_id, __entry->ref_desc,
- (u64)__entry->node_ptr)
-);
-
-TRACE_EVENT(binder_transaction_ref_to_ref,
- TP_PROTO(struct binder_transaction *t, struct binder_node *node,
- struct binder_ref_data *src_ref,
- struct binder_ref_data *dest_ref),
- TP_ARGS(t, node, src_ref, dest_ref),
-
- TP_STRUCT__entry(
- __field(int, debug_id)
- __field(int, node_debug_id)
- __field(int, src_ref_debug_id)
- __field(uint32_t, src_ref_desc)
- __field(int, dest_ref_debug_id)
- __field(uint32_t, dest_ref_desc)
- ),
- TP_fast_assign(
- __entry->debug_id = t->debug_id;
- __entry->node_debug_id = node->debug_id;
- __entry->src_ref_debug_id = src_ref->debug_id;
- __entry->src_ref_desc = src_ref->desc;
- __entry->dest_ref_debug_id = dest_ref->debug_id;
- __entry->dest_ref_desc = dest_ref->desc;
- ),
- TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ref=%d dest_desc=%d",
- __entry->debug_id, __entry->node_debug_id,
- __entry->src_ref_debug_id, __entry->src_ref_desc,
- __entry->dest_ref_debug_id, __entry->dest_ref_desc)
-);
-
-TRACE_EVENT(binder_transaction_fd_send,
- TP_PROTO(struct binder_transaction *t, int fd, size_t offset),
- TP_ARGS(t, fd, offset),
-
- TP_STRUCT__entry(
- __field(int, debug_id)
- __field(int, fd)
- __field(size_t, offset)
- ),
- TP_fast_assign(
- __entry->debug_id = t->debug_id;
- __entry->fd = fd;
- __entry->offset = offset;
- ),
- TP_printk("transaction=%d src_fd=%d offset=%zu",
- __entry->debug_id, __entry->fd, __entry->offset)
-);
-
-TRACE_EVENT(binder_transaction_fd_recv,
- TP_PROTO(struct binder_transaction *t, int fd, size_t offset),
- TP_ARGS(t, fd, offset),
-
- TP_STRUCT__entry(
- __field(int, debug_id)
- __field(int, fd)
- __field(size_t, offset)
- ),
- TP_fast_assign(
- __entry->debug_id = t->debug_id;
- __entry->fd = fd;
- __entry->offset = offset;
- ),
- TP_printk("transaction=%d dest_fd=%d offset=%zu",
- __entry->debug_id, __entry->fd, __entry->offset)
-);
-
-DECLARE_EVENT_CLASS(binder_buffer_class,
- TP_PROTO(struct binder_buffer *buf),
- TP_ARGS(buf),
- TP_STRUCT__entry(
- __field(int, debug_id)
- __field(size_t, data_size)
- __field(size_t, offsets_size)
- __field(size_t, extra_buffers_size)
- ),
- TP_fast_assign(
- __entry->debug_id = buf->debug_id;
- __entry->data_size = buf->data_size;
- __entry->offsets_size = buf->offsets_size;
- __entry->extra_buffers_size = buf->extra_buffers_size;
- ),
- TP_printk("transaction=%d data_size=%zd offsets_size=%zd extra_buffers_size=%zd",
- __entry->debug_id, __entry->data_size, __entry->offsets_size,
- __entry->extra_buffers_size)
-);
-
-DEFINE_EVENT(binder_buffer_class, binder_transaction_alloc_buf,
- TP_PROTO(struct binder_buffer *buffer),
- TP_ARGS(buffer));
-
-DEFINE_EVENT(binder_buffer_class, binder_transaction_buffer_release,
- TP_PROTO(struct binder_buffer *buffer),
- TP_ARGS(buffer));
-
-DEFINE_EVENT(binder_buffer_class, binder_transaction_failed_buffer_release,
- TP_PROTO(struct binder_buffer *buffer),
- TP_ARGS(buffer));
-
-DEFINE_EVENT(binder_buffer_class, binder_transaction_update_buffer_release,
- TP_PROTO(struct binder_buffer *buffer),
- TP_ARGS(buffer));
-
-TRACE_EVENT(binder_update_page_range,
- TP_PROTO(struct binder_alloc *alloc, bool allocate,
- unsigned long start, unsigned long end),
- TP_ARGS(alloc, allocate, start, end),
- TP_STRUCT__entry(
- __field(int, proc)
- __field(bool, allocate)
- __field(size_t, offset)
- __field(size_t, size)
- ),
- TP_fast_assign(
- __entry->proc = alloc->pid;
- __entry->allocate = allocate;
- __entry->offset = start - alloc->vm_start;
- __entry->size = end - start;
- ),
- TP_printk("proc=%d allocate=%d offset=%zu size=%zu",
- __entry->proc, __entry->allocate,
- __entry->offset, __entry->size)
-);
-
-DECLARE_EVENT_CLASS(binder_lru_page_class,
- TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
- TP_ARGS(alloc, page_index),
- TP_STRUCT__entry(
- __field(int, proc)
- __field(size_t, page_index)
- ),
- TP_fast_assign(
- __entry->proc = alloc->pid;
- __entry->page_index = page_index;
- ),
- TP_printk("proc=%d page_index=%zu",
- __entry->proc, __entry->page_index)
-);
-
-DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_start,
- TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
- TP_ARGS(alloc, page_index));
-
-DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_end,
- TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
- TP_ARGS(alloc, page_index));
-
-DEFINE_EVENT(binder_lru_page_class, binder_free_lru_start,
- TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
- TP_ARGS(alloc, page_index));
-
-DEFINE_EVENT(binder_lru_page_class, binder_free_lru_end,
- TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
- TP_ARGS(alloc, page_index));
-
-DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_start,
- TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
- TP_ARGS(alloc, page_index));
-
-DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_end,
- TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
- TP_ARGS(alloc, page_index));
-
-DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_start,
- TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
- TP_ARGS(alloc, page_index));
-
-DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_end,
- TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
- TP_ARGS(alloc, page_index));
-
-DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_start,
- TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
- TP_ARGS(alloc, page_index));
-
-DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_end,
- TP_PROTO(const struct binder_alloc *alloc, size_t page_index),
- TP_ARGS(alloc, page_index));
-
-TRACE_EVENT(binder_command,
- TP_PROTO(uint32_t cmd),
- TP_ARGS(cmd),
- TP_STRUCT__entry(
- __field(uint32_t, cmd)
- ),
- TP_fast_assign(
- __entry->cmd = cmd;
- ),
- TP_printk("cmd=0x%x %s",
- __entry->cmd,
- _IOC_NR(__entry->cmd) < ARRAY_SIZE(binder_command_strings) ?
- binder_command_strings[_IOC_NR(__entry->cmd)] :
- "unknown")
-);
-
-TRACE_EVENT(binder_return,
- TP_PROTO(uint32_t cmd),
- TP_ARGS(cmd),
- TP_STRUCT__entry(
- __field(uint32_t, cmd)
- ),
- TP_fast_assign(
- __entry->cmd = cmd;
- ),
- TP_printk("cmd=0x%x %s",
- __entry->cmd,
- _IOC_NR(__entry->cmd) < ARRAY_SIZE(binder_return_strings) ?
- binder_return_strings[_IOC_NR(__entry->cmd)] :
- "unknown")
-);
-
-TRACE_EVENT(binder_netlink_report,
- TP_PROTO(const char *context,
- struct binder_transaction *t,
- u32 data_size,
- u32 error),
- TP_ARGS(context, t, data_size, error),
- TP_STRUCT__entry(
- __field(const char *, context)
- __field(u32, error)
- __field(int, from_pid)
- __field(int, from_tid)
- __field(int, to_pid)
- __field(int, to_tid)
- __field(bool, is_reply)
- __field(unsigned int, flags)
- __field(unsigned int, code)
- __field(size_t, data_size)
- ),
- TP_fast_assign(
- __entry->context = context;
- __entry->error = error;
- __entry->from_pid = t->from_pid;
- __entry->from_tid = t->from_tid;
- __entry->to_pid = t->to_proc ? t->to_proc->pid : 0;
- __entry->to_tid = t->to_thread ? t->to_thread->pid : 0;
- __entry->is_reply = t->is_reply;
- __entry->flags = t->flags;
- __entry->code = t->code;
- __entry->data_size = data_size;
- ),
- TP_printk("from %d:%d to %d:%d context=%s error=%d is_reply=%d flags=0x%x code=0x%x size=%zu",
- __entry->from_pid, __entry->from_tid,
- __entry->to_pid, __entry->to_tid,
- __entry->context, __entry->error, __entry->is_reply,
- __entry->flags, __entry->code, __entry->data_size)
-);
-
-#endif /* _BINDER_TRACE_H */
-
-#undef TRACE_INCLUDE_PATH
-#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_PATH .
-#define TRACE_INCLUDE_FILE binder_trace
-#include <trace/define_trace.h>
diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c
deleted file mode 100644
index 361d69f756f5..000000000000
--- a/drivers/android/binderfs.c
+++ /dev/null
@@ -1,786 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <linux/compiler_types.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/fsnotify.h>
-#include <linux/gfp.h>
-#include <linux/idr.h>
-#include <linux/init.h>
-#include <linux/ipc_namespace.h>
-#include <linux/kdev_t.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/namei.h>
-#include <linux/magic.h>
-#include <linux/major.h>
-#include <linux/miscdevice.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/mount.h>
-#include <linux/fs_parser.h>
-#include <linux/sched.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/spinlock_types.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/uaccess.h>
-#include <linux/user_namespace.h>
-#include <linux/xarray.h>
-#include <uapi/linux/android/binder.h>
-#include <uapi/linux/android/binderfs.h>
-
-#include "binder_internal.h"
-
-#define FIRST_INODE 1
-#define SECOND_INODE 2
-#define INODE_OFFSET 3
-#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)
-
-static dev_t binderfs_dev;
-static DEFINE_MUTEX(binderfs_minors_mutex);
-static DEFINE_IDA(binderfs_minors);
-
-enum binderfs_param {
- Opt_max,
- Opt_stats_mode,
-};
-
-enum binderfs_stats_mode {
- binderfs_stats_mode_unset,
- binderfs_stats_mode_global,
-};
-
-struct binder_features {
- bool oneway_spam_detection;
- bool extended_error;
- bool freeze_notification;
- bool transaction_report;
-};
-
-static const struct constant_table binderfs_param_stats[] = {
- { "global", binderfs_stats_mode_global },
- {}
-};
-
-static const struct fs_parameter_spec binderfs_fs_parameters[] = {
- fsparam_u32("max", Opt_max),
- fsparam_enum("stats", Opt_stats_mode, binderfs_param_stats),
- {}
-};
-
-static struct binder_features binder_features = {
- .oneway_spam_detection = true,
- .extended_error = true,
- .freeze_notification = true,
- .transaction_report = true,
-};
-
-static inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb)
-{
- return sb->s_fs_info;
-}
-
-bool is_binderfs_device(const struct inode *inode)
-{
- if (inode->i_sb->s_magic == BINDERFS_SUPER_MAGIC)
- return true;
-
- return false;
-}
-
-/**
- * binderfs_binder_device_create - allocate inode from super block of a
- * binderfs mount
- * @ref_inode: inode from which the super block will be taken
- * @userp: buffer to copy information about new device for userspace to
- * @req: struct binderfs_device as copied from userspace
- *
- * This function allocates a new binder_device and reserves a new minor
- * number for it.
- * Minor numbers are limited and tracked globally in binderfs_minors. The
- * function will stash a struct binder_device for the specific binder
- * device in i_private of the inode.
- * It will go on to allocate a new inode from the super block of the
- * filesystem mount, stash a struct binder_device in its i_private field
- * and attach a dentry to that inode.
- *
- * Return: 0 on success, negative errno on failure
- */
-static int binderfs_binder_device_create(struct inode *ref_inode,
- struct binderfs_device __user *userp,
- struct binderfs_device *req)
-{
- int minor, ret;
- struct dentry *dentry, *root;
- struct binder_device *device;
- char *name = NULL;
- struct inode *inode = NULL;
- struct super_block *sb = ref_inode->i_sb;
- struct binderfs_info *info = sb->s_fs_info;
-#if defined(CONFIG_IPC_NS)
- bool use_reserve = (info->ipc_ns == &init_ipc_ns);
-#else
- bool use_reserve = true;
-#endif
-
- /* Reserve new minor number for the new device. */
- mutex_lock(&binderfs_minors_mutex);
- if (++info->device_count <= info->mount_opts.max)
- minor = ida_alloc_max(&binderfs_minors,
- use_reserve ? BINDERFS_MAX_MINOR - 1 :
- BINDERFS_MAX_MINOR_CAPPED - 1,
- GFP_KERNEL);
- else
- minor = -ENOSPC;
- if (minor < 0) {
- --info->device_count;
- mutex_unlock(&binderfs_minors_mutex);
- return minor;
- }
- mutex_unlock(&binderfs_minors_mutex);
-
- ret = -ENOMEM;
- device = kzalloc_obj(*device);
- if (!device)
- goto err;
-
- inode = new_inode(sb);
- if (!inode)
- goto err;
-
- inode->i_ino = minor + INODE_OFFSET;
- simple_inode_init_ts(inode);
- init_special_inode(inode, S_IFCHR | 0600,
- MKDEV(MAJOR(binderfs_dev), minor));
- inode->i_fop = &binder_fops;
- inode->i_uid = info->root_uid;
- inode->i_gid = info->root_gid;
-
- req->name[BINDERFS_MAX_NAME] = '\0'; /* NUL-terminate */
- name = kstrdup(req->name, GFP_KERNEL);
- if (!name)
- goto err;
-
- refcount_set(&device->ref, 1);
- device->binderfs_inode = inode;
- device->context.binder_context_mgr_uid = INVALID_UID;
- device->context.name = name;
- device->miscdev.name = name;
- device->miscdev.minor = minor;
- mutex_init(&device->context.context_mgr_node_lock);
-
- req->major = MAJOR(binderfs_dev);
- req->minor = minor;
-
- if (userp && copy_to_user(userp, req, sizeof(*req))) {
- ret = -EFAULT;
- goto err;
- }
-
- root = sb->s_root;
- dentry = simple_start_creating(root, name);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto err;
- }
- inode->i_private = device;
- d_make_persistent(dentry, inode);
- fsnotify_create(root->d_inode, dentry);
- simple_done_creating(dentry);
-
- binder_add_device(device);
-
- return 0;
-
-err:
- kfree(name);
- kfree(device);
- mutex_lock(&binderfs_minors_mutex);
- --info->device_count;
- ida_free(&binderfs_minors, minor);
- mutex_unlock(&binderfs_minors_mutex);
- iput(inode);
-
- return ret;
-}
-
-/**
- * binder_ctl_ioctl - handle binder device node allocation requests
- * @file: The file pointer for the binder-control device node.
- * @cmd: The ioctl command.
- * @arg: The ioctl argument.
- *
- * The request handler for the binder-control device. All requests operate on
- * the binderfs mount the binder-control device resides in:
- * - BINDER_CTL_ADD
- * Allocate a new binder device.
- *
- * Return: %0 on success, negative errno on failure.
- */
-static long binder_ctl_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- int ret = -EINVAL;
- struct inode *inode = file_inode(file);
- struct binderfs_device __user *device = (struct binderfs_device __user *)arg;
- struct binderfs_device device_req;
-
- switch (cmd) {
- case BINDER_CTL_ADD:
- ret = copy_from_user(&device_req, device, sizeof(device_req));
- if (ret) {
- ret = -EFAULT;
- break;
- }
-
- ret = binderfs_binder_device_create(inode, device, &device_req);
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-static void binderfs_evict_inode(struct inode *inode)
-{
- struct binder_device *device = inode->i_private;
- struct binderfs_info *info = BINDERFS_SB(inode->i_sb);
-
- clear_inode(inode);
-
- if (!S_ISCHR(inode->i_mode) || !device)
- return;
-
- mutex_lock(&binderfs_minors_mutex);
- --info->device_count;
- ida_free(&binderfs_minors, device->miscdev.minor);
- mutex_unlock(&binderfs_minors_mutex);
-
- if (refcount_dec_and_test(&device->ref)) {
- binder_remove_device(device);
- kfree(device->context.name);
- kfree(device);
- }
-}
-
-static int binderfs_fs_context_parse_param(struct fs_context *fc,
- struct fs_parameter *param)
-{
- int opt;
- struct binderfs_mount_opts *ctx = fc->fs_private;
- struct fs_parse_result result;
-
- opt = fs_parse(fc, binderfs_fs_parameters, param, &result);
- if (opt < 0)
- return opt;
-
- switch (opt) {
- case Opt_max:
- if (result.uint_32 > BINDERFS_MAX_MINOR)
- return invalfc(fc, "Bad value for '%s'", param->key);
-
- ctx->max = result.uint_32;
- break;
- case Opt_stats_mode:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- ctx->stats_mode = result.uint_32;
- break;
- default:
- return invalfc(fc, "Unsupported parameter '%s'", param->key);
- }
-
- return 0;
-}
-
-static int binderfs_fs_context_reconfigure(struct fs_context *fc)
-{
- struct binderfs_mount_opts *ctx = fc->fs_private;
- struct binderfs_info *info = BINDERFS_SB(fc->root->d_sb);
-
- if (info->mount_opts.stats_mode != ctx->stats_mode)
- return invalfc(fc, "Binderfs stats mode cannot be changed during a remount");
-
- info->mount_opts.stats_mode = ctx->stats_mode;
- info->mount_opts.max = ctx->max;
- return 0;
-}
-
-static int binderfs_show_options(struct seq_file *seq, struct dentry *root)
-{
- struct binderfs_info *info = BINDERFS_SB(root->d_sb);
-
- if (info->mount_opts.max <= BINDERFS_MAX_MINOR)
- seq_printf(seq, ",max=%d", info->mount_opts.max);
-
- switch (info->mount_opts.stats_mode) {
- case binderfs_stats_mode_unset:
- break;
- case binderfs_stats_mode_global:
- seq_printf(seq, ",stats=global");
- break;
- }
-
- return 0;
-}
-
-static const struct super_operations binderfs_super_ops = {
- .evict_inode = binderfs_evict_inode,
- .show_options = binderfs_show_options,
- .statfs = simple_statfs,
-};
-
-static inline bool is_binderfs_control_device(const struct dentry *dentry)
-{
- struct binderfs_info *info = dentry->d_sb->s_fs_info;
-
- return info->control_dentry == dentry;
-}
-
-static int binderfs_rename(struct mnt_idmap *idmap,
- struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry,
- unsigned int flags)
-{
- if (is_binderfs_control_device(old_dentry) ||
- is_binderfs_control_device(new_dentry))
- return -EPERM;
-
- return simple_rename(idmap, old_dir, old_dentry, new_dir,
- new_dentry, flags);
-}
-
-static int binderfs_unlink(struct inode *dir, struct dentry *dentry)
-{
- if (is_binderfs_control_device(dentry))
- return -EPERM;
-
- return simple_unlink(dir, dentry);
-}
-
-static const struct file_operations binder_ctl_fops = {
- .owner = THIS_MODULE,
- .open = nonseekable_open,
- .unlocked_ioctl = binder_ctl_ioctl,
- .compat_ioctl = binder_ctl_ioctl,
- .llseek = noop_llseek,
-};
-
-/**
- * binderfs_binder_ctl_create - create a new binder-control device
- * @sb: super block of the binderfs mount
- *
- * This function creates a new binder-control device node in the binderfs mount
- * referred to by @sb.
- *
- * Return: 0 on success, negative errno on failure
- */
-static int binderfs_binder_ctl_create(struct super_block *sb)
-{
- int minor, ret;
- struct dentry *dentry;
- struct binder_device *device;
- struct inode *inode = NULL;
- struct dentry *root = sb->s_root;
- struct binderfs_info *info = sb->s_fs_info;
-#if defined(CONFIG_IPC_NS)
- bool use_reserve = (info->ipc_ns == &init_ipc_ns);
-#else
- bool use_reserve = true;
-#endif
-
- device = kzalloc_obj(*device);
- if (!device)
- return -ENOMEM;
-
- ret = -ENOMEM;
- inode = new_inode(sb);
- if (!inode)
- goto out;
-
- /* Reserve a new minor number for the new device. */
- mutex_lock(&binderfs_minors_mutex);
- minor = ida_alloc_max(&binderfs_minors,
- use_reserve ? BINDERFS_MAX_MINOR - 1 :
- BINDERFS_MAX_MINOR_CAPPED - 1,
- GFP_KERNEL);
- mutex_unlock(&binderfs_minors_mutex);
- if (minor < 0) {
- ret = minor;
- goto out;
- }
-
- inode->i_ino = SECOND_INODE;
- simple_inode_init_ts(inode);
- init_special_inode(inode, S_IFCHR | 0600,
- MKDEV(MAJOR(binderfs_dev), minor));
- inode->i_fop = &binder_ctl_fops;
- inode->i_uid = info->root_uid;
- inode->i_gid = info->root_gid;
-
- refcount_set(&device->ref, 1);
- device->binderfs_inode = inode;
- device->miscdev.minor = minor;
-
- dentry = d_alloc_name(root, "binder-control");
- if (!dentry)
- goto out;
-
- inode->i_private = device;
- info->control_dentry = dentry;
- d_make_persistent(dentry, inode);
- dput(dentry);
-
- return 0;
-
-out:
- kfree(device);
- iput(inode);
-
- return ret;
-}
-
-static const struct inode_operations binderfs_dir_inode_operations = {
- .lookup = simple_lookup,
- .rename = binderfs_rename,
- .unlink = binderfs_unlink,
-};
-
-static struct inode *binderfs_make_inode(struct super_block *sb, int mode)
-{
- struct inode *ret;
-
- ret = new_inode(sb);
- if (ret) {
- ret->i_ino = iunique(sb, BINDERFS_MAX_MINOR + INODE_OFFSET);
- ret->i_mode = mode;
- simple_inode_init_ts(ret);
- }
- return ret;
-}
-
-struct dentry *binderfs_create_file(struct dentry *parent, const char *name,
- const struct file_operations *fops,
- void *data)
-{
- struct dentry *dentry;
- struct inode *new_inode, *parent_inode;
- struct super_block *sb;
-
- parent_inode = d_inode(parent);
-
- dentry = simple_start_creating(parent, name);
- if (IS_ERR(dentry))
- return dentry;
-
- sb = parent_inode->i_sb;
- new_inode = binderfs_make_inode(sb, S_IFREG | 0444);
- if (!new_inode) {
- simple_done_creating(dentry);
- return ERR_PTR(-ENOMEM);
- }
-
- new_inode->i_fop = fops;
- new_inode->i_private = data;
- d_make_persistent(dentry, new_inode);
- fsnotify_create(parent_inode, dentry);
- simple_done_creating(dentry);
- return dentry; // borrowed
-}
-
-static struct dentry *binderfs_create_dir(struct dentry *parent,
- const char *name)
-{
- struct dentry *dentry;
- struct inode *new_inode, *parent_inode;
- struct super_block *sb;
-
- parent_inode = d_inode(parent);
-
- dentry = simple_start_creating(parent, name);
- if (IS_ERR(dentry))
- return dentry;
-
- sb = parent_inode->i_sb;
- new_inode = binderfs_make_inode(sb, S_IFDIR | 0755);
- if (!new_inode) {
- simple_done_creating(dentry);
- return ERR_PTR(-ENOMEM);
- }
-
- new_inode->i_fop = &simple_dir_operations;
- new_inode->i_op = &simple_dir_inode_operations;
-
- set_nlink(new_inode, 2);
- d_make_persistent(dentry, new_inode);
- inc_nlink(parent_inode);
- fsnotify_mkdir(parent_inode, dentry);
- simple_done_creating(dentry);
- return dentry;
-}
-
-static int binder_features_show(struct seq_file *m, void *unused)
-{
- bool *feature = m->private;
-
- seq_printf(m, "%d\n", *feature);
-
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(binder_features);
-
-static int init_binder_features(struct super_block *sb)
-{
- struct dentry *dentry, *dir;
-
- dir = binderfs_create_dir(sb->s_root, "features");
- if (IS_ERR(dir))
- return PTR_ERR(dir);
-
- dentry = binderfs_create_file(dir, "oneway_spam_detection",
- &binder_features_fops,
- &binder_features.oneway_spam_detection);
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
-
- dentry = binderfs_create_file(dir, "extended_error",
- &binder_features_fops,
- &binder_features.extended_error);
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
-
- dentry = binderfs_create_file(dir, "freeze_notification",
- &binder_features_fops,
- &binder_features.freeze_notification);
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
-
- dentry = binderfs_create_file(dir, "transaction_report",
- &binder_features_fops,
- &binder_features.transaction_report);
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
-
- return 0;
-}
-
-static int init_binder_logs(struct super_block *sb)
-{
- struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir;
- const struct binder_debugfs_entry *db_entry;
- struct binderfs_info *info;
- int ret = 0;
-
- binder_logs_root_dir = binderfs_create_dir(sb->s_root,
- "binder_logs");
- if (IS_ERR(binder_logs_root_dir)) {
- ret = PTR_ERR(binder_logs_root_dir);
- goto out;
- }
-
- binder_for_each_debugfs_entry(db_entry) {
- dentry = binderfs_create_file(binder_logs_root_dir,
- db_entry->name,
- db_entry->fops,
- db_entry->data);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto out;
- }
- }
-
- proc_log_dir = binderfs_create_dir(binder_logs_root_dir, "proc");
- if (IS_ERR(proc_log_dir)) {
- ret = PTR_ERR(proc_log_dir);
- goto out;
- }
- info = sb->s_fs_info;
- info->proc_log_dir = proc_log_dir;
-
-out:
- return ret;
-}
-
-static int binderfs_fill_super(struct super_block *sb, struct fs_context *fc)
-{
- int ret;
- struct binderfs_info *info;
- struct binderfs_mount_opts *ctx = fc->fs_private;
- struct inode *inode = NULL;
- struct binderfs_device device_info = {};
- const char *name;
- size_t len;
-
- sb->s_blocksize = PAGE_SIZE;
- sb->s_blocksize_bits = PAGE_SHIFT;
-
- /*
- * The binderfs filesystem can be mounted by userns root in a
- * non-initial userns. By default such mounts have the SB_I_NODEV flag
- * set in s_iflags to prevent security issues where userns root can
- * just create random device nodes via mknod() since it owns the
- * filesystem mount. But binderfs does not allow to create any files
- * including devices nodes. The only way to create binder devices nodes
- * is through the binder-control device which userns root is explicitly
- * allowed to do. So removing the SB_I_NODEV flag from s_iflags is both
- * necessary and safe.
- */
- sb->s_iflags &= ~SB_I_NODEV;
- sb->s_iflags |= SB_I_NOEXEC;
- sb->s_magic = BINDERFS_SUPER_MAGIC;
- sb->s_op = &binderfs_super_ops;
- sb->s_time_gran = 1;
-
- sb->s_fs_info = kzalloc_obj(struct binderfs_info);
- if (!sb->s_fs_info)
- return -ENOMEM;
- info = sb->s_fs_info;
-
- info->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns);
-
- info->root_gid = make_kgid(sb->s_user_ns, 0);
- if (!gid_valid(info->root_gid))
- info->root_gid = GLOBAL_ROOT_GID;
- info->root_uid = make_kuid(sb->s_user_ns, 0);
- if (!uid_valid(info->root_uid))
- info->root_uid = GLOBAL_ROOT_UID;
- info->mount_opts.max = ctx->max;
- info->mount_opts.stats_mode = ctx->stats_mode;
-
- inode = new_inode(sb);
- if (!inode)
- return -ENOMEM;
-
- inode->i_ino = FIRST_INODE;
- inode->i_fop = &simple_dir_operations;
- inode->i_mode = S_IFDIR | 0755;
- simple_inode_init_ts(inode);
- inode->i_op = &binderfs_dir_inode_operations;
- set_nlink(inode, 2);
-
- sb->s_root = d_make_root(inode);
- if (!sb->s_root)
- return -ENOMEM;
-
- ret = binderfs_binder_ctl_create(sb);
- if (ret)
- return ret;
-
- name = binder_devices_param;
- for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) {
- strscpy(device_info.name, name, len + 1);
- ret = binderfs_binder_device_create(inode, NULL, &device_info);
- if (ret)
- return ret;
- name += len;
- if (*name == ',')
- name++;
- }
-
- ret = init_binder_features(sb);
- if (ret)
- return ret;
-
- if (info->mount_opts.stats_mode == binderfs_stats_mode_global)
- return init_binder_logs(sb);
-
- return 0;
-}
-
-static int binderfs_fs_context_get_tree(struct fs_context *fc)
-{
- return get_tree_nodev(fc, binderfs_fill_super);
-}
-
-static void binderfs_fs_context_free(struct fs_context *fc)
-{
- struct binderfs_mount_opts *ctx = fc->fs_private;
-
- kfree(ctx);
-}
-
-static const struct fs_context_operations binderfs_fs_context_ops = {
- .free = binderfs_fs_context_free,
- .get_tree = binderfs_fs_context_get_tree,
- .parse_param = binderfs_fs_context_parse_param,
- .reconfigure = binderfs_fs_context_reconfigure,
-};
-
-static int binderfs_init_fs_context(struct fs_context *fc)
-{
- struct binderfs_mount_opts *ctx;
-
- ctx = kzalloc_obj(struct binderfs_mount_opts);
- if (!ctx)
- return -ENOMEM;
-
- ctx->max = BINDERFS_MAX_MINOR;
- ctx->stats_mode = binderfs_stats_mode_unset;
-
- fc->fs_private = ctx;
- fc->ops = &binderfs_fs_context_ops;
-
- 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_anon_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 = binderfs_kill_super,
- .fs_flags = FS_USERNS_MOUNT,
-};
-
-int __init init_binderfs(void)
-{
- int ret;
- const char *name;
- size_t len;
-
- /* Verify that the default binderfs device names are valid. */
- name = binder_devices_param;
- for (len = strcspn(name, ","); len > 0; len = strcspn(name, ",")) {
- if (len > BINDERFS_MAX_NAME)
- return -E2BIG;
- name += len;
- if (*name == ',')
- name++;
- }
-
- /* Allocate new major number for binderfs. */
- ret = alloc_chrdev_region(&binderfs_dev, 0, BINDERFS_MAX_MINOR,
- "binder");
- if (ret)
- return ret;
-
- ret = register_filesystem(&binder_fs_type);
- if (ret) {
- unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR);
- return ret;
- }
-
- return ret;
-}
diff --git a/drivers/android/dbitmap.h b/drivers/android/dbitmap.h
deleted file mode 100644
index c7299ce8b374..000000000000
--- a/drivers/android/dbitmap.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright 2024 Google LLC
- *
- * dbitmap - dynamically sized bitmap library.
- *
- * Used by the binder driver to optimize the allocation of the smallest
- * available descriptor ID. Each bit in the bitmap represents the state
- * of an ID.
- *
- * A dbitmap can grow or shrink as needed. This part has been designed
- * considering that users might need to briefly release their locks in
- * order to allocate memory for the new bitmap. These operations then,
- * are verified to determine if the grow or shrink is sill valid.
- *
- * This library does not provide protection against concurrent access
- * by itself. Binder uses the proc->outer_lock for this purpose.
- */
-
-#ifndef _LINUX_DBITMAP_H
-#define _LINUX_DBITMAP_H
-#include <linux/bitmap.h>
-
-#define NBITS_MIN BITS_PER_TYPE(unsigned long)
-
-struct dbitmap {
- unsigned int nbits;
- unsigned long *map;
-};
-
-static inline int dbitmap_enabled(struct dbitmap *dmap)
-{
- return !!dmap->nbits;
-}
-
-static inline void dbitmap_free(struct dbitmap *dmap)
-{
- dmap->nbits = 0;
- kfree(dmap->map);
- dmap->map = NULL;
-}
-
-/* Returns the nbits that a dbitmap can shrink to, 0 if not possible. */
-static inline unsigned int dbitmap_shrink_nbits(struct dbitmap *dmap)
-{
- unsigned int bit;
-
- if (dmap->nbits <= NBITS_MIN)
- return 0;
-
- /*
- * Determine if the bitmap can shrink based on the position of
- * its last set bit. If the bit is within the first quarter of
- * the bitmap then shrinking is possible. In this case, the
- * bitmap should shrink to half its current size.
- */
- bit = find_last_bit(dmap->map, dmap->nbits);
- if (bit < (dmap->nbits >> 2))
- return dmap->nbits >> 1;
-
- /* find_last_bit() returns dmap->nbits when no bits are set. */
- if (bit == dmap->nbits)
- return NBITS_MIN;
-
- return 0;
-}
-
-/* Replace the internal bitmap with a new one of different size */
-static inline void
-dbitmap_replace(struct dbitmap *dmap, unsigned long *new, unsigned int nbits)
-{
- bitmap_copy(new, dmap->map, min(dmap->nbits, nbits));
- kfree(dmap->map);
- dmap->map = new;
- dmap->nbits = nbits;
-}
-
-static inline void
-dbitmap_shrink(struct dbitmap *dmap, unsigned long *new, unsigned int nbits)
-{
- if (!new)
- return;
-
- /*
- * Verify that shrinking to @nbits is still possible. The @new
- * bitmap might have been allocated without locks, so this call
- * could now be outdated. In this case, free @new and move on.
- */
- if (!dbitmap_enabled(dmap) || dbitmap_shrink_nbits(dmap) != nbits) {
- kfree(new);
- return;
- }
-
- dbitmap_replace(dmap, new, nbits);
-}
-
-/* Returns the nbits that a dbitmap can grow to. */
-static inline unsigned int dbitmap_grow_nbits(struct dbitmap *dmap)
-{
- return dmap->nbits << 1;
-}
-
-static inline void
-dbitmap_grow(struct dbitmap *dmap, unsigned long *new, unsigned int nbits)
-{
- /*
- * Verify that growing to @nbits is still possible. The @new
- * bitmap might have been allocated without locks, so this call
- * could now be outdated. In this case, free @new and move on.
- */
- if (!dbitmap_enabled(dmap) || nbits <= dmap->nbits) {
- kfree(new);
- return;
- }
-
- /*
- * Check for ENOMEM after confirming the grow operation is still
- * required. This ensures we only disable the dbitmap when it's
- * necessary. Once the dbitmap is disabled, binder will fallback
- * to slow_desc_lookup_olocked().
- */
- if (!new) {
- dbitmap_free(dmap);
- return;
- }
-
- dbitmap_replace(dmap, new, nbits);
-}
-
-/*
- * Finds and sets the next zero bit in the bitmap. Upon success @bit
- * is populated with the index and 0 is returned. Otherwise, -ENOSPC
- * is returned to indicate that a dbitmap_grow() is needed.
- */
-static inline int
-dbitmap_acquire_next_zero_bit(struct dbitmap *dmap, unsigned long offset,
- unsigned long *bit)
-{
- unsigned long n;
-
- n = find_next_zero_bit(dmap->map, dmap->nbits, offset);
- if (n == dmap->nbits)
- return -ENOSPC;
-
- *bit = n;
- set_bit(n, dmap->map);
-
- return 0;
-}
-
-static inline void
-dbitmap_clear_bit(struct dbitmap *dmap, unsigned long bit)
-{
- clear_bit(bit, dmap->map);
-}
-
-static inline int dbitmap_init(struct dbitmap *dmap)
-{
- dmap->map = bitmap_zalloc(NBITS_MIN, GFP_KERNEL);
- if (!dmap->map) {
- dmap->nbits = 0;
- return -ENOMEM;
- }
-
- dmap->nbits = NBITS_MIN;
-
- return 0;
-}
-#endif
diff --git a/drivers/android/tests/.kunitconfig b/drivers/android/tests/.kunitconfig
deleted file mode 100644
index 39b76bab9d9a..000000000000
--- a/drivers/android/tests/.kunitconfig
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Copyright 2025 Google LLC.
-#
-
-CONFIG_KUNIT=y
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ANDROID_BINDER_ALLOC_KUNIT_TEST=y
diff --git a/drivers/android/tests/Makefile b/drivers/android/tests/Makefile
deleted file mode 100644
index 27268418eb03..000000000000
--- a/drivers/android/tests/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Copyright 2025 Google LLC.
-#
-
-obj-$(CONFIG_ANDROID_BINDER_ALLOC_KUNIT_TEST) += binder_alloc_kunit.o
diff --git a/drivers/android/tests/binder_alloc_kunit.c b/drivers/android/tests/binder_alloc_kunit.c
deleted file mode 100644
index 7f9cc003bbe3..000000000000
--- a/drivers/android/tests/binder_alloc_kunit.c
+++ /dev/null
@@ -1,572 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Test cases for binder allocator code.
- *
- * Copyright 2025 Google LLC.
- * Author: Tiffany Yang <ynaffit@google.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <kunit/test.h>
-#include <linux/anon_inodes.h>
-#include <linux/err.h>
-#include <linux/file.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/seq_buf.h>
-#include <linux/sizes.h>
-
-#include "../binder_alloc.h"
-#include "../binder_internal.h"
-
-MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
-
-#define BINDER_MMAP_SIZE SZ_128K
-
-#define BUFFER_NUM 5
-#define BUFFER_MIN_SIZE (PAGE_SIZE / 8)
-
-#define FREESEQ_BUFLEN ((3 * BUFFER_NUM) + 1)
-
-#define ALIGN_TYPE_STRLEN (12)
-
-#define ALIGNMENTS_BUFLEN (((ALIGN_TYPE_STRLEN + 6) * BUFFER_NUM) + 1)
-
-#define PRINT_ALL_CASES (0)
-
-/* 5^5 alignment combinations * 2 places to share pages * 5! free sequences */
-#define TOTAL_EXHAUSTIVE_CASES (3125 * 2 * 120)
-
-/**
- * enum buf_end_align_type - Page alignment of a buffer
- * end with regard to the end of the previous buffer.
- *
- * In the pictures below, buf2 refers to the buffer we
- * are aligning. buf1 refers to previous buffer by addr.
- * Symbol [ means the start of a buffer, ] means the end
- * of a buffer, and | means page boundaries.
- */
-enum buf_end_align_type {
- /**
- * @SAME_PAGE_UNALIGNED: The end of this buffer is on
- * the same page as the end of the previous buffer and
- * is not page aligned. Examples:
- * buf1 ][ buf2 ][ ...
- * buf1 ]|[ buf2 ][ ...
- */
- SAME_PAGE_UNALIGNED = 0,
- /**
- * @SAME_PAGE_ALIGNED: When the end of the previous buffer
- * is not page aligned, the end of this buffer is on the
- * same page as the end of the previous buffer and is page
- * aligned. When the previous buffer is page aligned, the
- * end of this buffer is aligned to the next page boundary.
- * Examples:
- * buf1 ][ buf2 ]| ...
- * buf1 ]|[ buf2 ]| ...
- */
- SAME_PAGE_ALIGNED,
- /**
- * @NEXT_PAGE_UNALIGNED: The end of this buffer is on
- * the page next to the end of the previous buffer and
- * is not page aligned. Examples:
- * buf1 ][ buf2 | buf2 ][ ...
- * buf1 ]|[ buf2 | buf2 ][ ...
- */
- NEXT_PAGE_UNALIGNED,
- /**
- * @NEXT_PAGE_ALIGNED: The end of this buffer is on
- * the page next to the end of the previous buffer and
- * is page aligned. Examples:
- * buf1 ][ buf2 | buf2 ]| ...
- * buf1 ]|[ buf2 | buf2 ]| ...
- */
- NEXT_PAGE_ALIGNED,
- /**
- * @NEXT_NEXT_UNALIGNED: The end of this buffer is on
- * the page that follows the page after the end of the
- * previous buffer and is not page aligned. Examples:
- * buf1 ][ buf2 | buf2 | buf2 ][ ...
- * buf1 ]|[ buf2 | buf2 | buf2 ][ ...
- */
- NEXT_NEXT_UNALIGNED,
- /**
- * @LOOP_END: The number of enum values in &buf_end_align_type.
- * It is used for controlling loop termination.
- */
- LOOP_END,
-};
-
-static const char *const buf_end_align_type_strs[LOOP_END] = {
- [SAME_PAGE_UNALIGNED] = "SP_UNALIGNED",
- [SAME_PAGE_ALIGNED] = " SP_ALIGNED ",
- [NEXT_PAGE_UNALIGNED] = "NP_UNALIGNED",
- [NEXT_PAGE_ALIGNED] = " NP_ALIGNED ",
- [NEXT_NEXT_UNALIGNED] = "NN_UNALIGNED",
-};
-
-struct binder_alloc_test_case_info {
- char alignments[ALIGNMENTS_BUFLEN];
- struct seq_buf alignments_sb;
- size_t *buffer_sizes;
- int *free_sequence;
- bool front_pages;
-};
-
-static void stringify_free_seq(struct kunit *test, int *seq, struct seq_buf *sb)
-{
- int i;
-
- for (i = 0; i < BUFFER_NUM; i++)
- seq_buf_printf(sb, "[%d]", seq[i]);
-
- KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(sb));
-}
-
-static void stringify_alignments(struct kunit *test, int *alignments,
- struct seq_buf *sb)
-{
- int i;
-
- for (i = 0; i < BUFFER_NUM; i++)
- seq_buf_printf(sb, "[ %d:%s ]", i,
- buf_end_align_type_strs[alignments[i]]);
-
- KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(sb));
-}
-
-static bool check_buffer_pages_allocated(struct kunit *test,
- struct binder_alloc *alloc,
- struct binder_buffer *buffer,
- size_t size)
-{
- unsigned long page_addr;
- unsigned long end;
- int page_index;
-
- end = PAGE_ALIGN(buffer->user_data + size);
- page_addr = buffer->user_data;
- for (; page_addr < end; page_addr += PAGE_SIZE) {
- page_index = (page_addr - alloc->vm_start) / PAGE_SIZE;
- if (!alloc->pages[page_index] ||
- !list_empty(page_to_lru(alloc->pages[page_index]))) {
- kunit_err(test, "expect alloc but is %s at page index %d\n",
- alloc->pages[page_index] ?
- "lru" : "free", page_index);
- return false;
- }
- }
- return true;
-}
-
-static unsigned long binder_alloc_test_alloc_buf(struct kunit *test,
- struct binder_alloc *alloc,
- struct binder_buffer *buffers[],
- size_t *sizes, int *seq)
-{
- unsigned long failures = 0;
- int i;
-
- for (i = 0; i < BUFFER_NUM; i++) {
- buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0);
- if (IS_ERR(buffers[i]) ||
- !check_buffer_pages_allocated(test, alloc, buffers[i], sizes[i]))
- failures++;
- }
-
- return failures;
-}
-
-static unsigned long binder_alloc_test_free_buf(struct kunit *test,
- struct binder_alloc *alloc,
- struct binder_buffer *buffers[],
- size_t *sizes, int *seq, size_t end)
-{
- unsigned long failures = 0;
- int i;
-
- for (i = 0; i < BUFFER_NUM; i++)
- binder_alloc_free_buf(alloc, buffers[seq[i]]);
-
- for (i = 0; i <= (end - 1) / PAGE_SIZE; i++) {
- if (list_empty(page_to_lru(alloc->pages[i]))) {
- kunit_err(test, "expect lru but is %s at page index %d\n",
- alloc->pages[i] ? "alloc" : "free", i);
- failures++;
- }
- }
-
- return failures;
-}
-
-static unsigned long binder_alloc_test_free_page(struct kunit *test,
- struct binder_alloc *alloc)
-{
- unsigned long failures = 0;
- unsigned long count;
- int i;
-
- while ((count = list_lru_count(alloc->freelist))) {
- list_lru_walk(alloc->freelist, binder_alloc_free_page,
- NULL, count);
- }
-
- for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) {
- if (alloc->pages[i]) {
- kunit_err(test, "expect free but is %s at page index %d\n",
- list_empty(page_to_lru(alloc->pages[i])) ?
- "alloc" : "lru", i);
- failures++;
- }
- }
-
- return failures;
-}
-
-/* Executes one full test run for the given test case. */
-static bool binder_alloc_test_alloc_free(struct kunit *test,
- struct binder_alloc *alloc,
- struct binder_alloc_test_case_info *tc,
- size_t end)
-{
- unsigned long pages = PAGE_ALIGN(end) / PAGE_SIZE;
- struct binder_buffer *buffers[BUFFER_NUM];
- unsigned long failures;
- bool failed = false;
-
- failures = binder_alloc_test_alloc_buf(test, alloc, buffers,
- tc->buffer_sizes,
- tc->free_sequence);
- failed = failed || failures;
- KUNIT_EXPECT_EQ_MSG(test, failures, 0,
- "Initial allocation failed: %lu/%u buffers with errors",
- failures, BUFFER_NUM);
-
- failures = binder_alloc_test_free_buf(test, alloc, buffers,
- tc->buffer_sizes,
- tc->free_sequence, end);
- failed = failed || failures;
- KUNIT_EXPECT_EQ_MSG(test, failures, 0,
- "Initial buffers not freed correctly: %lu/%lu pages not on lru list",
- failures, pages);
-
- /* Allocate from lru. */
- failures = binder_alloc_test_alloc_buf(test, alloc, buffers,
- tc->buffer_sizes,
- tc->free_sequence);
- failed = failed || failures;
- KUNIT_EXPECT_EQ_MSG(test, failures, 0,
- "Reallocation failed: %lu/%u buffers with errors",
- failures, BUFFER_NUM);
-
- failures = list_lru_count(alloc->freelist);
- failed = failed || failures;
- KUNIT_EXPECT_EQ_MSG(test, failures, 0,
- "lru list should be empty after reallocation but still has %lu pages",
- failures);
-
- failures = binder_alloc_test_free_buf(test, alloc, buffers,
- tc->buffer_sizes,
- tc->free_sequence, end);
- failed = failed || failures;
- KUNIT_EXPECT_EQ_MSG(test, failures, 0,
- "Reallocated buffers not freed correctly: %lu/%lu pages not on lru list",
- failures, pages);
-
- failures = binder_alloc_test_free_page(test, alloc);
- failed = failed || failures;
- KUNIT_EXPECT_EQ_MSG(test, failures, 0,
- "Failed to clean up allocated pages: %lu/%lu pages still installed",
- failures, (alloc->buffer_size / PAGE_SIZE));
-
- return failed;
-}
-
-static bool is_dup(int *seq, int index, int val)
-{
- int i;
-
- for (i = 0; i < index; i++) {
- if (seq[i] == val)
- return true;
- }
- return false;
-}
-
-/* Generate BUFFER_NUM factorial free orders. */
-static void permute_frees(struct kunit *test, struct binder_alloc *alloc,
- struct binder_alloc_test_case_info *tc,
- unsigned long *runs, unsigned long *failures,
- int index, size_t end)
-{
- bool case_failed;
- int i;
-
- if (index == BUFFER_NUM) {
- DECLARE_SEQ_BUF(freeseq_sb, FREESEQ_BUFLEN);
-
- case_failed = binder_alloc_test_alloc_free(test, alloc, tc, end);
- *runs += 1;
- *failures += case_failed;
-
- if (case_failed || PRINT_ALL_CASES) {
- stringify_free_seq(test, tc->free_sequence,
- &freeseq_sb);
- kunit_err(test, "case %lu: [%s] | %s - %s - %s", *runs,
- case_failed ? "FAILED" : "PASSED",
- tc->front_pages ? "front" : "back ",
- seq_buf_str(&tc->alignments_sb),
- seq_buf_str(&freeseq_sb));
- }
-
- return;
- }
- for (i = 0; i < BUFFER_NUM; i++) {
- if (is_dup(tc->free_sequence, index, i))
- continue;
- tc->free_sequence[index] = i;
- permute_frees(test, alloc, tc, runs, failures, index + 1, end);
- }
-}
-
-static void gen_buf_sizes(struct kunit *test,
- struct binder_alloc *alloc,
- struct binder_alloc_test_case_info *tc,
- size_t *end_offset, unsigned long *runs,
- unsigned long *failures)
-{
- size_t last_offset, offset = 0;
- size_t front_sizes[BUFFER_NUM];
- size_t back_sizes[BUFFER_NUM];
- int seq[BUFFER_NUM] = {0};
- int i;
-
- tc->free_sequence = seq;
- for (i = 0; i < BUFFER_NUM; i++) {
- last_offset = offset;
- offset = end_offset[i];
- front_sizes[i] = offset - last_offset;
- back_sizes[BUFFER_NUM - i - 1] = front_sizes[i];
- }
- back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1];
-
- /*
- * Buffers share the first or last few pages.
- * Only BUFFER_NUM - 1 buffer sizes are adjustable since
- * we need one giant buffer before getting to the last page.
- */
- tc->front_pages = true;
- tc->buffer_sizes = front_sizes;
- permute_frees(test, alloc, tc, runs, failures, 0,
- end_offset[BUFFER_NUM - 1]);
-
- tc->front_pages = false;
- tc->buffer_sizes = back_sizes;
- permute_frees(test, alloc, tc, runs, failures, 0, alloc->buffer_size);
-}
-
-static void gen_buf_offsets(struct kunit *test, struct binder_alloc *alloc,
- size_t *end_offset, int *alignments,
- unsigned long *runs, unsigned long *failures,
- int index)
-{
- size_t end, prev;
- int align;
-
- if (index == BUFFER_NUM) {
- struct binder_alloc_test_case_info tc = {0};
-
- seq_buf_init(&tc.alignments_sb, tc.alignments,
- ALIGNMENTS_BUFLEN);
- stringify_alignments(test, alignments, &tc.alignments_sb);
-
- gen_buf_sizes(test, alloc, &tc, end_offset, runs, failures);
- return;
- }
- prev = index == 0 ? 0 : end_offset[index - 1];
- end = prev;
-
- BUILD_BUG_ON(BUFFER_MIN_SIZE * BUFFER_NUM >= PAGE_SIZE);
-
- for (align = SAME_PAGE_UNALIGNED; align < LOOP_END; align++) {
- if (align % 2)
- end = ALIGN(end, PAGE_SIZE);
- else
- end += BUFFER_MIN_SIZE;
- end_offset[index] = end;
- alignments[index] = align;
- gen_buf_offsets(test, alloc, end_offset, alignments, runs,
- failures, index + 1);
- }
-}
-
-struct binder_alloc_test {
- struct binder_alloc alloc;
- struct list_lru binder_test_freelist;
- struct file *filp;
- unsigned long mmap_uaddr;
-};
-
-static void binder_alloc_test_init_freelist(struct kunit *test)
-{
- struct binder_alloc_test *priv = test->priv;
-
- KUNIT_EXPECT_PTR_EQ(test, priv->alloc.freelist,
- &priv->binder_test_freelist);
-}
-
-static void binder_alloc_test_mmap(struct kunit *test)
-{
- struct binder_alloc_test *priv = test->priv;
- struct binder_alloc *alloc = &priv->alloc;
- struct binder_buffer *buf;
- struct rb_node *n;
-
- KUNIT_EXPECT_EQ(test, alloc->mapped, true);
- KUNIT_EXPECT_EQ(test, alloc->buffer_size, BINDER_MMAP_SIZE);
-
- n = rb_first(&alloc->allocated_buffers);
- KUNIT_EXPECT_PTR_EQ(test, n, NULL);
-
- n = rb_first(&alloc->free_buffers);
- buf = rb_entry(n, struct binder_buffer, rb_node);
- KUNIT_EXPECT_EQ(test, binder_alloc_buffer_size(alloc, buf),
- BINDER_MMAP_SIZE);
- KUNIT_EXPECT_TRUE(test, list_is_last(&buf->entry, &alloc->buffers));
-}
-
-/**
- * binder_alloc_exhaustive_test() - Exhaustively test alloc and free of buffer pages.
- * @test: The test context object.
- *
- * Allocate BUFFER_NUM buffers to cover all page alignment cases,
- * then free them in all orders possible. Check that pages are
- * correctly allocated, put onto lru when buffers are freed, and
- * are freed when binder_alloc_free_page() is called.
- */
-static void binder_alloc_exhaustive_test(struct kunit *test)
-{
- struct binder_alloc_test *priv = test->priv;
- size_t end_offset[BUFFER_NUM];
- int alignments[BUFFER_NUM];
- unsigned long failures = 0;
- unsigned long runs = 0;
-
- gen_buf_offsets(test, &priv->alloc, end_offset, alignments, &runs,
- &failures, 0);
-
- KUNIT_EXPECT_EQ(test, runs, TOTAL_EXHAUSTIVE_CASES);
- KUNIT_EXPECT_EQ(test, failures, 0);
-}
-
-/* ===== End test cases ===== */
-
-static void binder_alloc_test_vma_close(struct vm_area_struct *vma)
-{
- struct binder_alloc *alloc = vma->vm_private_data;
-
- binder_alloc_vma_close(alloc);
-}
-
-static const struct vm_operations_struct binder_alloc_test_vm_ops = {
- .close = binder_alloc_test_vma_close,
- .fault = binder_vm_fault,
-};
-
-static int binder_alloc_test_mmap_handler(struct file *filp,
- struct vm_area_struct *vma)
-{
- struct binder_alloc *alloc = filp->private_data;
-
- vm_flags_mod(vma, VM_DONTCOPY | VM_MIXEDMAP, VM_MAYWRITE);
-
- vma->vm_ops = &binder_alloc_test_vm_ops;
- vma->vm_private_data = alloc;
-
- return binder_alloc_mmap_handler(alloc, vma);
-}
-
-static const struct file_operations binder_alloc_test_fops = {
- .mmap = binder_alloc_test_mmap_handler,
-};
-
-static int binder_alloc_test_init(struct kunit *test)
-{
- struct binder_alloc_test *priv;
- int ret;
-
- priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- test->priv = priv;
-
- ret = list_lru_init(&priv->binder_test_freelist);
- if (ret) {
- kunit_err(test, "Failed to initialize test freelist\n");
- return ret;
- }
-
- /* __binder_alloc_init requires mm to be attached */
- ret = kunit_attach_mm();
- if (ret) {
- kunit_err(test, "Failed to attach mm\n");
- return ret;
- }
- __binder_alloc_init(&priv->alloc, &priv->binder_test_freelist);
-
- priv->filp = anon_inode_getfile("binder_alloc_kunit",
- &binder_alloc_test_fops, &priv->alloc,
- O_RDWR | O_CLOEXEC);
- if (IS_ERR_OR_NULL(priv->filp)) {
- kunit_err(test, "Failed to open binder alloc test driver file\n");
- return priv->filp ? PTR_ERR(priv->filp) : -ENOMEM;
- }
-
- priv->mmap_uaddr = kunit_vm_mmap(test, priv->filp, 0, BINDER_MMAP_SIZE,
- PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
- 0);
- if (!priv->mmap_uaddr) {
- kunit_err(test, "Could not map the test's transaction memory\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static void binder_alloc_test_exit(struct kunit *test)
-{
- struct binder_alloc_test *priv = test->priv;
-
- /* Close the backing file to make sure binder_alloc_vma_close runs */
- if (!IS_ERR_OR_NULL(priv->filp))
- fput(priv->filp);
-
- if (priv->alloc.mm)
- binder_alloc_deferred_release(&priv->alloc);
-
- /* Make sure freelist is empty */
- KUNIT_EXPECT_EQ(test, list_lru_count(&priv->binder_test_freelist), 0);
- list_lru_destroy(&priv->binder_test_freelist);
-}
-
-static struct kunit_case binder_alloc_test_cases[] = {
- KUNIT_CASE(binder_alloc_test_init_freelist),
- KUNIT_CASE(binder_alloc_test_mmap),
- KUNIT_CASE_SLOW(binder_alloc_exhaustive_test),
- {}
-};
-
-static struct kunit_suite binder_alloc_test_suite = {
- .name = "binder_alloc",
- .test_cases = binder_alloc_test_cases,
- .init = binder_alloc_test_init,
- .exit = binder_alloc_test_exit,
-};
-
-kunit_test_suite(binder_alloc_test_suite);
-
-MODULE_AUTHOR("Tiffany Yang <ynaffit@google.com>");
-MODULE_DESCRIPTION("Binder Alloc KUnit tests");
-MODULE_LICENSE("GPL");