mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-18 12:22:27 -04:00
Pull Rust updates from Miguel Ojeda:
"Toolchain and infrastructure:
- Bump the minimum Rust version to 1.85.0 (and 'bindgen' to 0.71.1).
As proposed in LPC 2025 and the Maintainers Summit [1], we are
going to follow Debian Stable's Rust versions as our minimum
versions.
Debian Trixie was released on 2025-08-09 with a Rust 1.85.0 and
'bindgen' 0.71.1 toolchain, which is a fair amount of time for e.g.
kernel developers to upgrade.
Other major distributions support a Rust version that is high
enough as well, including:
+ Arch Linux.
+ Fedora Linux.
+ Gentoo Linux.
+ Nix.
+ openSUSE Slowroll and openSUSE Tumbleweed.
+ Ubuntu 25.10 and 26.04 LTS. In addition, 24.04 LTS using
their versioned packages.
The merged patch series comes with the associated cleanups and
simplifications treewide that can be performed thanks to both
bumps, as well as documentation updates.
In addition, start using 'bindgen''s '--with-attribute-custom-enum'
feature to set the 'cfi_encoding' attribute for the 'lru_status'
enum used in Binder.
Link: https://lwn.net/Articles/1050174/ [1]
- Add experimental Kconfig option ('CONFIG_RUST_INLINE_HELPERS') that
inlines C helpers into Rust.
Essentially, it performs a step similar to LTO, but just for the
helpers, i.e. very local and fast.
It relies on 'llvm-link' and its '--internalize' flag, and requires
a compatible LLVM between Clang and 'rustc' (i.e. same major
version, 'CONFIG_RUSTC_CLANG_LLVM_COMPATIBLE'). It is only enabled
for two architectures for now.
The result is a measurable speedup in different workloads that
different users have tested. For instance, for the null block
driver, it amounts to a 2%.
- Support global per-version flags.
While we already have per-version flags in many places, we didn't
have a place to set global ones that depend on the compiler
version, i.e. in 'rust_common_flags', which sometimes is needed to
e.g. tweak the lints set per version.
Use that to allow the 'clippy::precedence' lint for Rust < 1.86.0,
since it had a change in behavior.
- Support overriding the crate name and apply it to Rust Binder,
which wanted the module to be called 'rust_binder'.
- Add the remaining '__rust_helper' annotations (started in the
previous cycle).
'kernel' crate:
- Introduce the 'const_assert!' macro: a more powerful version of
'static_assert!' that can refer to generics inside functions or
implementation bodies, e.g.:
fn f<const N: usize>() {
const_assert!(N > 1);
}
fn g<T>() {
const_assert!(size_of::<T>() > 0, "T cannot be ZST");
}
In addition, reorganize our set of build-time assertion macros
('{build,const,static_assert}!') to live in the 'build_assert'
module.
Finally, improve the docs as well to clarify how these are
different from one another and how to pick the right one to use,
and their equivalence (if any) to the existing C ones for extra
clarity.
- 'sizes' module: add 'SizeConstants' trait.
This gives us typed 'SZ_*' constants (avoiding casts) for use in
device address spaces where the address width depends on the
hardware (e.g. 32-bit MMIO windows, 64-bit GPU framebuffers, etc.),
e.g.:
let gpu_heap = 14 * u64::SZ_1M;
let mmio_window = u32::SZ_16M;
- 'clk' module: implement 'Send' and 'Sync' for 'Clk' and thus
simplify the users in Tyr and PWM.
- 'ptr' module: add 'const_align_up'.
- 'str' module: improve the documentation of the 'c_str!' macro to
explain that one should only use it for non-literal cases (for the
other case we instead use C string literals, e.g. 'c"abc"').
- Disallow the use of 'CStr::{as_ptr,from_ptr}' and clean one such
use in the 'task' module.
- 'sync' module: finish the move of 'ARef' and 'AlwaysRefCounted'
outside of the 'types' module, i.e. update the last remaining
instances and finally remove the re-exports.
- 'error' module: clarify that 'from_err_ptr' can return 'Ok(NULL)',
including runtime-tested examples.
The intention is to hopefully prevent UB that assumes the result of
the function is not 'NULL' if successful. This originated from a
case of UB I noticed in 'regulator' that created a 'NonNull' on it.
Timekeeping:
- Expand the example section in the 'HrTimer' documentation.
- Mark the 'ClockSource' trait as unsafe to ensure valid values for
'ktime_get()'.
- Add 'Delta::from_nanos()'.
'pin-init' crate:
- Replace the 'Zeroable' impls for 'Option<NonZero*>' with impls of
'ZeroableOption' for 'NonZero*'.
- Improve feature gate handling for unstable features.
- Declutter the documentation of implementations of 'Zeroable' for
tuples.
- Replace uses of 'addr_of[_mut]!' with '&raw [mut]'.
rust-analyzer:
- Add type annotations to 'generate_rust_analyzer.py'.
- Add support for scripts written in Rust ('generate_rust_target.rs',
'rustdoc_test_builder.rs', 'rustdoc_test_gen.rs').
- Refactor 'generate_rust_analyzer.py' to explicitly identify host
and target crates, improve readability, and reduce duplication.
And some other fixes, cleanups and improvements"
* tag 'rust-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (79 commits)
rust: sizes: add SizeConstants trait for device address space constants
rust: kernel: update `file_with_nul` comment
rust: kbuild: allow `clippy::precedence` for Rust < 1.86.0
rust: kbuild: support global per-version flags
rust: declare cfi_encoding for lru_status
docs: rust: general-information: use real example
docs: rust: general-information: simplify Kconfig example
docs: rust: quick-start: remove GDB/Binutils mention
docs: rust: quick-start: remove Nix "unstable channel" note
docs: rust: quick-start: remove Gentoo "testing" note
docs: rust: quick-start: add Ubuntu 26.04 LTS and remove subsection title
docs: rust: quick-start: update minimum Ubuntu version
docs: rust: quick-start: update Ubuntu versioned packages
docs: rust: quick-start: openSUSE provides `rust-src` package nowadays
rust: kbuild: remove "dummy parameter" workaround for `bindgen` < 0.71.1
rust: kbuild: update `bindgen --rust-target` version and replace comment
rust: rust_is_available: remove warning for `bindgen` < 0.69.5 && libclang >= 19.1
rust: rust_is_available: remove warning for `bindgen` 0.66.[01]
rust: bump `bindgen` minimum supported version to 0.71.1 (Debian Trixie)
rust: block: update `const_refs_to_static` MSRV TODO comment
...
620 lines
18 KiB
Rust
620 lines
18 KiB
Rust
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
// Copyright (C) 2025 Google LLC.
|
|
|
|
//! Binder -- the Android IPC mechanism.
|
|
|
|
#![crate_name = "rust_binder"]
|
|
#![recursion_limit = "256"]
|
|
#![allow(
|
|
clippy::as_underscore,
|
|
clippy::ref_as_ptr,
|
|
clippy::ptr_as_ptr,
|
|
clippy::cast_lossless
|
|
)]
|
|
|
|
use kernel::{
|
|
bindings::{self, seq_file},
|
|
fs::File,
|
|
list::{ListArc, ListArcSafe, ListLinksSelfPtr, TryNewListArc},
|
|
prelude::*,
|
|
seq_file::SeqFile,
|
|
seq_print,
|
|
sync::atomic::{ordering::Relaxed, Atomic},
|
|
sync::poll::PollTable,
|
|
sync::Arc,
|
|
task::Pid,
|
|
transmute::AsBytes,
|
|
types::ForeignOwnable,
|
|
uaccess::UserSliceWriter,
|
|
};
|
|
|
|
use crate::{context::Context, page_range::Shrinker, process::Process, thread::Thread};
|
|
|
|
use core::ptr::NonNull;
|
|
|
|
mod allocation;
|
|
mod context;
|
|
mod deferred_close;
|
|
mod defs;
|
|
mod error;
|
|
mod node;
|
|
mod page_range;
|
|
mod process;
|
|
mod range_alloc;
|
|
mod stats;
|
|
mod thread;
|
|
mod trace;
|
|
mod transaction;
|
|
|
|
#[allow(warnings)] // generated bindgen code
|
|
mod binderfs {
|
|
use kernel::bindings::{dentry, inode};
|
|
|
|
extern "C" {
|
|
pub fn init_rust_binderfs() -> kernel::ffi::c_int;
|
|
}
|
|
extern "C" {
|
|
pub fn rust_binderfs_create_proc_file(
|
|
nodp: *mut inode,
|
|
pid: kernel::ffi::c_int,
|
|
) -> *mut dentry;
|
|
}
|
|
extern "C" {
|
|
pub fn rust_binderfs_remove_file(dentry: *mut dentry);
|
|
}
|
|
pub type rust_binder_context = *mut kernel::ffi::c_void;
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone)]
|
|
pub struct binder_device {
|
|
pub minor: kernel::ffi::c_int,
|
|
pub ctx: rust_binder_context,
|
|
}
|
|
impl Default for binder_device {
|
|
fn default() -> Self {
|
|
let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
|
|
unsafe {
|
|
::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
|
|
s.assume_init()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
module! {
|
|
type: BinderModule,
|
|
name: "rust_binder",
|
|
authors: ["Wedson Almeida Filho", "Alice Ryhl"],
|
|
description: "Android Binder",
|
|
license: "GPL",
|
|
}
|
|
|
|
use kernel::bindings::rust_binder_layout;
|
|
#[no_mangle]
|
|
static RUST_BINDER_LAYOUT: rust_binder_layout = rust_binder_layout {
|
|
t: transaction::TRANSACTION_LAYOUT,
|
|
p: process::PROCESS_LAYOUT,
|
|
n: node::NODE_LAYOUT,
|
|
};
|
|
|
|
fn next_debug_id() -> usize {
|
|
static NEXT_DEBUG_ID: Atomic<usize> = Atomic::new(0);
|
|
|
|
NEXT_DEBUG_ID.fetch_add(1, Relaxed)
|
|
}
|
|
|
|
/// Provides a single place to write Binder return values via the
|
|
/// supplied `UserSliceWriter`.
|
|
pub(crate) struct BinderReturnWriter<'a> {
|
|
writer: UserSliceWriter,
|
|
thread: &'a Thread,
|
|
}
|
|
|
|
impl<'a> BinderReturnWriter<'a> {
|
|
fn new(writer: UserSliceWriter, thread: &'a Thread) -> Self {
|
|
BinderReturnWriter { writer, thread }
|
|
}
|
|
|
|
/// Write a return code back to user space.
|
|
/// Should be a `BR_` constant from [`defs`] e.g. [`defs::BR_TRANSACTION_COMPLETE`].
|
|
fn write_code(&mut self, code: u32) -> Result {
|
|
stats::GLOBAL_STATS.inc_br(code);
|
|
self.thread.process.stats.inc_br(code);
|
|
self.writer.write(&code)
|
|
}
|
|
|
|
/// Write something *other than* a return code to user space.
|
|
fn write_payload<T: AsBytes>(&mut self, payload: &T) -> Result {
|
|
self.writer.write(payload)
|
|
}
|
|
|
|
fn len(&self) -> usize {
|
|
self.writer.len()
|
|
}
|
|
}
|
|
|
|
/// Specifies how a type should be delivered to the read part of a BINDER_WRITE_READ ioctl.
|
|
///
|
|
/// When a value is pushed to the todo list for a process or thread, it is stored as a trait object
|
|
/// with the type `Arc<dyn DeliverToRead>`. Trait objects are a Rust feature that lets you
|
|
/// implement dynamic dispatch over many different types. This lets us store many different types
|
|
/// in the todo list.
|
|
trait DeliverToRead: ListArcSafe + Send + Sync {
|
|
/// Performs work. Returns true if remaining work items in the queue should be processed
|
|
/// immediately, or false if it should return to caller before processing additional work
|
|
/// items.
|
|
fn do_work(
|
|
self: DArc<Self>,
|
|
thread: &Thread,
|
|
writer: &mut BinderReturnWriter<'_>,
|
|
) -> Result<bool>;
|
|
|
|
/// Cancels the given work item. This is called instead of [`DeliverToRead::do_work`] when work
|
|
/// won't be delivered.
|
|
fn cancel(self: DArc<Self>);
|
|
|
|
/// Should we use `wake_up_interruptible_sync` or `wake_up_interruptible` when scheduling this
|
|
/// work item?
|
|
///
|
|
/// 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<()>;
|
|
}
|
|
|
|
// Wrapper around a `DeliverToRead` with linked list links.
|
|
#[pin_data]
|
|
struct DTRWrap<T: ?Sized> {
|
|
#[pin]
|
|
links: ListLinksSelfPtr<DTRWrap<dyn DeliverToRead>>,
|
|
#[pin]
|
|
wrapped: T,
|
|
}
|
|
kernel::list::impl_list_arc_safe! {
|
|
impl{T: ListArcSafe + ?Sized} ListArcSafe<0> for DTRWrap<T> {
|
|
tracked_by wrapped: T;
|
|
}
|
|
}
|
|
kernel::list::impl_list_item! {
|
|
impl ListItem<0> for DTRWrap<dyn DeliverToRead> {
|
|
using ListLinksSelfPtr { self.links };
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized> core::ops::Deref for DTRWrap<T> {
|
|
type Target = T;
|
|
fn deref(&self) -> &T {
|
|
&self.wrapped
|
|
}
|
|
}
|
|
|
|
type DArc<T> = kernel::sync::Arc<DTRWrap<T>>;
|
|
type DLArc<T> = kernel::list::ListArc<DTRWrap<T>>;
|
|
|
|
impl<T: ListArcSafe> DTRWrap<T> {
|
|
fn new(val: impl PinInit<T>) -> impl PinInit<Self> {
|
|
pin_init!(Self {
|
|
links <- ListLinksSelfPtr::new(),
|
|
wrapped <- val,
|
|
})
|
|
}
|
|
|
|
fn arc_try_new(val: T) -> Result<DLArc<T>, kernel::alloc::AllocError> {
|
|
ListArc::pin_init(
|
|
try_pin_init!(Self {
|
|
links <- ListLinksSelfPtr::new(),
|
|
wrapped: val,
|
|
}),
|
|
GFP_KERNEL,
|
|
)
|
|
.map_err(|_| kernel::alloc::AllocError)
|
|
}
|
|
|
|
fn arc_pin_init(init: impl PinInit<T>) -> Result<DLArc<T>, kernel::error::Error> {
|
|
ListArc::pin_init(
|
|
try_pin_init!(Self {
|
|
links <- ListLinksSelfPtr::new(),
|
|
wrapped <- init,
|
|
}),
|
|
GFP_KERNEL,
|
|
)
|
|
}
|
|
}
|
|
|
|
struct DeliverCode {
|
|
code: u32,
|
|
skip: Atomic<bool>,
|
|
}
|
|
|
|
kernel::list::impl_list_arc_safe! {
|
|
impl ListArcSafe<0> for DeliverCode { untracked; }
|
|
}
|
|
|
|
impl DeliverCode {
|
|
fn new(code: u32) -> Self {
|
|
Self {
|
|
code,
|
|
skip: Atomic::new(false),
|
|
}
|
|
}
|
|
|
|
/// Disable this DeliverCode and make it do nothing.
|
|
///
|
|
/// This is used instead of removing it from the work list, since `LinkedList::remove` is
|
|
/// unsafe, whereas this method is not.
|
|
fn skip(&self) {
|
|
self.skip.store(true, Relaxed);
|
|
}
|
|
}
|
|
|
|
impl DeliverToRead for DeliverCode {
|
|
fn do_work(
|
|
self: DArc<Self>,
|
|
_thread: &Thread,
|
|
writer: &mut BinderReturnWriter<'_>,
|
|
) -> Result<bool> {
|
|
if !self.skip.load(Relaxed) {
|
|
writer.write_code(self.code)?;
|
|
}
|
|
Ok(true)
|
|
}
|
|
|
|
fn cancel(self: DArc<Self>) {}
|
|
|
|
fn should_sync_wakeup(&self) -> bool {
|
|
false
|
|
}
|
|
|
|
fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> {
|
|
seq_print!(m, "{}", prefix);
|
|
if self.skip.load(Relaxed) {
|
|
seq_print!(m, "(skipped) ");
|
|
}
|
|
if self.code == defs::BR_TRANSACTION_COMPLETE {
|
|
seq_print!(m, "transaction complete\n");
|
|
} else {
|
|
seq_print!(m, "transaction error: {}\n", self.code);
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
fn ptr_align(value: usize) -> Option<usize> {
|
|
let size = core::mem::size_of::<usize>() - 1;
|
|
Some(value.checked_add(size)? & !size)
|
|
}
|
|
|
|
// SAFETY: We call register in `init`.
|
|
static BINDER_SHRINKER: Shrinker = unsafe { Shrinker::new() };
|
|
|
|
struct BinderModule {}
|
|
|
|
impl kernel::Module for BinderModule {
|
|
fn init(_module: &'static kernel::ThisModule) -> Result<Self> {
|
|
// SAFETY: The module initializer never runs twice, so we only call this once.
|
|
unsafe { crate::context::CONTEXTS.init() };
|
|
|
|
pr_warn!("Loaded Rust Binder.");
|
|
|
|
BINDER_SHRINKER.register(c"android-binder")?;
|
|
|
|
// SAFETY: The module is being loaded, so we can initialize binderfs.
|
|
unsafe { kernel::error::to_result(binderfs::init_rust_binderfs())? };
|
|
|
|
Ok(Self {})
|
|
}
|
|
}
|
|
|
|
/// Makes the inner type Sync.
|
|
#[repr(transparent)]
|
|
pub struct AssertSync<T>(T);
|
|
// SAFETY: Used only to insert C bindings types into globals, which is safe.
|
|
unsafe impl<T> Sync for AssertSync<T> {}
|
|
|
|
/// File operations that rust_binderfs.c can use.
|
|
#[no_mangle]
|
|
#[used]
|
|
pub static rust_binder_fops: AssertSync<kernel::bindings::file_operations> = {
|
|
// SAFETY: All zeroes is safe for the `file_operations` type.
|
|
let zeroed_ops = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
|
|
|
|
let ops = kernel::bindings::file_operations {
|
|
owner: THIS_MODULE.as_ptr(),
|
|
poll: Some(rust_binder_poll),
|
|
unlocked_ioctl: Some(rust_binder_ioctl),
|
|
compat_ioctl: bindings::compat_ptr_ioctl,
|
|
mmap: Some(rust_binder_mmap),
|
|
open: Some(rust_binder_open),
|
|
release: Some(rust_binder_release),
|
|
flush: Some(rust_binder_flush),
|
|
..zeroed_ops
|
|
};
|
|
AssertSync(ops)
|
|
};
|
|
|
|
/// # Safety
|
|
/// Only called by binderfs.
|
|
#[no_mangle]
|
|
unsafe extern "C" fn rust_binder_new_context(
|
|
name: *const kernel::ffi::c_char,
|
|
) -> *mut kernel::ffi::c_void {
|
|
// SAFETY: The caller will always provide a valid c string here.
|
|
let name = unsafe { kernel::str::CStr::from_char_ptr(name) };
|
|
match Context::new(name) {
|
|
Ok(ctx) => Arc::into_foreign(ctx),
|
|
Err(_err) => core::ptr::null_mut(),
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
/// Only called by binderfs.
|
|
#[no_mangle]
|
|
unsafe extern "C" fn rust_binder_remove_context(device: *mut kernel::ffi::c_void) {
|
|
if !device.is_null() {
|
|
// SAFETY: The caller ensures that the `device` pointer came from a previous call to
|
|
// `rust_binder_new_device`.
|
|
let ctx = unsafe { Arc::<Context>::from_foreign(device) };
|
|
ctx.deregister();
|
|
drop(ctx);
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
/// Only called by binderfs.
|
|
unsafe extern "C" fn rust_binder_open(
|
|
inode: *mut bindings::inode,
|
|
file_ptr: *mut bindings::file,
|
|
) -> kernel::ffi::c_int {
|
|
// SAFETY: The `rust_binderfs.c` file ensures that `i_private` is set to a
|
|
// `struct binder_device`.
|
|
let device = unsafe { (*inode).i_private } as *const binderfs::binder_device;
|
|
|
|
assert!(!device.is_null());
|
|
|
|
// SAFETY: The `rust_binderfs.c` file ensures that `device->ctx` holds a binder context when
|
|
// using the rust binder fops.
|
|
let ctx = unsafe { Arc::<Context>::borrow((*device).ctx) };
|
|
|
|
// SAFETY: The caller provides a valid file pointer to a new `struct file`.
|
|
let file = unsafe { File::from_raw_file(file_ptr) };
|
|
let process = match Process::open(ctx, file) {
|
|
Ok(process) => process,
|
|
Err(err) => return err.to_errno(),
|
|
};
|
|
|
|
// SAFETY: This is an `inode` for a newly created binder file.
|
|
match unsafe { BinderfsProcFile::new(inode, process.task.pid()) } {
|
|
Ok(Some(file)) => process.inner.lock().binderfs_file = Some(file),
|
|
Ok(None) => { /* pid already exists */ }
|
|
Err(err) => return err.to_errno(),
|
|
}
|
|
|
|
// SAFETY: This file is associated with Rust binder, so we own the `private_data` field.
|
|
unsafe { (*file_ptr).private_data = process.into_foreign() };
|
|
0
|
|
}
|
|
|
|
/// # Safety
|
|
/// Only called by binderfs.
|
|
unsafe extern "C" fn rust_binder_release(
|
|
_inode: *mut bindings::inode,
|
|
file: *mut bindings::file,
|
|
) -> kernel::ffi::c_int {
|
|
// SAFETY: We previously set `private_data` in `rust_binder_open`.
|
|
let process = unsafe { Arc::<Process>::from_foreign((*file).private_data) };
|
|
// SAFETY: The caller ensures that the file is valid.
|
|
let file = unsafe { File::from_raw_file(file) };
|
|
Process::release(process, file);
|
|
0
|
|
}
|
|
|
|
/// # Safety
|
|
/// Only called by binderfs.
|
|
unsafe extern "C" fn rust_binder_ioctl(
|
|
file: *mut bindings::file,
|
|
cmd: kernel::ffi::c_uint,
|
|
arg: kernel::ffi::c_ulong,
|
|
) -> kernel::ffi::c_long {
|
|
// SAFETY: We previously set `private_data` in `rust_binder_open`.
|
|
let f = unsafe { Arc::<Process>::borrow((*file).private_data) };
|
|
// SAFETY: The caller ensures that the file is valid.
|
|
match Process::ioctl(f, unsafe { File::from_raw_file(file) }, cmd as _, arg as _) {
|
|
Ok(()) => 0,
|
|
Err(err) => err.to_errno() as isize,
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
/// Only called by binderfs.
|
|
unsafe extern "C" fn rust_binder_mmap(
|
|
file: *mut bindings::file,
|
|
vma: *mut bindings::vm_area_struct,
|
|
) -> kernel::ffi::c_int {
|
|
// SAFETY: We previously set `private_data` in `rust_binder_open`.
|
|
let f = unsafe { Arc::<Process>::borrow((*file).private_data) };
|
|
// SAFETY: The caller ensures that the vma is valid.
|
|
let area = unsafe { kernel::mm::virt::VmaNew::from_raw(vma) };
|
|
// SAFETY: The caller ensures that the file is valid.
|
|
match Process::mmap(f, unsafe { File::from_raw_file(file) }, area) {
|
|
Ok(()) => 0,
|
|
Err(err) => err.to_errno(),
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
/// Only called by binderfs.
|
|
unsafe extern "C" fn rust_binder_poll(
|
|
file: *mut bindings::file,
|
|
wait: *mut bindings::poll_table_struct,
|
|
) -> bindings::__poll_t {
|
|
// SAFETY: We previously set `private_data` in `rust_binder_open`.
|
|
let f = unsafe { Arc::<Process>::borrow((*file).private_data) };
|
|
// SAFETY: The caller ensures that the file is valid.
|
|
let fileref = unsafe { File::from_raw_file(file) };
|
|
// SAFETY: The caller ensures that the `PollTable` is valid.
|
|
match Process::poll(f, fileref, unsafe { PollTable::from_raw(wait) }) {
|
|
Ok(v) => v,
|
|
Err(_) => bindings::POLLERR,
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
/// Only called by binderfs.
|
|
unsafe extern "C" fn rust_binder_flush(
|
|
file: *mut bindings::file,
|
|
_id: bindings::fl_owner_t,
|
|
) -> kernel::ffi::c_int {
|
|
// SAFETY: We previously set `private_data` in `rust_binder_open`.
|
|
let f = unsafe { Arc::<Process>::borrow((*file).private_data) };
|
|
match Process::flush(f) {
|
|
Ok(()) => 0,
|
|
Err(err) => err.to_errno(),
|
|
}
|
|
}
|
|
|
|
/// # Safety
|
|
/// Only called by binderfs.
|
|
#[no_mangle]
|
|
unsafe extern "C" fn rust_binder_stats_show(
|
|
ptr: *mut seq_file,
|
|
_: *mut kernel::ffi::c_void,
|
|
) -> kernel::ffi::c_int {
|
|
// SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which
|
|
// this method is called.
|
|
let m = unsafe { SeqFile::from_raw(ptr) };
|
|
if let Err(err) = rust_binder_stats_show_impl(m) {
|
|
seq_print!(m, "failed to generate state: {:?}\n", err);
|
|
}
|
|
0
|
|
}
|
|
|
|
/// # Safety
|
|
/// Only called by binderfs.
|
|
#[no_mangle]
|
|
unsafe extern "C" fn rust_binder_state_show(
|
|
ptr: *mut seq_file,
|
|
_: *mut kernel::ffi::c_void,
|
|
) -> kernel::ffi::c_int {
|
|
// SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which
|
|
// this method is called.
|
|
let m = unsafe { SeqFile::from_raw(ptr) };
|
|
if let Err(err) = rust_binder_state_show_impl(m) {
|
|
seq_print!(m, "failed to generate state: {:?}\n", err);
|
|
}
|
|
0
|
|
}
|
|
|
|
/// # Safety
|
|
/// Only called by binderfs.
|
|
#[no_mangle]
|
|
unsafe extern "C" fn rust_binder_proc_show(
|
|
ptr: *mut seq_file,
|
|
_: *mut kernel::ffi::c_void,
|
|
) -> kernel::ffi::c_int {
|
|
// SAFETY: Accessing the private field of `seq_file` is okay.
|
|
let pid = (unsafe { (*ptr).private }) as usize as Pid;
|
|
// SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which
|
|
// this method is called.
|
|
let m = unsafe { SeqFile::from_raw(ptr) };
|
|
if let Err(err) = rust_binder_proc_show_impl(m, pid) {
|
|
seq_print!(m, "failed to generate state: {:?}\n", err);
|
|
}
|
|
0
|
|
}
|
|
|
|
/// # Safety
|
|
/// Only called by binderfs.
|
|
#[no_mangle]
|
|
unsafe extern "C" fn rust_binder_transactions_show(
|
|
ptr: *mut seq_file,
|
|
_: *mut kernel::ffi::c_void,
|
|
) -> kernel::ffi::c_int {
|
|
// SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which
|
|
// this method is called.
|
|
let m = unsafe { SeqFile::from_raw(ptr) };
|
|
if let Err(err) = rust_binder_transactions_show_impl(m) {
|
|
seq_print!(m, "failed to generate state: {:?}\n", err);
|
|
}
|
|
0
|
|
}
|
|
|
|
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 {
|
|
let procs = ctx.get_all_procs()?;
|
|
for proc in procs {
|
|
proc.debug_print(m, &ctx, false)?;
|
|
seq_print!(m, "\n");
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
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()?;
|
|
for ctx in contexts {
|
|
let procs = ctx.get_all_procs()?;
|
|
for proc in procs {
|
|
proc.debug_print_stats(m, &ctx)?;
|
|
seq_print!(m, "\n");
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
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 {
|
|
let procs = ctx.get_all_procs()?;
|
|
for proc in procs {
|
|
proc.debug_print(m, &ctx, true)?;
|
|
seq_print!(m, "\n");
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
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 {
|
|
let procs = ctx.get_procs_with_pid(pid)?;
|
|
for proc in procs {
|
|
proc.debug_print(m, &ctx, true)?;
|
|
seq_print!(m, "\n");
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
struct BinderfsProcFile(NonNull<bindings::dentry>);
|
|
|
|
// SAFETY: Safe to drop any thread.
|
|
unsafe impl Send for BinderfsProcFile {}
|
|
|
|
impl BinderfsProcFile {
|
|
/// # Safety
|
|
///
|
|
/// Takes an inode from a newly created binder file.
|
|
unsafe fn new(nodp: *mut bindings::inode, pid: i32) -> Result<Option<Self>> {
|
|
// SAFETY: The caller passes an `inode` for a newly created binder file.
|
|
let dentry = unsafe { binderfs::rust_binderfs_create_proc_file(nodp, pid) };
|
|
match kernel::error::from_err_ptr(dentry) {
|
|
Ok(dentry) => Ok(NonNull::new(dentry).map(Self)),
|
|
Err(err) if err == EEXIST => Ok(None),
|
|
Err(err) => Err(err),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Drop for BinderfsProcFile {
|
|
fn drop(&mut self) {
|
|
// SAFETY: This is a dentry from `rust_binderfs_remove_file` that has not been deleted yet.
|
|
unsafe { binderfs::rust_binderfs_remove_file(self.0.as_ptr()) };
|
|
}
|
|
}
|