Skip to content

Commit b6050dc

Browse files
committed
Make FileOpenAdapter compatibility an unsafe requirement.
1 parent 5a28fe6 commit b6050dc

3 files changed

Lines changed: 85 additions & 65 deletions

File tree

rust/kernel/chrdev.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,9 @@ impl<const N: usize> Registration<{ N }> {
114114
unsafe {
115115
bindings::cdev_init(
116116
cdev,
117-
&file_operations::FileOperationsVtable::<Self, T>::VTABLE,
117+
// SAFETY: The adapter doesn't retrieve any state yet, so it's compatible with any
118+
// registration.
119+
file_operations::build_file_operations::<Self, T>(),
118120
);
119121
(*cdev).owner = this.this_module.0;
120122
let rc = bindings::cdev_add(cdev, inner.dev + inner.used as bindings::dev_t, 1);
@@ -134,6 +136,8 @@ impl<const N: usize> file_operations::FileOpenAdapter for Registration<{ N }> {
134136
_inode: *mut bindings::inode,
135137
_file: *mut bindings::file,
136138
) -> *const Self::Arg {
139+
// TODO: Update the SAFETY comment on the call to `build_file_operations` above once this
140+
// is updated to retrieve state.
137141
&()
138142
}
139143
}

rust/kernel/file_operations.rs

Lines changed: 77 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::c_types;
1515
use crate::error::{Error, KernelResult};
1616
use crate::sync::{Ref, RefCounted};
1717
use crate::user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter};
18+
pub use file_operations_struct::build_file_operations;
1819

1920
/// Wraps the kernel's `struct file`.
2021
///
@@ -201,68 +202,82 @@ unsafe extern "C" fn fsync_callback<T: FileOperations>(
201202
}
202203
}
203204

204-
pub(crate) struct FileOperationsVtable<A, T>(marker::PhantomData<A>, marker::PhantomData<T>);
205-
206-
impl<A: FileOpenAdapter, T: FileOpener<A::Arg>> FileOperationsVtable<A, T> {
207-
pub(crate) const VTABLE: bindings::file_operations = bindings::file_operations {
208-
open: Some(open_callback::<A, T>),
209-
release: Some(release_callback::<T>),
210-
read: if T::TO_USE.read {
211-
Some(read_callback::<T>)
212-
} else {
213-
None
214-
},
215-
write: if T::TO_USE.write {
216-
Some(write_callback::<T>)
217-
} else {
218-
None
219-
},
220-
llseek: if T::TO_USE.seek {
221-
Some(llseek_callback::<T>)
222-
} else {
223-
None
224-
},
225-
226-
check_flags: None,
227-
compat_ioctl: if T::TO_USE.compat_ioctl {
228-
Some(compat_ioctl_callback::<T>)
229-
} else {
230-
None
231-
},
232-
copy_file_range: None,
233-
fallocate: None,
234-
fadvise: None,
235-
fasync: None,
236-
flock: None,
237-
flush: None,
238-
fsync: if T::TO_USE.fsync {
239-
Some(fsync_callback::<T>)
240-
} else {
241-
None
242-
},
243-
get_unmapped_area: None,
244-
iterate: None,
245-
iterate_shared: None,
246-
iopoll: None,
247-
lock: None,
248-
mmap: None,
249-
mmap_supported_flags: 0,
250-
owner: ptr::null_mut(),
251-
poll: None,
252-
read_iter: None,
253-
remap_file_range: None,
254-
sendpage: None,
255-
setlease: None,
256-
show_fdinfo: None,
257-
splice_read: None,
258-
splice_write: None,
259-
unlocked_ioctl: if T::TO_USE.ioctl {
260-
Some(unlocked_ioctl_callback::<T>)
261-
} else {
262-
None
263-
},
264-
write_iter: None,
265-
};
205+
mod file_operations_struct {
206+
use super::*;
207+
208+
struct FileOperationsVtable<A, T>(marker::PhantomData<A>, marker::PhantomData<T>);
209+
210+
impl<A: FileOpenAdapter, T: FileOpener<A::Arg>> FileOperationsVtable<A, T> {
211+
const VTABLE: bindings::file_operations = bindings::file_operations {
212+
open: Some(open_callback::<A, T>),
213+
release: Some(release_callback::<T>),
214+
read: if T::TO_USE.read {
215+
Some(read_callback::<T>)
216+
} else {
217+
None
218+
},
219+
write: if T::TO_USE.write {
220+
Some(write_callback::<T>)
221+
} else {
222+
None
223+
},
224+
llseek: if T::TO_USE.seek {
225+
Some(llseek_callback::<T>)
226+
} else {
227+
None
228+
},
229+
230+
check_flags: None,
231+
compat_ioctl: if T::TO_USE.compat_ioctl {
232+
Some(compat_ioctl_callback::<T>)
233+
} else {
234+
None
235+
},
236+
copy_file_range: None,
237+
fallocate: None,
238+
fadvise: None,
239+
fasync: None,
240+
flock: None,
241+
flush: None,
242+
fsync: if T::TO_USE.fsync {
243+
Some(fsync_callback::<T>)
244+
} else {
245+
None
246+
},
247+
get_unmapped_area: None,
248+
iterate: None,
249+
iterate_shared: None,
250+
iopoll: None,
251+
lock: None,
252+
mmap: None,
253+
mmap_supported_flags: 0,
254+
owner: ptr::null_mut(),
255+
poll: None,
256+
read_iter: None,
257+
remap_file_range: None,
258+
sendpage: None,
259+
setlease: None,
260+
show_fdinfo: None,
261+
splice_read: None,
262+
splice_write: None,
263+
unlocked_ioctl: if T::TO_USE.ioctl {
264+
Some(unlocked_ioctl_callback::<T>)
265+
} else {
266+
None
267+
},
268+
write_iter: None,
269+
};
270+
}
271+
272+
/// Builds an instance of the [`struct file_operations`] for the given file adapter and opener.
273+
///
274+
/// # Safety
275+
///
276+
/// The caller must ensure that the adapter is compatible with the way the device is registered.
277+
pub const unsafe fn build_file_operations<A: FileOpenAdapter, T: FileOpener<A::Arg>>(
278+
) -> &'static bindings::file_operations {
279+
&FileOperationsVtable::<A, T>::VTABLE
280+
}
266281
}
267282

268283
/// Represents which fields of [`struct file_operations`] should be populated with pointers.

rust/kernel/miscdev.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! Reference: <https://www.kernel.org/doc/html/latest/driver-api/misc_devices.html>
88
99
use crate::error::{Error, KernelResult};
10-
use crate::file_operations::{FileOpenAdapter, FileOpener, FileOperationsVtable};
10+
use crate::file_operations::{build_file_operations, FileOpenAdapter, FileOpener};
1111
use crate::{bindings, c_types, CStr};
1212
use alloc::boxed::Box;
1313
use core::marker::PhantomPinned;
@@ -71,7 +71,8 @@ impl<T: Sync> Registration<T> {
7171
return Err(Error::EINVAL);
7272
}
7373

74-
this.mdev.fops = &FileOperationsVtable::<Self, F>::VTABLE;
74+
// SAFETY: The adapter is compatible with `misc_register`.
75+
this.mdev.fops = unsafe { build_file_operations::<Self, F>() };
7576
this.mdev.name = name.as_ptr() as *const c_types::c_char;
7677
this.mdev.minor = minor.unwrap_or(bindings::MISC_DYNAMIC_MINOR as i32);
7778

0 commit comments

Comments
 (0)