rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] Miscdevices in Rust
@ 2024-09-26 14:58 Alice Ryhl
  2024-09-26 14:58 ` [PATCH 1/3] rust: types: add Opaque::try_ffi_init Alice Ryhl
                   ` (4 more replies)
  0 siblings, 5 replies; 19+ messages in thread
From: Alice Ryhl @ 2024-09-26 14:58 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Arnd Bergmann, Miguel Ojeda, Alexander Viro,
	Christian Brauner, Jan Kara
  Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Trevor Gross, rust-for-linux, linux-fsdevel,
	linux-kernel, Alice Ryhl

A misc device is generally the best place to start with your first Rust
driver, so having abstractions for miscdevice in Rust will be important
for our ability to teach Rust to kernel developers.

I intend to add a sample driver using these abstractions, and I also
intend to use it in Rust Binder to handle the case where binderfs is
turned off.

I know that the patchset is still a bit rough. It could use some work on
the file position aspect. But I'm sending this out now to get feedback
on the overall approach.

This patchset depends on files [1] and vma [2].

Link: https://lore.kernel.org/all/20240915-alice-file-v10-0-88484f7a3dcf@google.com/ [1]
Link: https://lore.kernel.org/all/20240806-vma-v5-1-04018f05de2b@google.com/ [2]
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
Alice Ryhl (3):
      rust: types: add Opaque::try_ffi_init
      rust: file: add f_pos and set_f_pos
      rust: miscdevice: add abstraction for defining miscdevices

 rust/bindings/bindings_helper.h |   1 +
 rust/kernel/fs/file.rs          |  20 ++
 rust/kernel/lib.rs              |   1 +
 rust/kernel/miscdevice.rs       | 401 ++++++++++++++++++++++++++++++++++++++++
 rust/kernel/types.rs            |  16 ++
 5 files changed, 439 insertions(+)
---
base-commit: a6266fcab443f4b6ae31016bd6c3872f8200d5e1
change-id: 20240926-b4-miscdevice-29a0fd8438b1

Best regards,
-- 
Alice Ryhl <aliceryhl@google.com>


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 1/3] rust: types: add Opaque::try_ffi_init
  2024-09-26 14:58 [PATCH 0/3] Miscdevices in Rust Alice Ryhl
@ 2024-09-26 14:58 ` Alice Ryhl
  2024-09-27  9:00   ` Fiona Behrens
  2024-09-26 14:58 ` [PATCH 2/3] rust: file: add f_pos and set_f_pos Alice Ryhl
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 19+ messages in thread
From: Alice Ryhl @ 2024-09-26 14:58 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Arnd Bergmann, Miguel Ojeda, Alexander Viro,
	Christian Brauner, Jan Kara
  Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Trevor Gross, rust-for-linux, linux-fsdevel,
	linux-kernel, Alice Ryhl

This will be used by the miscdevice abstractions, as the C function
`misc_register` is fallible.

Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
 rust/kernel/types.rs | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index 3238ffaab031..dd9c606c515c 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -299,6 +299,22 @@ pub fn ffi_init(init_func: impl FnOnce(*mut T)) -> impl PinInit<Self> {
         }
     }
 
+    /// Creates a fallible pin-initializer from the given initializer closure.
+    ///
+    /// The returned initializer calls the given closure with the pointer to the inner `T` of this
+    /// `Opaque`. Since this memory is uninitialized, the closure is not allowed to read from it.
+    ///
+    /// This function is safe, because the `T` inside of an `Opaque` is allowed to be
+    /// uninitialized. Additionally, access to the inner `T` requires `unsafe`, so the caller needs
+    /// to verify at that point that the inner value is valid.
+    pub fn try_ffi_init<E>(
+        init_func: impl FnOnce(*mut T) -> Result<(), E>,
+    ) -> impl PinInit<Self, E> {
+        // SAFETY: We contain a `MaybeUninit`, so it is OK for the `init_func` to not fully
+        // initialize the `T`.
+        unsafe { init::pin_init_from_closure::<_, E>(move |slot| init_func(Self::raw_get(slot))) }
+    }
+
     /// Returns a raw pointer to the opaque data.
     pub const fn get(&self) -> *mut T {
         UnsafeCell::get(&self.value).cast::<T>()

-- 
2.46.0.792.g87dc391469-goog


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 2/3] rust: file: add f_pos and set_f_pos
  2024-09-26 14:58 [PATCH 0/3] Miscdevices in Rust Alice Ryhl
  2024-09-26 14:58 ` [PATCH 1/3] rust: types: add Opaque::try_ffi_init Alice Ryhl
@ 2024-09-26 14:58 ` Alice Ryhl
  2024-09-26 22:08   ` Al Viro
  2024-09-27  7:32   ` Christian Brauner
  2024-09-26 14:58 ` [PATCH 3/3] rust: miscdevice: add abstraction for defining miscdevices Alice Ryhl
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 19+ messages in thread
From: Alice Ryhl @ 2024-09-26 14:58 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Arnd Bergmann, Miguel Ojeda, Alexander Viro,
	Christian Brauner, Jan Kara
  Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Trevor Gross, rust-for-linux, linux-fsdevel,
	linux-kernel, Alice Ryhl

Add accessors for the file position. Most of the time, you should not
use these methods directly, and you should instead use a guard for the
file position to prove that you hold the fpos lock. However, under
limited circumstances, files are allowed to choose a different locking
strategy for their file position. These accessors can be used to handle
that case.

For now, these accessors are the only way to access the file position
within the llseek and read_iter callbacks.

Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
 rust/kernel/fs/file.rs | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs
index e03dbe14d62a..c896a3b1d182 100644
--- a/rust/kernel/fs/file.rs
+++ b/rust/kernel/fs/file.rs
@@ -333,6 +333,26 @@ pub fn flags(&self) -> u32 {
         // FIXME(read_once): Replace with `read_once` when available on the Rust side.
         unsafe { core::ptr::addr_of!((*self.as_ptr()).f_flags).read_volatile() }
     }
+
+    /// Read the file position.
+    ///
+    /// # Safety
+    ///
+    /// You must hold the fpos lock or otherwise ensure that no data race will happen.
+    #[inline]
+    pub unsafe fn f_pos(&self) -> i64 {
+        unsafe { (*self.as_ptr()).f_pos }
+    }
+
+    /// Set the file position.
+    ///
+    /// # Safety
+    ///
+    /// You must hold the fpos lock or otherwise ensure that no data race will happen.
+    #[inline]
+    pub unsafe fn set_f_pos(&self, value: i64) {
+        unsafe { (*self.as_ptr()).f_pos = value };
+    }
 }
 
 impl File {

-- 
2.46.0.792.g87dc391469-goog


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 3/3] rust: miscdevice: add abstraction for defining miscdevices
  2024-09-26 14:58 [PATCH 0/3] Miscdevices in Rust Alice Ryhl
  2024-09-26 14:58 ` [PATCH 1/3] rust: types: add Opaque::try_ffi_init Alice Ryhl
  2024-09-26 14:58 ` [PATCH 2/3] rust: file: add f_pos and set_f_pos Alice Ryhl
