5
5
//! C header: [`include/linux/fs.h`](../../../../include/linux/fs.h)
6
6
7
7
use core:: convert:: { TryFrom , TryInto } ;
8
- use core:: { marker, mem, ptr} ;
8
+ use core:: { marker, mem, ops :: Deref , ptr} ;
9
9
10
10
use alloc:: boxed:: Box ;
11
11
@@ -99,10 +99,14 @@ unsafe extern "C" fn read_callback<T: FileOperations>(
99
99
) -> c_types:: c_ssize_t {
100
100
from_kernel_result ! {
101
101
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) } ;
103
107
// No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
104
108
// 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( ) ?) ?;
106
110
unsafe { ( * offset) += bindings:: loff_t:: try_from( read) . unwrap( ) } ;
107
111
Ok ( read as _)
108
112
}
@@ -116,8 +120,12 @@ unsafe extern "C" fn read_iter_callback<T: FileOperations>(
116
120
let mut iter = unsafe { IovIter :: from_ptr( raw_iter) } ;
117
121
let file = unsafe { ( * iocb) . ki_filp } ;
118
122
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( ) ?) ?;
121
129
unsafe { ( * iocb) . ki_pos += bindings:: loff_t:: try_from( read) . unwrap( ) } ;
122
130
Ok ( read as _)
123
131
}
@@ -131,10 +139,14 @@ unsafe extern "C" fn write_callback<T: FileOperations>(
131
139
) -> c_types:: c_ssize_t {
132
140
from_kernel_result ! {
133
141
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) } ;
135
147
// No `FMODE_UNSIGNED_OFFSET` support, so `offset` must be in [0, 2^63).
136
148
// 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( ) ?) ?;
138
150
unsafe { ( * offset) += bindings:: loff_t:: try_from( written) . unwrap( ) } ;
139
151
Ok ( written as _)
140
152
}
@@ -148,8 +160,12 @@ unsafe extern "C" fn write_iter_callback<T: FileOperations>(
148
160
let mut iter = unsafe { IovIter :: from_ptr( raw_iter) } ;
149
161
let file = unsafe { ( * iocb) . ki_filp } ;
150
162
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( ) ?) ?;
153
169
unsafe { ( * iocb) . ki_pos += bindings:: loff_t:: try_from( written) . unwrap( ) } ;
154
170
Ok ( written as _)
155
171
}
@@ -178,8 +194,12 @@ unsafe extern "C" fn llseek_callback<T: FileOperations>(
178
194
bindings:: SEEK_END => SeekFrom :: End ( offset) ,
179
195
_ => return Err ( Error :: EINVAL ) ,
180
196
} ;
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) ?;
183
203
Ok ( off as bindings:: loff_t)
184
204
}
185
205
}
@@ -190,10 +210,13 @@ unsafe extern "C" fn unlocked_ioctl_callback<T: FileOperations>(
190
210
arg : c_types:: c_ulong ,
191
211
) -> c_types:: c_long {
192
212
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) } ;
195
218
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) ?;
197
220
Ok ( ret as _)
198
221
}
199
222
}
@@ -204,10 +227,13 @@ unsafe extern "C" fn compat_ioctl_callback<T: FileOperations>(
204
227
arg : c_types:: c_ulong ,
205
228
) -> c_types:: c_long {
206
229
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) } ;
209
235
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) ?;
211
237
Ok ( ret as _)
212
238
}
213
239
}
@@ -217,8 +243,12 @@ unsafe extern "C" fn mmap_callback<T: FileOperations>(
217
243
vma : * mut bindings:: vm_area_struct ,
218
244
) -> c_types:: c_int {
219
245
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 } ) ?;
222
252
Ok ( 0 )
223
253
}
224
254
}
@@ -233,8 +263,12 @@ unsafe extern "C" fn fsync_callback<T: FileOperations>(
233
263
let start = start. try_into( ) ?;
234
264
let end = end. try_into( ) ?;
235
265
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) ?;
238
272
Ok ( res. try_into( ) . unwrap( ) )
239
273
}
240
274
}
@@ -243,8 +277,12 @@ unsafe extern "C" fn poll_callback<T: FileOperations>(
243
277
file : * mut bindings:: file ,
244
278
wait : * mut bindings:: poll_table_struct ,
245
279
) -> 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 {
248
286
& PollTable :: from_ptr ( wait)
249
287
} ) {
250
288
Ok ( v) => v,
@@ -549,58 +587,94 @@ pub trait FileOperations: Send + Sync + Sized {
549
587
/// Reads data from this file to the caller's buffer.
550
588
///
551
589
/// 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 > {
553
596
Err ( Error :: EINVAL )
554
597
}
555
598
556
599
/// Writes data from the caller's buffer to this file.
557
600
///
558
601
/// 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 > {
560
608
Err ( Error :: EINVAL )
561
609
}
562
610
563
611
/// Changes the position of the file.
564
612
///
565
613
/// 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 > {
567
619
Err ( Error :: EINVAL )
568
620
}
569
621
570
622
/// Performs IO control operations that are specific to the file.
571
623
///
572
624
/// 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 > {
574
630
Err ( Error :: EINVAL )
575
631
}
576
632
577
633
/// Performs 32-bit IO control operations on that are specific to the file on 64-bit kernels.
578
634
///
579
635
/// 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 > {
581
641
Err ( Error :: EINVAL )
582
642
}
583
643
584
644
/// Syncs pending changes to this file.
585
645
///
586
646
/// 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 > {
588
654
Err ( Error :: EINVAL )
589
655
}
590
656
591
657
/// Maps areas of the caller's virtual memory with device/file memory.
592
658
///
593
659
/// Corresponds to the `mmap` function pointer in `struct file_operations`.
594
660
/// 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 {
596
666
Err ( Error :: EINVAL )
597
667
}
598
668
599
669
/// Checks the state of the file and optionally registers for notification when the state
600
670
/// changes.
601
671
///
602
672
/// 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 > {
604
678
Ok ( bindings:: POLLIN | bindings:: POLLOUT | bindings:: POLLRDNORM | bindings:: POLLWRNORM )
605
679
}
606
680
}
0 commit comments