From 7d9c745097089bc26ee0b4b7f9fedde23ee4defc Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 13 Sep 2024 14:38:35 +0000 Subject: [PATCH] ANDROID: ashmem_rust: add ASHMEM_PURGE_ALL_CACHES Add the simplest way of freeing pages that are unpinned: the ASHMEM_PURGE_ALL_CACHES ioctl. It will free every single unpinned page. Bug: 370906207 Change-Id: Ic1411148c036dec6528aa99f32d47a5b2e145c86 Signed-off-by: Alice Ryhl --- drivers/staging/android/ashmem_rust.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/staging/android/ashmem_rust.rs b/drivers/staging/android/ashmem_rust.rs index fb50a5aceb9e..ae96ff09a0b5 100644 --- a/drivers/staging/android/ashmem_rust.rs +++ b/drivers/staging/android/ashmem_rust.rs @@ -45,7 +45,7 @@ mod ashmem_shrinker; use ashmem_shrinker::{ShrinkerBuilder, ShrinkerRegistration}; mod ashmem_range; -use ashmem_range::{Area, AshmemGuard, NewRange, ASHMEM_MUTEX}; +use ashmem_range::{Area, AshmemGuard, NewRange, ASHMEM_MUTEX, LRU_COUNT}; mod shmem; use shmem::ShmemFile; @@ -57,6 +57,12 @@ fn read_implies_exec(task: &Task) -> bool { (personality & bindings::READ_IMPLIES_EXEC) != 0 } +/// Calls `capable(CAP_SYS_ADMIN)`. +fn has_cap_sys_admin() -> bool { + use kernel::bindings::CAP_SYS_ADMIN; + unsafe { bindings::capable(CAP_SYS_ADMIN as c_int) } +} + static NUM_PIN_IOCTLS_WAITING: AtomicUsize = AtomicUsize::new(0); fn shrinker_should_stop() -> bool { @@ -239,6 +245,7 @@ impl MiscDevice for Ashmem { ASHMEM_PIN | ASHMEM_UNPIN | ASHMEM_GET_PIN_STATUS => { me.pin_unpin(cmd, UserSlice::new(arg, size).reader()) } + bindings::ASHMEM_PURGE_ALL_CACHES => me.purge_all_caches(), _ => Err(EINVAL), } } @@ -430,6 +437,17 @@ impl Ashmem { _ => unreachable!(), } } + + fn purge_all_caches(&self) -> Result { + if !has_cap_sys_admin() { + return Err(EPERM); + } + let mut guard = AshmemGuard(ASHMEM_MUTEX.lock()); + let total_num_pages = LRU_COUNT.load(Ordering::Relaxed); + let _num_freed = guard.free_lru(usize::MAX); + // ASHMEM_PURGE_ALL_CACHES returns the total number of pages even if we stopped early. + Ok(isize::try_from(total_num_pages).unwrap_or(isize::MAX)) + } } impl AshmemInner {