@ 2024-09-26 14:58 ` Alice Ryhl
  2024-09-26 15:05 ` [PATCH 0/3] Miscdevices in Rust Greg Kroah-Hartman
  2024-09-26 18:58 ` Benno Lossin
  4 siblings, 0 replies; 19+ messages in thread
From: Alice Ryhl @ 2024-09-26 14:58 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Arnd Bergmann, Miguel Ojeda, Alexander Viro,
	Christian Brauner, Jan Kara
  Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Trevor Gross, rust-for-linux, linux-fsdevel,
	linux-kernel, Alice Ryhl

Provide a `MiscDevice` trait that lets you specify the file operations
that you wish to provide for your misc device. Most operations are
optional.

In the future, the file operations in the `MiscDevice` can be moved to a
general `FileOperations` trait so that it is useful for other file
systems too.

Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
 rust/bindings/bindings_helper.h |   1 +
 rust/kernel/lib.rs              |   1 +
 rust/kernel/miscdevice.rs       | 401 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 403 insertions(+)

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index ca13659ded4c..ec2e28ef6568 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -18,6 +18,7 @@
 #include <linux/fs.h>
 #include <linux/jiffies.h>
 #include <linux/mdio.h>
+#include <linux/miscdevice.h>
 #include <linux/phy.h>
 #include <linux/pid_namespace.h>
 #include <linux/poll.h>
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 819126fc2d89..bf97817842c9 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -41,6 +41,7 @@
 #[cfg(CONFIG_KUNIT)]
 pub mod kunit;
 pub mod list;
+pub mod miscdevice;
 pub mod mm;
 #[cfg(CONFIG_NET)]
 pub mod net;
diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
new file mode 100644
index 000000000000..6c4e33d77c58
--- /dev/null
+++ b/rust/kernel/miscdevice.rs
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Copyright (C) 2024 Google LLC.
+
+//! Miscdevice support.
+//!
+//! C headers: [`include/linux/miscdevice.h`](srctree/include/linux/miscdevice.h).
+//!
+//! Reference: <https://www.kernel.org/doc/html/latest/driver-api/misc_devices.html>
+
+use crate::{
+    bindings,
+    error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
+    fs::{File, LocalFile},
+    mm::virt::VmArea,
+    prelude::*,
+    str::CStr,
+    types::{ForeignOwnable, Opaque},
+};
+use core::{
+    ffi::{c_int, c_long, c_uint, c_ulong},
+    marker::PhantomData,
+    mem::MaybeUninit,
+    pin::Pin,
+    ptr::NonNull,
+};
+
+/// The kernel `loff_t` type.
+#[allow(non_camel_case_types)]
+pub type loff_t = bindings::loff_t;
+
+/// Options for creating a misc device.
+#[derive(Copy, Clone)]
+pub struct MiscDeviceOptions {
+    /// The name of the miscdevice.
+    pub name: &'static CStr,
+}
+
+impl MiscDeviceOptions {
+    /// Create a raw `struct miscdev` ready for registration.
+    pub const fn into_raw<T: MiscDevice>(self) -> bindings::miscdevice {
+        // SAFETY: All zeros is valid for this C type.
+        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
+    }
+}
+
+/// A registration of a miscdevice.
+///
+/// # Invariants
+///
+/// `inner` is a registered misc device.
+#[repr(transparent)]
+#[pin_data(PinnedDrop)]
+pub struct MiscDeviceRegistration<T> {
+    #[pin]
+    inner: Opaque<bindings::miscdevice>,
+    _t: PhantomData<T>,
+}
+
+unsafe impl<T> Send for MiscDeviceRegistration<T> {}
+unsafe impl<T> Sync for MiscDeviceRegistration<T> {}
+
+impl<T: MiscDevice> MiscDeviceRegistration<T> {
+    /// Register a misc device.
+    pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
+        try_pin_init!(Self {
+            inner <- Opaque::try_ffi_init(move |slot: *mut bindings::miscdevice| {
+                // SAFETY: The initializer can write to the provided `slot`.
+                unsafe { slot.write(opts.into_raw::<T>()) };
+
+                // SAFETY: We just wrote the misc device options to the slot. The miscdevice will
+                // get unregistered before `slot` is deallocated because the memory is pinned and
+                // the destructor of this type deallocates the memory.
+                // INVARIANT: If this returns `Ok(())`, then the `slot` will contain a registered
+                // misc device.
+                to_result(unsafe { bindings::misc_register(slot) })
+            }),
+            _t: PhantomData,
+        })
+    }
+
+    /// Returns the private data associated with the provided file.
+    ///
+    /// Returns `None` if the file is not associated with this misc device.
+    pub fn try_get_private_data<'a>(
+        &self,
+        file: &'a LocalFile,
+    ) -> Option<<T::Ptr as ForeignOwnable>::Borrowed<'a>> {
+        // SAFETY: `fops` of a miscdevice is immutable after initialization.
+        let fops_this = unsafe { (*self.as_raw()).fops };
+        // SAFETY: `f_op` of a file is immutable after initialization.
+        let fops_file = unsafe { (*file.as_ptr()).f_op };
+
+        if core::ptr::eq(fops_this, fops_file) {
+            // SAFETY: We know that `file` is associated with a `MiscDeviceRegistration<T>`, so
+            // `private_data` is immutable.
+            let private_data = unsafe { (*file.as_ptr()).private_data };
+            // SAFETY:
+            // * The fops match, so the file's private date has the right type.
+            // * The returned borrow cannot outlive the file.
+            Some(unsafe { <T::Ptr as ForeignOwnable>::borrow(private_data) })
+        } else {
+            None
+        }
+    }
+
+    /// Returns a raw pointer to the misc device.
+    pub fn as_raw(&self) -> *mut bindings::miscdevice {
+        self.inner.get()
+    }
+}
+
+#[pinned_drop]
+impl<T> PinnedDrop for MiscDeviceRegistration<T> {
+    fn drop(self: Pin<&mut Self>) {
+        // SAFETY: We know that the device is registered by the type invariants.
+        unsafe { bindings::misc_deregister(self.inner.get()) };
+    }
+}
+
+/// Trait implemented by the private data of an open misc device.
+#[vtable]
+pub trait MiscDevice {
+    /// What kind of pointer should `Self` be wrapped in.
+    type Ptr: ForeignOwnable + Send + Sync;
+
+    /// Called when the misc device is opened.
+    ///
+    /// The returned pointer will be stored as the private data for the file.
+    fn open(_file: &File) -> Result<Self::Ptr>;
+
+    /// Called when the misc device is released.
+    fn release(device: Self::Ptr, _file: &File) {
+        drop(device);
+    }
+
+    /// Handle for mmap.
+    fn mmap(
+        _device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
+        _file: &File,
+        _vma: Pin<&mut VmArea>,
+    ) -> Result<()> {
+        kernel::build_error(VTABLE_DEFAULT_ERROR)
+    }
+
+    /// Seeks this miscdevice.
+    fn llseek(
+        _device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
+        _file: &LocalFile,
+        _offset: loff_t,
+        _whence: c_int,
+    ) -> Result<loff_t> {
+        kernel::build_error(VTABLE_DEFAULT_ERROR)
+    }
+
+    /// Read from this miscdevice.
+    fn read_iter(_kiocb: Kiocb<'_, Self::Ptr>, _iov: &mut IovIter) -> Result<usize> {
+        kernel::build_error(VTABLE_DEFAULT_ERROR)
+    }
+
+    /// Handler for ioctls
+    ///
+    /// The `cmd` argument is usually manipulated using the utilties in [`kernel::ioctl`].
+    ///
+    /// [`kernel::ioctl`]: mod@crate::ioctl
+    fn ioctl(
+        _device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
+        _file: &File,
+        _cmd: u32,
+        _arg: usize,
+    ) -> Result<c_long> {
+        kernel::build_error(VTABLE_DEFAULT_ERROR)
+    }
+
+    /// Handler for ioctls
+    ///
+    /// Used for 32-bit userspace on 64-bit platforms.
+    #[cfg(CONFIG_COMPAT)]
+    fn compat_ioctl(
+        device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
+        file: &File,
+        cmd: u32,
+        arg: usize,
+    ) -> Result<c_long> {
+        Self::ioctl(device, file, cmd, arg)
+    }
+}
+
+/// Wrapper for the kernel's `struct kiocb`.
+///
+/// The type `T` represents the private data of the file.
+pub struct Kiocb<'a, T> {
+    inner: NonNull<bindings::kiocb>,
+    _phantom: PhantomData<&'a T>,
+}
+
+impl<'a, T: ForeignOwnable> Kiocb<'a, T> {
+    /// Get the private data in this kiocb.
+    pub fn private_data(&self) -> <T as ForeignOwnable>::Borrowed<'a> {
+        // SAFETY: The `kiocb` lets us access the private data.
+        let private = unsafe { (*(*self.inner.as_ptr()).ki_filp).private_data };
+        // SAFETY: The kiocb has shared access to the private data.
+        unsafe { <T as ForeignOwnable>::borrow(private) }
+    }
+
+    /// Gets the current value of `ki_pos`.
+    pub fn ki_pos(&self) -> loff_t {
+        // SAFETY: The `kiocb` can access `ki_pos`.
+        unsafe { (*self.inner.as_ptr()).ki_pos }
+    }
+
+    /// Gets a mutable reference to the `ki_pos` field.
+    pub fn ki_pos_mut(&mut self) -> &mut loff_t {
+        // SAFETY: The `kiocb` can access `ki_pos`.
+        unsafe { &mut (*self.inner.as_ptr()).ki_pos }
+    }
+}
+
+/// Wrapper for the kernel's `struct iov_iter`.
+pub struct IovIter {
+    inner: Opaque<bindings::iov_iter>,
+}
+
+impl IovIter {
+    /// Gets a raw pointer to the contents.
+    pub fn as_raw(&self) -> *mut bindings::iov_iter {
+        self.inner.get()
+    }
+}
+
+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
+        }
+    }
+
+    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>),
+            mmap: maybe_fn(T::HAS_MMAP, fops_mmap::<T>),
+            llseek: maybe_fn(T::HAS_LLSEEK, fops_llseek::<T>),
+            read_iter: maybe_fn(T::HAS_READ_ITER, fops_read_iter::<T>),
+            unlocked_ioctl: maybe_fn(T::HAS_IOCTL, fops_ioctl::<T>),
+            #[cfg(CONFIG_COMPAT)]
+            compat_ioctl: maybe_fn(T::HAS_IOCTL || T::HAS_COMPAT_IOCTL, fops_compat_ioctl::<T>),
+            ..unsafe { MaybeUninit::zeroed().assume_init() }
+        };
+    }
+
+    &VtableHelper::<T>::VTABLE
+}
+
+unsafe extern "C" fn fops_open<T: MiscDevice>(
+    inode: *mut bindings::inode,
+    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, file) };
+    if ret != 0 {
+        return ret;
+    }
+
+    // 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 ptr = match T::open(unsafe { File::from_raw_file(file) }) {
+        Ok(ptr) => ptr,
+        Err(err) => return err.to_errno(),
+    };
+
+    // SAFETY: The open call of a file owns the private data.
+    unsafe { (*file).private_data = ptr.into_foreign().cast_mut() };
+
+    0
+}
+
+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: We are taking ownership of the private data, so we can drop it.
+    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
+}
+
+unsafe extern "C" fn fops_mmap<T: MiscDevice>(
+    file: *mut bindings::file,
+    vma: *mut bindings::vm_area_struct,
+) -> c_int {
+    // 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 vma is valid.
+    let area = unsafe { kernel::mm::virt::VmArea::from_raw_mut(vma) };
+
+    match T::mmap(device, file, area) {
+        Ok(()) => 0,
+        Err(err) => err.to_errno() as c_int,
+    }
+}
+
+unsafe extern "C" fn fops_llseek<T: MiscDevice>(
+    file: *mut bindings::file,
+    offset: loff_t,
+    whence: c_int,
+) -> loff_t {
+    // 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.
+    // * We are inside an fdget_pos region, so there cannot be any active fdget_pos regions on
+    //   other threads.
+    let file = unsafe { LocalFile::from_raw_file(file) };
+
+    match T::llseek(device, file, offset, whence) {
+        Ok(res) => res as loff_t,
+        Err(err) => err.to_errno() as loff_t,
+    }
+}
+
+unsafe extern "C" fn fops_read_iter<T: MiscDevice>(
+    kiocb: *mut bindings::kiocb,
+    iter: *mut bindings::iov_iter,
+) -> isize {
+    let kiocb = Kiocb {
+        inner: unsafe { NonNull::new_unchecked(kiocb) },
+        _phantom: PhantomData,
+    };
+    let iov = unsafe { &mut *iter.cast::<IovIter>() };
+
+    match T::read_iter(kiocb, iov) {
+        Ok(res) => res as isize,
+        Err(err) => err.to_errno() as isize,
+    }
+}
+
+unsafe extern "C" fn fops_ioctl<T: MiscDevice>(
+    file: *mut bindings::file,
+    cmd: c_uint,
+    arg: c_ulong,
+) -> c_long {
+    // 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) };
+
+    match T::ioctl(device, file, cmd as u32, arg as usize) {
+        Ok(ret) => ret,
+        Err(err) => err.to_errno() as c_long,
+    }
+}
+
+#[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 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) };
+
+    match T::compat_ioctl(device, file, cmd as u32, arg as usize) {
+        Ok(ret) => ret,
+        Err(err) => err.to_errno() as c_long,
+    }
+}

-- 
2.46.0.792.g87dc391469-goog


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/3] Miscdevices in Rust
  2024-09-26 14:58 [PATCH 0/3] Miscdevices in Rust Alice Ryhl
                   ` (2 preceding siblings ...)
  2024-09-26 14:58 ` [PATCH 3/3] rust: miscdevice: add abstraction for defining miscdevices Alice Ryhl
@ 2024-09-26 15:05 ` Greg Kroah-Hartman
  2024-09-26 15:11   ` Miguel Ojeda
  2024-09-26 15:20   ` Alice Ryhl
  2024-09-26 18:58 ` Benno Lossin
  4 siblings, 2 replies; 19+ messages in thread
From: Greg Kroah-Hartman @ 2024-09-26 15:05 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: Arnd Bergmann, Miguel Ojeda, Alexander Viro, Christian Brauner,
	Jan Kara, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, rust-for-linux,
	linux-fsdevel, linux-kernel

On Thu, Sep 26, 2024 at 02:58:54PM +0000, Alice Ryhl wrote:
> A misc device is generally the best place to start with your first Rust
> driver, so having abstractions for miscdevice in Rust will be important
> for our ability to teach Rust to kernel developers.
> 
> I intend to add a sample driver using these abstractions, and I also
> intend to use it in Rust Binder to handle the case where binderfs is
> turned off.
> 
> I know that the patchset is still a bit rough. It could use some work on
> the file position aspect. But I'm sending this out now to get feedback
> on the overall approach.

Very cool!

> This patchset depends on files [1] and vma [2].
>
> Link: https://lore.kernel.org/all/20240915-alice-file-v10-0-88484f7a3dcf@google.com/ [1]
> Link: https://lore.kernel.org/all/20240806-vma-v5-1-04018f05de2b@google.com/ [2]
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>

Does it really need all of those dependencies?  I know your development
stack is deep here, but maybe I can unwind a bit of the file stuff to
get this in for the next merge window (6.13-rc1) if those two aren't
going to be planned for there.

I'll look into this some more next week, thanks!

greg k-h

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/3] Miscdevices in Rust
  2024-09-26 15:05 ` [PATCH 0/3] Miscdevices in Rust Greg Kroah-Hartman
