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

Commit

Permalink
Refs #164 -- added write suppot to FileOperations
Browse files Browse the repository at this point in the history
  • Loading branch information
alex committed Sep 29, 2019
1 parent 8ece413 commit 82a2f4f
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 1 deletion.
34 changes: 33 additions & 1 deletion src/chrdev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,32 @@ unsafe extern "C" fn read_callback<T: FileOperations>(
}
}

unsafe extern "C" fn write_callback<T: FileOperations>(
file: *mut bindings::file,
buf: *mut c_ctypes::c_char,
len: c_types::c_size_t,
offset: *mut bindings::loff_t,
) -> c_types::c_ssize_t {
let mut data = match UserSlicePtr::new(buf as *mut c_types::c_void, len) {
Ok(ptr) => ptr.reader(),
Err(e) => return e.to_kernel_errno().try_into().unwrap(),
};
let f = &*((*file).private_data as *const T);
// No FMODE_UNSIGNED_OFFSET support, so offset must be in [0, 2^63).
// See discussion in #113
let positive_offset = match (*offset).try_into() {
Ok(v) => v,
Err(_) => return Error::EINVAL.to_kernel_errno().try_into().unwrap(),
};
match f.write(&data, positive_offset) {
Ok(()) => {
let read = len - data.len();
read.try_into().unwrap()
}
Err(e) => e.to_kernel_errno().try_into().unwrap(),
}
}

unsafe extern "C" fn release_callback<T: FileOperations>(
_inode: *mut bindings::inode,
file: *mut bindings::file,
Expand Down Expand Up @@ -193,6 +219,7 @@ impl FileOperationsVtable {
FileOperationsVtable(bindings::file_operations {
open: Some(open_callback::<T>),
read: Some(read_callback::<T>),
write: Some(write_callback::<T>),
release: Some(release_callback::<T>),
llseek: Some(llseek_callback::<T>),

Expand Down Expand Up @@ -232,7 +259,6 @@ impl FileOperationsVtable {
splice_read: None,
splice_write: None,
unlocked_ioctl: None,
write: None,
write_iter: None,
})
}
Expand Down Expand Up @@ -260,6 +286,12 @@ pub trait FileOperations: Sync + Sized {
Err(Error::EINVAL)
}

/// Writes data from userspace o this file. Corresponds to the `write`
/// function pointer in `struct file_operations`.
fn write(&self, _buf: &mut UserSlicePtrReader, _offset: u64) -> KernelResult<()> {
Err(Error::EINVAL);
}

/// Changes the position of the file. Corresponds to the `llseek` function
/// pointer in `struct file_operations`.
fn seek(&self, _file: &File, _offset: SeekFrom) -> KernelResult<u64> {
Expand Down
34 changes: 34 additions & 0 deletions tests/chrdev/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,39 @@ impl linux_kernel_module::chrdev::FileOperations for SeekFile {
}
}

struct WiteFile {
written: AtomUsize,
}

impl linux_kernel_module::chrdev::FileOperations for WriteFile {
const VTABLE: linux_kernel_module::chrdev::FileOperationsVtable =
linux_kernel_module::chrdev::FileOperationsVtable::self::<Self>();

fn open() -> linux_kernel_module::KernelResult<Self> {
return Ok(WriteFile { data: vec![] });
}

fn write(
&self,
buf: &linux_kernel_module::user_ptr::UserSlicePtrReader,
offset: u64,
) -> linux_kernel_module::KernelResult<()> {
let data = buf.read_all()?;
self.written.fetch_add(data.len(), Ordering::SeqCst);
return Ok(());
}

fn read(
&self,
buf: &mut linux_kernel_module::user_ptr::UserSlicePtrWriter,
offset: u64,
) -> linux_kernel_module::KernelResult<()> {
let val = self.written.load(Ordering::SeqCst);
buf.write(val.to_string().as_bytes())?;
return Ok(());
}
}

struct ChrdevTestModule {
_chrdev_registration: linux_kernel_module::chrdev::Registration,
}
Expand All @@ -58,6 +91,7 @@ impl linux_kernel_module::KernelModule for ChrdevTestModule {
linux_kernel_module::chrdev::builder(cstr!("chrdev-tests"), 0..2)?
.register_device::<CycleFile>()
.register_device::<SeekFile>()
.register_device::<WriteFile>()
.build()?;
Ok(ChrdevTestModule {
_chrdev_registration: chrdev_registration,
Expand Down
38 changes: 38 additions & 0 deletions tests/chrdev/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ fn mknod(path: &PathBuf, major: libc::dev_t, minor: libc::dev_t) -> UnlinkOnDrop

const READ_FILE_MINOR: libc::dev_t = 0;
const SEEK_FILE_MINOR: libc::dev_t = 1;
const WRITE_FILE_MINOR: libc::dev_t = 2;

#[test]
fn test_mknod() {
Expand Down Expand Up @@ -178,3 +179,40 @@ fn test_lseek() {
);
});
}

#[test]
fn test_write_unimplemented() {
with_kernel_module(|| {
let device_number = get_device_major_number();
let p = temporary_file_path();
let _u = mknod(&p, device_number, READ_FILE_MINOR);

let mut f = fs::File::open(&p).unwrap();
assert_eq!(
f.write(&[1, 2, 3]).unwrap_err().raw_os_error().unwrap(),
libc::EINVAL
);
})
}

#[test]
fn test_write() {
with_kernel_module(|| {
let device_number = get_device_major_number();
let p = temporary_file_path();
let _u = mknod(&p, device_number, WRITE_FILE_MINOR);

let mut f = fs::File::open(&p).unwrap();
assert_eq(f.write(&[1, 2, 3]), Ok(3));

let buf = vec![];
f.read_to_end(&mut buf).unwrap();
assert_eq(buf, b"3");

assert_eq(f.write(&[1, 2, 3, 4, 5]), Ok(3));

let buf = vec![];
f.read_to_end(&mut buf).unwrap();
assert_eq(buf, b"8");
})
}

0 comments on commit 82a2f4f

Please sign in to comment.