Skip to content

rust: update IoctlHandler to allow arbitrary type as well. #388

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions drivers/android/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -766,27 +766,29 @@ impl Process {
}

impl IoctlHandler for Process {
fn write(&self, _file: &File, cmd: u32, reader: &mut UserSlicePtrReader) -> Result<i32> {
let thread = self.get_thread(unsafe { rust_helper_current_pid() })?;
type Target = Self;

fn write(this: &Self, _file: &File, cmd: u32, reader: &mut UserSlicePtrReader) -> Result<i32> {
let thread = this.get_thread(unsafe { rust_helper_current_pid() })?;
match cmd {
bindings::BINDER_SET_MAX_THREADS => self.set_max_threads(reader.read()?),
bindings::BINDER_SET_CONTEXT_MGR => self.set_as_manager(None, &thread)?,
bindings::BINDER_THREAD_EXIT => self.remove_thread(thread),
bindings::BINDER_SET_MAX_THREADS => this.set_max_threads(reader.read()?),
bindings::BINDER_SET_CONTEXT_MGR => this.set_as_manager(None, &thread)?,
bindings::BINDER_THREAD_EXIT => this.remove_thread(thread),
bindings::BINDER_SET_CONTEXT_MGR_EXT => {
self.set_as_manager(Some(reader.read()?), &thread)?
this.set_as_manager(Some(reader.read()?), &thread)?
}
_ => return Err(Error::EINVAL),
}
Ok(0)
}

fn read_write(&self, file: &File, cmd: u32, data: UserSlicePtr) -> Result<i32> {
let thread = self.get_thread(unsafe { rust_helper_current_pid() })?;
fn read_write(this: &Self, file: &File, cmd: u32, data: UserSlicePtr) -> Result<i32> {
let thread = this.get_thread(unsafe { rust_helper_current_pid() })?;
match cmd {
bindings::BINDER_WRITE_READ => thread.write_read(data, file.is_blocking())?,
bindings::BINDER_GET_NODE_DEBUG_INFO => self.get_node_debug_info(data)?,
bindings::BINDER_GET_NODE_INFO_FOR_REF => self.get_node_info_from_ref(data)?,
bindings::BINDER_VERSION => self.version(data)?,
bindings::BINDER_GET_NODE_DEBUG_INFO => this.get_node_debug_info(data)?,
bindings::BINDER_GET_NODE_INFO_FOR_REF => this.get_node_info_from_ref(data)?,
bindings::BINDER_VERSION => this.version(data)?,
_ => return Err(Error::EINVAL),
}
Ok(0)
Expand Down
36 changes: 27 additions & 9 deletions rust/kernel/file_operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,26 +446,44 @@ macro_rules! declare_file_operations {
///
/// For each macro, there is a handler function that takes the appropriate types as arguments.
pub trait IoctlHandler: Sync {
/// The type of the first argument to each associated function.
type Target;

/// Handles ioctls defined with the `_IO` macro, that is, with no buffer as argument.
fn pure(&self, _file: &File, _cmd: u32, _arg: usize) -> Result<i32> {
fn pure(_this: &Self::Target, _file: &File, _cmd: u32, _arg: usize) -> Result<i32> {
Err(Error::EINVAL)
}

/// Handles ioctls defined with the `_IOR` macro, that is, with an output buffer provided as
/// argument.
fn read(&self, _file: &File, _cmd: u32, _writer: &mut UserSlicePtrWriter) -> Result<i32> {
fn read(
_this: &Self::Target,
_file: &File,
_cmd: u32,
_writer: &mut UserSlicePtrWriter,
) -> Result<i32> {
Err(Error::EINVAL)
}

/// Handles ioctls defined with the `_IOW` macro, that is, with an input buffer provided as
/// argument.
fn write(&self, _file: &File, _cmd: u32, _reader: &mut UserSlicePtrReader) -> Result<i32> {
fn write(
_this: &Self::Target,
_file: &File,
_cmd: u32,
_reader: &mut UserSlicePtrReader,
) -> Result<i32> {
Err(Error::EINVAL)
}

/// Handles ioctls defined with the `_IOWR` macro, that is, with a buffer for both input and
/// output provided as argument.
fn read_write(&self, _file: &File, _cmd: u32, _data: UserSlicePtr) -> Result<i32> {
fn read_write(
_this: &Self::Target,
_file: &File,
_cmd: u32,
_data: UserSlicePtr,
) -> Result<i32> {
Err(Error::EINVAL)
}
}
Expand Down Expand Up @@ -501,18 +519,18 @@ impl IoctlCommand {
///
/// It is meant to be used in implementations of [`FileOperations::ioctl`] and
/// [`FileOperations::compat_ioctl`].
pub fn dispatch<T: IoctlHandler>(&mut self, handler: &T, file: &File) -> Result<i32> {
pub fn dispatch<T: IoctlHandler>(&mut self, handler: &T::Target, file: &File) -> Result<i32> {
let dir = (self.cmd >> bindings::_IOC_DIRSHIFT) & bindings::_IOC_DIRMASK;
if dir == bindings::_IOC_NONE {
return handler.pure(file, self.cmd, self.arg);
return T::pure(handler, file, self.cmd, self.arg);
}

let data = self.user_slice.take().ok_or(Error::EINVAL)?;
const READ_WRITE: u32 = bindings::_IOC_READ | bindings::_IOC_WRITE;
match dir {
bindings::_IOC_WRITE => handler.write(file, self.cmd, &mut data.reader()),
bindings::_IOC_READ => handler.read(file, self.cmd, &mut data.writer()),
READ_WRITE => handler.read_write(file, self.cmd, data),
bindings::_IOC_WRITE => T::write(handler, file, self.cmd, &mut data.reader()),
bindings::_IOC_READ => T::read(handler, file, self.cmd, &mut data.writer()),
READ_WRITE => T::read_write(handler, file, self.cmd, data),
_ => Err(Error::EINVAL),
}
}
Expand Down
10 changes: 6 additions & 4 deletions samples/rust/rust_semaphore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,20 +153,22 @@ const IOCTL_GET_READ_COUNT: u32 = 0x80086301;
const IOCTL_SET_READ_COUNT: u32 = 0x40086301;

impl IoctlHandler for FileState {
fn read(&self, _: &File, cmd: u32, writer: &mut UserSlicePtrWriter) -> Result<i32> {
type Target = Self;

fn read(this: &Self, _: &File, cmd: u32, writer: &mut UserSlicePtrWriter) -> Result<i32> {
match cmd {
IOCTL_GET_READ_COUNT => {
writer.write(&self.read_count.load(Ordering::Relaxed))?;
writer.write(&this.read_count.load(Ordering::Relaxed))?;
Ok(0)
}
_ => Err(Error::EINVAL),
}
}

fn write(&self, _: &File, cmd: u32, reader: &mut UserSlicePtrReader) -> Result<i32> {
fn write(this: &Self, _: &File, cmd: u32, reader: &mut UserSlicePtrReader) -> Result<i32> {
match cmd {
IOCTL_SET_READ_COUNT => {
self.read_count.store(reader.read()?, Ordering::Relaxed);
this.read_count.store(reader.read()?, Ordering::Relaxed);
Ok(0)
}
_ => Err(Error::EINVAL),
Expand Down