@ 2024-09-26 15:11   ` Miguel Ojeda
  2024-09-26 15:20   ` Alice Ryhl
  1 sibling, 0 replies; 19+ messages in thread
From: Miguel Ojeda @ 2024-09-26 15:11 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Christian Brauner
  Cc: Alice Ryhl, Arnd Bergmann, Miguel Ojeda, Alexander Viro, Jan Kara,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Trevor Gross, rust-for-linux, linux-fsdevel,
	linux-kernel

On Thu, Sep 26, 2024 at 5:05 PM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
>
> stack is deep here, but maybe I can unwind a bit of the file stuff to
> get this in for the next merge window (6.13-rc1) if those two aren't
> going to be planned for there.

I think Christian wanted to merge the file abstractions in 6.13, he
has them here:

    https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git/log/?h=vfs.rust.file

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/3] Miscdevices in Rust
  2024-09-26 15:05 ` [PATCH 0/3] Miscdevices in Rust Greg Kroah-Hartman
  2024-09-26 15:11   ` Miguel Ojeda
@ 2024-09-26 15:20   ` Alice Ryhl
  2024-09-26 15:36     ` Greg Kroah-Hartman
  1 sibling, 1 reply; 19+ messages in thread
From: Alice Ryhl @ 2024-09-26 15:20 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Arnd Bergmann, Miguel Ojeda, Alexander Viro, Christian Brauner,
	Jan Kara, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, rust-for-linux,
	linux-fsdevel, linux-kernel

