In order to prevent possible hangs, if the fence is not signaled for more than 10 seconds, force the fence to expire by being signaled. Signed-off-by: Maíra Canal <mcanal@xxxxxxxxxx> --- drivers/gpu/drm/rustgem/fence.rs | 31 +++++++++++++++++++++++++++++-- drivers/gpu/drm/rustgem/file.rs | 7 +++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rustgem/fence.rs b/drivers/gpu/drm/rustgem/fence.rs index 9ef1399548e2..eb1d7faa7e8e 100644 --- a/drivers/gpu/drm/rustgem/fence.rs +++ b/drivers/gpu/drm/rustgem/fence.rs @@ -2,10 +2,13 @@ use core::fmt::Write; use core::ops::Deref; -use kernel::c_str; +use core::time::Duration; use kernel::dma_fence::*; use kernel::prelude::*; use kernel::sync::Arc; +use kernel::time::timer::*; +use kernel::time::*; +use kernel::{bindings, c_str, timer_init}; static QUEUE_NAME: &CStr = c_str!("vgem_fence"); static QUEUE_CLASS_KEY: kernel::sync::LockClassKey = kernel::sync::LockClassKey::new(); @@ -36,6 +39,7 @@ impl FenceOps for Fence { pub(crate) struct VgemFence { fence: Arc<UniqueFence<Fence>>, + _timer: Box<FnTimer<Box<dyn FnMut() -> Result<Next> + Sync>>>, } impl VgemFence { @@ -43,7 +47,30 @@ impl VgemFence { let fence_ctx = FenceContexts::new(1, QUEUE_NAME, &QUEUE_CLASS_KEY)?; let fence = Arc::try_new(fence_ctx.new_fence(0, Fence {})?)?; - Ok(Self { fence }) + // SAFETY: The caller calls [`FnTimer::init_timer`] before using the timer. + let t = Box::try_new(unsafe { + FnTimer::new(Box::try_new({ + let fence = fence.clone(); + move || { + let _ = fence.signal(); + Ok(Next::Done) + } + })? as Box<_>) + })?; + + // SAFETY: As FnTimer is inside a Box, it won't be moved. + let ptr = unsafe { core::pin::Pin::new_unchecked(&*t) }; + + timer_init!(ptr, 0, "vgem_timer"); + + // SAFETY: Duration.as_millis() returns a valid total number of whole milliseconds. + let timeout = + unsafe { bindings::msecs_to_jiffies(Duration::from_secs(10).as_millis().try_into()?) }; + + // We force the fence to expire within 10s to prevent driver hangs + ptr.raw_timer().schedule_at(jiffies_later(timeout)); + + Ok(Self { fence, _timer: t }) } } diff --git a/drivers/gpu/drm/rustgem/file.rs b/drivers/gpu/drm/rustgem/file.rs index 2552c7892b0e..a3714e8ca206 100644 --- a/drivers/gpu/drm/rustgem/file.rs +++ b/drivers/gpu/drm/rustgem/file.rs @@ -33,6 +33,10 @@ impl File { /// via the dma-buf reservation object and visible to consumers of the exported /// dma-buf. /// + /// This returns the handle for the new fence that must be signaled within 10 + /// seconds (or otherwise it will automatically expire). See + /// signal (DRM_IOCTL_VGEM_FENCE_SIGNAL). + /// /// If the vGEM handle does not exist, attach returns -ENOENT. /// pub(crate) fn attach( @@ -84,6 +88,9 @@ impl File { /// Signal and consume a fence earlier attached to a vGEM handle using /// attach (DRM_IOCTL_VGEM_FENCE_ATTACH). /// + /// All fences must be signaled within 10s of attachment or otherwise they + /// will automatically expire (and signal returns -ETIMEDOUT). + /// /// Signaling a fence indicates to all consumers of the dma-buf that the /// client has completed the operation associated with the fence, and that the /// buffer is then ready for consumption. -- 2.39.2