mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 11:06:41 -05:00
Merge tag 'vfs-6.17-rc1.rust' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs rust updates from Christian Brauner: - Allow poll_table pointers to be NULL - Add Rust files to vfs MAINTAINERS entry * tag 'vfs-6.17-rc1.rust' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: vfs: add Rust files to MAINTAINERS poll: rust: allow poll_table ptrs to be null
This commit is contained in:
@@ -9246,6 +9246,10 @@ F: include/linux/fs.h
|
||||
F: include/linux/fs_types.h
|
||||
F: include/uapi/linux/fs.h
|
||||
F: include/uapi/linux/openat2.h
|
||||
F: rust/kernel/fs.rs
|
||||
F: rust/kernel/fs/
|
||||
F: rust/kernel/seq_file.rs
|
||||
F: rust/kernel/sync/poll.rs
|
||||
F: Documentation/driver-api/early-userspace/buffer-format.rst
|
||||
F: init/do_mounts*
|
||||
F: init/*initramfs*
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "platform.c"
|
||||
#include "pci.c"
|
||||
#include "pid_namespace.c"
|
||||
#include "poll.c"
|
||||
#include "rbtree.c"
|
||||
#include "rcu.c"
|
||||
#include "refcount.c"
|
||||
|
||||
10
rust/helpers/poll.c
Normal file
10
rust/helpers/poll.c
Normal file
@@ -0,0 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/poll.h>
|
||||
|
||||
void rust_helper_poll_wait(struct file *filp, wait_queue_head_t *wait_address,
|
||||
poll_table *p)
|
||||
{
|
||||
poll_wait(filp, wait_address, p);
|
||||
}
|
||||
@@ -9,9 +9,8 @@
|
||||
fs::File,
|
||||
prelude::*,
|
||||
sync::{CondVar, LockClassKey},
|
||||
types::Opaque,
|
||||
};
|
||||
use core::ops::Deref;
|
||||
use core::{marker::PhantomData, ops::Deref};
|
||||
|
||||
/// Creates a [`PollCondVar`] initialiser with the given name and a newly-created lock class.
|
||||
#[macro_export]
|
||||
@@ -23,58 +22,43 @@ macro_rules! new_poll_condvar {
|
||||
};
|
||||
}
|
||||
|
||||
/// Wraps the kernel's `struct poll_table`.
|
||||
/// Wraps the kernel's `poll_table`.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// This struct contains a valid `struct poll_table`.
|
||||
///
|
||||
/// For a `struct poll_table` to be valid, its `_qproc` function must follow the safety
|
||||
/// requirements of `_qproc` functions:
|
||||
///
|
||||
/// * The `_qproc` function is given permission to enqueue a waiter to the provided `poll_table`
|
||||
/// during the call. Once the waiter is removed and an rcu grace period has passed, it must no
|
||||
/// longer access the `wait_queue_head`.
|
||||
/// The pointer must be null or reference a valid `poll_table`.
|
||||
#[repr(transparent)]
|
||||
pub struct PollTable(Opaque<bindings::poll_table>);
|
||||
pub struct PollTable<'a> {
|
||||
table: *mut bindings::poll_table,
|
||||
_lifetime: PhantomData<&'a bindings::poll_table>,
|
||||
}
|
||||
|
||||
impl PollTable {
|
||||
/// Creates a reference to a [`PollTable`] from a valid pointer.
|
||||
impl<'a> PollTable<'a> {
|
||||
/// Creates a [`PollTable`] from a valid pointer.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that for the duration of `'a`, the pointer will point at a valid poll
|
||||
/// table (as defined in the type invariants).
|
||||
///
|
||||
/// The caller must also ensure that the `poll_table` is only accessed via the returned
|
||||
/// reference for the duration of `'a`.
|
||||
pub unsafe fn from_ptr<'a>(ptr: *mut bindings::poll_table) -> &'a mut PollTable {
|
||||
// SAFETY: The safety requirements guarantee the validity of the dereference, while the
|
||||
// `PollTable` type being transparent makes the cast ok.
|
||||
unsafe { &mut *ptr.cast() }
|
||||
}
|
||||
|
||||
fn get_qproc(&self) -> bindings::poll_queue_proc {
|
||||
let ptr = self.0.get();
|
||||
// SAFETY: The `ptr` is valid because it originates from a reference, and the `_qproc`
|
||||
// field is not modified concurrently with this call since we have an immutable reference.
|
||||
unsafe { (*ptr)._qproc }
|
||||
/// The pointer must be null or reference a valid `poll_table` for the duration of `'a`.
|
||||
pub unsafe fn from_raw(table: *mut bindings::poll_table) -> Self {
|
||||
// INVARIANTS: The safety requirements are the same as the struct invariants.
|
||||
PollTable {
|
||||
table,
|
||||
_lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Register this [`PollTable`] with the provided [`PollCondVar`], so that it can be notified
|
||||
/// using the condition variable.
|
||||
pub fn register_wait(&mut self, file: &File, cv: &PollCondVar) {
|
||||
if let Some(qproc) = self.get_qproc() {
|
||||
// SAFETY: The pointers to `file` and `self` need to be valid for the duration of this
|
||||
// call to `qproc`, which they are because they are references.
|
||||
//
|
||||
// The `cv.wait_queue_head` pointer must be valid until an rcu grace period after the
|
||||
// waiter is removed. The `PollCondVar` is pinned, so before `cv.wait_queue_head` can
|
||||
// be destroyed, the destructor must run. That destructor first removes all waiters,
|
||||
// and then waits for an rcu grace period. Therefore, `cv.wait_queue_head` is valid for
|
||||
// long enough.
|
||||
unsafe { qproc(file.as_ptr() as _, cv.wait_queue_head.get(), self.0.get()) };
|
||||
}
|
||||
pub fn register_wait(&self, file: &File, cv: &PollCondVar) {
|
||||
// SAFETY:
|
||||
// * `file.as_ptr()` references a valid file for the duration of this call.
|
||||
// * `self.table` is null or references a valid poll_table for the duration of this call.
|
||||
// * Since `PollCondVar` is pinned, its destructor is guaranteed to run before the memory
|
||||
// containing `cv.wait_queue_head` is invalidated. Since the destructor clears all
|
||||
// waiters and then waits for an rcu grace period, it's guaranteed that
|
||||
// `cv.wait_queue_head` remains valid for at least an rcu grace period after the removal
|
||||
// of the last waiter.
|
||||
unsafe { bindings::poll_wait(file.as_ptr(), cv.wait_queue_head.get(), self.table) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user