On Thu, Sep 26, 2024 at 5:05 PM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
>
> On Thu, Sep 26, 2024 at 02:58:54PM +0000, Alice Ryhl wrote:
> > A misc device is generally the best place to start with your first Rust
> > driver, so having abstractions for miscdevice in Rust will be important
> > for our ability to teach Rust to kernel developers.
> >
> > I intend to add a sample driver using these abstractions, and I also
> > intend to use it in Rust Binder to handle the case where binderfs is
> > turned off.
> >
> > I know that the patchset is still a bit rough. It could use some work on
> > the file position aspect. But I'm sending this out now to get feedback
> > on the overall approach.
>
> Very cool!
>
> > This patchset depends on files [1] and vma [2].
> >
> > Link: https://lore.kernel.org/all/20240915-alice-file-v10-0-88484f7a3dcf@google.com/ [1]
> > Link: https://lore.kernel.org/all/20240806-vma-v5-1-04018f05de2b@google.com/ [2]
> > Signed-off-by: Alice Ryhl <aliceryhl@google.com>
>
> Does it really need all of those dependencies?  I know your development
> stack is deep here, but maybe I can unwind a bit of the file stuff to
> get this in for the next merge window (6.13-rc1) if those two aren't
> going to be planned for there.

Ah, maybe not. The dependency on files is necessary to allow the file
to look at its own fields, e.g. whether O_NONBLOCK is set or what the
file position is. But we can take that out for now and add it once
both miscdevice and file have landed. I'm hoping that file will land
for 6.13, but untangling them allows both to land in 6.13.

As for vma, it's needed for mmap, but if I take out the ability to
define an mmap operation, I don't need it. We can always add back mmap
once both miscdevice and vma have landed.

Thank you for the suggestion on untangling the dependencies.

> I'll look into this some more next week, thanks!

Thanks!

Alice

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/3] Miscdevices in Rust
  2024-09-26 15:20   ` Alice Ryhl
@ 2024-09-26 15:36     ` Greg Kroah-Hartman
  0 siblings, 0 replies; 19+ messages in thread
From: Greg Kroah-Hartman @ 2024-09-26 15:36 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: Arnd Bergmann, Miguel Ojeda, Alexander Viro, Christian Brauner,
	Jan Kara, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, rust-for-linux,
	linux-fsdevel, linux-kernel

