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 <aliceryhl@google.com>
This commit is contained in:
Alice Ryhl
2024-09-13 14:38:35 +00:00
committed by Treehugger Robot
parent c843dcd086
commit 7d9c745097
+19 -1
View File
@@ -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<isize> {
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 {