diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-04-01 11:26:08 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-04-01 11:26:08 -0700 | 
| commit | 25601e85441dd91cf7973b002f27af4c5b8691ea (patch) | |
| tree | 821267764ed1dbdfb7d08839f7bf0054358eb4f8 /rust/kernel/miscdevice.rs | |
| parent | 2cd5769fb0b78b8ef583ab4c0015c2c48d525dac (diff) | |
| parent | 5d1a5c4f121f0ec50327e899c9450978505f1560 (diff) | |
Merge tag 'char-misc-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char / misc / IIO driver updates from Greg KH:
 "Here is the big set of char, misc, iio, and other smaller driver
  subsystems for 6.15-rc1. Lots of stuff in here, including:
   - loads of IIO changes and driver updates
   - counter driver updates
   - w1 driver updates
   - faux conversions for some drivers that were abusing the platform
     bus interface
   - coresight driver updates
   - rust miscdevice binding updates based on real-world-use
   - other minor driver updates
  All of these have been in linux-next with no reported issues for quite
  a while"
* tag 'char-misc-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (292 commits)
  samples: rust_misc_device: fix markup in top-level docs
  Coresight: Fix a NULL vs IS_ERR() bug in probe
  misc: lis3lv02d: convert to use faux_device
  tlclk: convert to use faux_device
  regulator: dummy: convert to use the faux device interface
  bus: mhi: host: Fix race between unprepare and queue_buf
  coresight: configfs: Constify struct config_item_type
  doc: iio: ad7380: describe offload support
  iio: ad7380: add support for SPI offload
  iio: light: Add check for array bounds in veml6075_read_int_time_ms
  iio: adc: ti-ads7924 Drop unnecessary function parameters
  staging: iio: ad9834: Use devm_regulator_get_enable()
  staging: iio: ad9832: Use devm_regulator_get_enable()
  iio: gyro: bmg160_spi: add of_match_table
  dt-bindings: iio: adc: Add i.MX94 and i.MX95 support
  iio: adc: ad7768-1: remove unnecessary locking
  Documentation: ABI: add wideband filter type to sysfs-bus-iio
  iio: adc: ad7768-1: set MOSI idle state to prevent accidental reset
  iio: adc: ad7768-1: Fix conversion result sign
  iio: adc: ad7124: Benefit of dev = indio_dev->dev.parent in ad7124_parse_channel_config()
  ...
