Skip to content

rust: update FileOperations to use arbitrary type from PointerWrapper. #387

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
18 changes: 9 additions & 9 deletions drivers/android/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -891,15 +891,15 @@ impl FileOperations for Process {
}
}

fn ioctl(&self, file: &File, cmd: &mut IoctlCommand) -> Result<i32> {
cmd.dispatch(self, file)
fn ioctl(this: &Process, file: &File, cmd: &mut IoctlCommand) -> Result<i32> {
cmd.dispatch::<Self>(this, file)
}

fn compat_ioctl(&self, file: &File, cmd: &mut IoctlCommand) -> Result<i32> {
cmd.dispatch(self, file)
fn compat_ioctl(this: &Process, file: &File, cmd: &mut IoctlCommand) -> Result<i32> {
cmd.dispatch::<Self>(this, file)
}

fn mmap(&self, _file: &File, vma: &mut bindings::vm_area_struct) -> Result {
fn mmap(this: &Process, _file: &File, vma: &mut bindings::vm_area_struct) -> Result {
// TODO: Only group leader is allowed to create mappings.

if vma.vm_start == 0 {
Expand All @@ -914,13 +914,13 @@ impl FileOperations for Process {
vma.vm_flags &= !(bindings::VM_MAYWRITE as c_types::c_ulong);

// TODO: Set ops. We need to learn when the user unmaps so that we can stop using it.
self.create_mapping(vma)
this.create_mapping(vma)
}

fn poll(&self, file: &File, table: &PollTable) -> Result<u32> {
let thread = self.get_thread(unsafe { rust_helper_current_pid() })?;
fn poll(this: &Process, file: &File, table: &PollTable) -> Result<u32> {
let thread = this.get_thread(unsafe { rust_helper_current_pid() })?;
let (from_proc, mut mask) = thread.poll(file, table);
if mask == 0 && from_proc && !self.inner.lock().work.is_empty() {
if mask == 0 && from_proc && !this.inner.lock().work.is_empty() {
mask |= bindings::POLLIN;
}
Ok(mask)
Expand Down
2 changes: 1 addition & 1 deletion drivers/char/hw_random/bcm2835_rng_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl FileOpener<()> for RngDevice {
impl FileOperations for RngDevice {
kernel::declare_file_operations!(read);

fn read<T: IoBufferWriter>(&self, _: &File, data: &mut T, offset: u64) -> Result<usize> {
fn read<T: IoBufferWriter>(_: &Self, _: &File, data: &mut T, offset: u64) -> Result<usize> {
// Succeed if the caller doesn't provide a buffer or if not at the start.
if data.is_empty() || offset != 0 {
return Ok(0);
Expand Down
136 changes: 105 additions & 31 deletions rust/kernel/file_operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! C header: [`include/linux/fs.h`](../../../../include/linux/fs.h)

use core::convert::{TryFrom, TryInto};
use core::{marker, mem, ptr};
use core::{marker, mem, ops::Deref, ptr};

use alloc::boxed::Box;

Expand Down Expand Up @@ -99,10 +99,14 @@ unsafe extern "C" fn read_callback<T: FileOperations>(
) -> c_types::c_ssize_t {
from_kernel_result! {
let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).writer() };
let f = unsafe { &*((*file).private_data as *const T) };
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
// callback, which the C API guarantees that will be called only when all references to
// `file` have been released, so we know it can't be called while this function is running.
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
// No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
// See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
let read = f.read(unsafe { &FileRef::from_ptr(file) }, &mut data, unsafe { *offset }.try_into()?)?;
let read = T::read(&f, unsafe { &FileRef::from_ptr(file) }, &mut data, unsafe { *offset }.try_into()?)?;
unsafe { (*offset) += bindings::loff_t::try_from(read).unwrap() };
Ok(read as _)
}
Expand All @@ -116,8 +120,12 @@ unsafe extern "C" fn read_iter_callback<T: FileOperations>(
let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
let file = unsafe { (*iocb).ki_filp };
let offset = unsafe { (*iocb).ki_pos };
let f = unsafe { &*((*file).private_data as *const T) };
let read = f.read(unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
// callback, which the C API guarantees that will be called only when all references to
// `file` have been released, so we know it can't be called while this function is running.
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
let read = T::read(&f, unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(read).unwrap() };
Ok(read as _)
}
Expand All @@ -131,10 +139,14 @@ unsafe extern "C" fn write_callback<T: FileOperations>(
) -> c_types::c_ssize_t {
from_kernel_result! {
let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).reader() };
let f = unsafe { &*((*file).private_data as *const T) };
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
// callback, which the C API guarantees that will be called only when all references to
// `file` have been released, so we know it can't be called while this function is running.
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
// No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
// See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
let written = f.write(unsafe { &FileRef::from_ptr(file) }, &mut data, unsafe { *offset }.try_into()?)?;
let written = T::write(&f, unsafe { &FileRef::from_ptr(file) }, &mut data, unsafe { *offset }.try_into()?)?;
unsafe { (*offset) += bindings::loff_t::try_from(written).unwrap() };
Ok(written as _)
}
Expand All @@ -148,8 +160,12 @@ unsafe extern "C" fn write_iter_callback<T: FileOperations>(
let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
let file = unsafe { (*iocb).ki_filp };
let offset = unsafe { (*iocb).ki_pos };
let f = unsafe { &*((*file).private_data as *const T) };
let written = f.write(unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
// callback, which the C API guarantees that will be called only when all references to
// `file` have been released, so we know it can't be called while this function is running.
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
let written = T::write(&f, unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(written).unwrap() };
Ok(written as _)
}
Expand Down Expand Up @@ -178,8 +194,12 @@ unsafe extern "C" fn llseek_callback<T: FileOperations>(
bindings::SEEK_END => SeekFrom::End(offset),
_ => return Err(Error::EINVAL),
};
let f = unsafe { &*((*file).private_data as *const T) };
let off = f.seek(unsafe { &FileRef::from_ptr(file) }, off)?;
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
// callback, which the C API guarantees that will be called only when all references to
// `file` have been released, so we know it can't be called while this function is running.
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
let off = T::seek(&f, unsafe { &FileRef::from_ptr(file) }, off)?;
Ok(off as bindings::loff_t)
}
}
Expand All @@ -190,10 +210,13 @@ unsafe extern "C" fn unlocked_ioctl_callback<T: FileOperations>(
arg: c_types::c_ulong,
) -> c_types::c_long {
from_kernel_result! {
let f = unsafe { &*((*file).private_data as *const T) };
// SAFETY: This function is called by the kernel, so it must set `fs` appropriately.
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
// callback, which the C API guarantees that will be called only when all references to
// `file` have been released, so we know it can't be called while this function is running.
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
let mut cmd = IoctlCommand::new(cmd as _, arg as _);
let ret = f.ioctl(unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
let ret = T::ioctl(&f, unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
Ok(ret as _)
}
}
Expand All @@ -204,10 +227,13 @@ unsafe extern "C" fn compat_ioctl_callback<T: FileOperations>(
arg: c_types::c_ulong,
) -> c_types::c_long {
from_kernel_result! {
let f = unsafe { &*((*file).private_data as *const T) };
// SAFETY: This function is called by the kernel, so it must set `fs` appropriately.
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
// callback, which the C API guarantees that will be called only when all references to
// `file` have been released, so we know it can't be called while this function is running.
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
let mut cmd = IoctlCommand::new(cmd as _, arg as _);
let ret = f.compat_ioctl(unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
let ret = T::compat_ioctl(&f, unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
Ok(ret as _)
}
}
Expand All @@ -217,8 +243,12 @@ unsafe extern "C" fn mmap_callback<T: FileOperations>(
vma: *mut bindings::vm_area_struct,
) -> c_types::c_int {
from_kernel_result! {
let f = unsafe { &*((*file).private_data as *const T) };
f.mmap(unsafe { &FileRef::from_ptr(file) }, unsafe { &mut *vma })?;
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
// callback, which the C API guarantees that will be called only when all references to
// `file` have been released, so we know it can't be called while this function is running.
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
T::mmap(&f, unsafe { &FileRef::from_ptr(file) }, unsafe { &mut *vma })?;
Ok(0)
}
}
Expand All @@ -233,8 +263,12 @@ unsafe extern "C" fn fsync_callback<T: FileOperations>(
let start = start.try_into()?;
let end = end.try_into()?;
let datasync = datasync != 0;
let f = unsafe { &*((*file).private_data as *const T) };
let res = f.fsync(unsafe { &FileRef::from_ptr(file) }, start, end, datasync)?;
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
// callback, which the C API guarantees that will be called only when all references to
// `file` have been released, so we know it can't be called while this function is running.
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
let res = T::fsync(&f, unsafe { &FileRef::from_ptr(file) }, start, end, datasync)?;
Ok(res.try_into().unwrap())
}
}
Expand All @@ -243,8 +277,12 @@ unsafe extern "C" fn poll_callback<T: FileOperations>(
file: *mut bindings::file,
wait: *mut bindings::poll_table_struct,
) -> bindings::__poll_t {
let f = unsafe { &*((*file).private_data as *const T) };
match f.poll(unsafe { &FileRef::from_ptr(file) }, unsafe {
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
// callback, which the C API guarantees that will be called only when all references to `file`
// have been released, so we know it can't be called while this function is running.
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
match T::poll(&f, unsafe { &FileRef::from_ptr(file) }, unsafe {
&PollTable::from_ptr(wait)
}) {
Ok(v) => v,
Expand Down Expand Up @@ -549,58 +587,94 @@ pub trait FileOperations: Send + Sync + Sized {
/// Reads data from this file to the caller's buffer.
///
/// Corresponds to the `read` and `read_iter` function pointers in `struct file_operations`.
fn read<T: IoBufferWriter>(&self, _file: &File, _data: &mut T, _offset: u64) -> Result<usize> {
fn read<T: IoBufferWriter>(
_this: &<<Self::Wrapper as PointerWrapper>::Borrowed as Deref>::Target,
_file: &File,
_data: &mut T,
_offset: u64,
) -> Result<usize> {
Err(Error::EINVAL)
}

/// Writes data from the caller's buffer to this file.
///
/// Corresponds to the `write` and `write_iter` function pointers in `struct file_operations`.
fn write<T: IoBufferReader>(&self, _file: &File, _data: &mut T, _offset: u64) -> Result<usize> {
fn write<T: IoBufferReader>(
_this: &<<Self::Wrapper as PointerWrapper>::Borrowed as Deref>::Target,
_file: &File,
_data: &mut T,
_offset: u64,
) -> Result<usize> {
Err(Error::EINVAL)
}

/// Changes the position of the file.
///
/// Corresponds to the `llseek` function pointer in `struct file_operations`.
fn seek(&self, _file: &File, _offset: SeekFrom) -> Result<u64> {
fn seek(
_this: &<<Self::Wrapper as PointerWrapper>::Borrowed as Deref>::Target,
_file: &File,
_offset: SeekFrom,
) -> Result<u64> {
Err(Error::EINVAL)
}

/// Performs IO control operations that are specific to the file.
///
/// Corresponds to the `unlocked_ioctl` function pointer in `struct file_operations`.
fn ioctl(&self, _file: &File, _cmd: &mut IoctlCommand) -> Result<i32> {
fn ioctl(
_this: &<<Self::Wrapper as PointerWrapper>::Borrowed as Deref>::Target,
_file: &File,
_cmd: &mut IoctlCommand,
) -> Result<i32> {
Err(Error::EINVAL)
}

/// Performs 32-bit IO control operations on that are specific to the file on 64-bit kernels.
///
/// Corresponds to the `compat_ioctl` function pointer in `struct file_operations`.
fn compat_ioctl(&self, _file: &File, _cmd: &mut IoctlCommand) -> Result<i32> {
fn compat_ioctl(
_this: &<<Self::Wrapper as PointerWrapper>::Borrowed as Deref>::Target,
_file: &File,
_cmd: &mut IoctlCommand,
) -> Result<i32> {
Err(Error::EINVAL)
}

/// Syncs pending changes to this file.
///
/// Corresponds to the `fsync` function pointer in `struct file_operations`.
fn fsync(&self, _file: &File, _start: u64, _end: u64, _datasync: bool) -> Result<u32> {
fn fsync(
_this: &<<Self::Wrapper as PointerWrapper>::Borrowed as Deref>::Target,
_file: &File,
_start: u64,
_end: u64,
_datasync: bool,
) -> Result<u32> {
Err(Error::EINVAL)
}

/// Maps areas of the caller's virtual memory with device/file memory.
///
/// Corresponds to the `mmap` function pointer in `struct file_operations`.
/// TODO: wrap `vm_area_struct` so that we don't have to expose it.
fn mmap(&self, _file: &File, _vma: &mut bindings::vm_area_struct) -> Result {
fn mmap(
_this: &<<Self::Wrapper as PointerWrapper>::Borrowed as Deref>::Target,
_file: &File,
_vma: &mut bindings::vm_area_struct,
) -> Result {
Err(Error::EINVAL)
}

/// Checks the state of the file and optionally registers for notification when the state
/// changes.
///
/// Corresponds to the `poll` function pointer in `struct file_operations`.
fn poll(&self, _file: &File, _table: &PollTable) -> Result<u32> {
fn poll(
_this: &<<Self::Wrapper as PointerWrapper>::Borrowed as Deref>::Target,
_file: &File,
_table: &PollTable,
) -> Result<u32> {
Ok(bindings::POLLIN | bindings::POLLOUT | bindings::POLLRDNORM | bindings::POLLWRNORM)
}
}
Loading