On Thu, Sep 26, 2024 at 05:20:15PM +0200, Alice Ryhl wrote:
> On Thu, Sep 26, 2024 at 5:05 PM Greg Kroah-Hartman
> <gregkh@linuxfoundation.org> wrote:
> >
> > On Thu, Sep 26, 2024 at 02:58:54PM +0000, Alice Ryhl wrote:
> > > A misc device is generally the best place to start with your first Rust
> > > driver, so having abstractions for miscdevice in Rust will be important
> > > for our ability to teach Rust to kernel developers.
> > >
> > > I intend to add a sample driver using these abstractions, and I also
> > > intend to use it in Rust Binder to handle the case where binderfs is
> > > turned off.
> > >
> > > I know that the patchset is still a bit rough. It could use some work on
> > > the file position aspect. But I'm sending this out now to get feedback
> > > on the overall approach.
> >
> > Very cool!
> >
> > > This patchset depends on files [1] and vma [2].
> > >
> > > Link: https://lore.kernel.org/all/20240915-alice-file-v10-0-88484f7a3dcf@google.com/ [1]
> > > Link: https://lore.kernel.org/all/20240806-vma-v5-1-04018f05de2b@google.com/ [2]
> > > Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> >
> > Does it really need all of those dependencies?  I know your development
> > stack is deep here, but maybe I can unwind a bit of the file stuff to
> > get this in for the next merge window (6.13-rc1) if those two aren't
> > going to be planned for there.
> 
> Ah, maybe not. The dependency on files is necessary to allow the file
> to look at its own fields, e.g. whether O_NONBLOCK is set or what the
> file position is. But we can take that out for now and add it once
> both miscdevice and file have landed. I'm hoping that file will land
> for 6.13, but untangling them allows both to land in 6.13.
> 
> As for vma, it's needed for mmap, but if I take out the ability to
> define an mmap operation, I don't need it. We can always add back mmap
> once both miscdevice and vma have landed.

Yes, let's drop the mmap interface for now, and probably the seek stuff
too as most "normal" misc devices do not mess with them at all.

If that makes the dependencies simpler, that would be great.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/3] Miscdevices in Rust
  2024-09-26 14:58 [PATCH 0/3] Miscdevices in Rust Alice Ryhl
                   ` (3 preceding siblings ...)
  2024-09-26 15:05 ` [PATCH 0/3] Miscdevices in Rust Greg Kroah-Hartman
@ 2024-09-26 18:58 ` Benno Lossin
  2024-09-27  6:04   ` Greg Kroah-Hartman
  4 siblings, 1 reply; 19+ messages in thread
From: Benno Lossin @ 2024-09-26 18:58 UTC (permalink / raw)
  To: Alice Ryhl, Greg Kroah-Hartman, Arnd Bergmann, Miguel Ojeda,
	Alexander Viro, Christian Brauner, Jan Kara
  Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg,
	Trevor Gross, rust-for-linux, linux-fsdevel, linux-kernel

On 26.09.24 16:58, Alice Ryhl wrote:
> A misc device is generally the best place to start with your first Rust
> driver, so having abstractions for miscdevice in Rust will be important
> for our ability to teach Rust to kernel developers.

Sounds good!

> I intend to add a sample driver using these abstractions, and I also
> intend to use it in Rust Binder to handle the case where binderfs is
> turned off.
> 
> I know that the patchset is still a bit rough. It could use some work on
> the file position aspect. But I'm sending this out now to get feedback
> on the overall approach.
> 
> This patchset depends on files [1] and vma [2].
> 
> Link: https://lore.kernel.org/all/20240915-alice-file-v10-0-88484f7a3dcf@google.com/ [1]
> Link: https://lore.kernel.org/all/20240806-vma-v5-1-04018f05de2b@google.com/ [2]
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
> Alice Ryhl (3):
>       rust: types: add Opaque::try_ffi_init
>       rust: file: add f_pos and set_f_pos
>       rust: miscdevice: add abstraction for defining miscdevices

I recall that we had a sample miscdev driver in the old rust branch. Can
you include that in this series, or is there still some stuff missing? I
think it would be really useful for people that want to implement such a
driver to have something to look at.

---
Cheers,
Benno


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/3] rust: file: add f_pos and set_f_pos
  2024-09-26 14:58 ` [PATCH 2/3] rust: file: add f_pos and set_f_pos Alice Ryhl
@ 2024-09-26 22:08   ` Al Viro
  2024-09-26 22:47     ` Al Viro
  2024-09-27  6:48     ` Alice Ryhl
  2024-09-27  7:32   ` Christian Brauner
  1 sibling, 2 replies; 19+ messages in thread
From: Al Viro @ 2024-09-26 22:08 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: Greg Kroah-Hartman, Arnd Bergmann, Miguel Ojeda,
	Christian Brauner, Jan Kara, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross, rust-for-linux, linux-fsdevel, linux-kernel

On Thu, Sep 26, 2024 at 02:58:56PM +0000, Alice Ryhl wrote:
> Add accessors for the file position. Most of the time, you should not
> use these methods directly, and you should instead use a guard for the
> file position to prove that you hold the fpos lock. However, under
> limited circumstances, files are allowed to choose a different locking
> strategy for their file position. These accessors can be used to handle
> that case.
> 
> For now, these accessors are the only way to access the file position
> within the llseek and read_iter callbacks.

You really should not do that within ->read_iter().  If your method
does that, it has the wrong signature.

If nothing else, it should be usable for preadv(2), so what file position
are you talking about?

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/3] rust: file: add f_pos and set_f_pos
  2024-09-26 22:08   ` Al Viro
@ 2024-09-26 22:47     ` Al Viro
  2024-09-26 22:52       ` Al Viro
  2024-09-27  6:56       ` Alice Ryhl
  2024-09-27  6:48     ` Alice Ryhl
  1 sibling, 2 replies; 19+ messages in thread
From: Al Viro @ 2024-09-26 22:47 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: Greg Kroah-Hartman, Arnd Bergmann, Miguel Ojeda,
	Christian Brauner, Jan Kara, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross, rust-for-linux, linux-fsdevel, linux-kernel

On Thu, Sep 26, 2024 at 11:08:21PM +0100, Al Viro wrote:
> On Thu, Sep 26, 2024 at 02:58:56PM +0000, Alice Ryhl wrote:
> > Add accessors for the file position. Most of the time, you should not
> > use these methods directly, and you should instead use a guard for the
> > file position to prove that you hold the fpos lock. However, under
> > limited circumstances, files are allowed to choose a different locking
> > strategy for their file position. These accessors can be used to handle
> > that case.
> > 
> > For now, these accessors are the only way to access the file position
> > within the llseek and read_iter callbacks.
> 
> You really should not do that within ->read_iter().  If your method
> does that, it has the wrong signature.
> 
> If nothing else, it should be usable for preadv(2), so what file position
> are you talking about?

To elaborate: ->llseek() is the only method that has any business accessing
->f_pos (and that - possibly not forever).  Note, BTW, that most of the
time ->llseek() should be using one of the safe instances from fs/libfs.c
or helpers from the same place; direct ->f_pos access in drivers is
basically for things like
static loff_t cfam_llseek(struct file *file, loff_t offset, int whence)
{
        switch (whence) {
	case SEEK_CUR:
		break;
	case SEEK_SET:
		file->f_pos = offset;
		break;
	default:
		return -EINVAL;
	}

	return offset;
}
which is... really special.  Translation: lseek(fd, n, SEEK_CUR) - return n
and do nothing.  lseek(fd, n, SEEK_SET) - usual semantics.  Anything else
- fail with EINVAL.  The mind-boggling part is SEEK_CUR, but that's
userland ABI of that particular driver; if the authors can be convinced that
we don't need to preserve that wart, it can be replaced with use of
no_seek_end_llseek.  If their very special userland relies upon it...
not much we can do.

