Skip to content

Commit 2117c9f

Browse files
committed
rust: update FileOperations to use arbitrary type from PointerWrapper.
This allows `FileOperations` implementers to have arbitrary (wrapped) values as `private_data` (as opposed to only wrapped `Self`). It also allows wrappers to dictate the borrowed type. For now all wrappers of `T` just borrow `&T`, but in a subsequent PR `Ref<T>` will borrow to `&Ref<T>`, which allows implementations to increment the refcount. Signed-off-by: Wedson Almeida Filho <[email protected]>
1 parent 3c47616 commit 2117c9f

File tree

6 files changed

+146
-68
lines changed

6 files changed

+146
-68
lines changed

drivers/android/process.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -891,15 +891,15 @@ impl FileOperations for Process {
891891
}
892892
}
893893

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

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

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

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

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

920-
fn poll(&self, file: &File, table: &PollTable) -> Result<u32> {
921-
let thread = self.get_thread(unsafe { rust_helper_current_pid() })?;
920+
fn poll(this: &Process, file: &File, table: &PollTable) -> Result<u32> {
921+
let thread = this.get_thread(unsafe { rust_helper_current_pid() })?;
922922
let (from_proc, mut mask) = thread.poll(file, table);
923-
if mask == 0 && from_proc && !self.inner.lock().work.is_empty() {
923+
if mask == 0 && from_proc && !this.inner.lock().work.is_empty() {
924924
mask |= bindings::POLLIN;
925925
}
926926
Ok(mask)

drivers/char/hw_random/bcm2835_rng_rust.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ impl FileOpener<()> for RngDevice {
3737
impl FileOperations for RngDevice {
3838
kernel::declare_file_operations!(read);
3939

40-
fn read<T: IoBufferWriter>(&self, _: &File, data: &mut T, offset: u64) -> Result<usize> {
40+
fn read<T: IoBufferWriter>(_: &Self, _: &File, data: &mut T, offset: u64) -> Result<usize> {
4141
// Succeed if the caller doesn't provide a buffer or if not at the start.
4242
if data.is_empty() || offset != 0 {
4343
return Ok(0);

rust/kernel/file_operations.rs

Lines changed: 105 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//! C header: [`include/linux/fs.h`](../../../../include/linux/fs.h)
66
77
use core::convert::{TryFrom, TryInto};
8-
use core::{marker, mem, ptr};
8+
use core::{marker, mem, ops::Deref, ptr};
99

1010
use alloc::boxed::Box;
1111

@@ -99,10 +99,14 @@ unsafe extern "C" fn read_callback<T: FileOperations>(
9999
) -> c_types::c_ssize_t {
100100
from_kernel_result! {
101101
let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).writer() };
102-
let f = unsafe { &*((*file).private_data as *const T) };
102+
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
103+
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
104+
// callback, which the C API guarantees that will be called only when all references to
105+
// `file` have been released, so we know it can't be called while this function is running.
106+
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
103107
// No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
104108
// See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
105-
let read = f.read(unsafe { &FileRef::from_ptr(file) }, &mut data, unsafe { *offset }.try_into()?)?;
109+
let read = T::read(&f, unsafe { &FileRef::from_ptr(file) }, &mut data, unsafe { *offset }.try_into()?)?;
106110
unsafe { (*offset) += bindings::loff_t::try_from(read).unwrap() };
107111
Ok(read as _)
108112
}
@@ -116,8 +120,12 @@ unsafe extern "C" fn read_iter_callback<T: FileOperations>(
116120
let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
117121
let file = unsafe { (*iocb).ki_filp };
118122
let offset = unsafe { (*iocb).ki_pos };
119-
let f = unsafe { &*((*file).private_data as *const T) };
120-
let read = f.read(unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
123+
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
124+
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
125+
// callback, which the C API guarantees that will be called only when all references to
126+
// `file` have been released, so we know it can't be called while this function is running.
127+
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
128+
let read = T::read(&f, unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
121129
unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(read).unwrap() };
122130
Ok(read as _)
123131
}
@@ -131,10 +139,14 @@ unsafe extern "C" fn write_callback<T: FileOperations>(
131139
) -> c_types::c_ssize_t {
132140
from_kernel_result! {
133141
let mut data = unsafe { UserSlicePtr::new(buf as *mut c_types::c_void, len).reader() };
134-
let f = unsafe { &*((*file).private_data as *const T) };
142+
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
143+
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
144+
// callback, which the C API guarantees that will be called only when all references to
145+
// `file` have been released, so we know it can't be called while this function is running.
146+
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
135147
// No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
136148
// See discussion in https://github.com/fishinabarrel/linux-kernel-module-rust/pull/113
137-
let written = f.write(unsafe { &FileRef::from_ptr(file) }, &mut data, unsafe { *offset }.try_into()?)?;
149+
let written = T::write(&f, unsafe { &FileRef::from_ptr(file) }, &mut data, unsafe { *offset }.try_into()?)?;
138150
unsafe { (*offset) += bindings::loff_t::try_from(written).unwrap() };
139151
Ok(written as _)
140152
}
@@ -148,8 +160,12 @@ unsafe extern "C" fn write_iter_callback<T: FileOperations>(
148160
let mut iter = unsafe { IovIter::from_ptr(raw_iter) };
149161
let file = unsafe { (*iocb).ki_filp };
150162
let offset = unsafe { (*iocb).ki_pos };
151-
let f = unsafe { &*((*file).private_data as *const T) };
152-
let written = f.write(unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
163+
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
164+
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
165+
// callback, which the C API guarantees that will be called only when all references to
166+
// `file` have been released, so we know it can't be called while this function is running.
167+
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
168+
let written = T::write(&f, unsafe { &FileRef::from_ptr(file) }, &mut iter, offset.try_into()?)?;
153169
unsafe { (*iocb).ki_pos += bindings::loff_t::try_from(written).unwrap() };
154170
Ok(written as _)
155171
}
@@ -178,8 +194,12 @@ unsafe extern "C" fn llseek_callback<T: FileOperations>(
178194
bindings::SEEK_END => SeekFrom::End(offset),
179195
_ => return Err(Error::EINVAL),
180196
};
181-
let f = unsafe { &*((*file).private_data as *const T) };
182-
let off = f.seek(unsafe { &FileRef::from_ptr(file) }, off)?;
197+
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
198+
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
199+
// callback, which the C API guarantees that will be called only when all references to
200+
// `file` have been released, so we know it can't be called while this function is running.
201+
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
202+
let off = T::seek(&f, unsafe { &FileRef::from_ptr(file) }, off)?;
183203
Ok(off as bindings::loff_t)
184204
}
185205
}
@@ -190,10 +210,13 @@ unsafe extern "C" fn unlocked_ioctl_callback<T: FileOperations>(
190210
arg: c_types::c_ulong,
191211
) -> c_types::c_long {
192212
from_kernel_result! {
193-
let f = unsafe { &*((*file).private_data as *const T) };
194-
// SAFETY: This function is called by the kernel, so it must set `fs` appropriately.
213+
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
214+
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
215+
// callback, which the C API guarantees that will be called only when all references to
216+
// `file` have been released, so we know it can't be called while this function is running.
217+
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
195218
let mut cmd = IoctlCommand::new(cmd as _, arg as _);
196-
let ret = f.ioctl(unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
219+
let ret = T::ioctl(&f, unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
197220
Ok(ret as _)
198221
}
199222
}
@@ -204,10 +227,13 @@ unsafe extern "C" fn compat_ioctl_callback<T: FileOperations>(
204227
arg: c_types::c_ulong,
205228
) -> c_types::c_long {
206229
from_kernel_result! {
207-
let f = unsafe { &*((*file).private_data as *const T) };
208-
// SAFETY: This function is called by the kernel, so it must set `fs` appropriately.
230+
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
231+
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
232+
// callback, which the C API guarantees that will be called only when all references to
233+
// `file` have been released, so we know it can't be called while this function is running.
234+
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
209235
let mut cmd = IoctlCommand::new(cmd as _, arg as _);
210-
let ret = f.compat_ioctl(unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
236+
let ret = T::compat_ioctl(&f, unsafe { &FileRef::from_ptr(file) }, &mut cmd)?;
211237
Ok(ret as _)
212238
}
213239
}
@@ -217,8 +243,12 @@ unsafe extern "C" fn mmap_callback<T: FileOperations>(
217243
vma: *mut bindings::vm_area_struct,
218244
) -> c_types::c_int {
219245
from_kernel_result! {
220-
let f = unsafe { &*((*file).private_data as *const T) };
221-
f.mmap(unsafe { &FileRef::from_ptr(file) }, unsafe { &mut *vma })?;
246+
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
247+
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
248+
// callback, which the C API guarantees that will be called only when all references to
249+
// `file` have been released, so we know it can't be called while this function is running.
250+
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
251+
T::mmap(&f, unsafe { &FileRef::from_ptr(file) }, unsafe { &mut *vma })?;
222252
Ok(0)
223253
}
224254
}
@@ -233,8 +263,12 @@ unsafe extern "C" fn fsync_callback<T: FileOperations>(
233263
let start = start.try_into()?;
234264
let end = end.try_into()?;
235265
let datasync = datasync != 0;
236-
let f = unsafe { &*((*file).private_data as *const T) };
237-
let res = f.fsync(unsafe { &FileRef::from_ptr(file) }, start, end, datasync)?;
266+
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
267+
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
268+
// callback, which the C API guarantees that will be called only when all references to
269+
// `file` have been released, so we know it can't be called while this function is running.
270+
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
271+
let res = T::fsync(&f, unsafe { &FileRef::from_ptr(file) }, start, end, datasync)?;
238272
Ok(res.try_into().unwrap())
239273
}
240274
}
@@ -243,8 +277,12 @@ unsafe extern "C" fn poll_callback<T: FileOperations>(
243277
file: *mut bindings::file,
244278
wait: *mut bindings::poll_table_struct,
245279
) -> bindings::__poll_t {
246-
let f = unsafe { &*((*file).private_data as *const T) };
247-
match f.poll(unsafe { &FileRef::from_ptr(file) }, unsafe {
280+
// SAFETY: `private_data` was initialised by `open_callback` with a value returned by
281+
// `T::Wrapper::into_pointer`. `T::Wrapper::from_pointer` is only called by the `release`
282+
// callback, which the C API guarantees that will be called only when all references to `file`
283+
// have been released, so we know it can't be called while this function is running.
284+
let f = unsafe { T::Wrapper::borrow((*file).private_data) };
285+
match T::poll(&f, unsafe { &FileRef::from_ptr(file) }, unsafe {
248286
&PollTable::from_ptr(wait)
249287
}) {
250288
Ok(v) => v,
@@ -549,58 +587,94 @@ pub trait FileOperations: Send + Sync + Sized {
549587
/// Reads data from this file to the caller's buffer.
550588
///
551589
/// Corresponds to the `read` and `read_iter` function pointers in `struct file_operations`.
552-
fn read<T: IoBufferWriter>(&self, _file: &File, _data: &mut T, _offset: u64) -> Result<usize> {
590+
fn read<T: IoBufferWriter>(
591+
_this: &<<Self::Wrapper as PointerWrapper>::Borrowed as Deref>::Target,
592+
_file: &File,
593+
_data: &mut T,
594+
_offset: u64,
595+
) -> Result<usize> {
553596
Err(Error::EINVAL)
554597
}
555598

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

563611
/// Changes the position of the file.
564612
///
565613
/// Corresponds to the `llseek` function pointer in `struct file_operations`.
566-
fn seek(&self, _file: &File, _offset: SeekFrom) -> Result<u64> {
614+
fn seek(
615+
_this: &<<Self::Wrapper as PointerWrapper>::Borrowed as Deref>::Target,
616+
_file: &File,
617+
_offset: SeekFrom,
618+
) -> Result<u64> {
567619
Err(Error::EINVAL)
568620
}
569621

570622
/// Performs IO control operations that are specific to the file.
571623
///
572624
/// Corresponds to the `unlocked_ioctl` function pointer in `struct file_operations`.
573-
fn ioctl(&self, _file: &File, _cmd: &mut IoctlCommand) -> Result<i32> {
625+
fn ioctl(
626+
_this: &<<Self::Wrapper as PointerWrapper>::Borrowed as Deref>::Target,
627+
_file: &File,
628+
_cmd: &mut IoctlCommand,
629+
) -> Result<i32> {
574630
Err(Error::EINVAL)
575631
}
576632

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

584644
/// Syncs pending changes to this file.
585645
///
586646
/// Corresponds to the `fsync` function pointer in `struct file_operations`.
587-
fn fsync(&self, _file: &File, _start: u64, _end: u64, _datasync: bool) -> Result<u32> {
647+
fn fsync(
648+
_this: &<<Self::Wrapper as PointerWrapper>::Borrowed as Deref>::Target,
649+
_file: &File,
650+
_start: u64,
651+
_end: u64,
652+
_datasync: bool,
653+
) -> Result<u32> {
588654
Err(Error::EINVAL)
589655
}
590656

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

599669
/// Checks the state of the file and optionally registers for notification when the state
600670
/// changes.
601671
///
602672
/// Corresponds to the `poll` function pointer in `struct file_operations`.
603-
fn poll(&self, _file: &File, _table: &PollTable) -> Result<u32> {
673+
fn poll(
674+
_this: &<<Self::Wrapper as PointerWrapper>::Borrowed as Deref>::Target,
675+
_file: &File,
676+
_table: &PollTable,
677+
) -> Result<u32> {
604678
Ok(bindings::POLLIN | bindings::POLLOUT | bindings::POLLRDNORM | bindings::POLLWRNORM)
605679
}
606680
}

0 commit comments

Comments
 (0)