Diffstat (limited to 'rust/kernel/miscdevice.rs')
| -rw-r--r-- | rust/kernel/miscdevice.rs | 297 | 
1 files changed, 143 insertions, 154 deletions
diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index e14433b2ab9d..fa9ecc42602a 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -35,7 +35,7 @@ impl MiscDeviceOptions {          let mut result: bindings::miscdevice = unsafe { MaybeUninit::zeroed().assume_init() };          result.minor = bindings::MISC_DYNAMIC_MINOR as _;          result.name = self.name.as_char_ptr(); -        result.fops = create_vtable::<T>(); +        result.fops = MiscdeviceVTable::<T>::build();          result      }  } @@ -160,171 +160,160 @@ pub trait MiscDevice: Sized {      }  } -const fn create_vtable<T: MiscDevice>() -> &'static bindings::file_operations { -    const fn maybe_fn<T: Copy>(check: bool, func: T) -> Option<T> { -        if check { -            Some(func) -        } else { -            None +/// A vtable for the file operations of a Rust miscdevice. +struct MiscdeviceVTable<T: MiscDevice>(PhantomData<T>); + +impl<T: MiscDevice> MiscdeviceVTable<T> { +    /// # Safety +    /// +    /// `file` and `inode` must be the file and inode for a file that is undergoing initialization. +    /// The file must be associated with a `MiscDeviceRegistration<T>`. +    unsafe extern "C" fn open(inode: *mut bindings::inode, raw_file: *mut bindings::file) -> c_int { +        // SAFETY: The pointers are valid and for a file being opened. +        let ret = unsafe { bindings::generic_file_open(inode, raw_file) }; +        if ret != 0 { +            return ret;          } -    } -    struct VtableHelper<T: MiscDevice> { -        _t: PhantomData<T>, -    } -    impl<T: MiscDevice> VtableHelper<T> { -        const VTABLE: bindings::file_operations = bindings::file_operations { -            open: Some(fops_open::<T>), -            release: Some(fops_release::<T>), -            unlocked_ioctl: maybe_fn(T::HAS_IOCTL, fops_ioctl::<T>), -            #[cfg(CONFIG_COMPAT)] -            compat_ioctl: if T::HAS_COMPAT_IOCTL { -                Some(fops_compat_ioctl::<T>) -            } else if T::HAS_IOCTL { -                Some(bindings::compat_ptr_ioctl) -            } else { -                None -            }, -            show_fdinfo: maybe_fn(T::HAS_SHOW_FDINFO, fops_show_fdinfo::<T>), -            // SAFETY: All zeros is a valid value for `bindings::file_operations`. -            ..unsafe { MaybeUninit::zeroed().assume_init() } -        }; -    } +        // SAFETY: The open call of a file can access the private data. +        let misc_ptr = unsafe { (*raw_file).private_data }; -    &VtableHelper::<T>::VTABLE -} +        // SAFETY: This is a miscdevice, so `misc_open()` set the private data to a pointer to the +        // associated `struct miscdevice` before calling into this method. Furthermore, +        // `misc_open()` ensures that the miscdevice can't be unregistered and freed during this +        // call to `fops_open`. +        let misc = unsafe { &*misc_ptr.cast::<MiscDeviceRegistration<T>>() }; -/// # Safety -/// -/// `file` and `inode` must be the file and inode for a file that is undergoing initialization. -/// The file must be associated with a `MiscDeviceRegistration<T>`. -unsafe extern "C" fn fops_open<T: MiscDevice>( -    inode: *mut bindings::inode, -    raw_file: *mut bindings::file, -) -> c_int { -    // SAFETY: The pointers are valid and for a file being opened. -    let ret = unsafe { bindings::generic_file_open(inode, raw_file) }; -    if ret != 0 { -        return ret; -    } +        // SAFETY: +        // * This underlying file is valid for (much longer than) the duration of `T::open`. +        // * There is no active fdget_pos region on the file on this thread. +        let file = unsafe { File::from_raw_file(raw_file) }; -    // SAFETY: The open call of a file can access the private data. -    let misc_ptr = unsafe { (*raw_file).private_data }; - -    // SAFETY: This is a miscdevice, so `misc_open()` set the private data to a pointer to the -    // associated `struct miscdevice` before calling into this method. Furthermore, `misc_open()` -    // ensures that the miscdevice can't be unregistered and freed during this call to `fops_open`. -    let misc = unsafe { &*misc_ptr.cast::<MiscDeviceRegistration<T>>() }; +        let ptr = match T::open(file, misc) { +            Ok(ptr) => ptr, +            Err(err) => return err.to_errno(), +        }; -    // SAFETY: -    // * This underlying file is valid for (much longer than) the duration of `T::open`. -    // * There is no active fdget_pos region on the file on this thread. -    let file = unsafe { File::from_raw_file(raw_file) }; +        // This overwrites the private data with the value specified by the user, changing the type +        // of this file's private data. All future accesses to the private data is performed by +        // other fops_* methods in this file, which all correctly cast the private data to the new +        // type. +        // +        // SAFETY: The open call of a file can access the private data. +        unsafe { (*raw_file).private_data = ptr.into_foreign() }; -    let ptr = match T::open(file, misc) { -        Ok(ptr) => ptr, -        Err(err) => return err.to_errno(), -    }; - -    // This overwrites the private data with the value specified by the user, changing the type of -    // this file's private data. All future accesses to the private data is performed by other -    // fops_* methods in this file, which all correctly cast the private data to the new type. -    // -    // SAFETY: The open call of a file can access the private data. -    unsafe { (*raw_file).private_data = ptr.into_foreign() }; +        0 +    } -    0 -} +    /// # Safety +    /// +    /// `file` and `inode` must be the file and inode for a file that is being released. The file +    /// must be associated with a `MiscDeviceRegistration<T>`. +    unsafe extern "C" fn release(_inode: *mut bindings::inode, file: *mut bindings::file) -> c_int { +        // SAFETY: The release call of a file owns the private data. +        let private = unsafe { (*file).private_data }; +        // SAFETY: The release call of a file owns the private data. +        let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) }; + +        // SAFETY: +        // * The file is valid for the duration of this call. +        // * There is no active fdget_pos region on the file on this thread. +        T::release(ptr, unsafe { File::from_raw_file(file) }); + +        0 +    } -/// # Safety -/// -/// `file` and `inode` must be the file and inode for a file that is being released. The file must -/// be associated with a `MiscDeviceRegistration<T>`. -unsafe extern "C" fn fops_release<T: MiscDevice>( -    _inode: *mut bindings::inode, -    file: *mut bindings::file, -) -> c_int { -    // SAFETY: The release call of a file owns the private data. -    let private = unsafe { (*file).private_data }; -    // SAFETY: The release call of a file owns the private data. -    let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) }; - -    // SAFETY: -    // * The file is valid for the duration of this call. -    // * There is no active fdget_pos region on the file on this thread. -    T::release(ptr, unsafe { File::from_raw_file(file) }); - -    0 -} +    /// # Safety +    /// +    /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. +    unsafe extern "C" fn ioctl(file: *mut bindings::file, cmd: c_uint, arg: c_ulong) -> c_long { +        // SAFETY: The ioctl call of a file can access the private data. +        let private = unsafe { (*file).private_data }; +        // SAFETY: Ioctl calls can borrow the private data of the file. +        let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; + +        // SAFETY: +        // * The file is valid for the duration of this call. +        // * There is no active fdget_pos region on the file on this thread. +        let file = unsafe { File::from_raw_file(file) }; + +        match T::ioctl(device, file, cmd, arg) { +            Ok(ret) => ret as c_long, +            Err(err) => err.to_errno() as c_long, +        } +    } -/// # Safety -/// -/// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. -unsafe extern "C" fn fops_ioctl<T: MiscDevice>( -    file: *mut bindings::file, -    cmd: c_uint, -    arg: c_ulong, -) -> c_long { -    // SAFETY: The ioctl call of a file can access the private data. -    let private = unsafe { (*file).private_data }; -    // SAFETY: Ioctl calls can borrow the private data of the file. -    let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; - -    // SAFETY: -    // * The file is valid for the duration of this call. -    // * There is no active fdget_pos region on the file on this thread. -    let file = unsafe { File::from_raw_file(file) }; - -    match T::ioctl(device, file, cmd, arg) { -        Ok(ret) => ret as c_long, -        Err(err) => err.to_errno() as c_long, +    /// # Safety +    /// +    /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. +    #[cfg(CONFIG_COMPAT)] +    unsafe extern "C" fn compat_ioctl( +        file: *mut bindings::file, +        cmd: c_uint, +        arg: c_ulong, +    ) -> c_long { +        // SAFETY: The compat ioctl call of a file can access the private data. +        let private = unsafe { (*file).private_data }; +        // SAFETY: Ioctl calls can borrow the private data of the file. +        let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; + +        // SAFETY: +        // * The file is valid for the duration of this call. +        // * There is no active fdget_pos region on the file on this thread. +        let file = unsafe { File::from_raw_file(file) }; + +        match T::compat_ioctl(device, file, cmd, arg) { +            Ok(ret) => ret as c_long, +            Err(err) => err.to_errno() as c_long, +        }      } -} -/// # Safety -/// -/// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. -#[cfg(CONFIG_COMPAT)] -unsafe extern "C" fn fops_compat_ioctl<T: MiscDevice>( -    file: *mut bindings::file, -    cmd: c_uint, -    arg: c_ulong, -) -> c_long { -    // SAFETY: The compat ioctl call of a file can access the private data. -    let private = unsafe { (*file).private_data }; -    // SAFETY: Ioctl calls can borrow the private data of the file. -    let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; - -    // SAFETY: -    // * The file is valid for the duration of this call. -    // * There is no active fdget_pos region on the file on this thread. -    let file = unsafe { File::from_raw_file(file) }; - -    match T::compat_ioctl(device, file, cmd, arg) { -        Ok(ret) => ret as c_long, -        Err(err) => err.to_errno() as c_long, +    /// # Safety +    /// +    /// - `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. +    /// - `seq_file` must be a valid `struct seq_file` that we can write to. +    unsafe extern "C" fn show_fdinfo(seq_file: *mut bindings::seq_file, file: *mut bindings::file) { +        // SAFETY: The release call of a file owns the private data. +        let private = unsafe { (*file).private_data }; +        // SAFETY: Ioctl calls can borrow the private data of the file. +        let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; +        // SAFETY: +        // * The file is valid for the duration of this call. +        // * There is no active fdget_pos region on the file on this thread. +        let file = unsafe { File::from_raw_file(file) }; +        // SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in +        // which this method is called. +        let m = unsafe { SeqFile::from_raw(seq_file) }; + +        T::show_fdinfo(device, m, file);      } -} -/// # Safety -/// -/// - `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. -/// - `seq_file` must be a valid `struct seq_file` that we can write to. -unsafe extern "C" fn fops_show_fdinfo<T: MiscDevice>( -    seq_file: *mut bindings::seq_file, -    file: *mut bindings::file, -) { -    // SAFETY: The release call of a file owns the private data. -    let private = unsafe { (*file).private_data }; -    // SAFETY: Ioctl calls can borrow the private data of the file. -    let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; -    // SAFETY: -    // * The file is valid for the duration of this call. -    // * There is no active fdget_pos region on the file on this thread. -    let file = unsafe { File::from_raw_file(file) }; -    // SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which -    // this method is called. -    let m = unsafe { SeqFile::from_raw(seq_file) }; - -    T::show_fdinfo(device, m, file); +    const VTABLE: bindings::file_operations = bindings::file_operations { +        open: Some(Self::open), +        release: Some(Self::release), +        unlocked_ioctl: if T::HAS_IOCTL { +            Some(Self::ioctl) +        } else { +            None +        }, +        #[cfg(CONFIG_COMPAT)] +        compat_ioctl: if T::HAS_COMPAT_IOCTL { +            Some(Self::compat_ioctl) +        } else if T::HAS_IOCTL { +            Some(bindings::compat_ptr_ioctl) +        } else { +            None +        }, +        show_fdinfo: if T::HAS_SHOW_FDINFO { +            Some(Self::show_fdinfo) +        } else { +            None +        }, +        // SAFETY: All zeros is a valid value for `bindings::file_operations`. +        ..unsafe { MaybeUninit::zeroed().assume_init() } +    }; + +    const fn build() -> &'static bindings::file_operations { +        &Self::VTABLE +    }  }  | 