Anything else outside of core VFS should not touch the damn thing, unless
they have a very good reason and are willing to explain what makes them
special.

From quick grep through the tree, we seem to have grown a bunch of bogosities
in vfio (including one in samples, presumably responsible for that infestation),
there's a few strange ioctls that reset it to 0 or do other unnatural things
(hell, VFAT has readdir() variant called that way), there are _really_ shitty
cases in HFS, HFS+ and HPFS, where things like unlink() while somebody has the
parent directory open will modify the current position(s), and then there's
whatever ksmbd is playing at.

We really should not expose ->f_pos - that can't be done on the C side (yet),
but let's not spread that idiocy.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/3] rust: file: add f_pos and set_f_pos
  2024-09-26 22:47     ` Al Viro
@ 2024-09-26 22:52       ` Al Viro
  2024-09-27  6:56       ` Alice Ryhl
  1 sibling, 0 replies; 19+ messages in thread
From: Al Viro @ 2024-09-26 22:52 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: Greg Kroah-Hartman, Arnd Bergmann, Miguel Ojeda,
	Christian Brauner, Jan Kara, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross, rust-for-linux, linux-fsdevel, linux-kernel

On Thu, Sep 26, 2024 at 11:47:33PM +0100, Al Viro wrote:
> time ->llseek() should be using one of the safe instances from fs/libfs.c

d'oh... s/libfs.c/read_write.c/ - sorry.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 0/3] Miscdevices in Rust
  2024-09-26 18:58 ` Benno Lossin
@ 2024-09-27  6:04   ` Greg Kroah-Hartman
  0 siblings, 0 replies; 19+ messages in thread
From: Greg Kroah-Hartman @ 2024-09-27  6:04 UTC (permalink / raw)
  To: Benno Lossin
  Cc: Alice Ryhl, Arnd Bergmann, Miguel Ojeda, Alexander Viro,
	Christian Brauner, Jan Kara, Boqun Feng, Gary Guo,
	Björn Roy Baron, Andreas Hindborg, Trevor Gross,
	rust-for-linux, linux-fsdevel, linux-kernel

On Thu, Sep 26, 2024 at 06:58:10PM +0000, Benno Lossin wrote:
> On 26.09.24 16:58, Alice Ryhl wrote:
> > A misc device is generally the best place to start with your first Rust
> > driver, so having abstractions for miscdevice in Rust will be important
> > for our ability to teach Rust to kernel developers.
> 
> Sounds good!
> 
> > I intend to add a sample driver using these abstractions, and I also
> > intend to use it in Rust Binder to handle the case where binderfs is
> > turned off.
> > 
> > I know that the patchset is still a bit rough. It could use some work on
> > the file position aspect. But I'm sending this out now to get feedback
> > on the overall approach.
> > 
> > This patchset depends on files [1] and vma [2].
> > 
> > Link: https://lore.kernel.org/all/20240915-alice-file-v10-0-88484f7a3dcf@google.com/ [1]
> > Link: https://lore.kernel.org/all/20240806-vma-v5-1-04018f05de2b@google.com/ [2]
> > Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> > ---
> > Alice Ryhl (3):
> >       rust: types: add Opaque::try_ffi_init
> >       rust: file: add f_pos and set_f_pos
> >       rust: miscdevice: add abstraction for defining miscdevices
> 
> I recall that we had a sample miscdev driver in the old rust branch. Can
> you include that in this series, or is there still some stuff missing? I
> think it would be really useful for people that want to implement such a
> driver to have something to look at.

I agree, I'll dig that up after -rc1 is out and add it to this series.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/3] rust: file: add f_pos and set_f_pos
  2024-09-26 22:08   ` Al Viro
  2024-09-26 22:47     ` Al Viro
@ 2024-09-27  6:48     ` Alice Ryhl
  1 sibling, 0 replies; 19+ messages in thread
From: Alice Ryhl @ 2024-09-27  6:48 UTC (permalink / raw)
  To: Al Viro
  Cc: Greg Kroah-Hartman, Arnd Bergmann, Miguel Ojeda,
	Christian Brauner, Jan Kara, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross, rust-for-linux, linux-fsdevel, linux-kernel

On Fri, Sep 27, 2024 at 12:08 AM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> On Thu, Sep 26, 2024 at 02:58:56PM +0000, Alice Ryhl wrote:
> > Add accessors for the file position. Most of the time, you should not
> > use these methods directly, and you should instead use a guard for the
> > file position to prove that you hold the fpos lock. However, under
> > limited circumstances, files are allowed to choose a different locking
> > strategy for their file position. These accessors can be used to handle
> > that case.
> >
> > For now, these accessors are the only way to access the file position
> > within the llseek and read_iter callbacks.
>
> You really should not do that within ->read_iter().  If your method
> does that, it has the wrong signature.
>
> If nothing else, it should be usable for preadv(2), so what file position
> are you talking about?

Sorry, you are right. In read_iter we can access the file position via
the kiocb. It only makes sense for seek.

Alice

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/3] rust: file: add f_pos and set_f_pos
  2024-09-26 22:47     ` Al Viro
  2024-09-26 22:52       ` Al Viro
@ 2024-09-27  6:56       ` Alice Ryhl
  2024-09-27 19:38         ` Al Viro
  1 sibling, 1 reply; 19+ messages in thread
From: Alice Ryhl @ 2024-09-27  6:56 UTC (permalink / raw)
  To: Al Viro
  Cc: Greg Kroah-Hartman, Arnd Bergmann, Miguel Ojeda,
	Christian Brauner, Jan Kara, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross, rust-for-linux, linux-fsdevel, linux-kernel

