From ad23cf4103aca2313c1113f71f8731d04742f62c Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 13 Sep 2024 13:00:22 +0000 Subject: [PATCH] ANDROID: ashmem_rust: add GET/SET_NAME Add the first ioctl to the ashmem device. The `Ashmem` struct is augmented with a mutex to hold the name. The Rust bindings helper is updated to pull in constants from the existing C header. For now, only ASHMEM_NAME_LEN is needed, but later patches will need more stuff from the C header. Bug: 370906207 Change-Id: I7fbbce12e1fa7c4fb811fcb2561806795ba2bd0f Signed-off-by: Alice Ryhl --- drivers/staging/android/ashmem_rust.rs | 79 +++++++++++++++++++++++++- rust/bindings/bindings_helper.h | 4 ++ 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/drivers/staging/android/ashmem_rust.rs b/drivers/staging/android/ashmem_rust.rs index 77de00d9e26a..40b46bf44a72 100644 --- a/drivers/staging/android/ashmem_rust.rs +++ b/drivers/staging/android/ashmem_rust.rs @@ -12,13 +12,18 @@ use core::pin::Pin; use kernel::{ - c_str, + bindings, c_str, error::Result, fs::File, + ioctl::_IOC_SIZE, miscdevice::{MiscDevice, MiscDeviceOptions, MiscDeviceRegistration}, prelude::*, + sync::{new_mutex, Mutex}, + uaccess::{UserSlice, UserSliceReader, UserSliceWriter}, }; +const ASHMEM_NAME_LEN: usize = bindings::ASHMEM_NAME_LEN as usize; + module! { type: AshmemModule, name: "ashmem_rust", @@ -48,13 +53,81 @@ impl kernel::Module for AshmemModule { /// Represents an open ashmem file. #[pin_data] -struct Ashmem {} +struct Ashmem { + #[pin] + inner: Mutex, +} + +struct AshmemInner { + /// If set, then this holds the ashmem name without the dev/ashmem/ prefix. No zero terminator. + name: Option>, +} #[vtable] impl MiscDevice for Ashmem { type Ptr = Pin>; fn open(_: &File, _: &MiscDeviceRegistration) -> Result>> { - Box::try_pin_init(Ashmem {}, GFP_KERNEL) + Box::try_pin_init( + try_pin_init! { + Ashmem { + inner <- new_mutex!(AshmemInner { + name: None, + }), + } + }, + GFP_KERNEL, + ) + } + + fn ioctl(me: Pin<&Ashmem>, _file: &File, cmd: u32, arg: usize) -> Result { + let size = _IOC_SIZE(cmd); + match cmd { + bindings::ASHMEM_SET_NAME => me.set_name(UserSlice::new(arg, size).reader()), + bindings::ASHMEM_GET_NAME => me.get_name(UserSlice::new(arg, size).writer()), + _ => Err(EINVAL), + } + } +} + +impl Ashmem { + fn set_name(&self, mut reader: UserSliceReader) -> Result { + let mut local_name = [0u8; ASHMEM_NAME_LEN]; + reader.read_slice(&mut local_name)?; + + // Find the zero terminator. If the zero terminator is missing, the string is truncated to + // `ASHMEM_NAME_LEN-1` so that `get_name` can return it and has enough space to add a zero + // terminator. + let len = local_name + .iter() + .position(|&c| c == 0) + .unwrap_or(local_name.len() - 1); + + let mut v = Vec::with_capacity(len, GFP_KERNEL)?; + v.extend_from_slice(&local_name[..len], GFP_KERNEL)?; + + let mut asma = self.inner.lock(); + // TODO: fail if `mmap` is already called + asma.name = Some(v); + Ok(0) + } + + fn get_name(&self, mut writer: UserSliceWriter) -> Result { + let mut local_name = [0u8; ASHMEM_NAME_LEN]; + let asma = self.inner.lock(); + let name = asma.name.as_deref().unwrap_or(b"dev/ashmem"); + let len = name.len(); + let len_with_nul = len + 1; + if local_name.len() <= len_with_nul { + // This shouldn't happen in practice since `set_name` will refuse to store a string + // that is too long. + return Err(EINVAL); + } + local_name[..len].copy_from_slice(name); + local_name[len_with_nul] = 0; + drop(asma); + + writer.write_slice(&local_name[..len_with_nul])?; + Ok(0) } } diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 2675215ec32e..cc0387de3b72 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -45,3 +45,7 @@ const gfp_t RUST_CONST_HELPER_GFP_NOWAIT = GFP_NOWAIT; const gfp_t RUST_CONST_HELPER___GFP_ZERO = __GFP_ZERO; const gfp_t RUST_CONST_HELPER___GFP_HIGHMEM = ___GFP_HIGHMEM; const blk_features_t RUST_CONST_HELPER_BLK_FEAT_ROTATIONAL = BLK_FEAT_ROTATIONAL; + +#ifdef CONFIG_ASHMEM_RUST +#include "../../drivers/staging/android/ashmem.h" +#endif