On Wed Aug 5, 2026 at 3:59 PM BST, Philipp Stanner wrote:
> rcu_barrier() is a frequently used C function which is always safe to be
> called.
>
> Add a safe abstraction for rcu_barrier().
>
> Signed-off-by: Philipp Stanner <phasta(a)kernel.org>
> Tested-by: Daniel Almeida <daniel.almeida(a)collabora.com>
Acked-by: Gary Guo <gary(a)garyguo.net>
> ---
> rust/kernel/sync/rcu.rs | 20 ++++++++++++++++++++
> 1 file changed, 20 insertions(+)
>
> diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs
> index a32bef6e490b..7031ca5d2473 100644
> --- a/rust/kernel/sync/rcu.rs
> +++ b/rust/kernel/sync/rcu.rs
> @@ -50,3 +50,23 @@ fn drop(&mut self) {
> pub fn read_lock() -> Guard {
> Guard::new()
> }
> +
> +/// Wait until all in-flight call_rcu() callbacks complete.
This misses some `` quoting but these can be applied on fixup.
Best,
Gary
> +///
> +/// Note that this primitive does not necessarily wait for an RCU grace period
> +/// to complete. For example, if there are no RCU callbacks queued anywhere
> +/// in the system, then rcu_barrier() is within its rights to return
> +/// immediately, without waiting for anything, much less an RCU grace period.
> +/// In fact, rcu_barrier() will normally not result in any RCU grace periods
> +/// beyond those that were already destined to be executed.
> +///
> +/// In kernels built with CONFIG_RCU_LAZY=y, this function also hurries all
> +/// pending lazy RCU callbacks.
> +///
> +/// Note that this is one of the RCU primitives which must not be called in
> +/// atomic context.
> +#[inline]
> +pub fn rcu_barrier() {
> + // SAFETY: `rcu_barrier()` is always safe to be called. It just might wait for a grace period.
> + unsafe { bindings::rcu_barrier() };
> +}
On Wed Aug 5, 2026 at 3:59 PM BST, Philipp Stanner wrote:
> From: Danilo Krummrich <dakr(a)kernel.org>
>
> Implement ForeignOwnable for ARef<T>, making it possible for C code to
> own an ARef<T>.
>
> Since ARef represents shared ownership, BorrowedMut is &T rather than
> &mut T, matching the semantics of the underlying reference-counted type.
>
> Signed-off-by: Danilo Krummrich <dakr(a)kernel.org>
> Reviewed-by: Alice Ryhl <aliceryhl(a)google.com>
> Tested-by: Daniel Almeida <daniel.almeida(a)collabora.com>
> ---
> rust/kernel/sync/aref.rs | 40 ++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 40 insertions(+)
>
> diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs
> index b721b2e00b98..540766613659 100644
> --- a/rust/kernel/sync/aref.rs
> +++ b/rust/kernel/sync/aref.rs
> @@ -24,6 +24,11 @@
> ptr::NonNull, //
> };
>
> +use crate::{
> + prelude::*,
> + types::ForeignOwnable, //
> +};
> +
> /// Types that are _always_ reference counted.
> ///
> /// It allows such types to define their own custom ref increment and decrement functions.
> @@ -188,6 +193,41 @@ fn eq(&self, other: &ARef<U>) -> bool {
> }
> impl<T: AlwaysRefCounted + Eq> Eq for ARef<T> {}
>
> +// SAFETY: `into_foreign` returns a pointer from `NonNull::as_ptr`, so it's non-null. The
> +// `ARef` invariant guarantees that `ptr` points to a valid `T`, so it's aligned to `T`.
> +unsafe impl<T: AlwaysRefCounted + 'static> ForeignOwnable for ARef<T> {
This doesn't need to be static, if you can add `where Self: 'a` on `Borrowed`
and `BorrowedMut` instead.
Best,
Gary
> + const FOREIGN_ALIGN: usize = core::mem::align_of::<T>();
> +
> + type Borrowed<'a> = &'a T;
> + type BorrowedMut<'a> = &'a T;
> +
> + fn into_foreign(self) -> *mut c_void {
> + ARef::into_raw(self).as_ptr().cast()
> + }
> +
> + unsafe fn from_foreign(ptr: *mut c_void) -> Self {
> + // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
> + // call to `Self::into_foreign`.
> + let ptr = unsafe { NonNull::new_unchecked(ptr.cast()) };
> +
> + // SAFETY: `ptr` came from `into_foreign`, which consumed an `ARef` without decrementing
> + // the refcount, so we can transfer the ownership to the new `ARef`.
> + unsafe { ARef::from_raw(ptr) }
> + }
> +
> + unsafe fn borrow<'a>(ptr: *mut c_void) -> &'a T {
> + // SAFETY: The safety requirements of this method ensure that the object remains alive and
> + // immutable for the duration of 'a.
> + unsafe { &*ptr.cast() }
> + }
> +
> + unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> &'a T {
> + // SAFETY: The safety requirements for `borrow_mut` are a superset of the safety
> + // requirements for `borrow`.
> + unsafe { <Self as ForeignOwnable>::borrow(ptr) }
> + }
> +}
> +
> impl<T, U> PartialEq<&'_ U> for ARef<T>
> where
> T: AlwaysRefCounted + PartialEq<U>,
On Mon, Jul 27, 2026 at 11:53:55AM -0700, Ackerley Tng wrote:
> Hope you also had a chance to look at [1] that David Woodhouse is
> working on :)
>
> [1] https://lore.kernel.org/all/1dc299af6b795a40c8887b3d84f915024f6446a9.camel@…
Heh, that's awfully DMABUF like :)
So, if that happens then sure we can probably create a VFIO exporter
for it as well along side the DMABUF exporter Matt is working on and
that should handle the shared/private steps intel needs
Jason
On Tue, Aug 04, 2026 at 10:19:11AM -0600, Logan Gunthorpe wrote:
> There's a vague convention for this already: the term 'p2pmem' is often
> used for cases where the driver uses the allocator, etc. (I think I had
> this intention when I wrote the code and have since forgotten about
> it).
I've been calling it the genalloc layer and the core layer. p2pmem
would be OK to refer to the genalloc stuff. So if you want to have
CONFIG_PCI_P2PDMA and CONFIG_PCI_P2PMEM that seem sOk
> code into it's own file, potentially renaming some functions. Then, in
> the end, we would probably have a pcim_p2pdma_supported() function and a
> pcim_p2pmem_supported() function, the latter being used by existing use
> cases.
Not quite sure why we need this?
Matt, the mlx5 stuff is the same as VFIO, it just uses the "core"
layer and does not use the genalloc. So there shouldn't be an issue
here, if the genalloc is off then the mlx5 stuff should still
work. There shouldn't be a case where CONFIG_PCI_P2PDMA=y and mlx5 is
broken?
Did some of APIs get mixed into the genalloc family that should not
have?
Jason
Hi all,
The goal of this series is to enable userspace driver designs that use
VFIO to export DMABUFs representing subsets of PCI device BARs, and
"vend" those buffers from a primary process to other subordinate
processes by fd. These processes then mmap() the buffers and their
access to the device is isolated to the exported ranges. This is an
improvement on sharing the VFIO device fd to subordinate processes,
which would allow unfettered access.
This is achieved by enabling mmap() of vfio-pci DMABUFs, passed by fd
to subordinate processes. Second, a new revocation mechanism is added
to allow the primary process to forcibly revoke access to
previously-shared BAR spans, even if the subordinate processes haven't
cleanly exited.
(The related topic of safe delegation of iommufd control to the
subordinate processes is not addressed here, and is follow-up work.)
The background/rationale is covered in more detail in the RFC cover
letters.
Feedback from the RFCs requested that, instead of creating
DMABUF-specific vm_ops and .fault paths, to go the whole way and
migrate the existing VFIO PCI BAR mmap() to be backed by a DMABUF too,
resulting in a common vm_ops and fault handler for mmap()s of both the
VFIO device and explicitly-exported DMABUFs. This will help future
iommufd emulation of VFIO Type1 peer-to-peer, making it easier to get
a DMABUF for a VFIO BAR as a DMA target.
mmap() conversion to use DMABUF underneath has been done for vfio-pci,
but not sub-drivers:
nvgrace-gpu's mmap() override path is unchanged; I kept this out of
scope for now not least because I don't have a thorough test setup
for this system. I would prefer to help the nvgrace-gpu maintainers
enable BAR mmap() DMABUFs themselves.
Notes on patches
================
PCI/P2PDMA: Split pool-related cleanup out of pci_p2pdma_release()
PCI/P2PDMA: Add CONFIG_PCI_P2PDMA_CORE
Later in the series, vfio-pci's mmap() is going to depend on
pcim_p2pdma_provider() which depended on CONFIG_PCI_P2PDMA, which
in turn depended on ZONE_DEVICE. That isn't available on 32-bit
and some archs, because they lack MEMORY_HOTPLUG and friends.
VFIO does _not_ require actual P2P to be present for basic mmap()
functionality, only for the optional CONFIG_DMA_SHARED_BUFFER
feature.
These split out p2pdma_core.c under CONFIG_PCI_P2PDMA_CORE (which
currently contains pcim_p2pdma_provider()), and an optional
CONFIG_PCI_P2PDMA which depends on ZONE_DEVICE etc. providing
P2P functionality in the existing p2pdma.c. The first splits
out pool cleanup from the release path, and the second does the
refactor/code move to the new file.
vfio/pci: Add a helper to look up PFNs for DMABUFs
vfio/pci: Add a helper to create a DMABUF for a BAR-map VMA
The first adds a DMABUF VMA fault handler helper to determine
arbitrary-sized PFNs from ranges in DMABUF. The second refactors
DMABUF export for use by the existing export feature, and adds a
helper that creates a DMABUF corresponding to a VFIO BAR mmap()
request.
vfio/pci: Convert BAR mmap() to use a DMABUF
The vfio-pci core mmap() creates a DMABUF with the helper above,
and the vm_ops fault handler uses the other helper to resolve the
fault. Because this depends on DMABUF structs/code,
CONFIG_VFIO_PCI_CORE needs to depend on CONFIG_DMA_SHARED_BUFFER.
The CONFIG_VFIO_PCI_DMABUF still conditionally enables the export
support code.
NOTE: The user mmap()s a device fd, but the resulting VMA's vm_file
becomes that of the DMABUF. The DMABUF takes ownership of the
device file and put()s it on release, which maintains the existing
behaviour of a VMA keeping the VFIO device open.
BAR zapping then happens via the existing vfio_pci_dma_buf_move()
path, which now needs to unmap PTEs in the DMABUF's address_space.
vfio/pci: Provide a user-facing name for BAR mappings
There was a request for decent debug naming in /proc/<pid>/maps
etc. comparable to the existing VFIO names: since the VMAs are
DMABUFs, they have a "dmabuf:" prefix and can't be 100% identical
to before. This is a user-visible change, but this patch at least
now gives us extra info on the BDF & BAR being mapped.
vfio/pci: Clean up BAR zap and revocation
In general (see NOTE!) the vfio_pci_zap_bars() is now obsolete,
since it unmaps PTEs in the VFIO device address_space which is now
unused. This consolidates all calls (e.g. around reset) with the
neighbouring vfio_pci_dma_buf_move()s into new functions, to
revoke/unrevoke (making the steps clearer).
NOTE: Because drivers can use their own vm_ops and override .mmap,
the core must conservatively assume an overridden .mmap might still
add PTEs to the VFIO device address_space and therefore still does
the zap. A new flag, zap_bars_on_revoke, enables the zap when
.mmap is overridden. A driver that does not need the zap can clear
this to opt-out, e.g. if the driver calls down to the common mmap
(and so uses DMABUFs). hisi-acc-vfio-pci does just this, and thus
sets the opt-out flag.
vfio/pci: Support mmap() of a VFIO DMABUF
Adds mmap() for a DMABUF fd exported from vfio-pci.
It was a goal to keep the VFIO device fd lifetime behaviour
unchanged with respect to the DMABUFs. An application can close
all device fds, and this will revoke/clean up all DMABUFs; then, no
mappings or other access can be performed. When enabling mmap() of
the DMABUFs, this means access through the VMA is also revoked.
This complicates the fault handler because whilst the DMABUF
exists, it has no guarantee that the corresponding VFIO device is
still alive. Adds synchronisation ensuring the vdev is available
before vdev->memory_lock is touched; this holds the device
registration so that even if the buffer has been cleaned up, vdev
hasn't been freed and so the lock can be safely taken.
vfio/pci: Permanently revoke a DMABUF on request
This is mostly a rename of `revoked` to an enum, `status`, and
adding a third state for a buffer: usable, revoked temporary,
revoked permanent. A new VFIO feature is added,
VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE, which takes a DMABUF (exported
from the same device) and permanently revokes it. Thus a userspace
driver can guarantee any downstream consumers of a shared fd are
prevented from accessing a BAR range, and that range can be reused.
NOTE: This might block userspace, waiting on importers to detach.
The code doing revocation in vfio_pci_dma_buf_move() is moved, to a
common function for use by ..._move() and this new feature.
NOTE: See changelog, by request v4 added a condition to the
existing code to elide the unnecessary invalidation/sync on the
un-revoke path.)
NOTE: Previous versions contained an additional feature patch,
"vfio/pci: Add mmap() attributes to DMABUF feature". This has been
dropped in v5 because:
- The mechanism simply set vma->vm_page_prot. This would be
sufficient for arm64 and other architectures.
- However, (locally-run claude-opus-4-8) Sashiko flagged that, on
x86, additional memtype handling is required to set up the PAT.
Without this, the memtype is returned back to UC- by
pfnmap_setup_cachemode() upon PTE creation.
Most other sources of userspace WC mappings create PTEs eagerly with
e.g. io_remap_pfn_range() which memtype_reserve() WC for the range.
Getting them with lazy-fault used by vfio-pci is more complicated
(e.g. perhaps registering WC for BARs with PAT/MTRRs, and deciding how
to deal with aliasing...). Since this feature is not critical for
this series to be useful, I've decided for now to drop it in favour of
a simpler series now and revisiting this separ*ately.
Testing
=======
(The [RFC ONLY] userspace test program, for QEMU edu-plus, can be
found in the GitHub branch below. It at least illustrates how the
export, map, revoke, and close semantics interoperate.)
This code has been tested in mapping DMABUFs of single/multiple ranges
from multiple BARs, aliasing mmap()s, aliasing ranges across DMABUFs,
vm_pgoff > 0, revocation, shutdown/cleanup scenarios, and hugepage
mappings. No regressions observed on the VFIO selftests, or on our
internal vfio-pci applications. VFIO on i386 has been build-tested.
Dear Reviewers,
===============
I was grateful for the reviews and Reviewed-Bys on previous versions.
Thanks; I've added some Reviewed-Bys/Acks. I have NOT included your
tags where the patch has materially changed after your review (or
where requested changes ended up more than super-trivial). I hope
that's okay.
End
===
This is based on v7.2-rc3.
These commits are on GitHub for easier browsing, along with
"[RFC ONLY] selftests: vfio: Add standalone vfio_dmabuf_mmap_test":
https://github.com/metamev/linux/compare/v7.2-rc3...dev/mev/vfio-dmabuf-mma…
Thanks for reading,
Matt
================================================================================
Changelog:
v5:
- Rebased on 7.2-rc3
- Dropped the memattr/WC feature (see explanation above).
- "vfio/pci: Convert BAR mmap() to use a DMABUF": Fixed a
potentially-nasty bug (which (locally-run) Sashiko found!) whereby
the unmap_mapping_range() performed in cleanup was passed a range
up from offset zero for the DMABUF size. Initially this was how
all DMABUFs were created and an appropriate zap, but a new version
kept the VFIO region index encoded in the offset -- for BAR > 0 the
unmap span would then mismatch. Instead, pass size 0 to mean an
"all" range. Because the goal is to shoot down everything relating
to one DMABUF and the address_space can only contain things
relating to that DMABUF, this is equivalent and has the bonus of
never failing to match mappings...
Praan, Kevin, I kept your R-Bs on this fix.
- The revoke patch converts vfio_pci_dma_buf_cleanup()'s priv->vdev =
NULL to a WRITE_ONCE, corresponding to the revoke function's
READ_ONCE (performed to test that the VFIO and DMABUF are related).
- Clarified the VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE UAPI comments,
documenting previously-missing error cases and their reasons.
v4: https://lore.kernel.org/all/20260701171245.90111-1-matt@ozlabs.org/
v3: https://lore.kernel.org/all/20260610154327.37758-1-matt@ozlabs.org/
v2: https://lore.kernel.org/all/20260527102319.100128-1-mattev@meta.com/
v1: https://lore.kernel.org/kvm/20260416131815.2729131-1-mattev@meta.com/
RFCv2: https://lore.kernel.org/kvm/20260312184613.3710705-1-mattev@meta.com/
RFCv1: https://lore.kernel.org/all/20260226202211.929005-1-mattev@meta.com/
Tech topic: https://lore.kernel.org/linux-iommu/20250918214425.2677057-1-amastro@fb.com/
Matt Evans (9):
PCI/P2PDMA: Split pool-related cleanup out of pci_p2pdma_release()
PCI/P2PDMA: Add CONFIG_PCI_P2PDMA_CORE
vfio/pci: Add a helper to look up PFNs for DMABUFs
vfio/pci: Add a helper to create a DMABUF for a BAR-map VMA
vfio/pci: Convert BAR mmap() to use a DMABUF
vfio/pci: Provide a user-facing name for BAR mappings
vfio/pci: Clean up BAR zap and revocation
vfio/pci: Support mmap() of a VFIO DMABUF
vfio/pci: Permanently revoke a DMABUF on request
MAINTAINERS | 2 +-
drivers/pci/Kconfig | 5 +
drivers/pci/Makefile | 1 +
drivers/pci/p2pdma.c | 113 +---
drivers/pci/p2pdma.h | 29 +
drivers/pci/p2pdma_core.c | 122 +++++
drivers/vfio/pci/Kconfig | 5 +-
drivers/vfio/pci/Makefile | 3 +-
.../vfio/pci/hisilicon/hisi_acc_vfio_pci.c | 8 +
drivers/vfio/pci/vfio_pci_config.c | 30 +-
drivers/vfio/pci/vfio_pci_core.c | 210 +++++--
drivers/vfio/pci/vfio_pci_dmabuf.c | 515 +++++++++++++++---
drivers/vfio/pci/vfio_pci_priv.h | 53 +-
include/linux/pci-p2pdma.h | 24 +-
include/linux/pci.h | 2 +-
include/linux/vfio_pci_core.h | 1 +
include/uapi/linux/vfio.h | 25 +
17 files changed, 875 insertions(+), 273 deletions(-)
create mode 100644 drivers/pci/p2pdma.h
create mode 100644 drivers/pci/p2pdma_core.c
--
2.50.1 (Apple Git-155)
On Wed, 2026-08-05 at 10:50 +0200, Andreas Hindborg wrote:
> "Philipp Stanner" <phasta(a)kernel.org> writes:
>
> > One often cannot allocate in the kernel with the desired flags, most
> > notably in atomic context. Pre-allocating the memory is the preferred
> > solution in such situations.
> >
> > Add support for xa_reserve() in the Rust abstractions of xarray. Create
> > a Reservation object similar to a lock-guard, that can be dropped once
> > the reservation is no longer needed or once the index was stored to.
> >
> > Signed-off-by: Philipp Stanner <phasta(a)kernel.org>
> > ---
> > Please regard this more as an RFC.
> >
> > I need pre-allocating in XArray for DmaFence. How exactly we achieve
> > this is open for discussion.
>
> Do you need to actually reserve a key, or do you just need atomic
> allocation?
I would just have needed a position to store to, but the fence sequence
number would be the only reasonable index, so you'd also reserve a key.
Anyways, please forget about this for now, we abstained from using the
XArray in the current revision (v8) of this patch series.
Thx
P.
On Tue, 2026-08-04 at 14:54 -0300, Daniel Almeida wrote:
>
> Hi Phillip :)
>
> Tested-by: Daniel Almeida <daniel.almeida(a)collabora.com>
Hi, thx for the test
I address your major feedback below; minor points like renaming I will
address in the next revision.
>
> > On 31 Jul 2026, at 05:04, Philipp Stanner <phasta(a)kernel.org> wrote:
> >
[…]
> > An additional issue discovered during the review process of this code is
> > that there is (currently) no mechanism in Rust to prevent someone from
> > circumventing the DriverFence's FenceContext-reference's lifetime by
> > "forgetting" the fence, e.g. with core::mem::forget(). Since this
> > apparently can also happen with recfounting cycles, it's quite likely
> > that it would enable UAF bugs on the FenceContext. Print warnings if
> > this or other misuse of the fence API happens.
>
> I think cycles are fine, if anything they make things live longer than intended
> (possibly leaking them forever), but at no point they lead to UAFs. And for the
> mem::forget() point, there seems to be precedent in other patches pointing to
> unsafe constructors, where the safety requirement is basically "don't
> mem::forget() this".
>
> In fact, if you mem::forget() in the previous Arc approach, it seems like you leak
> the context, while mem::forget() on the current solution does seem to allow UAF
> by ending the borrow as you said yourself:
>
> let ctx = .... // FenceContext in some driver queue structure
> let fence = ctx.fence_alloc(...).new_fence() // DriverFence<'_, T> // borrows ctx
> mem::forget(fence); // ends the borrow
> drop(ctx); // DriverFenceData contains a dangling &FenceContext, and that allocation is managed by C
>
> versus:
>
> let ctx: Arc<FenceCtx<...>> = ...; // same as above, assume refcount==1
> let fence = ctx.new_fence_allocation(..).new_fence(); // ctx refcount==2
> mem::forget(fence); // ctx refcount==2
> drop(ctx) //ctx refcount==1
>
> I noticed that you added a counter to catch the first case, but that assumes that
> signaled fences won’t reach into the context anymore, IIUC? More on that below.
Answering on that further down below
>
> >
[…]
>
> SPDX is being used here,
>
> > +
> > +/*
> > + * Copyright (C) 2025, 2026 Red Hat Inc.:
> > + * Author: Philipp Stanner <pstanner(a)redhat.com>
> > + */
>
> So perhaps SPDX-CopyrightText should be used here?
What does that look like? I think I never saw it anywhere.
>
> > +
> >
[…]
>
> > + // happening.
> > + //
> > + // However, we cannot fully guarantee in Rust that `DriverFence`s will not
> > + // be forgotten, e.g., through refcounting. This could circumvent the
> > + // lifetime which intends to enforce that all fences disappear before their
> > + // context.
> > + nr_of_unsignaled_fences: Atomic<u64>,
>
> Why are we tracking the number of unsignaled fences, specifically? Is it not
> possible for the C side (which controls the actual allocation) to reach back
> into the Rust side via the callbacks even after the context drops, regardless
> of their signaled status?
Tracking the number was agreed on as a compromise to move the
abstraction forward. It only exists for a warning-print.
The signaled status is absolutely decisive for preventing that both the
DriverFence::data and FenceContext cannot be reached anymore by both C
*and* Rust code consuming a Fence.
The reason is that the fence backend ops can reach the DriverFence and
the FenceContext. Only signalling the fence decouples them, and then
you still have to wait for an RCU grace period to be sure that all
accessors are gone. This is what the C backend forces on us, but it
also applies for someone doing (future implementations of)
Fence::get_driver_name() or Fence::is_signaled().
>
> And in any case, even side stepping this signaled vs unsignaled dilemma that
> this counter is trying to check, the end result seems to be "sorry, you misused
> the API and now a UAF is possible". In this specific sense, it doesn't sound
> that much better than what we are trying to move away from in C.
>
> The more I think about this borrow design, the more I believe a simple refcount
> would be way safer. I mean, this field would go away to begin with, IIUC, and
> that’s not even considering the point above.
Refcounting does not solve the fundamental issue. A dma_fence must
always correctly represent the state of the associated job on the GPU.
If you forget a fence, you might deadlock. If you signal a fence for a
job that is still running on the GPU, you might get unnoticed memory
corruptions.
Refcounting the fctx was also my solution, but was objected to by
various parties (IIRC at least Boris and Danilo) who argue that the
life time is the proper solution. If I understood correctly the major
objection is that the refcount enables the device resources in
FenceContext::data to arbitrarily outlive its device, which is
something Danilo is very concerned about.
Anyways, as we discussed in the call, and as also my code comment in
FenceContext::drop() highlights, this atomic is only there for printing
a warning, because the proper solution we actually want is to have the
FenceContext signal all forgotten fences when it drops. *Then* you are
really completely safe, because then the forgotten fences get decoupled
from the fence context. So no UAF, although a driver that forgets
fences would still be broken.
The reason why (IIRC) Alice proposed doing the counter + warning and a
TODO entry is to move forward faster with the fence implementation,
which I understood is also in Tyr's interest (regarding this unlikely
bug).
The reason why it is not solved right now is that you need a data
structure in FenceContext that keeps track of unsignaled fences.
Entries in that data structure then have to be pre-allocated. And you
have to remove entries from the data structure *whenever a fence
signals*.
The only good data structure we have in Rust currently is XArray, which
we cannot use because:
* it uses `usize` as an index, but dma_fence seqno is u64, so this
could become a problem for Tyr, supporting 32-bit architectures.
* We'd need to wait for Andreas' reservation mechanism for XArray.
* XArray is not a good data structure for ever-increasing seqnos like
the u64 of dma_fence. It quickly performance-degrades because it
preserves index order, resulting in like a dozen pointer
indirections for large indices.
So I had investigated using a List, but the list would force you then
to shove another refcounting mechanism (ListArc) on top of the stored
fences, and Rust's list implementation is really not trivial to be
used. At least not for me. Getting this right would take time.
Note that with the JobQueue design we're aiming at right now,
DriverFence and FenceContext would all be owned by JobQueue, so the
driver couldn't ever forget a DriverFence whithout also forgetting the
FenceContext. Hence, for the forseeable future, no one will encounter
that bug.
So, long story short, this is a solvable TODO, but we need a good data
structure for it. Preferably a hash table? Or the list implementation
needs to be improved so that it can take an ARef<Fence> instead of a
ListArc<Fence>. But someone needs to do that work.
Please tell me whether you agree with proceeding like this and make
FenceContext::drop() completely waterproof later, or whether you want
to suggest to do that now – but then I'd need help with the data
structures.
>
>
> >
[…]
> > + /// The `data` you pass here must not perform any operations that are illegal
> > + /// in atomic context in its [`Drop`] implementation.
> > + pub fn fence_alloc(&self, data: T::FenceDataType) -> Result<DriverFenceAllocation<'_, T>> {
>
> ^ In the same spirit as the last iteration, can we please rename this?
>
> We don’t need to shorten methods and types IMHO. We can just say
> “new_allocation” or a some other variation without “alloc”.
Well, the name IMO needs to reflect that this method creates some fency
object. So just "new_allocation" is not good I think because you want
to see *what* is being allocated.
new_fence_allocation() maybe?
>
> >
[…]
> > +/// The receiving counterpart of a [`DriverFence`].
> > +///
> > +/// The Rust DMA fence implementation has a dualistic design: [`DriverFence`]s
> > +/// are the producer-side, intended to be always owned by only one party. That
> > +/// party has the monopoly on signalling the fence.
> > +///
> > +/// A [`Fence`] is the counterpart for consumers. Thus, [`Fence`]s are always
> > +/// refcounted and can shared with an arbitrary number of parties, including
> > +/// userspace. Hereby, a [`Fence`] can only be used for actions such as checking
> > +/// the fence's status or for registering callbacks on it.
> > +///
> > +/// Once the associated [`DriverFence`] signals, all
> > +/// [`FenceCallbackRegistration`]s registered on the [`Fence`] will be executed.
> > +///
> > +/// A [`Fence`] can arbitrarily outlive its [`DriverFence`] and the
> > +/// [`FenceContext`]. Signalling a [`DriverFence`] decouples it from its
> > +/// [`Fence`]s.
> > +#[repr(transparent)]
> > +pub struct Fence {
> > + /// The actual dma_fence passed to C.
> > + inner: Opaque<bindings::dma_fence>,
> > +}
> > +
> > +/// Guard helper for locking within this module.
>
> Is this new? Needs a bit more documentation.
It is new, yes. Changelog mentions it.
>
> OTOH I think we shouldn’t come up with a new guard type. IIRC from
> Lyude’s et al previous work, there’s already a way to build a Rust lock
> from a C lock (Lock::from_raw()). In fact, I think this whole implementation
> can boil down to:
>
> pub fn lock(&self) -> SpinLockIrqGuard<‘_, ()> {
> let ptr = unsafe {bindings::dma_fence_spinlock(…)};
> unsafe { SpinLockIrq::<()>::from_raw(ptr)}.lock()
> }
>
> This has a few advantages:
>
> a) doesn’t introduce its own guard type, instead reusing something that was
> previously tested,
>
> b) you get the right behavior with the included NotThreadSafe token.
>
> c) the guard is now borrowed. Your guard is owned, which can easily lead to UB
> because the lifetime is detached from the &self that originated it.
This little helper is only used internally, and where it is used other
code bits have to operate on the rawpointer with other unsafe blocks.
At other places we use the fence rawpointer without taking the lock. So
I'm not sure whether this will ever be clean.
The only reason I added it was that I by now had 3 places where I do
unsafe { } lock and unlock.
Lyude's code is not yet merged.
[…]
>
> > +///
> > +/// let mut fctx = KBox::pin_init(FenceContext::new(0, driver_name, timeline_name, fctx_data), GFP_KERNEL)?;
>
> Missing rustfmt?
I do run rustfmt. It doesn't do anything about this line.
P.
Hey there, fellow digital adventurers and keyboard warriors! If you’ve ever found yourself staring at a blank browser tab during a free period, wondering how to turn five minutes of boredom into a heart-pumping, reflex-testing, neon-soaked thrill ride, then pull up a chair. We need to talk about Slope Unblocked.
You might have seen it. You might have even played it on a friend’s laptop when the teacher wasn’t looking. But let me tell you, this isn’t just another endless runner. This is a beautiful, chaotic, and surprisingly deep test of your spatial awareness, your reaction time, and your ability to stay calm while a glowing ball hurtles down a digital death trap at Mach speed. And the best part? You can access it right now for free at slopefree.org, no downloads, no logins, just pure unadulterated momentum.
So, grab your favorite beverage, get comfortable, and let’s take a deep dive into why this seemingly simple game has become a cultural phenomenon in schools, offices, and anywhere else with a strict firewall and a weak spot for addictive gameplay.
Visit: https://slopefree.org/
1. How to Play Slope Unblocked
Alright, let’s get down to business. How do you actually play this thing? I promise it’s easier than it looks, but mastering it is another story entirely.
The Core Mechanic
The entire game is controlled with just two keys (or one, if you’re feeling lazy). You use the Left Arrow and Right Arrow keys (or the A and D keys) to steer the ball. That’s it. There’s no jump button, no boost, no brake. Once you start, you’re committed to the roll until you either hit a red block or fly off the edge into the void.
The Art of Steering
The first mistake everyone makes is treating the game like a racing game. You don’t want to "correct" your path. You want to make smooth, sweeping adjustments. The ball has momentum and inertia. If you tap the right arrow, the ball starts drifting right. If you hold it, you’ll curve sharply. The key is to look ahead of the ball, not at it. Your eyes should be focused on the middle-distance, scanning for the next cluster of obstacles.
The Obstacles
The world of Slope is a harsh place. You’ll encounter two main types of hazards:
Red Blocks: These are solid, geometric barriers. Hitting one is instant death. They come in various sizes and configurations, sometimes forming narrow corridors, sometimes scattered randomly like a minefield.
The Void: The path has no guardrails. If you oversteer or mistime a turn, you’ll slip off the edge into the abyss below. This is actually more common than hitting a block, especially at higher speeds.
Reading the Path
The path isn't just flat. It tilts. Sometimes you’ll go over a hump, which sends you airborne for a split second. This is terrifying because you have no control while in the air. The best advice is to keep your ball steady during these moments, as landing off-center can spin you out. The floor also has a subtle purple/blue grid that gets dizzying if you stare too long. Focus on the solid colors and the red blocks.
2. Top Tips and Tricks from a Veteran Roller
Alright, you’ve got the basics. You know how to steer. But you want to actually get a high score, right? You want to last more than a minute without spiraling off into the neon void. Here are some battle-tested tips that I’ve picked up from losing hours of my life to this beautiful game.
Tip 1: Listen to Your Ears
This is the most underrated tip in the game. Yes, the music is a driving synthwave track that fits the aesthetic perfectly. But the sound effects are your best friend. The ball makes a rolling sound that gets faster and breaks up when you hit a bump. More importantly, listening helps with anticipation. You can hear the rhythm of the track, which surprisingly syncs up with the flow of the level in the early stages. Take your headphones off at your own risk.
Tip 2: Use the Full Width of the Track
Many beginners instinctively stay in the center. This is a fatal error. The center is full of blocks. The edges are your friend. Try to weave in a sine-wave pattern across the width of the path. This gives you more room to maneuver around obstacles. When you see a block coming, don’t panic. Steer wide around it, swing to the opposite side, and then come back to the middle. Being comfortable on the edge of the void is key to going far.
Tip 3: Small Taps, Not Long Presses
Huge sweeping movements will kill you. If the ball is drifting slightly left and you need to go right, do a quick tap. The less time you spend holding the key, the more stable your trajectory. The game is about finesse, not brute force. Think of it like steering a shopping cart; if you yank the wheel too hard, you’re going to tip over.
Tip 4: When in Doubt, Speed Up
This sounds counter-intuitive, but I’ve found it to be true. The game speeds up over time regardless, but if you are coming out of a turn and you have a clear straightaway, let it roll. Don’t try to slow down (you can’t) and don’t try to brake. Slower speeds make you feel like you have control, but actually, dragging the ball makes it twitchy. Trust the momentum and keep it flowing.
Tip 5: Master the "Wiggle"
Once you get to high scores (200+), the path becomes incredibly cramped. You’ll have to navigate slalom courses that seem impossible. The secret is to use the "wiggle" technique. This is where you tap left and right rapidly to thread the needle through tight gaps. It looks frantic, but it allows you to make micro-adjustments without committing to a full turn.
3. Ready to Roll?
So, there you have it. The lowdown on one of the greatest browser games ever conceived. Whether you’re looking to set a new personal best, show off to your friends, or just want to feel the wind in your digital hair while navigating a geometric nightmare, Slope Unblocked has got you covered.
Don’t just take my word for it. The proof is in the rolling.
If you’re stuck at your desk right now, bored out of your mind, do yourself a favor. Open a new tab. Head over to Slope Unblocked. Click play. And try not to blink. I guarantee that by your third run, you’ll be hooked. Go ahead, see how long you can last. I’ll be waiting at the top of the high-score table. Or, more likely, I’ll be falling off the edge right next to you.
See you on the neon track!
Have any amazing high scores? Or a story about getting caught playing this during class? Drop a comment below. I want to hear your chaos!
Visit: https://slopefree.org/
Hey there, fellow digital adventurers and keyboard warriors! If you’ve ever found yourself staring at a blank browser tab during a free period, wondering how to turn five minutes of boredom into a heart-pumping, reflex-testing, neon-soaked thrill ride, then pull up a chair. We need to talk about Slope Unblocked.
You might have seen it. You might have even played it on a friend’s laptop when the teacher wasn’t looking. But let me tell you, this isn’t just another endless runner. This is a beautiful, chaotic, and surprisingly deep test of your spatial awareness, your reaction time, and your ability to stay calm while a glowing ball hurtles down a digital death trap at Mach speed. And the best part? You can access it right now for free at slopefree.org, no downloads, no logins, just pure unadulterated momentum.
So, grab your favorite beverage, get comfortable, and let’s take a deep dive into why this seemingly simple game has become a cultural phenomenon in schools, offices, and anywhere else with a strict firewall and a weak spot for addictive gameplay.
Visit: https://slopefree.org/
1. How to Play Slope Unblocked
Before we get into the nitty-gritty, let’s define our subject. Slope Unblocked is a 3D endless runner game where you control a glowing ball rolling down an endless, procedurally generated corridor. The path is tilted, twisting, and full of obstacles. Your job? Don’t crash. That’s it. That’s the whole game.
But here’s the kicker: the game speeds up the further you go. What starts as a leisurely roll down a geometric rainbow quickly becomes a white-knuckle, split-second decision-making simulator. The camera is positioned behind the ball, giving you a slightly elevated third-person perspective. The aesthetic is pure neon wireframe, think Tron legacy if it was designed by a minimalist with a love for 80s synthwave.
Why is it so popular? It’s accessible. You don’t need a gaming PC. You don’t need to create an account. You just open a tab, click, and you’re rolling. It’s the digital equivalent of a stress ball, but way more fun and with a lot more flying off the edge of a digital cliff.
2. How to Play Slope Unblocked
Alright, let’s get down to business. How do you actually play this thing? I promise it’s easier than it looks, but mastering it is another story entirely.
The Core Mechanic
The entire game is controlled with just two keys (or one, if you’re feeling lazy). You use the Left Arrow and Right Arrow keys (or the A and D keys) to steer the ball. That’s it. There’s no jump button, no boost, no brake. Once you start, you’re committed to the roll until you either hit a red block or fly off the edge into the void.
The Art of Steering
The first mistake everyone makes is treating the game like a racing game. You don’t want to "correct" your path. You want to make smooth, sweeping adjustments. The ball has momentum and inertia. If you tap the right arrow, the ball starts drifting right. If you hold it, you’ll curve sharply. The key is to look ahead of the ball, not at it. Your eyes should be focused on the middle-distance, scanning for the next cluster of obstacles.
The Obstacles
The world of Slope is a harsh place. You’ll encounter two main types of hazards:
Red Blocks: These are solid, geometric barriers. Hitting one is instant death. They come in various sizes and configurations, sometimes forming narrow corridors, sometimes scattered randomly like a minefield.
The Void: The path has no guardrails. If you oversteer or mistime a turn, you’ll slip off the edge into the abyss below. This is actually more common than hitting a block, especially at higher speeds.
Reading the Path
The path isn't just flat. It tilts. Sometimes you’ll go over a hump, which sends you airborne for a split second. This is terrifying because you have no control while in the air. The best advice is to keep your ball steady during these moments, as landing off-center can spin you out. The floor also has a subtle purple/blue grid that gets dizzying if you stare too long. Focus on the solid colors and the red blocks.
3. Top Tips and Tricks from a Veteran Roller
Alright, you’ve got the basics. You know how to steer. But you want to actually get a high score, right? You want to last more than a minute without spiraling off into the neon void. Here are some battle-tested tips that I’ve picked up from losing hours of my life to this beautiful game.
Tip 1: Listen to Your Ears
This is the most underrated tip in the game. Yes, the music is a driving synthwave track that fits the aesthetic perfectly. But the sound effects are your best friend. The ball makes a rolling sound that gets faster and breaks up when you hit a bump. More importantly, listening helps with anticipation. You can hear the rhythm of the track, which surprisingly syncs up with the flow of the level in the early stages. Take your headphones off at your own risk.
Tip 2: Use the Full Width of the Track
Many beginners instinctively stay in the center. This is a fatal error. The center is full of blocks. The edges are your friend. Try to weave in a sine-wave pattern across the width of the path. This gives you more room to maneuver around obstacles. When you see a block coming, don’t panic. Steer wide around it, swing to the opposite side, and then come back to the middle. Being comfortable on the edge of the void is key to going far.
Tip 3: Small Taps, Not Long Presses
Huge sweeping movements will kill you. If the ball is drifting slightly left and you need to go right, do a quick tap. The less time you spend holding the key, the more stable your trajectory. The game is about finesse, not brute force. Think of it like steering a shopping cart; if you yank the wheel too hard, you’re going to tip over.
Tip 4: When in Doubt, Speed Up
This sounds counter-intuitive, but I’ve found it to be true. The game speeds up over time regardless, but if you are coming out of a turn and you have a clear straightaway, let it roll. Don’t try to slow down (you can’t) and don’t try to brake. Slower speeds make you feel like you have control, but actually, dragging the ball makes it twitchy. Trust the momentum and keep it flowing.
Tip 5: Master the "Wiggle"
Once you get to high scores (200+), the path becomes incredibly cramped. You’ll have to navigate slalom courses that seem impossible. The secret is to use the "wiggle" technique. This is where you tap left and right rapidly to thread the needle through tight gaps. It looks frantic, but it allows you to make micro-adjustments without committing to a full turn.
4. Ready to Roll?
So, there you have it. The lowdown on one of the greatest browser games ever conceived. Whether you’re looking to set a new personal best, show off to your friends, or just want to feel the wind in your digital hair while navigating a geometric nightmare, Slope Unblocked has got you covered.
Don’t just take my word for it. The proof is in the rolling.
If you’re stuck at your desk right now, bored out of your mind, do yourself a favor. Open a new tab. Head over to Slope Unblocked. Click play. And try not to blink. I guarantee that by your third run, you’ll be hooked. Go ahead, see how long you can last. I’ll be waiting at the top of the high-score table. Or, more likely, I’ll be falling off the edge right next to you.
See you on the neon track!
Have any amazing high scores? Or a story about getting caught playing this during class? Drop a comment below. I want to hear your chaos!
Visit: https://slopefree.org/