Skip to content

Implement a #[vtable] macro #322

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions drivers/android/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -805,12 +805,11 @@ impl IoctlHandler for Process {
}
}

#[vtable]
impl file::Operations for Process {
type Data = Ref<Self>;
type OpenData = Ref<Context>;

kernel::declare_file_operations!(ioctl, compat_ioctl, mmap, poll);

fn open(ctx: &Ref<Context>, file: &File) -> Result<Self::Data> {
Self::new(ctx.clone(), file.cred().into())
}
Expand Down
3 changes: 1 addition & 2 deletions drivers/char/hw_random/bcm2835_rng_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ module_platform_driver! {

struct RngDevice;

#[vtable]
impl file::Operations for RngDevice {
kernel::declare_file_operations!(read);

fn open(_open_data: &(), _file: &File) -> Result {
Ok(())
}
Expand Down
12 changes: 2 additions & 10 deletions drivers/gpio/gpio_pl061_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,10 @@ type DeviceData = device::Data<PL061Registrations, PL061Resources, PL061Data>;

struct PL061Device;

#[vtable]
impl gpio::Chip for PL061Device {
type Data = Ref<DeviceData>;

kernel::declare_gpio_chip_operations!(
get_direction,
direction_input,
direction_output,
get,
set
);

fn get_direction(data: RefBorrow<'_, DeviceData>, offset: u32) -> Result<gpio::LineDirection> {
let pl061 = data.resources().ok_or(ENXIO)?;
Ok(if pl061.base.readb(GPIODIR) & bit(offset) != 0 {
Expand Down Expand Up @@ -129,11 +122,10 @@ impl gpio::ChipWithIrqChip for PL061Device {
}
}

#[vtable]
impl irq::Chip for PL061Device {
type Data = Ref<DeviceData>;

kernel::declare_irq_chip_operations!(set_type, set_wake);

fn set_type(
data: RefBorrow<'_, DeviceData>,
irq_data: &mut LockedIrqData,
Expand Down
88 changes: 12 additions & 76 deletions rust/kernel/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::{
};
use core::convert::{TryFrom, TryInto};
use core::{cell::UnsafeCell, marker, mem, ptr};
use macros::vtable;

/// Wraps the kernel's `struct file`.
///
Expand Down Expand Up @@ -468,24 +469,24 @@ impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> {
const VTABLE: bindings::file_operations = bindings::file_operations {
open: Some(Self::open_callback),
release: Some(Self::release_callback),
read: if T::TO_USE.read {
read: if T::HAS_READ {
Some(Self::read_callback)
} else {
None
},
write: if T::TO_USE.write {
write: if T::HAS_WRITE {
Some(Self::write_callback)
} else {
None
},
llseek: if T::TO_USE.seek {
llseek: if T::HAS_SEEK {
Some(Self::llseek_callback)
} else {
None
},

check_flags: None,
compat_ioctl: if T::TO_USE.compat_ioctl {
compat_ioctl: if T::HAS_COMPAT_IOCTL {
Some(Self::compat_ioctl_callback)
} else {
None
Expand All @@ -496,7 +497,7 @@ impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> {
fasync: None,
flock: None,
flush: None,
fsync: if T::TO_USE.fsync {
fsync: if T::HAS_FSYNC {
Some(Self::fsync_callback)
} else {
None
Expand All @@ -506,19 +507,19 @@ impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> {
iterate_shared: None,
iopoll: None,
lock: None,
mmap: if T::TO_USE.mmap {
mmap: if T::HAS_MMAP {
Some(Self::mmap_callback)
} else {
None
},
mmap_supported_flags: 0,
owner: ptr::null_mut(),
poll: if T::TO_USE.poll {
poll: if T::HAS_POLL {
Some(Self::poll_callback)
} else {
None
},
read_iter: if T::TO_USE.read_iter {
read_iter: if T::HAS_READ {
Some(Self::read_iter_callback)
} else {
None
Expand All @@ -529,13 +530,13 @@ impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> {
show_fdinfo: None,
splice_read: None,
splice_write: None,
unlocked_ioctl: if T::TO_USE.ioctl {
unlocked_ioctl: if T::HAS_IOCTL {
Some(Self::unlocked_ioctl_callback)
} else {
None
},
uring_cmd: None,
write_iter: if T::TO_USE.write_iter {
write_iter: if T::HAS_WRITE {
Some(Self::write_iter_callback)
} else {
None
Expand All @@ -552,69 +553,6 @@ impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> {
}
}

/// Represents which fields of [`struct file_operations`] should be populated with pointers.
pub struct ToUse {
/// The `read` field of [`struct file_operations`].
pub read: bool,

/// The `read_iter` field of [`struct file_operations`].
pub read_iter: bool,

/// The `write` field of [`struct file_operations`].
pub write: bool,

/// The `write_iter` field of [`struct file_operations`].
pub write_iter: bool,

/// The `llseek` field of [`struct file_operations`].
pub seek: bool,

/// The `unlocked_ioctl` field of [`struct file_operations`].
pub ioctl: bool,

/// The `compat_ioctl` field of [`struct file_operations`].
pub compat_ioctl: bool,

/// The `fsync` field of [`struct file_operations`].
pub fsync: bool,

/// The `mmap` field of [`struct file_operations`].
pub mmap: bool,

/// The `poll` field of [`struct file_operations`].
pub poll: bool,
}

/// A constant version where all values are to set to `false`, that is, all supported fields will
/// be set to null pointers.
pub const USE_NONE: ToUse = ToUse {
read: false,
read_iter: false,
write: false,
write_iter: false,
seek: false,
ioctl: false,
compat_ioctl: false,
fsync: false,
mmap: false,
poll: false,
};

/// Defines the [`Operations::TO_USE`] field based on a list of fields to be populated.
#[macro_export]
macro_rules! declare_file_operations {
() => {
const TO_USE: $crate::file::ToUse = $crate::file::USE_NONE;
};
($($i:ident),+) => {
const TO_USE: kernel::file::ToUse =
$crate::file::ToUse {
$($i: true),+ ,
..$crate::file::USE_NONE
};
};
}

/// Allows the handling of ioctls defined with the `_IO`, `_IOR`, `_IOW`, and `_IOWR` macros.
///
/// For each macro, there is a handler function that takes the appropriate types as arguments.
Expand Down Expand Up @@ -742,10 +680,8 @@ pub trait OpenAdapter<T: Sync> {
/// File descriptors may be used from multiple threads/processes concurrently, so your type must be
/// [`Sync`]. It must also be [`Send`] because [`Operations::release`] will be called from the
/// thread that decrements that associated file's refcount to zero.
#[vtable]
pub trait Operations {
/// The methods to use to populate [`struct file_operations`].
const TO_USE: ToUse;

/// The type of the context data returned by [`Operations::open`] and made available to
/// other methods.
type Data: PointerWrapper + Send + Sync = ();
Expand Down
69 changes: 12 additions & 57 deletions rust/kernel/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use core::{
marker::{PhantomData, PhantomPinned},
pin::Pin,
};
use macros::vtable;

#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
pub use irqchip::{ChipWithIrqChip, RegistrationWithIrqChip};
Expand All @@ -27,16 +28,13 @@ pub enum LineDirection {
}

/// A gpio chip.
#[vtable]
pub trait Chip {
/// Context data associated with the gpio chip.
///
/// It determines the type of the context data passed to each of the methods of the trait.
type Data: PointerWrapper + Sync + Send;

/// The methods to use to populate [`struct gpio_chip`]. This is typically populated with
/// [`declare_gpio_chip_operations`].
const TO_USE: ToUse;

/// Returns the direction of the given gpio line.
fn get_direction(
_data: <Self::Data as PointerWrapper>::Borrowed<'_>,
Expand Down Expand Up @@ -73,52 +71,6 @@ pub trait Chip {
fn set(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32, _value: bool) {}
}

/// Represents which fields of [`struct gpio_chip`] should be populated with pointers.
///
/// This is typically populated with the [`declare_gpio_chip_operations`] macro.
pub struct ToUse {
/// The `get_direction` field of [`struct gpio_chip`].
pub get_direction: bool,

/// The `direction_input` field of [`struct gpio_chip`].
pub direction_input: bool,

/// The `direction_output` field of [`struct gpio_chip`].
pub direction_output: bool,

/// The `get` field of [`struct gpio_chip`].
pub get: bool,

/// The `set` field of [`struct gpio_chip`].
pub set: bool,
}

/// A constant version where all values are set to `false`, that is, all supported fields will be
/// set to null pointers.
pub const USE_NONE: ToUse = ToUse {
get_direction: false,
direction_input: false,
direction_output: false,
get: false,
set: false,
};

/// Defines the [`Chip::TO_USE`] field based on a list of fields to be populated.
#[macro_export]
macro_rules! declare_gpio_chip_operations {
() => {
const TO_USE: $crate::gpio::ToUse = $crate::gpio::USE_NONE;
};
($($i:ident),+) => {
#[allow(clippy::needless_update)]
const TO_USE: $crate::gpio::ToUse =
$crate::gpio::ToUse {
$($i: true),+ ,
..$crate::gpio::USE_NONE
};
};
}

/// A registration of a gpio chip.
///
/// # Examples
Expand All @@ -130,9 +82,9 @@ macro_rules! declare_gpio_chip_operations {
/// use kernel::{device::RawDevice, gpio::{self, Registration}};
///
/// struct MyGpioChip;
/// #[vtable]
/// impl gpio::Chip for MyGpioChip {
/// type Data = ();
/// kernel::declare_gpio_chip_operations!();
/// }
///
/// fn example(parent: &dyn RawDevice) -> Result<Pin<Box<Registration<MyGpioChip>>>> {
Expand Down Expand Up @@ -186,19 +138,19 @@ impl<T: Chip> Registration<T> {
// Set up the callbacks.
gc.request = Some(bindings::gpiochip_generic_request);
gc.free = Some(bindings::gpiochip_generic_free);
if T::TO_USE.get_direction {
if T::HAS_GET_DIRECTION {
gc.get_direction = Some(get_direction_callback::<T>);
}
if T::TO_USE.direction_input {
if T::HAS_DIRECTION_INPUT {
gc.direction_input = Some(direction_input_callback::<T>);
}
if T::TO_USE.direction_output {
if T::HAS_DIRECTION_OUTPUT {
gc.direction_output = Some(direction_output_callback::<T>);
}
if T::TO_USE.get {
if T::HAS_GET {
gc.get = Some(get_callback::<T>);
}
if T::TO_USE.set {
if T::HAS_SET {
gc.set = Some(set_callback::<T>);
}

Expand Down Expand Up @@ -475,9 +427,12 @@ mod irqchip {
/// data is passed as context.
struct IrqChipAdapter<T: irq::Chip>(PhantomData<T>);

#[vtable]
impl<T: irq::Chip> irq::Chip for IrqChipAdapter<T> {
type Data = *mut bindings::gpio_chip;
const TO_USE: irq::ToUse = T::TO_USE;

const HAS_SET_TYPE: bool = T::HAS_SET_TYPE;
const HAS_SET_WAKE: bool = T::HAS_SET_WAKE;

fn ack(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
// SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
Expand Down
Loading