Received: by 2002:a05:7412:f589:b0:e2:908c:2ebd with SMTP id eh9csp1093639rdb; Wed, 1 Nov 2023 11:04:00 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFICQmCy57vAo1vkPy8A5XJ3P6ACHz/q4S/BWBPmvVXKlOpa54sJ5hCLFOFRRqGU+a/ErmX X-Received: by 2002:a05:6358:6f8b:b0:169:57f3:754e with SMTP id s11-20020a0563586f8b00b0016957f3754emr11334437rwn.19.1698861839980; Wed, 01 Nov 2023 11:03:59 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1698861839; cv=none; d=google.com; s=arc-20160816; b=fVqMPTjf3atij7tcBUEW1pty4vW6Zozv08qnD4K4emx9umtTdws0yM1QcJZI/FtXD9 o5FrD6geVIYO9fggfFaC//9Xs7hey5hHJJyDnElctDUItgpDR3T/YPs9DdD3urGDk/xa PT9/pDvNLTHPTfDJgFMRzWOitwWxJaO/QlIB2fAALBVuF36ilWoeuyfBW/+fzsJ7JZVl yw4tT5qNiW4omAPp0fHCwHF7SqyHHH6Y1auQLunRqMRUCR57Z/ApG1KMJTvVFqZWRSc3 hBCp9H2+TS2glTxm1tq2PhKO4hyYR077545eG8GGUDgkCOfjHdcgJJ/RptZ8VzUq6qMm y5VQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=YNne2uV93ckwMpGguK52oBZlOAZFXC7MfuI9180HtAk=; fh=cHdDrFPTfwdP0/Ip9jHI/T24Yd8xIIOhbocUOLU1mtg=; b=awipZtkjTcZuS/IkstfZ3/l/H366iaEGwBOz8qtFoDAI29AKVu2CsjqoidERPScwru ABnHa0puUBTM9ZtmUMobALCPtEPiJWym8DD5uvH0eRM/3wjTN+297fU7RlTvYlFt9MP6 ALlwGOJoHl/2ZQO/B9bi6TPFyqfhVNa6aRUsry/eaMJRespHSNk1pc5McqMo2EMHd/DS dHCzIJ1oWjbw9u+BF5nL13XsYPbOV00g6Mic0ioBq70FiVrlzvdoxIx4BKTtzAWBFOLA fdyhjoa5ICcR0gBH9BlgbG+zeeW+dtjI7toWOv5I1uhgO/rqjA9D0MPuvPkHDkyjp+MH 7skA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=cbIJ2ins; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from snail.vger.email (snail.vger.email. [2620:137:e000::3:7]) by mx.google.com with ESMTPS id bx34-20020a056a02052200b00584aa817597si466988pgb.101.2023.11.01.11.03.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 01 Nov 2023 11:03:59 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) client-ip=2620:137:e000::3:7; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=cbIJ2ins; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by snail.vger.email (Postfix) with ESMTP id C1B09818ABE9; Wed, 1 Nov 2023 11:03:56 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at snail.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345025AbjKASDw (ORCPT + 99 others); Wed, 1 Nov 2023 14:03:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39460 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344951AbjKASDI (ORCPT ); Wed, 1 Nov 2023 14:03:08 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7FDF1111 for ; Wed, 1 Nov 2023 11:03:02 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-da040c021aeso12091276.3 for ; Wed, 01 Nov 2023 11:03:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1698861781; x=1699466581; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=YNne2uV93ckwMpGguK52oBZlOAZFXC7MfuI9180HtAk=; b=cbIJ2insncFswk6hAzuTTZwcesQ/J2lO0mj2Yq3IVqU15NJnrWwFq6pNS4pwajm9fn soPQkEZNwu7cViawUrtuASjbdF0ka6+eGU6wGdMaBRRwKo4pjt2vb+AJIWI8QmXdpvka L2X1836Hzh9UFykz6lwEzdBD3n9ZUoktUiyqOGG7rUfhdx1crqlOykXMopkc7m4cWoog 1C1+KXP+O8kHBFfVcII3569eIN92pAk918twl8wu7FogOiTkk+zS2MCALiQZ1YvoLwoO ISvPaxawcXdbD3v+mzo3jzI/Gi/b8UMspyOjkEVORBcKwopmdEJKNfr7A45pZSHCGKGX v0DA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1698861781; x=1699466581; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=YNne2uV93ckwMpGguK52oBZlOAZFXC7MfuI9180HtAk=; b=J0u/LksqUI1apF4AA3DO4KYeDOSbrOD4JU4vNHFemxnkw1Tk2LUFaigLseBdz/Cgn3 ECaYjBh81MvTH/jvwIJ59Lnu2z9/i32z4pX6AVH1aKl0hYR50YheqlTBbGYUdsIR5eY7 U3EaYrihFTGfG81fE7OAuZzzCydOJBxNjYYX/WY2nGuOR07QpXoXM8o79KsPRnEuW++v EGOtbVtsulJBms8t2DM01qTQAmbjtE2mDAyIOh1pgkNqfXS2FXaN9zg6WEP6rQux9sXN SOlNz3Pa4Ci30YC6zbxp3PiSxcB0RVveZrAJwxJrEIenbNjaMNvvvmqiOfLHsj6nqd/N lrRA== X-Gm-Message-State: AOJu0YyEqmIgjvTv8T4nVZ+9+cAG403Ql7CNcVuT/1c2JxDZJe8HBQmm 5CgZ9BBtxURqG/cep/jpmC4gI99u9kaCbGg= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a05:6902:1083:b0:da0:567d:f819 with SMTP id v3-20020a056902108300b00da0567df819mr389361ybu.10.1698861781743; Wed, 01 Nov 2023 11:03:01 -0700 (PDT) Date: Wed, 01 Nov 2023 18:01:48 +0000 In-Reply-To: <20231101-rust-binder-v1-0-08ba9197f637@google.com> Mime-Version: 1.0 References: <20231101-rust-binder-v1-0-08ba9197f637@google.com> X-Mailer: b4 0.13-dev-26615 Message-ID: <20231101-rust-binder-v1-18-08ba9197f637@google.com> Subject: [PATCH RFC 18/20] rust_binder: add binder_logs/state From: Alice Ryhl To: Greg Kroah-Hartman , "=?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?=" , Todd Kjos , Martijn Coenen , Joel Fernandes , Christian Brauner , Carlos Llamas , Suren Baghdasaryan , Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Matt Gilbride , Jeffrey Vander Stoep , Matthew Maurer , Alice Ryhl Content-Type: text/plain; charset="utf-8" X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED, USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (snail.vger.email [0.0.0.0]); Wed, 01 Nov 2023 11:03:56 -0700 (PDT) The binderfs directory has four files intended for debugging the driver. This patch implements the state file so that you can use it to view the current state of the driver. Signed-off-by: Alice Ryhl --- drivers/android/node.rs | 37 ++++++++++++++++++++ drivers/android/process.rs | 75 +++++++++++++++++++++++++++++++++++++++++ drivers/android/rust_binder.rs | 23 ++++++++++++- drivers/android/thread.rs | 68 +++++++++++++++++++++++++++++++++++++ drivers/android/transaction.rs | 25 ++++++++++++++ rust/bindings/bindings_helper.h | 1 + rust/kernel/lib.rs | 1 + rust/kernel/seq_file.rs | 47 ++++++++++++++++++++++++++ 8 files changed, 276 insertions(+), 1 deletion(-) diff --git a/drivers/android/node.rs b/drivers/android/node.rs index 2c056bd7582e..3acad1c2b963 100644 --- a/drivers/android/node.rs +++ b/drivers/android/node.rs @@ -7,6 +7,8 @@ TryNewListArc, }, prelude::*, + seq_file::SeqFile, + seq_print, sync::lock::{spinlock::SpinLockBackend, Guard}, sync::{Arc, LockedBy, SpinLock}, user_ptr::UserSlicePtrWriter, @@ -111,6 +113,41 @@ pub(crate) fn new( }) } + #[inline(never)] + pub(crate) fn debug_print(&self, m: &mut SeqFile) -> Result<()> { + let weak; + let strong; + let has_weak; + let has_strong; + let active_inc_refs; + { + let mut guard = self.owner.inner.lock(); + let inner = self.inner.access_mut(&mut guard); + weak = inner.weak.count; + has_weak = inner.weak.has_count; + strong = inner.strong.count; + has_strong = inner.strong.has_count; + active_inc_refs = inner.active_inc_refs; + } + + let has_weak = if has_weak { "Y" } else { "N" }; + let has_strong = if has_strong { "Y" } else { "N" }; + + seq_print!( + m, + "node gid:{},ptr:{:#x},cookie:{:#x}: strong{}{} weak{}{} active{}\n", + self.global_id, + self.ptr, + self.cookie, + strong, + has_strong, + weak, + has_weak, + active_inc_refs + ); + Ok(()) + } + pub(crate) fn get_id(&self) -> (usize, usize) { (self.ptr, self.cookie) } diff --git a/drivers/android/process.rs b/drivers/android/process.rs index 4ac5d09041a4..b5e44f9f2a14 100644 --- a/drivers/android/process.rs +++ b/drivers/android/process.rs @@ -20,6 +20,8 @@ pages::Pages, prelude::*, rbtree::RBTree, + seq_file::SeqFile, + seq_print, sync::{ lock::Guard, Arc, ArcBorrow, CondVar, CondVarTimeoutResult, Mutex, SpinLock, UniqueArc, }, @@ -405,6 +407,79 @@ fn new(ctx: Arc, cred: ARef) -> Result> { Ok(process) } + #[inline(never)] + pub(crate) fn debug_print(&self, m: &mut SeqFile) -> Result<()> { + seq_print!(m, "pid: {}\n", self.task.pid_in_current_ns()); + + let is_manager; + let started_threads; + let has_proc_work; + let mut ready_threads = Vec::new(); + let mut all_threads = Vec::new(); + let mut all_nodes = Vec::new(); + loop { + let inner = self.inner.lock(); + let ready_threads_len = inner.ready_threads.iter().count(); + let all_threads_len = inner.threads.values().count(); + let all_nodes_len = inner.nodes.values().count(); + + let resize_ready_threads = ready_threads_len > ready_threads.capacity(); + let resize_all_threads = all_threads_len > all_threads.capacity(); + let resize_all_nodes = all_nodes_len > all_nodes.capacity(); + if resize_ready_threads || resize_all_threads || resize_all_nodes { + drop(inner); + ready_threads.try_reserve(ready_threads_len)?; + all_threads.try_reserve(all_threads_len)?; + all_nodes.try_reserve(all_nodes_len)?; + continue; + } + + is_manager = inner.is_manager; + started_threads = inner.started_thread_count; + has_proc_work = !inner.work.is_empty(); + + for thread in &inner.ready_threads { + assert!(ready_threads.len() < ready_threads.capacity()); + ready_threads.try_push(thread.id)?; + } + + for thread in inner.threads.values() { + assert!(all_threads.len() < all_threads.capacity()); + all_threads.try_push(thread.clone())?; + } + + for node in inner.nodes.values() { + assert!(all_nodes.len() < all_nodes.capacity()); + all_nodes.try_push(node.clone())?; + } + + break; + } + + seq_print!(m, "is_manager: {}\n", is_manager); + seq_print!(m, "started_threads: {}\n", started_threads); + seq_print!(m, "has_proc_work: {}\n", has_proc_work); + if ready_threads.is_empty() { + seq_print!(m, "ready_thread_ids: none\n"); + } else { + seq_print!(m, "ready_thread_ids:"); + for thread_id in ready_threads { + seq_print!(m, " {}", thread_id); + } + seq_print!(m, "\n"); + } + + for node in all_nodes { + node.debug_print(m)?; + } + + seq_print!(m, "all threads:\n"); + for thread in all_threads { + thread.debug_print(m); + } + Ok(()) + } + /// Attempts to fetch a work item from the process queue. pub(crate) fn get_work(&self) -> Option> { self.inner.lock().work.pop_front() diff --git a/drivers/android/rust_binder.rs b/drivers/android/rust_binder.rs index adf542872f36..a1c95a1609d5 100644 --- a/drivers/android/rust_binder.rs +++ b/drivers/android/rust_binder.rs @@ -10,6 +10,8 @@ HasListLinks, ListArc, ListArcSafe, ListItem, ListLinks, ListLinksSelfPtr, TryNewListArc, }, prelude::*, + seq_file::SeqFile, + seq_print, sync::Arc, types::ForeignOwnable, user_ptr::UserSlicePtrWriter, @@ -347,7 +349,13 @@ unsafe impl Sync for AssertSync {} } #[no_mangle] -unsafe extern "C" fn rust_binder_state_show(_: *mut seq_file) -> core::ffi::c_int { +unsafe extern "C" fn rust_binder_state_show(ptr: *mut seq_file) -> core::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 } @@ -360,3 +368,16 @@ unsafe impl Sync for AssertSync {} unsafe extern "C" fn rust_binder_transaction_log_show(_: *mut seq_file) -> core::ffi::c_int { 0 } + +fn rust_binder_state_show_impl(m: &mut SeqFile) -> Result<()> { + let contexts = context::get_all_contexts()?; + for ctx in contexts { + let procs = ctx.get_all_procs()?; + seq_print!(m, "context {}: ({} processes)\n", &*ctx.name, procs.len()); + for proc in procs { + proc.debug_print(m)?; + seq_print!(m, "\n"); + } + } + Ok(()) +} diff --git a/drivers/android/thread.rs b/drivers/android/thread.rs index 414ffb1387a0..d5a56119cc19 100644 --- a/drivers/android/thread.rs +++ b/drivers/android/thread.rs @@ -15,6 +15,8 @@ }, prelude::*, security, + seq_file::SeqFile, + seq_print, sync::{Arc, SpinLock}, types::Either, user_ptr::{UserSlicePtr, UserSlicePtrWriter}, @@ -447,6 +449,72 @@ pub(crate) fn new(id: i32, process: Arc) -> Result> { })) } + #[inline(never)] + pub(crate) fn debug_print(&self, m: &mut SeqFile) { + let looper_flags; + let looper_need_return; + let is_dead; + let has_work; + let process_work_list; + let current_transaction; + { + let inner = self.inner.lock(); + looper_flags = inner.looper_flags; + looper_need_return = inner.looper_need_return; + is_dead = inner.is_dead; + has_work = !inner.work_list.is_empty(); + process_work_list = inner.process_work_list; + current_transaction = inner.current_transaction.clone(); + } + seq_print!(m, " tid: {}\n", self.id); + seq_print!(m, " state:"); + if is_dead { + seq_print!(m, " dead"); + } + if looper_need_return { + seq_print!(m, " pending_flush_wakeup"); + } + if has_work && process_work_list { + seq_print!(m, " has_work"); + } + if has_work && !process_work_list { + seq_print!(m, " has_deferred_work"); + } + if looper_flags & LOOPER_REGISTERED != 0 { + seq_print!(m, " registered"); + } + if looper_flags & LOOPER_ENTERED != 0 { + seq_print!(m, " entered"); + } + if looper_flags & LOOPER_EXITED != 0 { + seq_print!(m, " exited"); + } + if looper_flags & LOOPER_INVALID != 0 { + seq_print!(m, " invalid"); + } + if looper_flags & LOOPER_WAITING != 0 { + if looper_flags & LOOPER_WAITING_PROC != 0 { + seq_print!(m, " in_get_work"); + } else { + seq_print!(m, " in_get_work_local"); + } + } + if looper_flags & LOOPER_POLL != 0 { + seq_print!(m, " poll_is_initialized"); + } + seq_print!(m, "\n"); + if current_transaction.is_some() { + seq_print!(m, " tstack:"); + let mut t = current_transaction; + while let Some(tt) = t.as_ref() { + seq_print!(m, " "); + tt.debug_print(m); + t = tt.clone_next(); + } + seq_print!(m, "\n"); + } + } + pub(crate) fn get_extended_error(&self, data: UserSlicePtr) -> Result { let mut writer = data.writer(); let ee = self.inner.lock().extended_error; diff --git a/drivers/android/transaction.rs b/drivers/android/transaction.rs index 84b9fe58fe3e..30c411ab0778 100644 --- a/drivers/android/transaction.rs +++ b/drivers/android/transaction.rs @@ -5,6 +5,8 @@ io_buffer::IoBufferWriter, list::ListArcSafe, prelude::*, + seq_file::SeqFile, + seq_print, sync::{Arc, SpinLock}, task::Kuid, types::{Either, ScopeGuard}, @@ -140,6 +142,29 @@ pub(crate) fn new_reply( }))?) } + #[inline(never)] + pub(crate) fn debug_print(&self, m: &mut SeqFile) { + let from_pid = self.from.process.task.pid_in_current_ns(); + let to_pid = self.to.task.pid_in_current_ns(); + let from_tid = self.from.id; + match self.target_node.as_ref() { + Some(target_node) => { + let node_id = target_node.global_id; + seq_print!( + m, + "{}(tid:{})->{}(nid:{})", + from_pid, + from_tid, + to_pid, + node_id + ); + } + None => { + seq_print!(m, "{}(tid:{})->{}(nid:_)", from_pid, from_tid, to_pid); + } + } + } + /// Determines if the transaction is stacked on top of the given transaction. pub(crate) fn is_stacked_on(&self, onext: &Option>) -> bool { match (&self.stack_next, onext) { diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index ffeea312f2fd..b2d60b4a9df6 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index f4d58da9202e..d46187783464 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -48,6 +48,7 @@ pub mod print; pub mod rbtree; pub mod security; +pub mod seq_file; mod static_assert; #[doc(hidden)] pub mod std_vendor; diff --git a/rust/kernel/seq_file.rs b/rust/kernel/seq_file.rs new file mode 100644 index 000000000000..997d527b2e9e --- /dev/null +++ b/rust/kernel/seq_file.rs @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Seq file bindings. +//! +//! C header: [`include/linux/seq_file.h`](../../../../include/linux/seq_file.h) + +use crate::{bindings, c_str, types::Opaque}; + +/// A helper for implementing special files, where the complete contents can be generated on each +/// access. +pub struct SeqFile(Opaque); + +impl SeqFile { + /// Creates a new [`SeqFile`] from a raw pointer. + /// + /// # Safety + /// + /// The caller must ensure that, for the duration of 'a, the pointer must point at a valid + /// `seq_file` and that it will not be accessed via anything other than the returned reference. + pub unsafe fn from_raw<'a>(ptr: *mut bindings::seq_file) -> &'a mut SeqFile { + // SAFETY: The safety requirements guarantee the validity of the dereference, while the + // `Credential` type being transparent makes the cast ok. + unsafe { &mut *ptr.cast() } + } + + /// Used by the [`seq_print`] macro. + /// + /// [`seq_print`]: crate::seq_print + pub fn call_printf(&mut self, args: core::fmt::Arguments<'_>) { + // SAFETY: Passing a void pointer to `Arguments` is valid for `%pA`. + unsafe { + bindings::seq_printf( + self.0.get(), + c_str!("%pA").as_char_ptr(), + &args as *const _ as *const core::ffi::c_void, + ); + } + } +} + +/// Use for writing to a [`SeqFile`] with the ordinary Rust formatting syntax. +#[macro_export] +macro_rules! seq_print { + ($m:expr, $($arg:tt)+) => ( + $m.call_printf(format_args!($($arg)+)) + ); +} -- 2.42.0.820.g83a721a137-goog