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

Commit f3f24f2

Browse files
committed
Move FileOperations to its own mod
1 parent 75c82fb commit f3f24f2

File tree

4 files changed

+194
-184
lines changed

4 files changed

+194
-184
lines changed

src/chrdev.rs

Lines changed: 5 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use core::convert::{TryFrom, TryInto};
1+
use core::convert::TryInto;
2+
use core::mem;
23
use core::ops::Range;
3-
use core::{mem, ptr};
44

55
use alloc::boxed::Box;
66
use alloc::vec;
@@ -9,8 +9,8 @@ use alloc::vec::Vec;
99
use crate::bindings;
1010
use crate::c_types;
1111
use crate::error::{Error, KernelResult};
12+
use crate::file_operations;
1213
use crate::types::CStr;
13-
use crate::user_ptr::{UserSlicePtr, UserSlicePtrWriter};
1414

1515
pub fn builder(name: &'static CStr, minors: Range<u16>) -> KernelResult<Builder> {
1616
Ok(Builder {
@@ -23,11 +23,11 @@ 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 FileOperationsVtable>,
26+
file_ops: Vec<&'static file_operations::FileOperationsVtable>,
2727
}
2828

2929
impl Builder {
30-
pub fn register_device<T: FileOperations>(mut self) -> Builder {
30+
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
}
@@ -95,174 +95,3 @@ impl Drop for Registration {
9595
}
9696
}
9797
}
98-
99-
pub struct File {
100-
ptr: *const bindings::file,
101-
}
102-
103-
impl File {
104-
unsafe fn from_ptr(ptr: *const bindings::file) -> File {
105-
File { ptr }
106-
}
107-
108-
pub fn pos(&self) -> u64 {
109-
unsafe { (*self.ptr).f_pos as u64 }
110-
}
111-
}
112-
113-
// Matches std::io::SeekFrom in the Rust stdlib
114-
pub enum SeekFrom {
115-
Start(u64),
116-
End(i64),
117-
Current(i64),
118-
}
119-
120-
pub struct FileOperationsVtable(bindings::file_operations);
121-
122-
unsafe extern "C" fn open_callback<T: FileOperations>(
123-
_inode: *mut bindings::inode,
124-
file: *mut bindings::file,
125-
) -> c_types::c_int {
126-
let f = match T::open() {
127-
Ok(f) => Box::new(f),
128-
Err(e) => return e.to_kernel_errno(),
129-
};
130-
(*file).private_data = Box::into_raw(f) as *mut c_types::c_void;
131-
0
132-
}
133-
134-
unsafe extern "C" fn read_callback<T: FileOperations>(
135-
file: *mut bindings::file,
136-
buf: *mut c_types::c_char,
137-
len: c_types::c_size_t,
138-
offset: *mut bindings::loff_t,
139-
) -> c_types::c_ssize_t {
140-
let mut data = match UserSlicePtr::new(buf as *mut c_types::c_void, len) {
141-
Ok(ptr) => ptr.writer(),
142-
Err(e) => return e.to_kernel_errno().try_into().unwrap(),
143-
};
144-
let f = &*((*file).private_data as *const T);
145-
// No FMODE_UNSIGNED_OFFSET support, so offset must be in [0, 2^63).
146-
// See discussion in #113
147-
let positive_offset = match (*offset).try_into() {
148-
Ok(v) => v,
149-
Err(_) => return Error::EINVAL.to_kernel_errno().try_into().unwrap(),
150-
};
151-
match f.read(&mut data, positive_offset) {
152-
Ok(()) => {
153-
let written = len - data.len();
154-
(*offset) += bindings::loff_t::try_from(written).unwrap();
155-
written.try_into().unwrap()
156-
}
157-
Err(e) => e.to_kernel_errno().try_into().unwrap(),
158-
}
159-
}
160-
161-
unsafe extern "C" fn release_callback<T: FileOperations>(
162-
_inode: *mut bindings::inode,
163-
file: *mut bindings::file,
164-
) -> c_types::c_int {
165-
let ptr = mem::replace(&mut (*file).private_data, ptr::null_mut());
166-
drop(Box::from_raw(ptr as *mut T));
167-
0
168-
}
169-
170-
unsafe extern "C" fn llseek_callback<T: FileOperations>(
171-
file: *mut bindings::file,
172-
offset: bindings::loff_t,
173-
whence: c_types::c_int,
174-
) -> bindings::loff_t {
175-
let off = match whence as u32 {
176-
bindings::SEEK_SET => match offset.try_into() {
177-
Ok(v) => SeekFrom::Start(v),
178-
Err(_) => return Error::EINVAL.to_kernel_errno().into(),
179-
},
180-
bindings::SEEK_CUR => SeekFrom::Current(offset),
181-
bindings::SEEK_END => SeekFrom::End(offset),
182-
_ => return Error::EINVAL.to_kernel_errno().into(),
183-
};
184-
let f = &*((*file).private_data as *const T);
185-
match f.seek(&File::from_ptr(file), off) {
186-
Ok(off) => off as bindings::loff_t,
187-
Err(e) => e.to_kernel_errno().into(),
188-
}
189-
}
190-
191-
impl FileOperationsVtable {
192-
pub const fn new<T: FileOperations>() -> FileOperationsVtable {
193-
FileOperationsVtable(bindings::file_operations {
194-
open: Some(open_callback::<T>),
195-
read: Some(read_callback::<T>),
196-
release: Some(release_callback::<T>),
197-
llseek: Some(llseek_callback::<T>),
198-
199-
check_flags: None,
200-
#[cfg(not(kernel_4_20_0_or_greater))]
201-
clone_file_range: None,
202-
compat_ioctl: None,
203-
copy_file_range: None,
204-
#[cfg(not(kernel_4_20_0_or_greater))]
205-
dedupe_file_range: None,
206-
fallocate: None,
207-
#[cfg(kernel_4_19_0_or_greater)]
208-
fadvise: None,
209-
fasync: None,
210-
flock: None,
211-
flush: None,
212-
fsync: None,
213-
get_unmapped_area: None,
214-
iterate: None,
215-
iterate_shared: None,
216-
#[cfg(kernel_5_1_0_or_greater)]
217-
iopoll: None,
218-
lock: None,
219-
mmap: None,
220-
#[cfg(kernel_4_15_0_or_greater)]
221-
mmap_supported_flags: 0,
222-
owner: ptr::null_mut(),
223-
poll: None,
224-
read_iter: None,
225-
#[cfg(kernel_4_20_0_or_greater)]
226-
remap_file_range: None,
227-
sendpage: None,
228-
#[cfg(kernel_aufs_setfl)]
229-
setfl: None,
230-
setlease: None,
231-
show_fdinfo: None,
232-
splice_read: None,
233-
splice_write: None,
234-
unlocked_ioctl: None,
235-
write: None,
236-
write_iter: None,
237-
})
238-
}
239-
}
240-
241-
/// `FileOperations` corresponds to the kernel's `struct file_operations`. You
242-
/// implement this trait whenever you'd create a `struct file_operations`. File
243-
/// descriptors may be used from multiple threads (or processes) concurrently,
244-
/// so your type must be `Sync`.
245-
pub trait FileOperations: Sync + Sized {
246-
/// A container for the actual `file_operations` value. This will always be:
247-
/// ```
248-
/// const VTABLE: linux_kernel_module::chrdev::FileOperationsVtable =
249-
/// linux_kernel_module::chrdev::FileOperationsVtable::new::<Self>();
250-
/// ```
251-
const VTABLE: FileOperationsVtable;
252-
253-
/// Creates a new instance of this file. Corresponds to the `open` function
254-
/// pointer in `struct file_operations`.
255-
fn open() -> KernelResult<Self>;
256-
257-
/// Reads data from this file to userspace. Corresponds to the `read`
258-
/// function pointer in `struct file_operations`.
259-
fn read(&self, _buf: &mut UserSlicePtrWriter, _offset: u64) -> KernelResult<()> {
260-
Err(Error::EINVAL)
261-
}
262-
263-
/// Changes the position of the file. Corresponds to the `llseek` function
264-
/// pointer in `struct file_operations`.
265-
fn seek(&self, _file: &File, _offset: SeekFrom) -> KernelResult<u64> {
266-
Err(Error::ESPIPE)
267-
}
268-
}

src/file_operations.rs

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
use core::convert::{TryFrom, TryInto};
2+
use core::{mem, ptr};
3+
4+
use alloc::boxed::Box;
5+
6+
use crate::bindings;
7+
use crate::c_types;
8+
use crate::error::{Error, KernelResult};
9+
use crate::user_ptr::{UserSlicePtr, UserSlicePtrWriter};
10+
11+
pub struct File {
12+
ptr: *const bindings::file,
13+
}
14+
15+
impl File {
16+
unsafe fn from_ptr(ptr: *const bindings::file) -> File {
17+
File { ptr }
18+
}
19+
20+
pub fn pos(&self) -> u64 {
21+
unsafe { (*self.ptr).f_pos as u64 }
22+
}
23+
}
24+
25+
// Matches std::io::SeekFrom in the Rust stdlib
26+
pub enum SeekFrom {
27+
Start(u64),
28+
End(i64),
29+
Current(i64),
30+
}
31+
32+
pub struct FileOperationsVtable(pub(crate) bindings::file_operations);
33+
34+
unsafe extern "C" fn open_callback<T: FileOperations>(
35+
_inode: *mut bindings::inode,
36+
file: *mut bindings::file,
37+
) -> c_types::c_int {
38+
let f = match T::open() {
39+
Ok(f) => Box::new(f),
40+
Err(e) => return e.to_kernel_errno(),
41+
};
42+
(*file).private_data = Box::into_raw(f) as *mut c_types::c_void;
43+
0
44+
}
45+
46+
unsafe extern "C" fn read_callback<T: FileOperations>(
47+
file: *mut bindings::file,
48+
buf: *mut c_types::c_char,
49+
len: c_types::c_size_t,
50+
offset: *mut bindings::loff_t,
51+
) -> c_types::c_ssize_t {
52+
let mut data = match UserSlicePtr::new(buf as *mut c_types::c_void, len) {
53+
Ok(ptr) => ptr.writer(),
54+
Err(e) => return e.to_kernel_errno().try_into().unwrap(),
55+
};
56+
let f = &*((*file).private_data as *const T);
57+
// No FMODE_UNSIGNED_OFFSET support, so offset must be in [0, 2^63).
58+
// See discussion in #113
59+
let positive_offset = match (*offset).try_into() {
60+
Ok(v) => v,
61+
Err(_) => return Error::EINVAL.to_kernel_errno().try_into().unwrap(),
62+
};
63+
match f.read(&mut data, positive_offset) {
64+
Ok(()) => {
65+
let written = len - data.len();
66+
(*offset) += bindings::loff_t::try_from(written).unwrap();
67+
written.try_into().unwrap()
68+
}
69+
Err(e) => e.to_kernel_errno().try_into().unwrap(),
70+
}
71+
}
72+
73+
unsafe extern "C" fn release_callback<T: FileOperations>(
74+
_inode: *mut bindings::inode,
75+
file: *mut bindings::file,
76+
) -> c_types::c_int {
77+
let ptr = mem::replace(&mut (*file).private_data, ptr::null_mut());
78+
drop(Box::from_raw(ptr as *mut T));
79+
0
80+
}
81+
82+
unsafe extern "C" fn llseek_callback<T: FileOperations>(
83+
file: *mut bindings::file,
84+
offset: bindings::loff_t,
85+
whence: c_types::c_int,
86+
) -> bindings::loff_t {
87+
let off = match whence as u32 {
88+
bindings::SEEK_SET => match offset.try_into() {
89+
Ok(v) => SeekFrom::Start(v),
90+
Err(_) => return Error::EINVAL.to_kernel_errno().into(),
91+
},
92+
bindings::SEEK_CUR => SeekFrom::Current(offset),
93+
bindings::SEEK_END => SeekFrom::End(offset),
94+
_ => return Error::EINVAL.to_kernel_errno().into(),
95+
};
96+
let f = &*((*file).private_data as *const T);
97+
match f.seek(&File::from_ptr(file), off) {
98+
Ok(off) => off as bindings::loff_t,
99+
Err(e) => e.to_kernel_errno().into(),
100+
}
101+
}
102+
103+
impl FileOperationsVtable {
104+
pub const fn new<T: FileOperations>() -> FileOperationsVtable {
105+
FileOperationsVtable(bindings::file_operations {
106+
open: Some(open_callback::<T>),
107+
read: Some(read_callback::<T>),
108+
release: Some(release_callback::<T>),
109+
llseek: Some(llseek_callback::<T>),
110+
111+
check_flags: None,
112+
#[cfg(not(kernel_4_20_0_or_greater))]
113+
clone_file_range: None,
114+
compat_ioctl: None,
115+
copy_file_range: None,
116+
#[cfg(not(kernel_4_20_0_or_greater))]
117+
dedupe_file_range: None,
118+
fallocate: None,
119+
#[cfg(kernel_4_19_0_or_greater)]
120+
fadvise: None,
121+
fasync: None,
122+
flock: None,
123+
flush: None,
124+
fsync: None,
125+
get_unmapped_area: None,
126+
iterate: None,
127+
iterate_shared: None,
128+
#[cfg(kernel_5_1_0_or_greater)]
129+
iopoll: None,
130+
lock: None,
131+
mmap: None,
132+
#[cfg(kernel_4_15_0_or_greater)]
133+
mmap_supported_flags: 0,
134+
owner: ptr::null_mut(),
135+
poll: None,
136+
read_iter: None,
137+
#[cfg(kernel_4_20_0_or_greater)]
138+
remap_file_range: None,
139+
sendpage: None,
140+
#[cfg(kernel_aufs_setfl)]
141+
setfl: None,
142+
setlease: None,
143+
show_fdinfo: None,
144+
splice_read: None,
145+
splice_write: None,
146+
unlocked_ioctl: None,
147+
write: None,
148+
write_iter: None,
149+
})
150+
}
151+
}
152+
153+
/// `FileOperations` corresponds to the kernel's `struct file_operations`. You
154+
/// implement this trait whenever you'd create a `struct file_operations`. File
155+
/// descriptors may be used from multiple threads (or processes) concurrently,
156+
/// so your type must be `Sync`.
157+
pub trait FileOperations: Sync + Sized {
158+
/// A container for the actual `file_operations` value. This will always be:
159+
/// ```
160+
/// const VTABLE: linux_kernel_module::chrdev::FileOperationsVtable =
161+
/// linux_kernel_module::chrdev::FileOperationsVtable::new::<Self>();
162+
/// ```
163+
const VTABLE: FileOperationsVtable;
164+
165+
/// Creates a new instance of this file. Corresponds to the `open` function
166+
/// pointer in `struct file_operations`.
167+
fn open() -> KernelResult<Self>;
168+
169+
/// Reads data from this file to userspace. Corresponds to the `read`
170+
/// function pointer in `struct file_operations`.
171+
fn read(&self, _buf: &mut UserSlicePtrWriter, _offset: u64) -> KernelResult<()> {
172+
Err(Error::EINVAL)
173+
}
174+
175+
/// Changes the position of the file. Corresponds to the `llseek` function
176+
/// pointer in `struct file_operations`.
177+
fn seek(&self, _file: &File, _offset: SeekFrom) -> KernelResult<u64> {
178+
Err(Error::ESPIPE)
179+
}
180+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub mod bindings;
1010
pub mod c_types;
1111
pub mod chrdev;
1212
mod error;
13+
pub mod file_operations;
1314
pub mod filesystem;
1415
pub mod printk;
1516
pub mod sysctl;

0 commit comments

Comments
 (0)