Skip to content
This repository was archived by the owner on Mar 7, 2021. It is now read-only.

Commit 079f100

Browse files
authored
Change the FileOperations API to reduce the use of nightly features (#268)
1 parent 3ad884e commit 079f100

File tree

4 files changed

+131
-180
lines changed

4 files changed

+131
-180
lines changed

src/chrdev.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@ pub fn builder(name: &'static CStr, minors: Range<u16>) -> KernelResult<Builder>
2323
pub struct Builder {
2424
name: &'static CStr,
2525
minors: Range<u16>,
26-
file_ops: Vec<&'static file_operations::FileOperationsVtable>,
26+
file_ops: Vec<&'static bindings::file_operations>,
2727
}
2828

2929
impl Builder {
3030
pub fn register_device<T: file_operations::FileOperations>(mut self) -> Builder {
3131
if self.file_ops.len() >= self.minors.len() {
3232
panic!("More devices registered than minor numbers allocated.")
3333
}
34-
self.file_ops.push(&T::VTABLE);
34+
self.file_ops
35+
.push(&file_operations::FileOperationsVtable::<T>::VTABLE);
3536
self
3637
}
3738

@@ -54,7 +55,7 @@ impl Builder {
5455
let mut cdevs = vec![unsafe { mem::zeroed() }; self.file_ops.len()].into_boxed_slice();
5556
for (i, file_op) in self.file_ops.iter().enumerate() {
5657
unsafe {
57-
bindings::cdev_init(&mut cdevs[i], &file_op.0);
58+
bindings::cdev_init(&mut cdevs[i], *file_op);
5859
cdevs[i].owner = &mut bindings::__this_module;
5960
let rc = bindings::cdev_add(&mut cdevs[i], dev + i as bindings::dev_t, 1);
6061
if rc != 0 {

src/file_operations.rs

+80-109
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ pub enum SeekFrom {
3939
Current(i64),
4040
}
4141

42-
pub struct FileOperationsVtable(pub(crate) bindings::file_operations);
43-
4442
unsafe extern "C" fn open_callback<T: FileOperations>(
4543
_inode: *mut bindings::inode,
4644
file: *mut bindings::file,
@@ -53,7 +51,7 @@ unsafe extern "C" fn open_callback<T: FileOperations>(
5351
0
5452
}
5553

56-
unsafe extern "C" fn read_callback<T: Read>(
54+
unsafe extern "C" fn read_callback<T: FileOperations>(
5755
file: *mut bindings::file,
5856
buf: *mut c_types::c_char,
5957
len: c_types::c_size_t,
@@ -70,7 +68,8 @@ unsafe extern "C" fn read_callback<T: Read>(
7068
Ok(v) => v,
7169
Err(_) => return Error::EINVAL.to_kernel_errno().try_into().unwrap(),
7270
};
73-
match f.read(&File::from_ptr(file), &mut data, positive_offset) {
71+
let read = T::READ.unwrap();
72+
match read(f, &File::from_ptr(file), &mut data, positive_offset) {
7473
Ok(()) => {
7574
let written = len - data.len();
7675
(*offset) += bindings::loff_t::try_from(written).unwrap();
@@ -80,7 +79,7 @@ unsafe extern "C" fn read_callback<T: Read>(
8079
}
8180
}
8281

83-
unsafe extern "C" fn write_callback<T: Write>(
82+
unsafe extern "C" fn write_callback<T: FileOperations>(
8483
file: *mut bindings::file,
8584
buf: *const c_types::c_char,
8685
len: c_types::c_size_t,
@@ -97,7 +96,8 @@ unsafe extern "C" fn write_callback<T: Write>(
9796
Ok(v) => v,
9897
Err(_) => return Error::EINVAL.to_kernel_errno().try_into().unwrap(),
9998
};
100-
match f.write(&mut data, positive_offset) {
99+
let write = T::WRITE.unwrap();
100+
match write(f, &mut data, positive_offset) {
101101
Ok(()) => {
102102
let read = len - data.len();
103103
(*offset) += bindings::loff_t::try_from(read).unwrap();
@@ -116,7 +116,7 @@ unsafe extern "C" fn release_callback<T: FileOperations>(
116116
0
117117
}
118118

119-
unsafe extern "C" fn llseek_callback<T: Seek>(
119+
unsafe extern "C" fn llseek_callback<T: FileOperations>(
120120
file: *mut bindings::file,
121121
offset: bindings::loff_t,
122122
whence: c_types::c_int,
@@ -131,130 +131,101 @@ unsafe extern "C" fn llseek_callback<T: Seek>(
131131
_ => return Error::EINVAL.to_kernel_errno().into(),
132132
};
133133
let f = &*((*file).private_data as *const T);
134-
match f.seek(&File::from_ptr(file), off) {
134+
let seek = T::SEEK.unwrap();
135+
match seek(f, &File::from_ptr(file), off) {
135136
Ok(off) => off as bindings::loff_t,
136137
Err(e) => e.to_kernel_errno().into(),
137138
}
138139
}
139140

140-
impl FileOperationsVtable {
141-
pub const fn builder<T: FileOperations>() -> FileOperationsVtableBuilder<T> {
142-
FileOperationsVtableBuilder(
143-
bindings::file_operations {
144-
open: Some(open_callback::<T>),
145-
release: Some(release_callback::<T>),
146-
147-
#[cfg(not(kernel_4_9_0_or_greater))]
148-
aio_fsync: None,
149-
check_flags: None,
150-
#[cfg(all(kernel_4_5_0_or_greater, not(kernel_4_20_0_or_greater)))]
151-
clone_file_range: None,
152-
compat_ioctl: None,
153-
#[cfg(kernel_4_5_0_or_greater)]
154-
copy_file_range: None,
155-
#[cfg(all(kernel_4_5_0_or_greater, not(kernel_4_20_0_or_greater)))]
156-
dedupe_file_range: None,
157-
fallocate: None,
158-
#[cfg(kernel_4_19_0_or_greater)]
159-
fadvise: None,
160-
fasync: None,
161-
flock: None,
162-
flush: None,
163-
fsync: None,
164-
get_unmapped_area: None,
165-
iterate: None,
166-
#[cfg(kernel_4_7_0_or_greater)]
167-
iterate_shared: None,
168-
#[cfg(kernel_5_1_0_or_greater)]
169-
iopoll: None,
170-
llseek: None,
171-
lock: None,
172-
mmap: None,
173-
#[cfg(kernel_4_15_0_or_greater)]
174-
mmap_supported_flags: 0,
175-
owner: ptr::null_mut(),
176-
poll: None,
177-
read: None,
178-
read_iter: None,
179-
#[cfg(kernel_4_20_0_or_greater)]
180-
remap_file_range: None,
181-
sendpage: None,
182-
#[cfg(kernel_aufs_setfl)]
183-
setfl: None,
184-
setlease: None,
185-
show_fdinfo: None,
186-
splice_read: None,
187-
splice_write: None,
188-
unlocked_ioctl: None,
189-
write: None,
190-
write_iter: None,
191-
},
192-
marker::PhantomData,
193-
)
194-
}
195-
}
196-
197-
pub struct FileOperationsVtableBuilder<T>(bindings::file_operations, marker::PhantomData<T>);
141+
pub(crate) struct FileOperationsVtable<T>(marker::PhantomData<T>);
198142

199-
impl<T> FileOperationsVtableBuilder<T> {
200-
pub const fn build(self) -> FileOperationsVtable {
201-
FileOperationsVtable(self.0)
202-
}
203-
}
204-
205-
impl<T: Read> FileOperationsVtableBuilder<T> {
206-
pub const fn read(mut self) -> FileOperationsVtableBuilder<T> {
207-
self.0.read = Some(read_callback::<T>);
208-
self
209-
}
210-
}
143+
impl<T: FileOperations> FileOperationsVtable<T> {
144+
pub(crate) const VTABLE: bindings::file_operations = bindings::file_operations {
145+
open: Some(open_callback::<T>),
146+
release: Some(release_callback::<T>),
147+
read: if let Some(_) = T::READ {
148+
Some(read_callback::<T>)
149+
} else {
150+
None
151+
},
152+
write: if let Some(_) = T::WRITE {
153+
Some(write_callback::<T>)
154+
} else {
155+
None
156+
},
157+
llseek: if let Some(_) = T::SEEK {
158+
Some(llseek_callback::<T>)
159+
} else {
160+
None
161+
},
211162

212-
impl<T: Write> FileOperationsVtableBuilder<T> {
213-
pub const fn write(mut self) -> FileOperationsVtableBuilder<T> {
214-
self.0.write = Some(write_callback::<T>);
215-
self
216-
}
163+
#[cfg(not(kernel_4_9_0_or_greater))]
164+
aio_fsync: None,
165+
check_flags: None,
166+
#[cfg(all(kernel_4_5_0_or_greater, not(kernel_4_20_0_or_greater)))]
167+
clone_file_range: None,
168+
compat_ioctl: None,
169+
#[cfg(kernel_4_5_0_or_greater)]
170+
copy_file_range: None,
171+
#[cfg(all(kernel_4_5_0_or_greater, not(kernel_4_20_0_or_greater)))]
172+
dedupe_file_range: None,
173+
fallocate: None,
174+
#[cfg(kernel_4_19_0_or_greater)]
175+
fadvise: None,
176+
fasync: None,
177+
flock: None,
178+
flush: None,
179+
fsync: None,
180+
get_unmapped_area: None,
181+
iterate: None,
182+
#[cfg(kernel_4_7_0_or_greater)]
183+
iterate_shared: None,
184+
#[cfg(kernel_5_1_0_or_greater)]
185+
iopoll: None,
186+
lock: None,
187+
mmap: None,
188+
#[cfg(kernel_4_15_0_or_greater)]
189+
mmap_supported_flags: 0,
190+
owner: ptr::null_mut(),
191+
poll: None,
192+
read_iter: None,
193+
#[cfg(kernel_4_20_0_or_greater)]
194+
remap_file_range: None,
195+
sendpage: None,
196+
#[cfg(kernel_aufs_setfl)]
197+
setfl: None,
198+
setlease: None,
199+
show_fdinfo: None,
200+
splice_read: None,
201+
splice_write: None,
202+
unlocked_ioctl: None,
203+
write_iter: None,
204+
};
217205
}
218206

219-
impl<T: Seek> FileOperationsVtableBuilder<T> {
220-
pub const fn seek(mut self) -> FileOperationsVtableBuilder<T> {
221-
self.0.llseek = Some(llseek_callback::<T>);
222-
self
223-
}
224-
}
207+
pub type ReadFn<T> = Option<fn(&T, &File, &mut UserSlicePtrWriter, u64) -> KernelResult<()>>;
208+
pub type WriteFn<T> = Option<fn(&T, &mut UserSlicePtrReader, u64) -> KernelResult<()>>;
209+
pub type SeekFn<T> = Option<fn(&T, &File, SeekFrom) -> KernelResult<u64>>;
225210

226211
/// `FileOperations` corresponds to the kernel's `struct file_operations`. You
227-
/// implement this trait whenever you'd create a `struct file_operations`, and
228-
/// also an additional trait for each function pointer in the
229-
/// `struct file_operations`. File descriptors may be used from multiple threads
230-
/// (or processes) concurrently, so your type must be `Sync`.
212+
/// implement this trait whenever you'd create a `struct file_operations`.
213+
/// File descriptors may be used from multiple threads (or processes)
214+
/// concurrently, so your type must be `Sync`.
231215
pub trait FileOperations: Sync + Sized {
232-
/// A container for the actual `file_operations` value. This will always be:
233-
/// ```
234-
/// const VTABLE: linux_kernel_module::chrdev::FileOperationsVtable =
235-
/// linux_kernel_module::chrdev::FileOperationsVtable::new::<Self>();
236-
/// ```
237-
const VTABLE: FileOperationsVtable;
238-
239216
/// Creates a new instance of this file. Corresponds to the `open` function
240217
/// pointer in `struct file_operations`.
241218
fn open() -> KernelResult<Self>;
242-
}
243219

244-
pub trait Read {
245220
/// Reads data from this file to userspace. Corresponds to the `read`
246221
/// function pointer in `struct file_operations`.
247-
fn read(&self, file: &File, buf: &mut UserSlicePtrWriter, offset: u64) -> KernelResult<()>;
248-
}
222+
const READ: ReadFn<Self> = None;
249223

250-
pub trait Write {
251224
/// Writes data from userspace o this file. Corresponds to the `write`
252225
/// function pointer in `struct file_operations`.
253-
fn write(&self, buf: &mut UserSlicePtrReader, offset: u64) -> KernelResult<()>;
254-
}
226+
const WRITE: WriteFn<Self> = None;
255227

256-
pub trait Seek {
257228
/// Changes the position of the file. Corresponds to the `llseek` function
258229
/// pointer in `struct file_operations`.
259-
fn seek(&self, file: &File, offset: SeekFrom) -> KernelResult<u64>;
230+
const SEEK: SeekFn<Self> = None;
260231
}

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#![no_std]
2-
#![feature(allocator_api, alloc_error_handler, const_fn, const_raw_ptr_deref)]
2+
#![feature(allocator_api, alloc_error_handler, const_raw_ptr_deref)]
33

44
extern crate alloc;
55

0 commit comments

Comments
 (0)