On Fri, Sep 27, 2024 at 12:47 AM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> On Thu, Sep 26, 2024 at 11:08:21PM +0100, Al Viro wrote:
> > On Thu, Sep 26, 2024 at 02:58:56PM +0000, Alice Ryhl wrote:
> > > Add accessors for the file position. Most of the time, you should not
> > > use these methods directly, and you should instead use a guard for the
> > > file position to prove that you hold the fpos lock. However, under
> > > limited circumstances, files are allowed to choose a different locking
> > > strategy for their file position. These accessors can be used to handle
> > > that case.
> > >
> > > For now, these accessors are the only way to access the file position
> > > within the llseek and read_iter callbacks.
> >
> > You really should not do that within ->read_iter().  If your method
> > does that, it has the wrong signature.
> >
> > If nothing else, it should be usable for preadv(2), so what file position
> > are you talking about?
>
> To elaborate: ->llseek() is the only method that has any business accessing
> ->f_pos (and that - possibly not forever).  Note, BTW, that most of the
> time ->llseek() should be using one of the safe instances from fs/libfs.c
> or helpers from the same place; direct ->f_pos access in drivers is
> basically for things like
> static loff_t cfam_llseek(struct file *file, loff_t offset, int whence)
> {
>         switch (whence) {
>         case SEEK_CUR:
>                 break;
>         case SEEK_SET:
>                 file->f_pos = offset;
>                 break;
>         default:
>                 return -EINVAL;
>         }
>
>         return offset;
> }
> which is... really special.  Translation: lseek(fd, n, SEEK_CUR) - return n
> and do nothing.  lseek(fd, n, SEEK_SET) - usual semantics.  Anything else
> - fail with EINVAL.  The mind-boggling part is SEEK_CUR, but that's
> userland ABI of that particular driver; if the authors can be convinced that
> we don't need to preserve that wart, it can be replaced with use of
> no_seek_end_llseek.  If their very special userland relies upon it...
> not much we can do.
>
> Anything else outside of core VFS should not touch the damn thing, unless
> they have a very good reason and are willing to explain what makes them
> special.
>
> From quick grep through the tree, we seem to have grown a bunch of bogosities
> in vfio (including one in samples, presumably responsible for that infestation),
> there's a few strange ioctls that reset it to 0 or do other unnatural things
> (hell, VFAT has readdir() variant called that way), there are _really_ shitty
> cases in HFS, HFS+ and HPFS, where things like unlink() while somebody has the
> parent directory open will modify the current position(s), and then there's
> whatever ksmbd is playing at.
>
> We really should not expose ->f_pos - that can't be done on the C side (yet),
> but let's not spread that idiocy.

Okay, interesting. I did not know about all of these llseek helpers.
I'm definitely happy to make the Rust API force users to do the right
thing if we can.

It sounds like we basically have a few different seeking behaviors
that the driver can choose between, and we want to force the user to
use one of them?

Alice

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/3] rust: file: add f_pos and set_f_pos
  2024-09-26 14:58 ` [PATCH 2/3] rust: file: add f_pos and set_f_pos Alice Ryhl
  2024-09-26 22:08   ` Al Viro
@ 2024-09-27  7:32   ` Christian Brauner
  1 sibling, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2024-09-27  7:32 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: Greg Kroah-Hartman, Arnd Bergmann, Miguel Ojeda, Alexander Viro,
	Jan Kara, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Trevor Gross, rust-for-linux,
	linux-fsdevel, linux-kernel

On Thu, Sep 26, 2024 at 02:58:56PM GMT, Alice Ryhl wrote:
> Add accessors for the file position. Most of the time, you should not
> use these methods directly, and you should instead use a guard for the
> file position to prove that you hold the fpos lock. However, under
> limited circumstances, files are allowed to choose a different locking
> strategy for their file position. These accessors can be used to handle
> that case.
> 
> For now, these accessors are the only way to access the file position
> within the llseek and read_iter callbacks.
> 
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
>  rust/kernel/fs/file.rs | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
> 
> diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs
> index e03dbe14d62a..c896a3b1d182 100644
> --- a/rust/kernel/fs/file.rs
> +++ b/rust/kernel/fs/file.rs
> @@ -333,6 +333,26 @@ pub fn flags(&self) -> u32 {
>          // FIXME(read_once): Replace with `read_once` when available on the Rust side.
>          unsafe { core::ptr::addr_of!((*self.as_ptr()).f_flags).read_volatile() }
>      }
> +
> +    /// Read the file position.
> +    ///
> +    /// # Safety
> +    ///
> +    /// You must hold the fpos lock or otherwise ensure that no data race will happen.
> +    #[inline]
> +    pub unsafe fn f_pos(&self) -> i64 {
> +        unsafe { (*self.as_ptr()).f_pos }
> +    }
> +
> +    /// Set the file position.
> +    ///
> +    /// # Safety
> +    ///
> +    /// You must hold the fpos lock or otherwise ensure that no data race will happen.
> +    #[inline]
> +    pub unsafe fn set_f_pos(&self, value: i64) {
> +        unsafe { (*self.as_ptr()).f_pos = value };
> +    }

I don't think we want to expose f_pos with its weird locking rule
through rust wrappers. Ideally, it's completely opaque to the callers
and not accessed directly at all.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/3] rust: types: add Opaque::try_ffi_init
  2024-09-26 14:58 ` [PATCH 1/3] rust: types: add Opaque::try_ffi_init Alice Ryhl
@ 2024-09-27  9:00   ` Fiona Behrens
  0 siblings, 0 replies; 19+ messages in thread
From: Fiona Behrens @ 2024-09-27  9:00 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: Greg Kroah-Hartman, Arnd Bergmann, Miguel Ojeda, Alexander Viro,
	Christian Brauner, Jan Kara, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross, rust-for-linux, linux-fsdevel, linux-kernel



On 26 Sep 2024, at 16:58, Alice Ryhl wrote:

> This will be used by the miscdevice abstractions, as the C function
> `misc_register` is fallible.
>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---

Reviewed-by: Fiona Behrens <me@kloenk.dev>


>  rust/kernel/types.rs | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
>
> diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
> index 3238ffaab031..dd9c606c515c 100644
> --- a/rust/kernel/types.rs
> +++ b/rust/kernel/types.rs
> @@ -299,6 +299,22 @@ pub fn ffi_init(init_func: impl FnOnce(*mut T)) -> impl PinInit<Self> {
>          }
>      }
>
> +    /// Creates a fallible pin-initializer from the given initializer closure.
> +    ///
> +    /// The returned initializer calls the given closure with the pointer to the inner `T` of this
> +    /// `Opaque`. Since this memory is uninitialized, the closure is not allowed to read from it.
> +    ///
> +    /// This function is safe, because the `T` inside of an `Opaque` is allowed to be
> +    /// uninitialized. Additionally, access to the inner `T` requires `unsafe`, so the caller needs
> +    /// to verify at that point that the inner value is valid.
> +    pub fn try_ffi_init<E>(
> +        init_func: impl FnOnce(*mut T) -> Result<(), E>,
> +    ) -> impl PinInit<Self, E> {
> +        // SAFETY: We contain a `MaybeUninit`, so it is OK for the `init_func` to not fully
> +        // initialize the `T`.
> +        unsafe { init::pin_init_from_closure::<_, E>(move |slot| init_func(Self::raw_get(slot))) }
> +    }
> +
>      /// Returns a raw pointer to the opaque data.
>      pub const fn get(&self) -> *mut T {
>          UnsafeCell::get(&self.value).cast::<T>()
>
> -- 
> 2.46.0.792.g87dc391469-goog

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/3] rust: file: add f_pos and set_f_pos
  2024-09-27  6:56       ` Alice Ryhl
