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 <aliceryhl@google.com>
This commit is contained in:
Alice Ryhl
2024-09-13 13:00:22 +00:00
committed by Treehugger Robot
parent 306f5648d8
commit ad23cf4103
2 changed files with 80 additions and 3 deletions
+76 -3
View File
@@ -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<AshmemInner>,
}
struct AshmemInner {
/// If set, then this holds the ashmem name without the dev/ashmem/ prefix. No zero terminator.
name: Option<Vec<u8>>,
}
#[vtable]
impl MiscDevice for Ashmem {
type Ptr = Pin<Box<Self>>;
fn open(_: &File, _: &MiscDeviceRegistration<Ashmem>) -> Result<Pin<Box<Self>>> {
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<isize> {
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<isize> {
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<isize> {
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)
}
}
+4
View File
@@ -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