diff --git a/drivers/char/rust_example/src/lib.rs b/drivers/char/rust_example/src/lib.rs index c4f412022575a7..2c15dd163ac5ac 100644 --- a/drivers/char/rust_example/src/lib.rs +++ b/drivers/char/rust_example/src/lib.rs @@ -8,7 +8,7 @@ extern crate alloc; use alloc::boxed::Box; use core::pin::Pin; use kernel::prelude::*; -use kernel::{cstr, file_operations::FileOperations, miscdev}; +use kernel::{cstr, file_operations::FileOperations, miscdev, try_alloc}; module! { type: RustExample, @@ -33,9 +33,11 @@ module! { struct RustFile; impl FileOperations for RustFile { - fn open() -> KernelResult { + type Wrapper = Box; + + fn open() -> KernelResult { println!("rust file was opened!"); - Ok(Self) + try_alloc(Self) } } diff --git a/rust/kernel/src/file_operations.rs b/rust/kernel/src/file_operations.rs index 5873e815260106..fd0042c67f6d05 100644 --- a/rust/kernel/src/file_operations.rs +++ b/rust/kernel/src/file_operations.rs @@ -4,11 +4,11 @@ use core::convert::{TryFrom, TryInto}; use core::{marker, mem, ptr}; use alloc::boxed::Box; +use alloc::sync::Arc; use crate::bindings; use crate::c_types; use crate::error::{Error, KernelResult}; -use crate::try_alloc; use crate::user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter}; bitflags::bitflags! { @@ -66,8 +66,8 @@ unsafe extern "C" fn open_callback( file: *mut bindings::file, ) -> c_types::c_int { from_kernel_result! { - let f = try_alloc(T::open()?)?; - (*file).private_data = Box::into_raw(f) as *mut c_types::c_void; + let ptr = T::open()?.into_pointer(); + (*file).private_data = ptr as *mut c_types::c_void; Ok(0) } } @@ -113,7 +113,7 @@ unsafe extern "C" fn release_callback( file: *mut bindings::file, ) -> c_types::c_int { let ptr = mem::replace(&mut (*file).private_data, ptr::null_mut()); - drop(Box::from_raw(ptr as *mut T)); + drop(T::Wrapper::from_pointer(ptr as _)); 0 } @@ -217,9 +217,11 @@ pub type FSync = Option KernelResult>; /// File descriptors may be used from multiple threads (or processes) /// concurrently, so your type must be `Sync`. pub trait FileOperations: Sync + Sized { + type Wrapper: PointerWrapper; + /// Creates a new instance of this file. Corresponds to the `open` function /// pointer in `struct file_operations`. - fn open() -> KernelResult; + fn open() -> KernelResult; /// Reads data from this file to userspace. Corresponds to the `read` /// function pointer in `struct file_operations`. @@ -237,3 +239,32 @@ pub trait FileOperations: Sync + Sized { /// pointer in the `struct file_operations`. const FSYNC: FSync = None; } + +/// `PointerWrapper` is used to convert an object into a raw pointer that represents it. It can +/// eventually be converted back into the object. This is used to store objects as pointers in +/// kernel data structures, for example, an implementation of `FileOperations` in `struct +/// file::private_data`. +pub trait PointerWrapper { + fn into_pointer(self) -> *const T; + unsafe fn from_pointer(ptr: *const T) -> Self; +} + +impl PointerWrapper for Box { + fn into_pointer(self) -> *const T { + Box::into_raw(self) + } + + unsafe fn from_pointer(ptr: *const T) -> Self { + Box::::from_raw(ptr as _) + } +} + +impl PointerWrapper for Arc { + fn into_pointer(self) -> *const T { + Arc::into_raw(self) + } + + unsafe fn from_pointer(ptr: *const T) -> Self { + Arc::::from_raw(ptr) + } +}