@ 2024-09-27 19:38         ` Al Viro
  2024-10-01  8:20           ` Alice Ryhl
  0 siblings, 1 reply; 19+ messages in thread
From: Al Viro @ 2024-09-27 19:38 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: Greg Kroah-Hartman, Arnd Bergmann, Miguel Ojeda,
	Christian Brauner, Jan Kara, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross, rust-for-linux, linux-fsdevel, linux-kernel

On Fri, Sep 27, 2024 at 08:56:50AM +0200, Alice Ryhl wrote:

> Okay, interesting. I did not know about all of these llseek helpers.
> I'm definitely happy to make the Rust API force users to do the right
> thing if we can.
> 
> It sounds like we basically have a few different seeking behaviors
> that the driver can choose between, and we want to force the user to
> use one of them?

Depends...  Basically, SEEK_HOLE/SEEK_DATA is seriously fs-specific
(unsurprisingly), and pretty much everything wants the usual relation
between SEEK_SET and SEEK_CUR (<SEEK_CUR,n> is the same as <SEEK_SET,
current position + n>).  SEEK_END availability varies - the simplest
variant is <SEEK_END, n> == <SEEK_SET, size + n>, but there are
cases that genuinely have nothing resembling end-relative seek
(e.g. anything seq_file-related).

It's not so much available instances as available helpers; details of
semantics may seriously vary by the driver.

Note that once upon a time ->f_pos had been exposed to ->read() et.al.;
caused recurring bugs, until we switched to "sample ->f_pos before calling
->read(), pass the reference to local copy into the method, then put
what's the method left behind in there back into ->f_pos".

Something similar might be a good idea for ->llseek().  Locking is
an unpleasant problem, unfortunately.  lseek() is not a terribly hot
codepath, but read() and write() are.  For a while we used to do exclusion
on per-struct file basis for _all_ read/write/lseek; see 797964253d35
"file: reinstate f_pos locking optimization for regular files" for the
point where it eroded.

FWIW, I suspect that unconditionally taking ->f_pos_mutex for llseek(2)
would solve most of the problems - for one thing, with guaranteed
per-struct-file serialization of vfs_llseek() we could handle SEEK_CUR
right there, so that ->llseek() instances would never see it; for another,
we just might be able to pull the same 'pass a reference to local variable
and let it be handled there' trick for ->llseek().  That would require
an audit of locking in the instances, though...

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/3] rust: file: add f_pos and set_f_pos
  2024-09-27 19:38         ` Al Viro
@ 2024-10-01  8:20           ` Alice Ryhl
  0 siblings, 0 replies; 19+ messages in thread
From: Alice Ryhl @ 2024-10-01  8:20 UTC (permalink / raw)
  To: Al Viro
  Cc: Greg Kroah-Hartman, Arnd Bergmann, Miguel Ojeda,
	Christian Brauner, Jan Kara, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross, rust-for-linux, linux-fsdevel, linux-kernel

On Fri, Sep 27, 2024 at 9:38 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> On Fri, Sep 27, 2024 at 08:56:50AM +0200, Alice Ryhl wrote:
>
> > Okay, interesting. I did not know about all of these llseek helpers.
> > I'm definitely happy to make the Rust API force users to do the right
> > thing if we can.
> >
> > It sounds like we basically have a few different seeking behaviors
> > that the driver can choose between, and we want to force the user to
> > use one of them?
>
> Depends...  Basically, SEEK_HOLE/SEEK_DATA is seriously fs-specific
> (unsurprisingly), and pretty much everything wants the usual relation
> between SEEK_SET and SEEK_CUR (<SEEK_CUR,n> is the same as <SEEK_SET,
> current position + n>).  SEEK_END availability varies - the simplest
> variant is <SEEK_END, n> == <SEEK_SET, size + n>, but there are
> cases that genuinely have nothing resembling end-relative seek
> (e.g. anything seq_file-related).
>
> It's not so much available instances as available helpers; details of
> semantics may seriously vary by the driver.
>
> Note that once upon a time ->f_pos had been exposed to ->read() et.al.;
> caused recurring bugs, until we switched to "sample ->f_pos before calling
> ->read(), pass the reference to local copy into the method, then put
> what's the method left behind in there back into ->f_pos".
>
> Something similar might be a good idea for ->llseek().  Locking is
> an unpleasant problem, unfortunately.  lseek() is not a terribly hot
> codepath, but read() and write() are.  For a while we used to do exclusion
> on per-struct file basis for _all_ read/write/lseek; see 797964253d35
> "file: reinstate f_pos locking optimization for regular files" for the
> point where it eroded.
>
> FWIW, I suspect that unconditionally taking ->f_pos_mutex for llseek(2)
> would solve most of the problems - for one thing, with guaranteed
> per-struct-file serialization of vfs_llseek() we could handle SEEK_CUR
> right there, so that ->llseek() instances would never see it; for another,
> we just might be able to pull the same 'pass a reference to local variable
> and let it be handled there' trick for ->llseek().  That would require
> an audit of locking in the instances, though...

Okay, thanks for the explanation. The file position stuff seems pretty
complicated.

One thing to think about is whether there are some behaviors used by
old drivers that new drivers should not use. We can design our Rust
APIs to prevent using it in those legacy ways.

For now I'm dropping this patch from the series at Greg's request.

Alice

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2024-10-01  8:20 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-26 14:58 [PATCH 0/3] Miscdevices in Rust Alice Ryhl
2024-09-26 14:58 ` [PATCH 1/3] rust: types: add Opaque::try_ffi_init Alice Ryhl
2024-09-27  9:00   ` Fiona Behrens
2024-09-26 14:58 ` [PATCH 2/3] rust: file: add f_pos and set_f_pos Alice Ryhl
2024-09-26 22:08   ` Al Viro
2024-09-26 22:47     ` Al Viro
2024-09-26 22:52       ` Al Viro
2024-09-27  6:56       ` Alice Ryhl
2024-09-27 19:38         ` Al Viro
2024-10-01  8:20           ` Alice Ryhl
2024-09-27  6:48     ` Alice Ryhl
2024-09-27  7:32   ` Christian Brauner
2024-09-26 14:58 ` [PATCH 3/3] rust: miscdevice: add abstraction for defining miscdevices Alice Ryhl
2024-09-26 15:05 ` [PATCH 0/3] Miscdevices in Rust Greg Kroah-Hartman
2024-09-26 15:11   ` Miguel Ojeda
2024-09-26 15:20   ` Alice Ryhl
2024-09-26 15:36     ` Greg Kroah-Hartman
2024-09-26 18:58 ` Benno Lossin
2024-09-27  6:04   ` Greg Kroah-Hartman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).